dhcp4_parser.yy 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814
  1. /* Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
  2. This Source Code Form is subject to the terms of the Mozilla Public
  3. License, v. 2.0. If a copy of the MPL was not distributed with this
  4. file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. %skeleton "lalr1.cc" /* -*- C++ -*- */
  6. %require "3.0.0"
  7. %defines
  8. %define parser_class_name {Dhcp4Parser}
  9. %define api.prefix {parser4_}
  10. %define api.token.constructor
  11. %define api.value.type variant
  12. %define api.namespace {isc::dhcp}
  13. %define parse.assert
  14. %code requires
  15. {
  16. #include <string>
  17. #include <cc/data.h>
  18. #include <dhcp/option.h>
  19. #include <boost/lexical_cast.hpp>
  20. #include <dhcp4/parser_context_decl.h>
  21. using namespace isc::dhcp;
  22. using namespace isc::data;
  23. using namespace std;
  24. }
  25. // The parsing context.
  26. %param { isc::dhcp::Parser4Context& ctx }
  27. %locations
  28. %define parse.trace
  29. %define parse.error verbose
  30. %code
  31. {
  32. #include <dhcp4/parser_context.h>
  33. }
  34. %define api.token.prefix {TOKEN_}
  35. // Tokens in an order which makes sense and related to the intented use.
  36. // Actual regexps for tokens are defined in dhcp4_lexer.ll.
  37. %token
  38. END 0 "end of file"
  39. COMMA ","
  40. COLON ":"
  41. LSQUARE_BRACKET "["
  42. RSQUARE_BRACKET "]"
  43. LCURLY_BRACKET "{"
  44. RCURLY_BRACKET "}"
  45. NULL_TYPE "null"
  46. DHCP4 "Dhcp4"
  47. INTERFACES_CONFIG "interfaces-config"
  48. INTERFACES "interfaces"
  49. DHCP_SOCKET_TYPE "dhcp-socket-type"
  50. RAW "raw"
  51. UDP "udp"
  52. RE_DETECT "re-detect"
  53. ECHO_CLIENT_ID "echo-client-id"
  54. MATCH_CLIENT_ID "match-client-id"
  55. NEXT_SERVER "next-server"
  56. SERVER_HOSTNAME "server-hostname"
  57. BOOT_FILE_NAME "boot-file-name"
  58. LEASE_DATABASE "lease-database"
  59. HOSTS_DATABASE "hosts-database"
  60. TYPE "type"
  61. MEMFILE "memfile"
  62. MYSQL "mysql"
  63. POSTGRESQL "postgresql"
  64. CQL "cql"
  65. USER "user"
  66. PASSWORD "password"
  67. HOST "host"
  68. PORT "port"
  69. PERSIST "persist"
  70. LFC_INTERVAL "lfc-interval"
  71. READONLY "readonly"
  72. CONNECT_TIMEOUT "connect-timeout"
  73. CONTACT_POINTS "contact-points"
  74. KEYSPACE "keyspace"
  75. VALID_LIFETIME "valid-lifetime"
  76. RENEW_TIMER "renew-timer"
  77. REBIND_TIMER "rebind-timer"
  78. DECLINE_PROBATION_PERIOD "decline-probation-period"
  79. SUBNET4 "subnet4"
  80. SUBNET_4O6_INTERFACE "4o6-interface"
  81. SUBNET_4O6_INTERFACE_ID "4o6-interface-id"
  82. SUBNET_4O6_SUBNET "4o6-subnet"
  83. OPTION_DEF "option-def"
  84. OPTION_DATA "option-data"
  85. NAME "name"
  86. DATA "data"
  87. CODE "code"
  88. SPACE "space"
  89. CSV_FORMAT "csv-format"
  90. ALWAYS_SEND "always-send"
  91. RECORD_TYPES "record-types"
  92. ENCAPSULATE "encapsulate"
  93. ARRAY "array"
  94. POOLS "pools"
  95. POOL "pool"
  96. USER_CONTEXT "user-context"
  97. SUBNET "subnet"
  98. INTERFACE "interface"
  99. INTERFACE_ID "interface-id"
  100. ID "id"
  101. RAPID_COMMIT "rapid-commit"
  102. RESERVATION_MODE "reservation-mode"
  103. DISABLED "disabled"
  104. OUT_OF_POOL "out-of-pool"
  105. ALL "all"
  106. HOST_RESERVATION_IDENTIFIERS "host-reservation-identifiers"
  107. CLIENT_CLASSES "client-classes"
  108. TEST "test"
  109. CLIENT_CLASS "client-class"
  110. RESERVATIONS "reservations"
  111. DUID "duid"
  112. HW_ADDRESS "hw-address"
  113. CIRCUIT_ID "circuit-id"
  114. CLIENT_ID "client-id"
  115. HOSTNAME "hostname"
  116. FLEX_ID "flex-id"
  117. RELAY "relay"
  118. IP_ADDRESS "ip-address"
  119. HOOKS_LIBRARIES "hooks-libraries"
  120. LIBRARY "library"
  121. PARAMETERS "parameters"
  122. EXPIRED_LEASES_PROCESSING "expired-leases-processing"
  123. RECLAIM_TIMER_WAIT_TIME "reclaim-timer-wait-time"
  124. FLUSH_RECLAIMED_TIMER_WAIT_TIME "flush-reclaimed-timer-wait-time"
  125. HOLD_RECLAIMED_TIME "hold-reclaimed-time"
  126. MAX_RECLAIM_LEASES "max-reclaim-leases"
  127. MAX_RECLAIM_TIME "max-reclaim-time"
  128. UNWARNED_RECLAIM_CYCLES "unwarned-reclaim-cycles"
  129. DHCP4O6_PORT "dhcp4o6-port"
  130. CONTROL_SOCKET "control-socket"
  131. SOCKET_TYPE "socket-type"
  132. SOCKET_NAME "socket-name"
  133. DHCP_DDNS "dhcp-ddns"
  134. ENABLE_UPDATES "enable-updates"
  135. QUALIFYING_SUFFIX "qualifying-suffix"
  136. SERVER_IP "server-ip"
  137. SERVER_PORT "server-port"
  138. SENDER_IP "sender-ip"
  139. SENDER_PORT "sender-port"
  140. MAX_QUEUE_SIZE "max-queue-size"
  141. NCR_PROTOCOL "ncr-protocol"
  142. NCR_FORMAT "ncr-format"
  143. ALWAYS_INCLUDE_FQDN "always-include-fqdn"
  144. OVERRIDE_NO_UPDATE "override-no-update"
  145. OVERRIDE_CLIENT_UPDATE "override-client-update"
  146. REPLACE_CLIENT_NAME "replace-client-name"
  147. GENERATED_PREFIX "generated-prefix"
  148. TCP "tcp"
  149. JSON "JSON"
  150. WHEN_PRESENT "when-present"
  151. NEVER "never"
  152. ALWAYS "always"
  153. WHEN_NOT_PRESENT "when-not-present"
  154. LOGGING "Logging"
  155. LOGGERS "loggers"
  156. OUTPUT_OPTIONS "output_options"
  157. OUTPUT "output"
  158. DEBUGLEVEL "debuglevel"
  159. SEVERITY "severity"
  160. FLUSH "flush"
  161. MAXSIZE "maxsize"
  162. MAXVER "maxver"
  163. DHCP6 "Dhcp6"
  164. DHCPDDNS "DhcpDdns"
  165. CONTROL_AGENT "Control-agent"
  166. // Not real tokens, just a way to signal what the parser is expected to
  167. // parse.
  168. TOPLEVEL_JSON
  169. TOPLEVEL_DHCP4
  170. SUB_DHCP4
  171. SUB_INTERFACES4
  172. SUB_SUBNET4
  173. SUB_POOL4
  174. SUB_RESERVATION
  175. SUB_OPTION_DEF
  176. SUB_OPTION_DATA
  177. SUB_HOOKS_LIBRARY
  178. SUB_DHCP_DDNS
  179. ;
  180. %token <std::string> STRING "constant string"
  181. %token <int64_t> INTEGER "integer"
  182. %token <double> FLOAT "floating point"
  183. %token <bool> BOOLEAN "boolean"
  184. %type <ElementPtr> value
  185. %type <ElementPtr> map_value
  186. %type <ElementPtr> socket_type
  187. %type <ElementPtr> db_type
  188. %type <ElementPtr> hr_mode
  189. %type <ElementPtr> ncr_protocol_value
  190. %type <ElementPtr> replace_client_name_value
  191. %printer { yyoutput << $$; } <*>;
  192. %%
  193. // The whole grammar starts with a map, because the config file
  194. // consists of Dhcp, Logger and DhcpDdns entries in one big { }.
  195. // We made the same for subparsers at the exception of the JSON value.
  196. %start start;
  197. start: TOPLEVEL_JSON { ctx.ctx_ = ctx.NO_KEYWORD; } sub_json
  198. | TOPLEVEL_DHCP4 { ctx.ctx_ = ctx.CONFIG; } syntax_map
  199. | SUB_DHCP4 { ctx.ctx_ = ctx.DHCP4; } sub_dhcp4
  200. | SUB_INTERFACES4 { ctx.ctx_ = ctx.INTERFACES_CONFIG; } sub_interfaces4
  201. | SUB_SUBNET4 { ctx.ctx_ = ctx.SUBNET4; } sub_subnet4
  202. | SUB_POOL4 { ctx.ctx_ = ctx.POOLS; } sub_pool4
  203. | SUB_RESERVATION { ctx.ctx_ = ctx.RESERVATIONS; } sub_reservation
  204. | SUB_OPTION_DEF { ctx.ctx_ = ctx.OPTION_DEF; } sub_option_def
  205. | SUB_OPTION_DATA { ctx.ctx_ = ctx.OPTION_DATA; } sub_option_data
  206. | SUB_HOOKS_LIBRARY { ctx.ctx_ = ctx.HOOKS_LIBRARIES; } sub_hooks_library
  207. | SUB_DHCP_DDNS { ctx.ctx_ = ctx.DHCP_DDNS; } sub_dhcp_ddns
  208. ;
  209. // ---- generic JSON parser ---------------------------------
  210. // Note that ctx_ is NO_KEYWORD here
  211. // Values rule
  212. value: INTEGER { $$ = ElementPtr(new IntElement($1, ctx.loc2pos(@1))); }
  213. | FLOAT { $$ = ElementPtr(new DoubleElement($1, ctx.loc2pos(@1))); }
  214. | BOOLEAN { $$ = ElementPtr(new BoolElement($1, ctx.loc2pos(@1))); }
  215. | STRING { $$ = ElementPtr(new StringElement($1, ctx.loc2pos(@1))); }
  216. | NULL_TYPE { $$ = ElementPtr(new NullElement(ctx.loc2pos(@1))); }
  217. | map2 { $$ = ctx.stack_.back(); ctx.stack_.pop_back(); }
  218. | list_generic { $$ = ctx.stack_.back(); ctx.stack_.pop_back(); }
  219. ;
  220. sub_json: value {
  221. // Push back the JSON value on the stack
  222. ctx.stack_.push_back($1);
  223. };
  224. map2: LCURLY_BRACKET {
  225. // This code is executed when we're about to start parsing
  226. // the content of the map
  227. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  228. ctx.stack_.push_back(m);
  229. } map_content RCURLY_BRACKET {
  230. // map parsing completed. If we ever want to do any wrap up
  231. // (maybe some sanity checking), this would be the best place
  232. // for it.
  233. };
  234. map_value: map2 { $$ = ctx.stack_.back(); ctx.stack_.pop_back(); };
  235. // Assignments rule
  236. map_content: %empty // empty map
  237. | not_empty_map
  238. ;
  239. not_empty_map: STRING COLON value {
  240. // map containing a single entry
  241. ctx.stack_.back()->set($1, $3);
  242. }
  243. | not_empty_map COMMA STRING COLON value {
  244. // map consisting of a shorter map followed by
  245. // comma and string:value
  246. ctx.stack_.back()->set($3, $5);
  247. }
  248. ;
  249. list_generic: LSQUARE_BRACKET {
  250. ElementPtr l(new ListElement(ctx.loc2pos(@1)));
  251. ctx.stack_.push_back(l);
  252. } list_content RSQUARE_BRACKET {
  253. // list parsing complete. Put any sanity checking here
  254. };
  255. list_content: %empty // Empty list
  256. | not_empty_list
  257. ;
  258. not_empty_list: value {
  259. // List consisting of a single element.
  260. ctx.stack_.back()->add($1);
  261. }
  262. | not_empty_list COMMA value {
  263. // List ending with , and a value.
  264. ctx.stack_.back()->add($3);
  265. }
  266. ;
  267. // This one is used in syntax parser and is restricted to strings.
  268. list_strings: LSQUARE_BRACKET {
  269. // List parsing about to start
  270. } list_strings_content RSQUARE_BRACKET {
  271. // list parsing complete. Put any sanity checking here
  272. //ctx.stack_.pop_back();
  273. };
  274. list_strings_content: %empty // Empty list
  275. | not_empty_list_strings
  276. ;
  277. not_empty_list_strings: STRING {
  278. ElementPtr s(new StringElement($1, ctx.loc2pos(@1)));
  279. ctx.stack_.back()->add(s);
  280. }
  281. | not_empty_list_strings COMMA STRING {
  282. ElementPtr s(new StringElement($3, ctx.loc2pos(@3)));
  283. ctx.stack_.back()->add(s);
  284. }
  285. ;
  286. // ---- generic JSON parser ends here ----------------------------------
  287. // ---- syntax checking parser starts here -----------------------------
  288. // Unknown keyword in a map
  289. unknown_map_entry: STRING COLON {
  290. const std::string& where = ctx.contextName();
  291. const std::string& keyword = $1;
  292. error(@1,
  293. "got unexpected keyword \"" + keyword + "\" in " + where + " map.");
  294. };
  295. // This defines the top-level { } that holds Control-agent, Dhcp6, Dhcp4,
  296. // DhcpDdns or Logging objects.
  297. syntax_map: LCURLY_BRACKET {
  298. // This code is executed when we're about to start parsing
  299. // the content of the map
  300. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  301. ctx.stack_.push_back(m);
  302. } global_objects RCURLY_BRACKET {
  303. // map parsing completed. If we ever want to do any wrap up
  304. // (maybe some sanity checking), this would be the best place
  305. // for it.
  306. };
  307. // This represents top-level entries: Control-agent, Dhcp6, Dhcp4,
  308. // DhcpDdns, Logging
  309. global_objects: global_object
  310. | global_objects COMMA global_object
  311. ;
  312. // This represents a single top level entry, e.g. Dhcp4 or DhcpDdns.
  313. global_object: dhcp4_object
  314. | logging_object
  315. | dhcp6_json_object
  316. | dhcpddns_json_object
  317. | control_agent_json_object
  318. | unknown_map_entry
  319. ;
  320. dhcp4_object: DHCP4 {
  321. // This code is executed when we're about to start parsing
  322. // the content of the map
  323. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  324. ctx.stack_.back()->set("Dhcp4", m);
  325. ctx.stack_.push_back(m);
  326. ctx.enter(ctx.DHCP4);
  327. } COLON LCURLY_BRACKET global_params RCURLY_BRACKET {
  328. // map parsing completed. If we ever want to do any wrap up
  329. // (maybe some sanity checking), this would be the best place
  330. // for it.
  331. ctx.stack_.pop_back();
  332. ctx.leave();
  333. };
  334. // subparser: similar to the corresponding rule but without parent
  335. // so the stack is empty at the rule entry.
  336. sub_dhcp4: LCURLY_BRACKET {
  337. // Parse the Dhcp4 map
  338. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  339. ctx.stack_.push_back(m);
  340. } global_params RCURLY_BRACKET {
  341. // parsing completed
  342. };
  343. global_params: global_param
  344. | global_params COMMA global_param
  345. ;
  346. // These are the parameters that are allowed in the top-level for
  347. // Dhcp4.
  348. global_param: valid_lifetime
  349. | renew_timer
  350. | rebind_timer
  351. | decline_probation_period
  352. | subnet4_list
  353. | interfaces_config
  354. | lease_database
  355. | hosts_database
  356. | host_reservation_identifiers
  357. | client_classes
  358. | option_def_list
  359. | option_data_list
  360. | hooks_libraries
  361. | expired_leases_processing
  362. | dhcp4o6_port
  363. | control_socket
  364. | dhcp_ddns
  365. | echo_client_id
  366. | match_client_id
  367. | next_server
  368. | unknown_map_entry
  369. ;
  370. valid_lifetime: VALID_LIFETIME COLON INTEGER {
  371. ElementPtr prf(new IntElement($3, ctx.loc2pos(@3)));
  372. ctx.stack_.back()->set("valid-lifetime", prf);
  373. };
  374. renew_timer: RENEW_TIMER COLON INTEGER {
  375. ElementPtr prf(new IntElement($3, ctx.loc2pos(@3)));
  376. ctx.stack_.back()->set("renew-timer", prf);
  377. };
  378. rebind_timer: REBIND_TIMER COLON INTEGER {
  379. ElementPtr prf(new IntElement($3, ctx.loc2pos(@3)));
  380. ctx.stack_.back()->set("rebind-timer", prf);
  381. };
  382. decline_probation_period: DECLINE_PROBATION_PERIOD COLON INTEGER {
  383. ElementPtr dpp(new IntElement($3, ctx.loc2pos(@3)));
  384. ctx.stack_.back()->set("decline-probation-period", dpp);
  385. };
  386. echo_client_id: ECHO_CLIENT_ID COLON BOOLEAN {
  387. ElementPtr echo(new BoolElement($3, ctx.loc2pos(@3)));
  388. ctx.stack_.back()->set("echo-client-id", echo);
  389. };
  390. match_client_id: MATCH_CLIENT_ID COLON BOOLEAN {
  391. ElementPtr match(new BoolElement($3, ctx.loc2pos(@3)));
  392. ctx.stack_.back()->set("match-client-id", match);
  393. };
  394. interfaces_config: INTERFACES_CONFIG {
  395. ElementPtr i(new MapElement(ctx.loc2pos(@1)));
  396. ctx.stack_.back()->set("interfaces-config", i);
  397. ctx.stack_.push_back(i);
  398. ctx.enter(ctx.INTERFACES_CONFIG);
  399. } COLON LCURLY_BRACKET interfaces_config_params RCURLY_BRACKET {
  400. ctx.stack_.pop_back();
  401. ctx.leave();
  402. };
  403. interfaces_config_params: interfaces_config_param
  404. | interfaces_config_params COMMA interfaces_config_param
  405. ;
  406. interfaces_config_param: interfaces_list
  407. | dhcp_socket_type
  408. | re_detect
  409. ;
  410. sub_interfaces4: LCURLY_BRACKET {
  411. // Parse the interfaces-config map
  412. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  413. ctx.stack_.push_back(m);
  414. } interfaces_config_params RCURLY_BRACKET {
  415. // parsing completed
  416. };
  417. interfaces_list: INTERFACES {
  418. ElementPtr l(new ListElement(ctx.loc2pos(@1)));
  419. ctx.stack_.back()->set("interfaces", l);
  420. ctx.stack_.push_back(l);
  421. ctx.enter(ctx.NO_KEYWORD);
  422. } COLON list_strings {
  423. ctx.stack_.pop_back();
  424. ctx.leave();
  425. };
  426. dhcp_socket_type: DHCP_SOCKET_TYPE {
  427. ctx.enter(ctx.DHCP_SOCKET_TYPE);
  428. } COLON socket_type {
  429. ctx.stack_.back()->set("dhcp-socket-type", $4);
  430. ctx.leave();
  431. };
  432. socket_type: RAW { $$ = ElementPtr(new StringElement("raw", ctx.loc2pos(@1))); }
  433. | UDP { $$ = ElementPtr(new StringElement("udp", ctx.loc2pos(@1))); }
  434. ;
  435. re_detect: RE_DETECT COLON BOOLEAN {
  436. ElementPtr b(new BoolElement($3, ctx.loc2pos(@3)));
  437. ctx.stack_.back()->set("re-detect", b);
  438. };
  439. lease_database: LEASE_DATABASE {
  440. ElementPtr i(new MapElement(ctx.loc2pos(@1)));
  441. ctx.stack_.back()->set("lease-database", i);
  442. ctx.stack_.push_back(i);
  443. ctx.enter(ctx.LEASE_DATABASE);
  444. } COLON LCURLY_BRACKET database_map_params RCURLY_BRACKET {
  445. ctx.stack_.pop_back();
  446. ctx.leave();
  447. };
  448. hosts_database: HOSTS_DATABASE {
  449. ElementPtr i(new MapElement(ctx.loc2pos(@1)));
  450. ctx.stack_.back()->set("hosts-database", i);
  451. ctx.stack_.push_back(i);
  452. ctx.enter(ctx.HOSTS_DATABASE);
  453. } COLON LCURLY_BRACKET database_map_params RCURLY_BRACKET {
  454. ctx.stack_.pop_back();
  455. ctx.leave();
  456. };
  457. database_map_params: database_map_param
  458. | database_map_params COMMA database_map_param
  459. ;
  460. database_map_param: database_type
  461. | user
  462. | password
  463. | host
  464. | port
  465. | name
  466. | persist
  467. | lfc_interval
  468. | readonly
  469. | connect_timeout
  470. | contact_points
  471. | keyspace
  472. | unknown_map_entry
  473. ;
  474. database_type: TYPE {
  475. ctx.enter(ctx.DATABASE_TYPE);
  476. } COLON db_type {
  477. ctx.stack_.back()->set("type", $4);
  478. ctx.leave();
  479. };
  480. db_type: MEMFILE { $$ = ElementPtr(new StringElement("memfile", ctx.loc2pos(@1))); }
  481. | MYSQL { $$ = ElementPtr(new StringElement("mysql", ctx.loc2pos(@1))); }
  482. | POSTGRESQL { $$ = ElementPtr(new StringElement("postgresql", ctx.loc2pos(@1))); }
  483. | CQL { $$ = ElementPtr(new StringElement("cql", ctx.loc2pos(@1))); }
  484. ;
  485. user: USER {
  486. ctx.enter(ctx.NO_KEYWORD);
  487. } COLON STRING {
  488. ElementPtr user(new StringElement($4, ctx.loc2pos(@4)));
  489. ctx.stack_.back()->set("user", user);
  490. ctx.leave();
  491. };
  492. password: PASSWORD {
  493. ctx.enter(ctx.NO_KEYWORD);
  494. } COLON STRING {
  495. ElementPtr pwd(new StringElement($4, ctx.loc2pos(@4)));
  496. ctx.stack_.back()->set("password", pwd);
  497. ctx.leave();
  498. };
  499. host: HOST {
  500. ctx.enter(ctx.NO_KEYWORD);
  501. } COLON STRING {
  502. ElementPtr h(new StringElement($4, ctx.loc2pos(@4)));
  503. ctx.stack_.back()->set("host", h);
  504. ctx.leave();
  505. };
  506. port: PORT COLON INTEGER {
  507. ElementPtr p(new IntElement($3, ctx.loc2pos(@3)));
  508. ctx.stack_.back()->set("port", p);
  509. };
  510. name: NAME {
  511. ctx.enter(ctx.NO_KEYWORD);
  512. } COLON STRING {
  513. ElementPtr name(new StringElement($4, ctx.loc2pos(@4)));
  514. ctx.stack_.back()->set("name", name);
  515. ctx.leave();
  516. };
  517. persist: PERSIST COLON BOOLEAN {
  518. ElementPtr n(new BoolElement($3, ctx.loc2pos(@3)));
  519. ctx.stack_.back()->set("persist", n);
  520. };
  521. lfc_interval: LFC_INTERVAL COLON INTEGER {
  522. ElementPtr n(new IntElement($3, ctx.loc2pos(@3)));
  523. ctx.stack_.back()->set("lfc-interval", n);
  524. };
  525. readonly: READONLY COLON BOOLEAN {
  526. ElementPtr n(new BoolElement($3, ctx.loc2pos(@3)));
  527. ctx.stack_.back()->set("readonly", n);
  528. };
  529. connect_timeout: CONNECT_TIMEOUT COLON INTEGER {
  530. ElementPtr n(new IntElement($3, ctx.loc2pos(@3)));
  531. ctx.stack_.back()->set("connect-timeout", n);
  532. };
  533. contact_points: CONTACT_POINTS {
  534. ctx.enter(ctx.NO_KEYWORD);
  535. } COLON STRING {
  536. ElementPtr cp(new StringElement($4, ctx.loc2pos(@4)));
  537. ctx.stack_.back()->set("contact-points", cp);
  538. ctx.leave();
  539. };
  540. keyspace: KEYSPACE {
  541. ctx.enter(ctx.NO_KEYWORD);
  542. } COLON STRING {
  543. ElementPtr ks(new StringElement($4, ctx.loc2pos(@4)));
  544. ctx.stack_.back()->set("keyspace", ks);
  545. ctx.leave();
  546. };
  547. host_reservation_identifiers: HOST_RESERVATION_IDENTIFIERS {
  548. ElementPtr l(new ListElement(ctx.loc2pos(@1)));
  549. ctx.stack_.back()->set("host-reservation-identifiers", l);
  550. ctx.stack_.push_back(l);
  551. ctx.enter(ctx.HOST_RESERVATION_IDENTIFIERS);
  552. } COLON LSQUARE_BRACKET host_reservation_identifiers_list RSQUARE_BRACKET {
  553. ctx.stack_.pop_back();
  554. ctx.leave();
  555. };
  556. host_reservation_identifiers_list: host_reservation_identifier
  557. | host_reservation_identifiers_list COMMA host_reservation_identifier
  558. ;
  559. host_reservation_identifier: duid_id
  560. | hw_address_id
  561. | circuit_id
  562. | client_id
  563. | flex_id
  564. ;
  565. duid_id : DUID {
  566. ElementPtr duid(new StringElement("duid", ctx.loc2pos(@1)));
  567. ctx.stack_.back()->add(duid);
  568. };
  569. hw_address_id : HW_ADDRESS {
  570. ElementPtr hwaddr(new StringElement("hw-address", ctx.loc2pos(@1)));
  571. ctx.stack_.back()->add(hwaddr);
  572. };
  573. circuit_id : CIRCUIT_ID {
  574. ElementPtr circuit(new StringElement("circuit-id", ctx.loc2pos(@1)));
  575. ctx.stack_.back()->add(circuit);
  576. };
  577. client_id : CLIENT_ID {
  578. ElementPtr client(new StringElement("client-id", ctx.loc2pos(@1)));
  579. ctx.stack_.back()->add(client);
  580. };
  581. flex_id: FLEX_ID {
  582. ElementPtr flex_id(new StringElement("flex-id", ctx.loc2pos(@1)));
  583. ctx.stack_.back()->add(flex_id);
  584. }
  585. hooks_libraries: HOOKS_LIBRARIES {
  586. ElementPtr l(new ListElement(ctx.loc2pos(@1)));
  587. ctx.stack_.back()->set("hooks-libraries", l);
  588. ctx.stack_.push_back(l);
  589. ctx.enter(ctx.HOOKS_LIBRARIES);
  590. } COLON LSQUARE_BRACKET hooks_libraries_list RSQUARE_BRACKET {
  591. ctx.stack_.pop_back();
  592. ctx.leave();
  593. };
  594. hooks_libraries_list: %empty
  595. | not_empty_hooks_libraries_list
  596. ;
  597. not_empty_hooks_libraries_list: hooks_library
  598. | not_empty_hooks_libraries_list COMMA hooks_library
  599. ;
  600. hooks_library: LCURLY_BRACKET {
  601. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  602. ctx.stack_.back()->add(m);
  603. ctx.stack_.push_back(m);
  604. } hooks_params RCURLY_BRACKET {
  605. ctx.stack_.pop_back();
  606. };
  607. sub_hooks_library: LCURLY_BRACKET {
  608. // Parse the hooks-libraries list entry map
  609. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  610. ctx.stack_.push_back(m);
  611. } hooks_params RCURLY_BRACKET {
  612. // parsing completed
  613. };
  614. hooks_params: hooks_param
  615. | hooks_params COMMA hooks_param
  616. | unknown_map_entry
  617. ;
  618. hooks_param: library
  619. | parameters
  620. ;
  621. library: LIBRARY {
  622. ctx.enter(ctx.NO_KEYWORD);
  623. } COLON STRING {
  624. ElementPtr lib(new StringElement($4, ctx.loc2pos(@4)));
  625. ctx.stack_.back()->set("library", lib);
  626. ctx.leave();
  627. };
  628. parameters: PARAMETERS {
  629. ctx.enter(ctx.NO_KEYWORD);
  630. } COLON value {
  631. ctx.stack_.back()->set("parameters", $4);
  632. ctx.leave();
  633. };
  634. // --- expired-leases-processing ------------------------
  635. expired_leases_processing: EXPIRED_LEASES_PROCESSING {
  636. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  637. ctx.stack_.back()->set("expired-leases-processing", m);
  638. ctx.stack_.push_back(m);
  639. ctx.enter(ctx.EXPIRED_LEASES_PROCESSING);
  640. } COLON LCURLY_BRACKET expired_leases_params RCURLY_BRACKET {
  641. ctx.stack_.pop_back();
  642. ctx.leave();
  643. };
  644. expired_leases_params: expired_leases_param
  645. | expired_leases_params COMMA expired_leases_param
  646. ;
  647. expired_leases_param: reclaim_timer_wait_time
  648. | flush_reclaimed_timer_wait_time
  649. | hold_reclaimed_time
  650. | max_reclaim_leases
  651. | max_reclaim_time
  652. | unwarned_reclaim_cycles
  653. ;
  654. reclaim_timer_wait_time: RECLAIM_TIMER_WAIT_TIME COLON INTEGER {
  655. ElementPtr value(new IntElement($3, ctx.loc2pos(@3)));
  656. ctx.stack_.back()->set("reclaim-timer-wait-time", value);
  657. };
  658. flush_reclaimed_timer_wait_time: FLUSH_RECLAIMED_TIMER_WAIT_TIME COLON INTEGER {
  659. ElementPtr value(new IntElement($3, ctx.loc2pos(@3)));
  660. ctx.stack_.back()->set("flush-reclaimed-timer-wait-time", value);
  661. };
  662. hold_reclaimed_time: HOLD_RECLAIMED_TIME COLON INTEGER {
  663. ElementPtr value(new IntElement($3, ctx.loc2pos(@3)));
  664. ctx.stack_.back()->set("hold-reclaimed-time", value);
  665. };
  666. max_reclaim_leases: MAX_RECLAIM_LEASES COLON INTEGER {
  667. ElementPtr value(new IntElement($3, ctx.loc2pos(@3)));
  668. ctx.stack_.back()->set("max-reclaim-leases", value);
  669. };
  670. max_reclaim_time: MAX_RECLAIM_TIME COLON INTEGER {
  671. ElementPtr value(new IntElement($3, ctx.loc2pos(@3)));
  672. ctx.stack_.back()->set("max-reclaim-time", value);
  673. };
  674. unwarned_reclaim_cycles: UNWARNED_RECLAIM_CYCLES COLON INTEGER {
  675. ElementPtr value(new IntElement($3, ctx.loc2pos(@3)));
  676. ctx.stack_.back()->set("unwarned-reclaim-cycles", value);
  677. };
  678. // --- subnet4 ------------------------------------------
  679. // This defines subnet4 as a list of maps.
  680. // "subnet4": [ ... ]
  681. subnet4_list: SUBNET4 {
  682. ElementPtr l(new ListElement(ctx.loc2pos(@1)));
  683. ctx.stack_.back()->set("subnet4", l);
  684. ctx.stack_.push_back(l);
  685. ctx.enter(ctx.SUBNET4);
  686. } COLON LSQUARE_BRACKET subnet4_list_content RSQUARE_BRACKET {
  687. ctx.stack_.pop_back();
  688. ctx.leave();
  689. };
  690. // This defines the ... in "subnet4": [ ... ]
  691. // It can either be empty (no subnets defined), have one subnet
  692. // or have multiple subnets separate by comma.
  693. subnet4_list_content: %empty
  694. | not_empty_subnet4_list
  695. ;
  696. not_empty_subnet4_list: subnet4
  697. | not_empty_subnet4_list COMMA subnet4
  698. ;
  699. // --- Subnet definitions -------------------------------
  700. // This defines a single subnet, i.e. a single map with
  701. // subnet4 array.
  702. subnet4: LCURLY_BRACKET {
  703. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  704. ctx.stack_.back()->add(m);
  705. ctx.stack_.push_back(m);
  706. } subnet4_params RCURLY_BRACKET {
  707. // Once we reached this place, the subnet parsing is now complete.
  708. // If we want to, we can implement default values here.
  709. // In particular we can do things like this:
  710. // if (!ctx.stack_.back()->get("interface")) {
  711. // ctx.stack_.back()->set("interface", StringElement("loopback"));
  712. // }
  713. //
  714. // We can also stack up one level (Dhcp4) and copy over whatever
  715. // global parameters we want to:
  716. // if (!ctx.stack_.back()->get("renew-timer")) {
  717. // ElementPtr renew = ctx_stack_[...].get("renew-timer");
  718. // if (renew) {
  719. // ctx.stack_.back()->set("renew-timer", renew);
  720. // }
  721. // }
  722. ctx.stack_.pop_back();
  723. };
  724. sub_subnet4: LCURLY_BRACKET {
  725. // Parse the subnet4 list entry map
  726. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  727. ctx.stack_.push_back(m);
  728. } subnet4_params RCURLY_BRACKET {
  729. // parsing completed
  730. };
  731. // This defines that subnet can have one or more parameters.
  732. subnet4_params: subnet4_param
  733. | subnet4_params COMMA subnet4_param
  734. ;
  735. // This defines a list of allowed parameters for each subnet.
  736. subnet4_param: valid_lifetime
  737. | renew_timer
  738. | rebind_timer
  739. | option_data_list
  740. | pools_list
  741. | subnet
  742. | interface
  743. | interface_id
  744. | id
  745. | rapid_commit
  746. | client_class
  747. | reservations
  748. | reservation_mode
  749. | relay
  750. | match_client_id
  751. | next_server
  752. | subnet_4o6_interface
  753. | subnet_4o6_interface_id
  754. | subnet_4o6_subnet
  755. | unknown_map_entry
  756. ;
  757. subnet: SUBNET {
  758. ctx.enter(ctx.NO_KEYWORD);
  759. } COLON STRING {
  760. ElementPtr subnet(new StringElement($4, ctx.loc2pos(@4)));
  761. ctx.stack_.back()->set("subnet", subnet);
  762. ctx.leave();
  763. };
  764. subnet_4o6_interface: SUBNET_4O6_INTERFACE {
  765. ctx.enter(ctx.NO_KEYWORD);
  766. } COLON STRING {
  767. ElementPtr iface(new StringElement($4, ctx.loc2pos(@4)));
  768. ctx.stack_.back()->set("4o6-interface", iface);
  769. ctx.leave();
  770. };
  771. subnet_4o6_interface_id: SUBNET_4O6_INTERFACE_ID {
  772. ctx.enter(ctx.NO_KEYWORD);
  773. } COLON STRING {
  774. ElementPtr iface(new StringElement($4, ctx.loc2pos(@4)));
  775. ctx.stack_.back()->set("4o6-interface-id", iface);
  776. ctx.leave();
  777. };
  778. subnet_4o6_subnet: SUBNET_4O6_SUBNET {
  779. ctx.enter(ctx.NO_KEYWORD);
  780. } COLON STRING {
  781. ElementPtr iface(new StringElement($4, ctx.loc2pos(@4)));
  782. ctx.stack_.back()->set("4o6-subnet", iface);
  783. ctx.leave();
  784. };
  785. interface: INTERFACE {
  786. ctx.enter(ctx.NO_KEYWORD);
  787. } COLON STRING {
  788. ElementPtr iface(new StringElement($4, ctx.loc2pos(@4)));
  789. ctx.stack_.back()->set("interface", iface);
  790. ctx.leave();
  791. };
  792. interface_id: INTERFACE_ID {
  793. ctx.enter(ctx.NO_KEYWORD);
  794. } COLON STRING {
  795. ElementPtr iface(new StringElement($4, ctx.loc2pos(@4)));
  796. ctx.stack_.back()->set("interface-id", iface);
  797. ctx.leave();
  798. };
  799. client_class: CLIENT_CLASS {
  800. ctx.enter(ctx.CLIENT_CLASS);
  801. } COLON STRING {
  802. ElementPtr cls(new StringElement($4, ctx.loc2pos(@4)));
  803. ctx.stack_.back()->set("client-class", cls);
  804. ctx.leave();
  805. };
  806. reservation_mode: RESERVATION_MODE {
  807. ctx.enter(ctx.RESERVATION_MODE);
  808. } COLON hr_mode {
  809. ctx.stack_.back()->set("reservation-mode", $4);
  810. ctx.leave();
  811. };
  812. hr_mode: DISABLED { $$ = ElementPtr(new StringElement("disabled", ctx.loc2pos(@1))); }
  813. | OUT_OF_POOL { $$ = ElementPtr(new StringElement("out-of-pool", ctx.loc2pos(@1))); }
  814. | ALL { $$ = ElementPtr(new StringElement("all", ctx.loc2pos(@1))); }
  815. ;
  816. id: ID COLON INTEGER {
  817. ElementPtr id(new IntElement($3, ctx.loc2pos(@3)));
  818. ctx.stack_.back()->set("id", id);
  819. };
  820. rapid_commit: RAPID_COMMIT COLON BOOLEAN {
  821. ElementPtr rc(new BoolElement($3, ctx.loc2pos(@3)));
  822. ctx.stack_.back()->set("rapid-commit", rc);
  823. };
  824. // ---- option-def --------------------------
  825. // This defines the "option-def": [ ... ] entry that may appear
  826. // at a global option.
  827. option_def_list: OPTION_DEF {
  828. ElementPtr l(new ListElement(ctx.loc2pos(@1)));
  829. ctx.stack_.back()->set("option-def", l);
  830. ctx.stack_.push_back(l);
  831. ctx.enter(ctx.OPTION_DEF);
  832. } COLON LSQUARE_BRACKET option_def_list_content RSQUARE_BRACKET {
  833. ctx.stack_.pop_back();
  834. ctx.leave();
  835. };
  836. // This defines the content of option-def. It may be empty,
  837. // have one entry or multiple entries separated by comma.
  838. option_def_list_content: %empty
  839. | not_empty_option_def_list
  840. ;
  841. not_empty_option_def_list: option_def_entry
  842. | not_empty_option_def_list COMMA option_def_entry
  843. ;
  844. // This defines the content of a single entry { ... } within
  845. // option-def list.
  846. option_def_entry: LCURLY_BRACKET {
  847. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  848. ctx.stack_.back()->add(m);
  849. ctx.stack_.push_back(m);
  850. } option_def_params RCURLY_BRACKET {
  851. ctx.stack_.pop_back();
  852. };
  853. // This defines the top level scope when the parser is told to parse a single
  854. // option definition. It's almost exactly the same as option_def_entry, except
  855. // that it does leave its value on stack.
  856. sub_option_def: LCURLY_BRACKET {
  857. // Parse the option-def list entry map
  858. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  859. ctx.stack_.push_back(m);
  860. } option_def_params RCURLY_BRACKET {
  861. // parsing completed
  862. };
  863. // This defines parameters specified inside the map that itself
  864. // is an entry in option-def list.
  865. option_def_params: %empty
  866. | not_empty_option_def_params
  867. ;
  868. not_empty_option_def_params: option_def_param
  869. | not_empty_option_def_params COMMA option_def_param
  870. ;
  871. option_def_param: option_def_name
  872. | option_def_code
  873. | option_def_type
  874. | option_def_record_types
  875. | option_def_space
  876. | option_def_encapsulate
  877. | option_def_array
  878. | unknown_map_entry
  879. ;
  880. option_def_name: name;
  881. code: CODE COLON INTEGER {
  882. ElementPtr code(new IntElement($3, ctx.loc2pos(@3)));
  883. ctx.stack_.back()->set("code", code);
  884. };
  885. option_def_code: code;
  886. option_def_type: TYPE {
  887. ctx.enter(ctx.NO_KEYWORD);
  888. } COLON STRING {
  889. ElementPtr prf(new StringElement($4, ctx.loc2pos(@4)));
  890. ctx.stack_.back()->set("type", prf);
  891. ctx.leave();
  892. };
  893. option_def_record_types: RECORD_TYPES {
  894. ctx.enter(ctx.NO_KEYWORD);
  895. } COLON STRING {
  896. ElementPtr rtypes(new StringElement($4, ctx.loc2pos(@4)));
  897. ctx.stack_.back()->set("record-types", rtypes);
  898. ctx.leave();
  899. };
  900. space: SPACE {
  901. ctx.enter(ctx.NO_KEYWORD);
  902. } COLON STRING {
  903. ElementPtr space(new StringElement($4, ctx.loc2pos(@4)));
  904. ctx.stack_.back()->set("space", space);
  905. ctx.leave();
  906. };
  907. option_def_space: space;
  908. option_def_encapsulate: ENCAPSULATE {
  909. ctx.enter(ctx.NO_KEYWORD);
  910. } COLON STRING {
  911. ElementPtr encap(new StringElement($4, ctx.loc2pos(@4)));
  912. ctx.stack_.back()->set("encapsulate", encap);
  913. ctx.leave();
  914. };
  915. option_def_array: ARRAY COLON BOOLEAN {
  916. ElementPtr array(new BoolElement($3, ctx.loc2pos(@3)));
  917. ctx.stack_.back()->set("array", array);
  918. };
  919. // ---- option-data --------------------------
  920. // This defines the "option-data": [ ... ] entry that may appear
  921. // in several places, but most notably in subnet4 entries.
  922. option_data_list: OPTION_DATA {
  923. ElementPtr l(new ListElement(ctx.loc2pos(@1)));
  924. ctx.stack_.back()->set("option-data", l);
  925. ctx.stack_.push_back(l);
  926. ctx.enter(ctx.OPTION_DATA);
  927. } COLON LSQUARE_BRACKET option_data_list_content RSQUARE_BRACKET {
  928. ctx.stack_.pop_back();
  929. ctx.leave();
  930. };
  931. // This defines the content of option-data. It may be empty,
  932. // have one entry or multiple entries separated by comma.
  933. option_data_list_content: %empty
  934. | not_empty_option_data_list
  935. ;
  936. // This defines the content of option-data list. It can either
  937. // be a single value or multiple entries separated by comma.
  938. not_empty_option_data_list: option_data_entry
  939. | not_empty_option_data_list COMMA option_data_entry
  940. ;
  941. // This defines th content of a single entry { ... } within
  942. // option-data list.
  943. option_data_entry: LCURLY_BRACKET {
  944. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  945. ctx.stack_.back()->add(m);
  946. ctx.stack_.push_back(m);
  947. } option_data_params RCURLY_BRACKET {
  948. ctx.stack_.pop_back();
  949. };
  950. // This defines the top level scope when the parser is told to parse a single
  951. // option data. It's almost exactly the same as option_data_entry, except
  952. // that it does leave its value on stack.
  953. sub_option_data: LCURLY_BRACKET {
  954. // Parse the option-data list entry map
  955. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  956. ctx.stack_.push_back(m);
  957. } option_data_params RCURLY_BRACKET {
  958. // parsing completed
  959. };
  960. // This defines parameters specified inside the map that itself
  961. // is an entry in option-data list. It can either be empty
  962. // or have a non-empty list of parameters.
  963. option_data_params: %empty
  964. | not_empty_option_data_params
  965. ;
  966. // Those parameters can either be a single parameter or
  967. // a list of parameters separated by comma.
  968. not_empty_option_data_params: option_data_param
  969. | not_empty_option_data_params COMMA option_data_param
  970. ;
  971. // Each single option-data parameter can be one of the following
  972. // expressions.
  973. option_data_param: option_data_name
  974. | option_data_data
  975. | option_data_code
  976. | option_data_space
  977. | option_data_csv_format
  978. | option_data_always_send
  979. | unknown_map_entry
  980. ;
  981. option_data_name: name;
  982. option_data_data: DATA {
  983. ctx.enter(ctx.NO_KEYWORD);
  984. } COLON STRING {
  985. ElementPtr data(new StringElement($4, ctx.loc2pos(@4)));
  986. ctx.stack_.back()->set("data", data);
  987. ctx.leave();
  988. };
  989. option_data_code: code;
  990. option_data_space: space;
  991. option_data_csv_format: CSV_FORMAT COLON BOOLEAN {
  992. ElementPtr space(new BoolElement($3, ctx.loc2pos(@3)));
  993. ctx.stack_.back()->set("csv-format", space);
  994. };
  995. option_data_always_send: ALWAYS_SEND COLON BOOLEAN {
  996. ElementPtr persist(new BoolElement($3, ctx.loc2pos(@3)));
  997. ctx.stack_.back()->set("always-send", persist);
  998. };
  999. // ---- pools ------------------------------------
  1000. // This defines the "pools": [ ... ] entry that may appear in subnet4.
  1001. pools_list: POOLS {
  1002. ElementPtr l(new ListElement(ctx.loc2pos(@1)));
  1003. ctx.stack_.back()->set("pools", l);
  1004. ctx.stack_.push_back(l);
  1005. ctx.enter(ctx.POOLS);
  1006. } COLON LSQUARE_BRACKET pools_list_content RSQUARE_BRACKET {
  1007. ctx.stack_.pop_back();
  1008. ctx.leave();
  1009. };
  1010. // Pools may be empty, contain a single pool entry or multiple entries
  1011. // separate by commas.
  1012. pools_list_content: %empty
  1013. | not_empty_pools_list
  1014. ;
  1015. not_empty_pools_list: pool_list_entry
  1016. | not_empty_pools_list COMMA pool_list_entry
  1017. ;
  1018. pool_list_entry: LCURLY_BRACKET {
  1019. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  1020. ctx.stack_.back()->add(m);
  1021. ctx.stack_.push_back(m);
  1022. } pool_params RCURLY_BRACKET {
  1023. ctx.stack_.pop_back();
  1024. };
  1025. sub_pool4: LCURLY_BRACKET {
  1026. // Parse the pool list entry map
  1027. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  1028. ctx.stack_.push_back(m);
  1029. } pool_params RCURLY_BRACKET {
  1030. // parsing completed
  1031. };
  1032. pool_params: pool_param
  1033. | pool_params COMMA pool_param
  1034. ;
  1035. pool_param: pool_entry
  1036. | option_data_list
  1037. | user_context
  1038. | unknown_map_entry
  1039. ;
  1040. pool_entry: POOL {
  1041. ctx.enter(ctx.NO_KEYWORD);
  1042. } COLON STRING {
  1043. ElementPtr pool(new StringElement($4, ctx.loc2pos(@4)));
  1044. ctx.stack_.back()->set("pool", pool);
  1045. ctx.leave();
  1046. };
  1047. user_context: USER_CONTEXT {
  1048. ctx.enter(ctx.NO_KEYWORD);
  1049. } COLON map_value {
  1050. ctx.stack_.back()->set("user-context", $4);
  1051. ctx.leave();
  1052. };
  1053. // --- end of pools definition -------------------------------
  1054. // --- reservations ------------------------------------------
  1055. reservations: RESERVATIONS {
  1056. ElementPtr l(new ListElement(ctx.loc2pos(@1)));
  1057. ctx.stack_.back()->set("reservations", l);
  1058. ctx.stack_.push_back(l);
  1059. ctx.enter(ctx.RESERVATIONS);
  1060. } COLON LSQUARE_BRACKET reservations_list RSQUARE_BRACKET {
  1061. ctx.stack_.pop_back();
  1062. ctx.leave();
  1063. };
  1064. reservations_list: %empty
  1065. | not_empty_reservations_list
  1066. ;
  1067. not_empty_reservations_list: reservation
  1068. | not_empty_reservations_list COMMA reservation
  1069. ;
  1070. reservation: LCURLY_BRACKET {
  1071. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  1072. ctx.stack_.back()->add(m);
  1073. ctx.stack_.push_back(m);
  1074. } reservation_params RCURLY_BRACKET {
  1075. ctx.stack_.pop_back();
  1076. };
  1077. sub_reservation: LCURLY_BRACKET {
  1078. // Parse the reservations list entry map
  1079. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  1080. ctx.stack_.push_back(m);
  1081. } reservation_params RCURLY_BRACKET {
  1082. // parsing completed
  1083. };
  1084. reservation_params: %empty
  1085. | not_empty_reservation_params
  1086. ;
  1087. not_empty_reservation_params: reservation_param
  1088. | not_empty_reservation_params COMMA reservation_param
  1089. ;
  1090. // @todo probably need to add mac-address as well here
  1091. reservation_param: duid
  1092. | reservation_client_classes
  1093. | client_id_value
  1094. | circuit_id_value
  1095. | flex_id_value
  1096. | ip_address
  1097. | hw_address
  1098. | hostname
  1099. | option_data_list
  1100. | next_server
  1101. | server_hostname
  1102. | boot_file_name
  1103. | unknown_map_entry
  1104. ;
  1105. next_server: NEXT_SERVER {
  1106. ctx.enter(ctx.NO_KEYWORD);
  1107. } COLON STRING {
  1108. ElementPtr next_server(new StringElement($4, ctx.loc2pos(@4)));
  1109. ctx.stack_.back()->set("next-server", next_server);
  1110. ctx.leave();
  1111. };
  1112. server_hostname: SERVER_HOSTNAME {
  1113. ctx.enter(ctx.NO_KEYWORD);
  1114. } COLON STRING {
  1115. ElementPtr srv(new StringElement($4, ctx.loc2pos(@4)));
  1116. ctx.stack_.back()->set("server-hostname", srv);
  1117. ctx.leave();
  1118. };
  1119. boot_file_name: BOOT_FILE_NAME {
  1120. ctx.enter(ctx.NO_KEYWORD);
  1121. } COLON STRING {
  1122. ElementPtr bootfile(new StringElement($4, ctx.loc2pos(@4)));
  1123. ctx.stack_.back()->set("boot-file-name", bootfile);
  1124. ctx.leave();
  1125. };
  1126. ip_address: IP_ADDRESS {
  1127. ctx.enter(ctx.NO_KEYWORD);
  1128. } COLON STRING {
  1129. ElementPtr addr(new StringElement($4, ctx.loc2pos(@4)));
  1130. ctx.stack_.back()->set("ip-address", addr);
  1131. ctx.leave();
  1132. };
  1133. duid: DUID {
  1134. ctx.enter(ctx.NO_KEYWORD);
  1135. } COLON STRING {
  1136. ElementPtr d(new StringElement($4, ctx.loc2pos(@4)));
  1137. ctx.stack_.back()->set("duid", d);
  1138. ctx.leave();
  1139. };
  1140. hw_address: HW_ADDRESS {
  1141. ctx.enter(ctx.NO_KEYWORD);
  1142. } COLON STRING {
  1143. ElementPtr hw(new StringElement($4, ctx.loc2pos(@4)));
  1144. ctx.stack_.back()->set("hw-address", hw);
  1145. ctx.leave();
  1146. };
  1147. client_id_value: CLIENT_ID {
  1148. ctx.enter(ctx.NO_KEYWORD);
  1149. } COLON STRING {
  1150. ElementPtr hw(new StringElement($4, ctx.loc2pos(@4)));
  1151. ctx.stack_.back()->set("client-id", hw);
  1152. ctx.leave();
  1153. };
  1154. circuit_id_value: CIRCUIT_ID {
  1155. ctx.enter(ctx.NO_KEYWORD);
  1156. } COLON STRING {
  1157. ElementPtr hw(new StringElement($4, ctx.loc2pos(@4)));
  1158. ctx.stack_.back()->set("circuit-id", hw);
  1159. ctx.leave();
  1160. };
  1161. flex_id_value: FLEX_ID {
  1162. ctx.enter(ctx.NO_KEYWORD);
  1163. } COLON STRING {
  1164. ElementPtr hw(new StringElement($4, ctx.loc2pos(@4)));
  1165. ctx.stack_.back()->set("flex-id", hw);
  1166. ctx.leave();
  1167. };
  1168. hostname: HOSTNAME {
  1169. ctx.enter(ctx.NO_KEYWORD);
  1170. } COLON STRING {
  1171. ElementPtr host(new StringElement($4, ctx.loc2pos(@4)));
  1172. ctx.stack_.back()->set("hostname", host);
  1173. ctx.leave();
  1174. };
  1175. reservation_client_classes: CLIENT_CLASSES {
  1176. ElementPtr c(new ListElement(ctx.loc2pos(@1)));
  1177. ctx.stack_.back()->set("client-classes", c);
  1178. ctx.stack_.push_back(c);
  1179. ctx.enter(ctx.NO_KEYWORD);
  1180. } COLON list_strings {
  1181. ctx.stack_.pop_back();
  1182. ctx.leave();
  1183. };
  1184. // --- end of reservations definitions -----------------------
  1185. // --- relay -------------------------------------------------
  1186. relay: RELAY {
  1187. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  1188. ctx.stack_.back()->set("relay", m);
  1189. ctx.stack_.push_back(m);
  1190. ctx.enter(ctx.RELAY);
  1191. } COLON LCURLY_BRACKET relay_map RCURLY_BRACKET {
  1192. ctx.stack_.pop_back();
  1193. ctx.leave();
  1194. };
  1195. relay_map: IP_ADDRESS {
  1196. ctx.enter(ctx.NO_KEYWORD);
  1197. } COLON STRING {
  1198. ElementPtr ip(new StringElement($4, ctx.loc2pos(@4)));
  1199. ctx.stack_.back()->set("ip-address", ip);
  1200. ctx.leave();
  1201. };
  1202. // --- end of relay definitions ------------------------------
  1203. // --- client classes ----------------------------------------
  1204. client_classes: CLIENT_CLASSES {
  1205. ElementPtr l(new ListElement(ctx.loc2pos(@1)));
  1206. ctx.stack_.back()->set("client-classes", l);
  1207. ctx.stack_.push_back(l);
  1208. ctx.enter(ctx.CLIENT_CLASSES);
  1209. } COLON LSQUARE_BRACKET client_classes_list RSQUARE_BRACKET {
  1210. ctx.stack_.pop_back();
  1211. ctx.leave();
  1212. };
  1213. client_classes_list: client_class
  1214. | client_classes_list COMMA client_class
  1215. ;
  1216. client_class: LCURLY_BRACKET {
  1217. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  1218. ctx.stack_.back()->add(m);
  1219. ctx.stack_.push_back(m);
  1220. } client_class_params RCURLY_BRACKET {
  1221. ctx.stack_.pop_back();
  1222. };
  1223. client_class_params: %empty
  1224. | not_empty_client_class_params
  1225. ;
  1226. not_empty_client_class_params: client_class_param
  1227. | not_empty_client_class_params COMMA client_class_param
  1228. ;
  1229. client_class_param: client_class_name
  1230. | client_class_test
  1231. | option_data_list
  1232. | next_server
  1233. | server_hostname
  1234. | boot_file_name
  1235. | unknown_map_entry
  1236. ;
  1237. client_class_name: name;
  1238. client_class_test: TEST {
  1239. ctx.enter(ctx.NO_KEYWORD);
  1240. } COLON STRING {
  1241. ElementPtr test(new StringElement($4, ctx.loc2pos(@4)));
  1242. ctx.stack_.back()->set("test", test);
  1243. ctx.leave();
  1244. };
  1245. // --- end of client classes ---------------------------------
  1246. // was server-id but in is DHCPv6-only
  1247. dhcp4o6_port: DHCP4O6_PORT COLON INTEGER {
  1248. ElementPtr time(new IntElement($3, ctx.loc2pos(@3)));
  1249. ctx.stack_.back()->set("dhcp4o6-port", time);
  1250. };
  1251. // --- control socket ----------------------------------------
  1252. control_socket: CONTROL_SOCKET {
  1253. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  1254. ctx.stack_.back()->set("control-socket", m);
  1255. ctx.stack_.push_back(m);
  1256. ctx.enter(ctx.CONTROL_SOCKET);
  1257. } COLON LCURLY_BRACKET control_socket_params RCURLY_BRACKET {
  1258. ctx.stack_.pop_back();
  1259. ctx.leave();
  1260. };
  1261. control_socket_params: control_socket_param
  1262. | control_socket_params COMMA control_socket_param
  1263. ;
  1264. control_socket_param: control_socket_type
  1265. | control_socket_name
  1266. ;
  1267. control_socket_type: SOCKET_TYPE {
  1268. ctx.enter(ctx.NO_KEYWORD);
  1269. } COLON STRING {
  1270. ElementPtr stype(new StringElement($4, ctx.loc2pos(@4)));
  1271. ctx.stack_.back()->set("socket-type", stype);
  1272. ctx.leave();
  1273. };
  1274. control_socket_name: SOCKET_NAME {
  1275. ctx.enter(ctx.NO_KEYWORD);
  1276. } COLON STRING {
  1277. ElementPtr name(new StringElement($4, ctx.loc2pos(@4)));
  1278. ctx.stack_.back()->set("socket-name", name);
  1279. ctx.leave();
  1280. };
  1281. // --- dhcp ddns ---------------------------------------------
  1282. dhcp_ddns: DHCP_DDNS {
  1283. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  1284. ctx.stack_.back()->set("dhcp-ddns", m);
  1285. ctx.stack_.push_back(m);
  1286. ctx.enter(ctx.DHCP_DDNS);
  1287. } COLON LCURLY_BRACKET dhcp_ddns_params RCURLY_BRACKET {
  1288. ctx.stack_.pop_back();
  1289. ctx.leave();
  1290. };
  1291. sub_dhcp_ddns: LCURLY_BRACKET {
  1292. // Parse the dhcp-ddns map
  1293. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  1294. ctx.stack_.push_back(m);
  1295. } dhcp_ddns_params RCURLY_BRACKET {
  1296. // parsing completed
  1297. };
  1298. dhcp_ddns_params: dhcp_ddns_param
  1299. | dhcp_ddns_params COMMA dhcp_ddns_param
  1300. ;
  1301. dhcp_ddns_param: enable_updates
  1302. | qualifying_suffix
  1303. | server_ip
  1304. | server_port
  1305. | sender_ip
  1306. | sender_port
  1307. | max_queue_size
  1308. | ncr_protocol
  1309. | ncr_format
  1310. | always_include_fqdn
  1311. | override_no_update
  1312. | override_client_update
  1313. | replace_client_name
  1314. | generated_prefix
  1315. | unknown_map_entry
  1316. ;
  1317. enable_updates: ENABLE_UPDATES COLON BOOLEAN {
  1318. ElementPtr b(new BoolElement($3, ctx.loc2pos(@3)));
  1319. ctx.stack_.back()->set("enable-updates", b);
  1320. };
  1321. qualifying_suffix: QUALIFYING_SUFFIX {
  1322. ctx.enter(ctx.NO_KEYWORD);
  1323. } COLON STRING {
  1324. ElementPtr s(new StringElement($4, ctx.loc2pos(@4)));
  1325. ctx.stack_.back()->set("qualifying-suffix", s);
  1326. ctx.leave();
  1327. };
  1328. server_ip: SERVER_IP {
  1329. ctx.enter(ctx.NO_KEYWORD);
  1330. } COLON STRING {
  1331. ElementPtr s(new StringElement($4, ctx.loc2pos(@4)));
  1332. ctx.stack_.back()->set("server-ip", s);
  1333. ctx.leave();
  1334. };
  1335. server_port: SERVER_PORT COLON INTEGER {
  1336. ElementPtr i(new IntElement($3, ctx.loc2pos(@3)));
  1337. ctx.stack_.back()->set("server-port", i);
  1338. };
  1339. sender_ip: SENDER_IP {
  1340. ctx.enter(ctx.NO_KEYWORD);
  1341. } COLON STRING {
  1342. ElementPtr s(new StringElement($4, ctx.loc2pos(@4)));
  1343. ctx.stack_.back()->set("sender-ip", s);
  1344. ctx.leave();
  1345. };
  1346. sender_port: SENDER_PORT COLON INTEGER {
  1347. ElementPtr i(new IntElement($3, ctx.loc2pos(@3)));
  1348. ctx.stack_.back()->set("sender-port", i);
  1349. };
  1350. max_queue_size: MAX_QUEUE_SIZE COLON INTEGER {
  1351. ElementPtr i(new IntElement($3, ctx.loc2pos(@3)));
  1352. ctx.stack_.back()->set("max-queue-size", i);
  1353. };
  1354. ncr_protocol: NCR_PROTOCOL {
  1355. ctx.enter(ctx.NCR_PROTOCOL);
  1356. } COLON ncr_protocol_value {
  1357. ctx.stack_.back()->set("ncr-protocol", $4);
  1358. ctx.leave();
  1359. };
  1360. ncr_protocol_value:
  1361. UDP { $$ = ElementPtr(new StringElement("UDP", ctx.loc2pos(@1))); }
  1362. | TCP { $$ = ElementPtr(new StringElement("TCP", ctx.loc2pos(@1))); }
  1363. ;
  1364. ncr_format: NCR_FORMAT {
  1365. ctx.enter(ctx.NCR_FORMAT);
  1366. } COLON JSON {
  1367. ElementPtr json(new StringElement("JSON", ctx.loc2pos(@4)));
  1368. ctx.stack_.back()->set("ncr-format", json);
  1369. ctx.leave();
  1370. };
  1371. always_include_fqdn: ALWAYS_INCLUDE_FQDN COLON BOOLEAN {
  1372. ElementPtr b(new BoolElement($3, ctx.loc2pos(@3)));
  1373. ctx.stack_.back()->set("always-include-fqdn", b);
  1374. };
  1375. override_no_update: OVERRIDE_NO_UPDATE COLON BOOLEAN {
  1376. ElementPtr b(new BoolElement($3, ctx.loc2pos(@3)));
  1377. ctx.stack_.back()->set("override-no-update", b);
  1378. };
  1379. override_client_update: OVERRIDE_CLIENT_UPDATE COLON BOOLEAN {
  1380. ElementPtr b(new BoolElement($3, ctx.loc2pos(@3)));
  1381. ctx.stack_.back()->set("override-client-update", b);
  1382. };
  1383. replace_client_name: REPLACE_CLIENT_NAME {
  1384. ctx.enter(ctx.REPLACE_CLIENT_NAME);
  1385. } COLON replace_client_name_value {
  1386. ctx.stack_.back()->set("replace-client-name", $4);
  1387. ctx.leave();
  1388. };
  1389. replace_client_name_value:
  1390. WHEN_PRESENT {
  1391. $$ = ElementPtr(new StringElement("when-present", ctx.loc2pos(@1)));
  1392. }
  1393. | NEVER {
  1394. $$ = ElementPtr(new StringElement("never", ctx.loc2pos(@1)));
  1395. }
  1396. | ALWAYS {
  1397. $$ = ElementPtr(new StringElement("always", ctx.loc2pos(@1)));
  1398. }
  1399. | WHEN_NOT_PRESENT {
  1400. $$ = ElementPtr(new StringElement("when-not-present", ctx.loc2pos(@1)));
  1401. }
  1402. | BOOLEAN {
  1403. error(@1, "boolean values for the replace-client-name are "
  1404. "no longer supported");
  1405. }
  1406. ;
  1407. generated_prefix: GENERATED_PREFIX {
  1408. ctx.enter(ctx.NO_KEYWORD);
  1409. } COLON STRING {
  1410. ElementPtr s(new StringElement($4, ctx.loc2pos(@4)));
  1411. ctx.stack_.back()->set("generated-prefix", s);
  1412. ctx.leave();
  1413. };
  1414. // JSON entries for Dhcp4 and DhcpDdns
  1415. dhcp6_json_object: DHCP6 {
  1416. ctx.enter(ctx.NO_KEYWORD);
  1417. } COLON value {
  1418. ctx.stack_.back()->set("Dhcp6", $4);
  1419. ctx.leave();
  1420. };
  1421. dhcpddns_json_object: DHCPDDNS {
  1422. ctx.enter(ctx.NO_KEYWORD);
  1423. } COLON value {
  1424. ctx.stack_.back()->set("DhcpDdns", $4);
  1425. ctx.leave();
  1426. };
  1427. control_agent_json_object: CONTROL_AGENT {
  1428. ctx.enter(ctx.NO_KEYWORD);
  1429. } COLON value {
  1430. ctx.stack_.back()->set("Control-agent", $4);
  1431. ctx.leave();
  1432. };
  1433. // --- logging entry -----------------------------------------
  1434. // This defines the top level "Logging" object. It parses
  1435. // the following "Logging": { ... }. The ... is defined
  1436. // by logging_params
  1437. logging_object: LOGGING {
  1438. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  1439. ctx.stack_.back()->set("Logging", m);
  1440. ctx.stack_.push_back(m);
  1441. ctx.enter(ctx.LOGGING);
  1442. } COLON LCURLY_BRACKET logging_params RCURLY_BRACKET {
  1443. ctx.stack_.pop_back();
  1444. ctx.leave();
  1445. };
  1446. // This defines the list of allowed parameters that may appear
  1447. // in the top-level Logging object. It can either be a single
  1448. // parameter or several parameters separated by commas.
  1449. logging_params: logging_param
  1450. | logging_params COMMA logging_param
  1451. ;
  1452. // There's currently only one parameter defined, which is "loggers".
  1453. logging_param: loggers;
  1454. // "loggers", the only parameter currently defined in "Logging" object,
  1455. // is "Loggers": [ ... ].
  1456. loggers: LOGGERS {
  1457. ElementPtr l(new ListElement(ctx.loc2pos(@1)));
  1458. ctx.stack_.back()->set("loggers", l);
  1459. ctx.stack_.push_back(l);
  1460. ctx.enter(ctx.LOGGERS);
  1461. } COLON LSQUARE_BRACKET loggers_entries RSQUARE_BRACKET {
  1462. ctx.stack_.pop_back();
  1463. ctx.leave();
  1464. };
  1465. // These are the parameters allowed in loggers: either one logger
  1466. // entry or multiple entries separate by commas.
  1467. loggers_entries: logger_entry
  1468. | loggers_entries COMMA logger_entry
  1469. ;
  1470. // This defines a single entry defined in loggers in Logging.
  1471. logger_entry: LCURLY_BRACKET {
  1472. ElementPtr l(new MapElement(ctx.loc2pos(@1)));
  1473. ctx.stack_.back()->add(l);
  1474. ctx.stack_.push_back(l);
  1475. } logger_params RCURLY_BRACKET {
  1476. ctx.stack_.pop_back();
  1477. };
  1478. logger_params: logger_param
  1479. | logger_params COMMA logger_param
  1480. ;
  1481. logger_param: name
  1482. | output_options_list
  1483. | debuglevel
  1484. | severity
  1485. | unknown_map_entry
  1486. ;
  1487. debuglevel: DEBUGLEVEL COLON INTEGER {
  1488. ElementPtr dl(new IntElement($3, ctx.loc2pos(@3)));
  1489. ctx.stack_.back()->set("debuglevel", dl);
  1490. };
  1491. severity: SEVERITY {
  1492. ctx.enter(ctx.NO_KEYWORD);
  1493. } COLON STRING {
  1494. ElementPtr sev(new StringElement($4, ctx.loc2pos(@4)));
  1495. ctx.stack_.back()->set("severity", sev);
  1496. ctx.leave();
  1497. };
  1498. output_options_list: OUTPUT_OPTIONS {
  1499. ElementPtr l(new ListElement(ctx.loc2pos(@1)));
  1500. ctx.stack_.back()->set("output_options", l);
  1501. ctx.stack_.push_back(l);
  1502. ctx.enter(ctx.OUTPUT_OPTIONS);
  1503. } COLON LSQUARE_BRACKET output_options_list_content RSQUARE_BRACKET {
  1504. ctx.stack_.pop_back();
  1505. ctx.leave();
  1506. };
  1507. output_options_list_content: output_entry
  1508. | output_options_list_content COMMA output_entry
  1509. ;
  1510. output_entry: LCURLY_BRACKET {
  1511. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  1512. ctx.stack_.back()->add(m);
  1513. ctx.stack_.push_back(m);
  1514. } output_params_list RCURLY_BRACKET {
  1515. ctx.stack_.pop_back();
  1516. };
  1517. output_params_list: output_params
  1518. | output_params_list COMMA output_params
  1519. ;
  1520. output_params: output
  1521. | flush
  1522. | maxsize
  1523. | maxver
  1524. ;
  1525. output: OUTPUT {
  1526. ctx.enter(ctx.NO_KEYWORD);
  1527. } COLON STRING {
  1528. ElementPtr sev(new StringElement($4, ctx.loc2pos(@4)));
  1529. ctx.stack_.back()->set("output", sev);
  1530. ctx.leave();
  1531. };
  1532. flush: FLUSH COLON BOOLEAN {
  1533. ElementPtr flush(new BoolElement($3, ctx.loc2pos(@3)));
  1534. ctx.stack_.back()->set("flush", flush);
  1535. }
  1536. maxsize: MAXSIZE COLON INTEGER {
  1537. ElementPtr maxsize(new IntElement($3, ctx.loc2pos(@3)));
  1538. ctx.stack_.back()->set("maxsize", maxsize);
  1539. }
  1540. maxver: MAXVER COLON INTEGER {
  1541. ElementPtr maxver(new IntElement($3, ctx.loc2pos(@3)));
  1542. ctx.stack_.back()->set("maxver", maxver);
  1543. }
  1544. %%
  1545. void
  1546. isc::dhcp::Dhcp4Parser::error(const location_type& loc,
  1547. const std::string& what)
  1548. {
  1549. ctx.error(loc, what);
  1550. }