dhcp4_parser.yy 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547
  1. /* Copyright (C) 2016 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. ECHO_CLIENT_ID "echo-client-id"
  51. MATCH_CLIENT_ID "match-client-id"
  52. NEXT_SERVER "next-server"
  53. SERVER_HOSTNAME "server-hostname"
  54. BOOT_FILE_NAME "boot-file-name"
  55. LEASE_DATABASE "lease-database"
  56. HOSTS_DATABASE "hosts-database"
  57. TYPE "type"
  58. USER "user"
  59. PASSWORD "password"
  60. HOST "host"
  61. PERSIST "persist"
  62. LFC_INTERVAL "lfc-interval"
  63. READONLY "readonly"
  64. VALID_LIFETIME "valid-lifetime"
  65. RENEW_TIMER "renew-timer"
  66. REBIND_TIMER "rebind-timer"
  67. DECLINE_PROBATION_PERIOD "decline-probation-period"
  68. SUBNET4 "subnet4"
  69. SUBNET_4O6_INTERFACE "4o6-interface"
  70. SUBNET_4O6_INTERFACE_ID "4o6-interface-id"
  71. SUBNET_4O6_SUBNET "4o6-subnet"
  72. OPTION_DEF "option-def"
  73. OPTION_DATA "option-data"
  74. NAME "name"
  75. DATA "data"
  76. CODE "code"
  77. SPACE "space"
  78. CSV_FORMAT "csv-format"
  79. RECORD_TYPES "record-types"
  80. ENCAPSULATE "encapsulate"
  81. ARRAY "array"
  82. POOLS "pools"
  83. POOL "pool"
  84. SUBNET "subnet"
  85. INTERFACE "interface"
  86. INTERFACE_ID "interface-id"
  87. ID "id"
  88. RAPID_COMMIT "rapid-commit"
  89. RESERVATION_MODE "reservation-mode"
  90. HOST_RESERVATION_IDENTIFIERS "host-reservation-identifiers"
  91. CLIENT_CLASSES "client-classes"
  92. TEST "test"
  93. CLIENT_CLASS "client-class"
  94. RESERVATIONS "reservations"
  95. DUID "duid"
  96. HW_ADDRESS "hw-address"
  97. CIRCUIT_ID "circuit-id"
  98. CLIENT_ID "client-id"
  99. HOSTNAME "hostname"
  100. RELAY "relay"
  101. IP_ADDRESS "ip-address"
  102. HOOKS_LIBRARIES "hooks-libraries"
  103. LIBRARY "library"
  104. PARAMETERS "parameters"
  105. EXPIRED_LEASES_PROCESSING "expired-leases-processing"
  106. SERVER_ID "server-id"
  107. IDENTIFIER "identifier"
  108. HTYPE "htype"
  109. TIME "time"
  110. ENTERPRISE_ID "enterprise-id"
  111. DHCP4O6_PORT "dhcp4o6-port"
  112. VERSION "version"
  113. CONTROL_SOCKET "control-socket"
  114. SOCKET_TYPE "socket-type"
  115. SOCKET_NAME "socket-name"
  116. DHCP_DDNS "dhcp-ddns"
  117. /// @todo: Implement proper parsing for those parameters in Dhcp4/dhcp-ddns/*.
  118. /// This should be part of the #5043 ticket. Listing the keywords here for
  119. /// completeness.
  120. // These are tokens defined in Dhcp4/dhcp-ddns/*
  121. // They're not
  122. // ENABLE_UPDATES "enable-updates"
  123. // SERVER_IP "server-ip"
  124. // SENDER_IP "sender-ip"
  125. // SENDER_PORT "sender-port"
  126. // MAX_QUEUE_SIZE "max-queue-size"
  127. // NCR_PROTOCOL "ncr-protocol"
  128. // NCR_FORMAT "ncr-format"
  129. // ALWAYS_INCLUDE_FQDN "always-include-fqdn"
  130. // OVERRDIDE_NO_UPDATE "override-no-update"
  131. // OVERRDIDE_CLIENT_UPDATE "override-client-update"
  132. // REPLACE_CLIENT_NAME "replace-client-name"
  133. // GENERATED_PREFIX "generated-prefix"
  134. // QUALIFYING_SUFFIX "qualifying-suffix"
  135. LOGGING "Logging"
  136. LOGGERS "loggers"
  137. OUTPUT_OPTIONS "output_options"
  138. OUTPUT "output"
  139. DEBUGLEVEL "debuglevel"
  140. SEVERITY "severity"
  141. DHCP6 "Dhcp6"
  142. DHCPDDNS "DhcpDdns"
  143. // Not real tokens, just a way to signal what the parser is expected to
  144. // parse.
  145. TOPLEVEL_JSON
  146. TOPLEVEL_DHCP4
  147. SUB_DHCP4
  148. SUB_INTERFACES4
  149. SUB_SUBNET4
  150. SUB_POOL4
  151. SUB_RESERVATION
  152. SUB_OPTION_DEF
  153. SUB_OPTION_DATA
  154. SUB_HOOKS_LIBRARY
  155. ;
  156. %token <std::string> STRING "constant string"
  157. %token <int64_t> INTEGER "integer"
  158. %token <double> FLOAT "floating point"
  159. %token <bool> BOOLEAN "boolean"
  160. %type <ElementPtr> value
  161. %type <ElementPtr> version_value
  162. %printer { yyoutput << $$; } <*>;
  163. %%
  164. // The whole grammar starts with a map, because the config file
  165. // constists of Dhcp, Logger and DhcpDdns entries in one big { }.
  166. // We made the same for subparsers at the exception of the JSON value.
  167. %start start;
  168. start: TOPLEVEL_JSON { ctx.ctx_ = ctx.NO_KEYWORD; } sub_json
  169. | TOPLEVEL_DHCP4 { ctx.ctx_ = ctx.CONFIG; } syntax_map
  170. | SUB_DHCP4 { ctx.ctx_ = ctx.DHCP4; } sub_dhcp4
  171. | SUB_INTERFACES4 { ctx.ctx_ = ctx.INTERFACES_CONFIG; } sub_interfaces4
  172. | SUB_SUBNET4 { ctx.ctx_ = ctx.SUBNET4; } sub_subnet4
  173. | SUB_POOL4 { ctx.ctx_ = ctx.POOLS; } sub_pool4
  174. | SUB_RESERVATION { ctx.ctx_ = ctx.RESERVATIONS; } sub_reservation
  175. | SUB_OPTION_DEF { ctx.ctx_ = ctx.OPTION_DEF; } sub_option_def
  176. | SUB_OPTION_DATA { ctx.ctx_ = ctx.OPTION_DATA; } sub_option_data
  177. | SUB_HOOKS_LIBRARY { ctx.ctx_ = ctx.HOOKS_LIBRARIES; } sub_hooks_library
  178. ;
  179. // ---- generic JSON parser ---------------------------------
  180. // Note that ctx_ is NO_KEYWORD here
  181. // Values rule
  182. value: INTEGER { $$ = ElementPtr(new IntElement($1, ctx.loc2pos(@1))); }
  183. | FLOAT { $$ = ElementPtr(new DoubleElement($1, ctx.loc2pos(@1))); }
  184. | BOOLEAN { $$ = ElementPtr(new BoolElement($1, ctx.loc2pos(@1))); }
  185. | STRING { $$ = ElementPtr(new StringElement($1, ctx.loc2pos(@1))); }
  186. | NULL_TYPE { $$ = ElementPtr(new NullElement(ctx.loc2pos(@1))); }
  187. | map2 { $$ = ctx.stack_.back(); ctx.stack_.pop_back(); }
  188. | list_generic { $$ = ctx.stack_.back(); ctx.stack_.pop_back(); }
  189. ;
  190. sub_json: value {
  191. // Push back the JSON value on the stack
  192. ctx.stack_.push_back($1);
  193. };
  194. map2: LCURLY_BRACKET {
  195. // This code is executed when we're about to start parsing
  196. // the content of the map
  197. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  198. ctx.stack_.push_back(m);
  199. } map_content RCURLY_BRACKET {
  200. // map parsing completed. If we ever want to do any wrap up
  201. // (maybe some sanity checking), this would be the best place
  202. // for it.
  203. };
  204. // Assignments rule
  205. map_content: %empty // empty map
  206. | not_empty_map
  207. ;
  208. not_empty_map: STRING COLON value {
  209. // map containing a single entry
  210. ctx.stack_.back()->set($1, $3);
  211. }
  212. | not_empty_map COMMA STRING COLON value {
  213. // map consisting of a shorter map followed by
  214. // comma and string:value
  215. ctx.stack_.back()->set($3, $5);
  216. }
  217. ;
  218. list_generic: LSQUARE_BRACKET {
  219. ElementPtr l(new ListElement(ctx.loc2pos(@1)));
  220. ctx.stack_.push_back(l);
  221. } list_content RSQUARE_BRACKET {
  222. // list parsing complete. Put any sanity checking here
  223. };
  224. // This one is used in syntax parser.
  225. list2: LSQUARE_BRACKET {
  226. // List parsing about to start
  227. } list_content RSQUARE_BRACKET {
  228. // list parsing complete. Put any sanity checking here
  229. //ctx.stack_.pop_back();
  230. };
  231. list_content: %empty // Empty list
  232. | not_empty_list
  233. ;
  234. not_empty_list: value {
  235. // List consisting of a single element.
  236. ctx.stack_.back()->add($1);
  237. }
  238. | not_empty_list COMMA value {
  239. // List ending with , and a value.
  240. ctx.stack_.back()->add($3);
  241. }
  242. ;
  243. // ---- generic JSON parser ends here ----------------------------------
  244. // ---- syntax checking parser starts here -----------------------------
  245. // Unknown keyword in a map
  246. unknown_map_entry: STRING COLON {
  247. const std::string& where = ctx.contextName();
  248. const std::string& keyword = $1;
  249. error(@1,
  250. "got unexpected keyword \"" + keyword + "\" in " + where + " map.");
  251. };
  252. // This defines the top-level { } that holds Dhcp6, Dhcp4, DhcpDdns or Logging
  253. // objects.
  254. syntax_map: LCURLY_BRACKET {
  255. // This code is executed when we're about to start parsing
  256. // the content of the map
  257. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  258. ctx.stack_.push_back(m);
  259. } global_objects RCURLY_BRACKET {
  260. // map parsing completed. If we ever want to do any wrap up
  261. // (maybe some sanity checking), this would be the best place
  262. // for it.
  263. };
  264. // This represents top-level entries: Dhcp6, Dhcp4, DhcpDdns, Logging
  265. global_objects: global_object
  266. | global_objects COMMA global_object
  267. ;
  268. // This represents a single top level entry, e.g. Dhcp4 or DhcpDdns.
  269. global_object: dhcp4_object
  270. | logging_object
  271. | dhcp6_json_object
  272. | dhcpddns_json_object
  273. | unknown_map_entry
  274. ;
  275. dhcp4_object: DHCP4 {
  276. // This code is executed when we're about to start parsing
  277. // the content of the map
  278. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  279. ctx.stack_.back()->set("Dhcp4", m);
  280. ctx.stack_.push_back(m);
  281. ctx.enter(ctx.DHCP4);
  282. } COLON LCURLY_BRACKET global_params RCURLY_BRACKET {
  283. // map parsing completed. If we ever want to do any wrap up
  284. // (maybe some sanity checking), this would be the best place
  285. // for it.
  286. ctx.stack_.pop_back();
  287. ctx.leave();
  288. };
  289. // subparser: similar to the corresponding rule but without parent
  290. // so the stack is empty at the rule entry.
  291. sub_dhcp4: LCURLY_BRACKET {
  292. // Parse the Dhcp4 map
  293. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  294. ctx.stack_.push_back(m);
  295. } global_params RCURLY_BRACKET {
  296. // parsing completed
  297. };
  298. global_params: global_param
  299. | global_params COMMA global_param
  300. ;
  301. // These are the parameters that are allowed in the top-level for
  302. // Dhcp4.
  303. global_param: valid_lifetime
  304. | renew_timer
  305. | rebind_timer
  306. | decline_probation_period
  307. | subnet4_list
  308. | interfaces_config
  309. | lease_database
  310. | hosts_database
  311. | host_reservation_identifiers
  312. | client_classes
  313. | option_def_list
  314. | option_data_list
  315. | hooks_libraries
  316. | expired_leases_processing
  317. | server_id
  318. | dhcp4o6_port
  319. | version
  320. | control_socket
  321. | dhcp_ddns
  322. | echo_client_id
  323. | match_client_id
  324. | next_server
  325. | unknown_map_entry
  326. ;
  327. valid_lifetime: VALID_LIFETIME COLON INTEGER {
  328. ElementPtr prf(new IntElement($3, ctx.loc2pos(@3)));
  329. ctx.stack_.back()->set("valid-lifetime", prf);
  330. };
  331. renew_timer: RENEW_TIMER COLON INTEGER {
  332. ElementPtr prf(new IntElement($3, ctx.loc2pos(@3)));
  333. ctx.stack_.back()->set("renew-timer", prf);
  334. };
  335. rebind_timer: REBIND_TIMER COLON INTEGER {
  336. ElementPtr prf(new IntElement($3, ctx.loc2pos(@3)));
  337. ctx.stack_.back()->set("rebind-timer", prf);
  338. };
  339. decline_probation_period: DECLINE_PROBATION_PERIOD COLON INTEGER {
  340. ElementPtr dpp(new IntElement($3, ctx.loc2pos(@3)));
  341. ctx.stack_.back()->set("decline-probation-period", dpp);
  342. };
  343. echo_client_id: ECHO_CLIENT_ID COLON BOOLEAN {
  344. ElementPtr echo(new BoolElement($3, ctx.loc2pos(@3)));
  345. ctx.stack_.back()->set("echo-client-id", echo);
  346. };
  347. match_client_id: MATCH_CLIENT_ID COLON BOOLEAN {
  348. ElementPtr match(new BoolElement($3, ctx.loc2pos(@3)));
  349. ctx.stack_.back()->set("match-client-id", match);
  350. };
  351. interfaces_config: INTERFACES_CONFIG {
  352. ElementPtr i(new MapElement(ctx.loc2pos(@1)));
  353. ctx.stack_.back()->set("interfaces-config", i);
  354. ctx.stack_.push_back(i);
  355. ctx.enter(ctx.INTERFACES_CONFIG);
  356. } COLON LCURLY_BRACKET interfaces_config_params RCURLY_BRACKET {
  357. ctx.stack_.pop_back();
  358. ctx.leave();
  359. };
  360. interfaces_config_params: interfaces_config_param
  361. | interfaces_config_params COMMA interfaces_config_param
  362. ;
  363. interfaces_config_param: interfaces_list
  364. | dhcp_socket_type
  365. ;
  366. sub_interfaces4: LCURLY_BRACKET {
  367. // Parse the interfaces-config map
  368. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  369. ctx.stack_.push_back(m);
  370. } interfaces_config_params RCURLY_BRACKET {
  371. // parsing completed
  372. };
  373. interfaces_list: INTERFACES {
  374. ElementPtr l(new ListElement(ctx.loc2pos(@1)));
  375. ctx.stack_.back()->set("interfaces", l);
  376. ctx.stack_.push_back(l);
  377. ctx.enter(ctx.NO_KEYWORD);
  378. } COLON list2 {
  379. ctx.stack_.pop_back();
  380. ctx.leave();
  381. };
  382. dhcp_socket_type: DHCP_SOCKET_TYPE {
  383. ctx.enter(ctx.NO_KEYWORD);
  384. } COLON STRING {
  385. ElementPtr type(new StringElement($4, ctx.loc2pos(@4)));
  386. ctx.stack_.back()->set("dhcp-socket-type", type);
  387. ctx.leave();
  388. };
  389. lease_database: LEASE_DATABASE {
  390. ElementPtr i(new MapElement(ctx.loc2pos(@1)));
  391. ctx.stack_.back()->set("lease-database", i);
  392. ctx.stack_.push_back(i);
  393. ctx.enter(ctx.LEASE_DATABASE);
  394. } COLON LCURLY_BRACKET database_map_params RCURLY_BRACKET {
  395. ctx.stack_.pop_back();
  396. ctx.leave();
  397. };
  398. hosts_database: HOSTS_DATABASE {
  399. ElementPtr i(new MapElement(ctx.loc2pos(@1)));
  400. ctx.stack_.back()->set("hosts-database", i);
  401. ctx.stack_.push_back(i);
  402. ctx.enter(ctx.HOSTS_DATABASE);
  403. } COLON LCURLY_BRACKET database_map_params RCURLY_BRACKET {
  404. ctx.stack_.pop_back();
  405. ctx.leave();
  406. };
  407. database_map_params: database_map_param
  408. | database_map_params COMMA database_map_param
  409. ;
  410. database_map_param: type
  411. | user
  412. | password
  413. | host
  414. | name
  415. | persist
  416. | lfc_interval
  417. | readonly
  418. | unknown_map_entry
  419. ;
  420. type: TYPE {
  421. ctx.enter(ctx.NO_KEYWORD);
  422. } COLON STRING {
  423. ElementPtr prf(new StringElement($4, ctx.loc2pos(@4)));
  424. ctx.stack_.back()->set("type", prf);
  425. ctx.leave();
  426. };
  427. user: USER {
  428. ctx.enter(ctx.NO_KEYWORD);
  429. } COLON STRING {
  430. ElementPtr user(new StringElement($4, ctx.loc2pos(@4)));
  431. ctx.stack_.back()->set("user", user);
  432. ctx.leave();
  433. };
  434. password: PASSWORD {
  435. ctx.enter(ctx.NO_KEYWORD);
  436. } COLON STRING {
  437. ElementPtr pwd(new StringElement($4, ctx.loc2pos(@4)));
  438. ctx.stack_.back()->set("password", pwd);
  439. ctx.leave();
  440. };
  441. host: HOST {
  442. ctx.enter(ctx.NO_KEYWORD);
  443. } COLON STRING {
  444. ElementPtr h(new StringElement($4, ctx.loc2pos(@4)));
  445. ctx.stack_.back()->set("host", h);
  446. ctx.leave();
  447. };
  448. name: NAME {
  449. ctx.enter(ctx.NO_KEYWORD);
  450. } COLON STRING {
  451. ElementPtr name(new StringElement($4, ctx.loc2pos(@4)));
  452. ctx.stack_.back()->set("name", name);
  453. ctx.leave();
  454. };
  455. persist: PERSIST COLON BOOLEAN {
  456. ElementPtr n(new BoolElement($3, ctx.loc2pos(@3)));
  457. ctx.stack_.back()->set("persist", n);
  458. };
  459. lfc_interval: LFC_INTERVAL COLON INTEGER {
  460. ElementPtr n(new IntElement($3, ctx.loc2pos(@3)));
  461. ctx.stack_.back()->set("lfc-interval", n);
  462. };
  463. readonly: READONLY COLON BOOLEAN {
  464. ElementPtr n(new BoolElement($3, ctx.loc2pos(@3)));
  465. ctx.stack_.back()->set("readonly", n);
  466. };
  467. duid_id : DUID {
  468. ElementPtr duid(new StringElement("duid", ctx.loc2pos(@1)));
  469. ctx.stack_.back()->add(duid);
  470. };
  471. host_reservation_identifiers: HOST_RESERVATION_IDENTIFIERS {
  472. ElementPtr l(new ListElement(ctx.loc2pos(@1)));
  473. ctx.stack_.back()->set("host-reservation-identifiers", l);
  474. ctx.stack_.push_back(l);
  475. ctx.enter(ctx.HOST_RESERVATION_IDENTIFIERS);
  476. } COLON LSQUARE_BRACKET host_reservation_identifiers_list RSQUARE_BRACKET {
  477. ctx.stack_.pop_back();
  478. ctx.leave();
  479. };
  480. host_reservation_identifiers_list: host_reservation_identifier
  481. | host_reservation_identifiers_list COMMA host_reservation_identifier
  482. ;
  483. host_reservation_identifier: duid_id
  484. | hw_address_id
  485. | circuit_id
  486. | client_id
  487. ;
  488. hw_address_id : HW_ADDRESS {
  489. ElementPtr hwaddr(new StringElement("hw-address", ctx.loc2pos(@1)));
  490. ctx.stack_.back()->add(hwaddr);
  491. };
  492. circuit_id : CIRCUIT_ID {
  493. ElementPtr circuit(new StringElement("circuit-id", ctx.loc2pos(@1)));
  494. ctx.stack_.back()->add(circuit);
  495. };
  496. client_id : CLIENT_ID {
  497. ElementPtr client(new StringElement("client-id", ctx.loc2pos(@1)));
  498. ctx.stack_.back()->add(client);
  499. };
  500. hooks_libraries: HOOKS_LIBRARIES {
  501. ElementPtr l(new ListElement(ctx.loc2pos(@1)));
  502. ctx.stack_.back()->set("hooks-libraries", l);
  503. ctx.stack_.push_back(l);
  504. ctx.enter(ctx.HOOKS_LIBRARIES);
  505. } COLON LSQUARE_BRACKET hooks_libraries_list RSQUARE_BRACKET {
  506. ctx.stack_.pop_back();
  507. ctx.leave();
  508. };
  509. hooks_libraries_list: %empty
  510. | not_empty_hooks_libraries_list
  511. ;
  512. not_empty_hooks_libraries_list: hooks_library
  513. | not_empty_hooks_libraries_list COMMA hooks_library
  514. ;
  515. hooks_library: LCURLY_BRACKET {
  516. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  517. ctx.stack_.back()->add(m);
  518. ctx.stack_.push_back(m);
  519. } hooks_params RCURLY_BRACKET {
  520. ctx.stack_.pop_back();
  521. };
  522. sub_hooks_library: LCURLY_BRACKET {
  523. // Parse the hooks-libraries list entry map
  524. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  525. ctx.stack_.push_back(m);
  526. } hooks_params RCURLY_BRACKET {
  527. // parsing completed
  528. };
  529. hooks_params: hooks_param
  530. | hooks_params COMMA hooks_param
  531. | unknown_map_entry
  532. ;
  533. hooks_param: library
  534. | parameters
  535. ;
  536. library: LIBRARY {
  537. ctx.enter(ctx.NO_KEYWORD);
  538. } COLON STRING {
  539. ElementPtr lib(new StringElement($4, ctx.loc2pos(@4)));
  540. ctx.stack_.back()->set("library", lib);
  541. ctx.leave();
  542. };
  543. parameters: PARAMETERS {
  544. ctx.enter(ctx.NO_KEYWORD);
  545. } COLON value {
  546. ctx.stack_.back()->set("parameters", $4);
  547. ctx.leave();
  548. };
  549. // --- expired-leases-processing ------------------------
  550. expired_leases_processing: EXPIRED_LEASES_PROCESSING {
  551. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  552. ctx.stack_.back()->set("expired-leases-processing", m);
  553. ctx.stack_.push_back(m);
  554. ctx.enter(ctx.NO_KEYWORD);
  555. } COLON LCURLY_BRACKET expired_leases_params RCURLY_BRACKET {
  556. ctx.stack_.pop_back();
  557. ctx.leave();
  558. };
  559. expired_leases_params: expired_leases_param
  560. | expired_leases_params COMMA expired_leases_param
  561. ;
  562. // This is a bit of a simplification. But it can also serve as an example.
  563. // Instead of explicitly listing all allowed expired leases parameters, we
  564. // simply say that all of them as integers.
  565. expired_leases_param: STRING COLON INTEGER {
  566. ElementPtr value(new IntElement($3, ctx.loc2pos(@3)));
  567. ctx.stack_.back()->set($1, value);
  568. };
  569. // --- subnet4 ------------------------------------------
  570. // This defines subnet4 as a list of maps.
  571. // "subnet4": [ ... ]
  572. subnet4_list: SUBNET4 {
  573. ElementPtr l(new ListElement(ctx.loc2pos(@1)));
  574. ctx.stack_.back()->set("subnet4", l);
  575. ctx.stack_.push_back(l);
  576. ctx.enter(ctx.SUBNET4);
  577. } COLON LSQUARE_BRACKET subnet4_list_content RSQUARE_BRACKET {
  578. ctx.stack_.pop_back();
  579. ctx.leave();
  580. };
  581. // This defines the ... in "subnet4": [ ... ]
  582. // It can either be empty (no subnets defined), have one subnet
  583. // or have multiple subnets separate by comma.
  584. subnet4_list_content: %empty
  585. | not_empty_subnet4_list
  586. ;
  587. not_empty_subnet4_list: subnet4
  588. | not_empty_subnet4_list COMMA subnet4
  589. ;
  590. // --- Subnet definitions -------------------------------
  591. // This defines a single subnet, i.e. a single map with
  592. // subnet4 array.
  593. subnet4: LCURLY_BRACKET {
  594. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  595. ctx.stack_.back()->add(m);
  596. ctx.stack_.push_back(m);
  597. } subnet4_params RCURLY_BRACKET {
  598. // Once we reached this place, the subnet parsing is now complete.
  599. // If we want to, we can implement default values here.
  600. // In particular we can do things like this:
  601. // if (!ctx.stack_.back()->get("interface")) {
  602. // ctx.stack_.back()->set("interface", StringElement("loopback"));
  603. // }
  604. //
  605. // We can also stack up one level (Dhcp4) and copy over whatever
  606. // global parameters we want to:
  607. // if (!ctx.stack_.back()->get("renew-timer")) {
  608. // ElementPtr renew = ctx_stack_[...].get("renew-timer");
  609. // if (renew) {
  610. // ctx.stack_.back()->set("renew-timer", renew);
  611. // }
  612. // }
  613. ctx.stack_.pop_back();
  614. };
  615. sub_subnet4: LCURLY_BRACKET {
  616. // Parse the subnet4 list entry map
  617. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  618. ctx.stack_.push_back(m);
  619. } subnet4_params RCURLY_BRACKET {
  620. // parsing completed
  621. };
  622. // This defines that subnet can have one or more parameters.
  623. subnet4_params: subnet4_param
  624. | subnet4_params COMMA subnet4_param
  625. ;
  626. // This defines a list of allowed parameters for each subnet.
  627. subnet4_param: valid_lifetime
  628. | renew_timer
  629. | rebind_timer
  630. | option_data_list
  631. | pools_list
  632. | subnet
  633. | interface
  634. | interface_id
  635. | id
  636. | rapid_commit
  637. | client_class
  638. | reservations
  639. | reservation_mode
  640. | relay
  641. | match_client_id
  642. | next_server
  643. | subnet_4o6_interface
  644. | subnet_4o6_interface_id
  645. | subnet_4o6_subnet
  646. | unknown_map_entry
  647. ;
  648. subnet: SUBNET {
  649. ctx.enter(ctx.NO_KEYWORD);
  650. } COLON STRING {
  651. ElementPtr subnet(new StringElement($4, ctx.loc2pos(@4)));
  652. ctx.stack_.back()->set("subnet", subnet);
  653. ctx.leave();
  654. };
  655. subnet_4o6_interface: SUBNET_4O6_INTERFACE {
  656. ctx.enter(ctx.NO_KEYWORD);
  657. } COLON STRING {
  658. ElementPtr iface(new StringElement($4, ctx.loc2pos(@4)));
  659. ctx.stack_.back()->set("4o6-interface", iface);
  660. ctx.leave();
  661. };
  662. subnet_4o6_interface_id: SUBNET_4O6_INTERFACE_ID {
  663. ctx.enter(ctx.NO_KEYWORD);
  664. } COLON STRING {
  665. ElementPtr iface(new StringElement($4, ctx.loc2pos(@4)));
  666. ctx.stack_.back()->set("4o6-interface-id", iface);
  667. ctx.leave();
  668. };
  669. subnet_4o6_subnet: SUBNET_4O6_SUBNET {
  670. ctx.enter(ctx.NO_KEYWORD);
  671. } COLON STRING {
  672. ElementPtr iface(new StringElement($4, ctx.loc2pos(@4)));
  673. ctx.stack_.back()->set("4o6-subnet", iface);
  674. ctx.leave();
  675. };
  676. interface: INTERFACE {
  677. ctx.enter(ctx.NO_KEYWORD);
  678. } COLON STRING {
  679. ElementPtr iface(new StringElement($4, ctx.loc2pos(@4)));
  680. ctx.stack_.back()->set("interface", iface);
  681. ctx.leave();
  682. };
  683. interface_id: INTERFACE_ID {
  684. ctx.enter(ctx.NO_KEYWORD);
  685. } COLON STRING {
  686. ElementPtr iface(new StringElement($4, ctx.loc2pos(@4)));
  687. ctx.stack_.back()->set("interface-id", iface);
  688. ctx.leave();
  689. };
  690. client_class: CLIENT_CLASS {
  691. ctx.enter(ctx.CLIENT_CLASS);
  692. } COLON STRING {
  693. ElementPtr cls(new StringElement($4, ctx.loc2pos(@4)));
  694. ctx.stack_.back()->set("client-class", cls);
  695. ctx.leave();
  696. };
  697. reservation_mode: RESERVATION_MODE {
  698. ctx.enter(ctx.NO_KEYWORD);
  699. } COLON STRING {
  700. ElementPtr rm(new StringElement($4, ctx.loc2pos(@4)));
  701. ctx.stack_.back()->set("reservation-mode", rm);
  702. ctx.leave();
  703. };
  704. id: ID COLON INTEGER {
  705. ElementPtr id(new IntElement($3, ctx.loc2pos(@3)));
  706. ctx.stack_.back()->set("id", id);
  707. };
  708. rapid_commit: RAPID_COMMIT COLON BOOLEAN {
  709. ElementPtr rc(new BoolElement($3, ctx.loc2pos(@3)));
  710. ctx.stack_.back()->set("rapid-commit", rc);
  711. };
  712. // ---- option-def --------------------------
  713. // This defines the "option-def": [ ... ] entry that may appear
  714. // at a global option.
  715. option_def_list: OPTION_DEF {
  716. ElementPtr l(new ListElement(ctx.loc2pos(@1)));
  717. ctx.stack_.back()->set("option-def", l);
  718. ctx.stack_.push_back(l);
  719. ctx.enter(ctx.OPTION_DEF);
  720. } COLON LSQUARE_BRACKET option_def_list_content RSQUARE_BRACKET {
  721. ctx.stack_.pop_back();
  722. ctx.leave();
  723. };
  724. // This defines the content of option-def. It may be empty,
  725. // have one entry or multiple entries separated by comma.
  726. option_def_list_content: %empty
  727. | not_empty_option_def_list
  728. ;
  729. not_empty_option_def_list: option_def_entry
  730. | not_empty_option_def_list COMMA option_def_entry
  731. ;
  732. // This defines the content of a single entry { ... } within
  733. // option-def list.
  734. option_def_entry: LCURLY_BRACKET {
  735. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  736. ctx.stack_.back()->add(m);
  737. ctx.stack_.push_back(m);
  738. } option_def_params RCURLY_BRACKET {
  739. ctx.stack_.pop_back();
  740. };
  741. // This defines the top level scope when the parser is told to parse a single
  742. // option definition. It's almost exactly the same as option_def_entry, except
  743. // that it does leave its value on stack.
  744. sub_option_def: LCURLY_BRACKET {
  745. // Parse the option-def list entry map
  746. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  747. ctx.stack_.push_back(m);
  748. } option_def_params RCURLY_BRACKET {
  749. // parsing completed
  750. };
  751. // This defines parameters specified inside the map that itself
  752. // is an entry in option-def list.
  753. option_def_params: %empty
  754. | not_empty_option_def_params
  755. ;
  756. not_empty_option_def_params: option_def_param
  757. | not_empty_option_def_params COMMA option_def_param
  758. ;
  759. option_def_param: option_def_name
  760. | option_def_code
  761. | option_def_type
  762. | option_def_record_types
  763. | option_def_space
  764. | option_def_encapsulate
  765. | option_def_array
  766. | unknown_map_entry
  767. ;
  768. option_def_name: name;
  769. code: CODE COLON INTEGER {
  770. ElementPtr code(new IntElement($3, ctx.loc2pos(@3)));
  771. ctx.stack_.back()->set("code", code);
  772. };
  773. option_def_code: code;
  774. option_def_type: type;
  775. option_def_record_types: RECORD_TYPES {
  776. ctx.enter(ctx.NO_KEYWORD);
  777. } COLON STRING {
  778. ElementPtr rtypes(new StringElement($4, ctx.loc2pos(@4)));
  779. ctx.stack_.back()->set("record-types", rtypes);
  780. ctx.leave();
  781. };
  782. space: SPACE {
  783. ctx.enter(ctx.NO_KEYWORD);
  784. } COLON STRING {
  785. ElementPtr space(new StringElement($4, ctx.loc2pos(@4)));
  786. ctx.stack_.back()->set("space", space);
  787. ctx.leave();
  788. };
  789. option_def_space: space;
  790. option_def_encapsulate: ENCAPSULATE {
  791. ctx.enter(ctx.NO_KEYWORD);
  792. } COLON STRING {
  793. ElementPtr encap(new StringElement($4, ctx.loc2pos(@4)));
  794. ctx.stack_.back()->set("encapsulate", encap);
  795. ctx.leave();
  796. };
  797. option_def_array: ARRAY COLON BOOLEAN {
  798. ElementPtr array(new BoolElement($3, ctx.loc2pos(@3)));
  799. ctx.stack_.back()->set("array", array);
  800. };
  801. // ---- option-data --------------------------
  802. // This defines the "option-data": [ ... ] entry that may appear
  803. // in several places, but most notably in subnet4 entries.
  804. option_data_list: OPTION_DATA {
  805. ElementPtr l(new ListElement(ctx.loc2pos(@1)));
  806. ctx.stack_.back()->set("option-data", l);
  807. ctx.stack_.push_back(l);
  808. ctx.enter(ctx.OPTION_DATA);
  809. } COLON LSQUARE_BRACKET option_data_list_content RSQUARE_BRACKET {
  810. ctx.stack_.pop_back();
  811. ctx.leave();
  812. };
  813. // This defines the content of option-data. It may be empty,
  814. // have one entry or multiple entries separated by comma.
  815. option_data_list_content: %empty
  816. | not_empty_option_data_list
  817. ;
  818. // This defines the content of option-data list. It can either
  819. // be a single value or multiple entries separated by comma.
  820. not_empty_option_data_list: option_data_entry
  821. | not_empty_option_data_list COMMA option_data_entry
  822. ;
  823. // This defines th content of a single entry { ... } within
  824. // option-data list.
  825. option_data_entry: LCURLY_BRACKET {
  826. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  827. ctx.stack_.back()->add(m);
  828. ctx.stack_.push_back(m);
  829. } option_data_params RCURLY_BRACKET {
  830. ctx.stack_.pop_back();
  831. };
  832. // This defines the top level scope when the parser is told to parse a single
  833. // option data. It's almost exactly the same as option_data_entry, except
  834. // that it does leave its value on stack.
  835. sub_option_data: LCURLY_BRACKET {
  836. // Parse the option-data list entry map
  837. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  838. ctx.stack_.push_back(m);
  839. } option_data_params RCURLY_BRACKET {
  840. // parsing completed
  841. };
  842. // This defines parameters specified inside the map that itself
  843. // is an entry in option-data list. It can either be empty
  844. // or have a non-empty list of parameters.
  845. option_data_params: %empty
  846. | not_empty_option_data_params
  847. ;
  848. // Those parameters can either be a single parameter or
  849. // a list of parameters separated by comma.
  850. not_empty_option_data_params: option_data_param
  851. | not_empty_option_data_params COMMA option_data_param
  852. ;
  853. // Each single option-data parameter can be one of the following
  854. // expressions.
  855. option_data_param: option_data_name
  856. | option_data_data
  857. | option_data_code
  858. | option_data_space
  859. | option_data_csv_format
  860. | unknown_map_entry
  861. ;
  862. option_data_name: name;
  863. option_data_data: DATA {
  864. ctx.enter(ctx.NO_KEYWORD);
  865. } COLON STRING {
  866. ElementPtr data(new StringElement($4, ctx.loc2pos(@4)));
  867. ctx.stack_.back()->set("data", data);
  868. ctx.leave();
  869. };
  870. option_data_code: code;
  871. option_data_space: space;
  872. option_data_csv_format: CSV_FORMAT COLON BOOLEAN {
  873. ElementPtr space(new BoolElement($3, ctx.loc2pos(@3)));
  874. ctx.stack_.back()->set("csv-format", space);
  875. };
  876. // ---- pools ------------------------------------
  877. // This defines the "pools": [ ... ] entry that may appear in subnet4.
  878. pools_list: POOLS {
  879. ElementPtr l(new ListElement(ctx.loc2pos(@1)));
  880. ctx.stack_.back()->set("pools", l);
  881. ctx.stack_.push_back(l);
  882. ctx.enter(ctx.POOLS);
  883. } COLON LSQUARE_BRACKET pools_list_content RSQUARE_BRACKET {
  884. ctx.stack_.pop_back();
  885. ctx.leave();
  886. };
  887. // Pools may be empty, contain a single pool entry or multiple entries
  888. // separate by commas.
  889. pools_list_content: %empty
  890. | not_empty_pools_list
  891. ;
  892. not_empty_pools_list: pool_list_entry
  893. | not_empty_pools_list COMMA pool_list_entry
  894. ;
  895. pool_list_entry: LCURLY_BRACKET {
  896. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  897. ctx.stack_.back()->add(m);
  898. ctx.stack_.push_back(m);
  899. } pool_params RCURLY_BRACKET {
  900. ctx.stack_.pop_back();
  901. };
  902. sub_pool4: LCURLY_BRACKET {
  903. // Parse the pool list entry map
  904. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  905. ctx.stack_.push_back(m);
  906. } pool_params RCURLY_BRACKET {
  907. // parsing completed
  908. };
  909. pool_params: pool_param
  910. | pool_params COMMA pool_param
  911. ;
  912. pool_param: pool_entry
  913. | option_data_list
  914. | unknown_map_entry
  915. ;
  916. pool_entry: POOL {
  917. ctx.enter(ctx.NO_KEYWORD);
  918. } COLON STRING {
  919. ElementPtr pool(new StringElement($4, ctx.loc2pos(@4)));
  920. ctx.stack_.back()->set("pool", pool);
  921. ctx.leave();
  922. };
  923. // --- end of pools definition -------------------------------
  924. // --- reservations ------------------------------------------
  925. reservations: RESERVATIONS {
  926. ElementPtr l(new ListElement(ctx.loc2pos(@1)));
  927. ctx.stack_.back()->set("reservations", l);
  928. ctx.stack_.push_back(l);
  929. ctx.enter(ctx.RESERVATIONS);
  930. } COLON LSQUARE_BRACKET reservations_list RSQUARE_BRACKET {
  931. ctx.stack_.pop_back();
  932. ctx.leave();
  933. };
  934. reservations_list: %empty
  935. | not_empty_reservations_list
  936. ;
  937. not_empty_reservations_list: reservation
  938. | not_empty_reservations_list COMMA reservation
  939. ;
  940. reservation: LCURLY_BRACKET {
  941. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  942. ctx.stack_.back()->add(m);
  943. ctx.stack_.push_back(m);
  944. } reservation_params RCURLY_BRACKET {
  945. ctx.stack_.pop_back();
  946. };
  947. sub_reservation: LCURLY_BRACKET {
  948. // Parse the reservations list entry map
  949. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  950. ctx.stack_.push_back(m);
  951. } reservation_params RCURLY_BRACKET {
  952. // parsing completed
  953. };
  954. reservation_params: %empty
  955. | not_empty_reservation_params
  956. ;
  957. not_empty_reservation_params: reservation_param
  958. | not_empty_reservation_params COMMA reservation_param
  959. ;
  960. // @todo probably need to add mac-address as well here
  961. reservation_param: duid
  962. | reservation_client_classes
  963. | client_id_value
  964. | circuit_id_value
  965. | ip_address
  966. | hw_address
  967. | hostname
  968. | option_data_list
  969. | next_server
  970. | server_hostname
  971. | boot_file_name
  972. | unknown_map_entry
  973. ;
  974. next_server: NEXT_SERVER {
  975. ctx.enter(ctx.NO_KEYWORD);
  976. } COLON STRING {
  977. ElementPtr next_server(new StringElement($4, ctx.loc2pos(@4)));
  978. ctx.stack_.back()->set("next-server", next_server);
  979. ctx.leave();
  980. };
  981. server_hostname: SERVER_HOSTNAME {
  982. ctx.enter(ctx.NO_KEYWORD);
  983. } COLON STRING {
  984. ElementPtr srv(new StringElement($4, ctx.loc2pos(@4)));
  985. ctx.stack_.back()->set("server-hostname", srv);
  986. ctx.leave();
  987. };
  988. boot_file_name: BOOT_FILE_NAME {
  989. ctx.enter(ctx.NO_KEYWORD);
  990. } COLON STRING {
  991. ElementPtr bootfile(new StringElement($4, ctx.loc2pos(@4)));
  992. ctx.stack_.back()->set("boot-file-name", bootfile);
  993. ctx.leave();
  994. };
  995. ip_address: IP_ADDRESS {
  996. ctx.enter(ctx.NO_KEYWORD);
  997. } COLON STRING {
  998. ElementPtr addr(new StringElement($4, ctx.loc2pos(@4)));
  999. ctx.stack_.back()->set("ip-address", addr);
  1000. ctx.leave();
  1001. };
  1002. duid: DUID {
  1003. ctx.enter(ctx.NO_KEYWORD);
  1004. } COLON STRING {
  1005. ElementPtr d(new StringElement($4, ctx.loc2pos(@4)));
  1006. ctx.stack_.back()->set("duid", d);
  1007. ctx.leave();
  1008. };
  1009. hw_address: HW_ADDRESS {
  1010. ctx.enter(ctx.NO_KEYWORD);
  1011. } COLON STRING {
  1012. ElementPtr hw(new StringElement($4, ctx.loc2pos(@4)));
  1013. ctx.stack_.back()->set("hw-address", hw);
  1014. ctx.leave();
  1015. };
  1016. client_id_value: CLIENT_ID {
  1017. ctx.enter(ctx.NO_KEYWORD);
  1018. } COLON STRING {
  1019. ElementPtr hw(new StringElement($4, ctx.loc2pos(@4)));
  1020. ctx.stack_.back()->set("client-id", hw);
  1021. ctx.leave();
  1022. };
  1023. circuit_id_value: CIRCUIT_ID {
  1024. ctx.enter(ctx.NO_KEYWORD);
  1025. } COLON STRING {
  1026. ElementPtr hw(new StringElement($4, ctx.loc2pos(@4)));
  1027. ctx.stack_.back()->set("circuit-id", hw);
  1028. ctx.leave();
  1029. };
  1030. hostname: HOSTNAME {
  1031. ctx.enter(ctx.NO_KEYWORD);
  1032. } COLON STRING {
  1033. ElementPtr host(new StringElement($4, ctx.loc2pos(@4)));
  1034. ctx.stack_.back()->set("hostname", host);
  1035. ctx.leave();
  1036. };
  1037. reservation_client_classes: CLIENT_CLASSES {
  1038. ElementPtr c(new ListElement(ctx.loc2pos(@1)));
  1039. ctx.stack_.back()->set("client-classes", c);
  1040. ctx.stack_.push_back(c);
  1041. ctx.enter(ctx.NO_KEYWORD);
  1042. } COLON list2 {
  1043. ctx.stack_.pop_back();
  1044. ctx.leave();
  1045. };
  1046. // --- end of reservations definitions -----------------------
  1047. // --- relay -------------------------------------------------
  1048. relay: RELAY {
  1049. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  1050. ctx.stack_.back()->set("relay", m);
  1051. ctx.stack_.push_back(m);
  1052. ctx.enter(ctx.RELAY);
  1053. } COLON LCURLY_BRACKET relay_map RCURLY_BRACKET {
  1054. ctx.stack_.pop_back();
  1055. ctx.leave();
  1056. };
  1057. relay_map: IP_ADDRESS {
  1058. ctx.enter(ctx.NO_KEYWORD);
  1059. } COLON STRING {
  1060. ElementPtr ip(new StringElement($4, ctx.loc2pos(@4)));
  1061. ctx.stack_.back()->set("ip-address", ip);
  1062. ctx.leave();
  1063. };
  1064. // --- end of relay definitions ------------------------------
  1065. // --- client classes ----------------------------------------
  1066. client_classes: CLIENT_CLASSES {
  1067. ElementPtr l(new ListElement(ctx.loc2pos(@1)));
  1068. ctx.stack_.back()->set("client-classes", l);
  1069. ctx.stack_.push_back(l);
  1070. ctx.enter(ctx.CLIENT_CLASSES);
  1071. } COLON LSQUARE_BRACKET client_classes_list RSQUARE_BRACKET {
  1072. ctx.stack_.pop_back();
  1073. ctx.leave();
  1074. };
  1075. client_classes_list: client_class
  1076. | client_classes_list COMMA client_class
  1077. ;
  1078. client_class: LCURLY_BRACKET {
  1079. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  1080. ctx.stack_.back()->add(m);
  1081. ctx.stack_.push_back(m);
  1082. } client_class_params RCURLY_BRACKET {
  1083. ctx.stack_.pop_back();
  1084. };
  1085. client_class_params: %empty
  1086. | not_empty_client_class_params
  1087. ;
  1088. not_empty_client_class_params: client_class_param
  1089. | not_empty_client_class_params COMMA client_class_param
  1090. ;
  1091. client_class_param: client_class_name
  1092. | client_class_test
  1093. | option_data_list
  1094. | next_server
  1095. | server_hostname
  1096. | boot_file_name
  1097. | unknown_map_entry
  1098. ;
  1099. client_class_name: name;
  1100. client_class_test: TEST {
  1101. ctx.enter(ctx.NO_KEYWORD);
  1102. } COLON STRING {
  1103. ElementPtr test(new StringElement($4, ctx.loc2pos(@4)));
  1104. ctx.stack_.back()->set("test", test);
  1105. ctx.leave();
  1106. };
  1107. // --- end of client classes ---------------------------------
  1108. // --- server-id ---------------------------------------------
  1109. server_id: SERVER_ID {
  1110. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  1111. ctx.stack_.back()->set("server-id", m);
  1112. ctx.stack_.push_back(m);
  1113. ctx.enter(ctx.SERVER_ID);
  1114. } COLON LCURLY_BRACKET server_id_params RCURLY_BRACKET {
  1115. ctx.stack_.pop_back();
  1116. ctx.leave();
  1117. };
  1118. server_id_params: server_id_param
  1119. | server_id_params COMMA server_id_param
  1120. ;
  1121. server_id_param: type
  1122. | identifier
  1123. | time
  1124. | htype
  1125. | enterprise_id
  1126. | persist
  1127. | unknown_map_entry
  1128. ;
  1129. htype: HTYPE COLON INTEGER {
  1130. ElementPtr htype(new IntElement($3, ctx.loc2pos(@3)));
  1131. ctx.stack_.back()->set("htype", htype);
  1132. };
  1133. identifier: IDENTIFIER {
  1134. ctx.enter(ctx.NO_KEYWORD);
  1135. } COLON STRING {
  1136. ElementPtr id(new StringElement($4, ctx.loc2pos(@4)));
  1137. ctx.stack_.back()->set("identifier", id);
  1138. ctx.leave();
  1139. };
  1140. time: TIME COLON INTEGER {
  1141. ElementPtr time(new IntElement($3, ctx.loc2pos(@3)));
  1142. ctx.stack_.back()->set("time", time);
  1143. };
  1144. enterprise_id: ENTERPRISE_ID COLON INTEGER {
  1145. ElementPtr time(new IntElement($3, ctx.loc2pos(@3)));
  1146. ctx.stack_.back()->set("enterprise-id", time);
  1147. };
  1148. // --- end of server-id --------------------------------------
  1149. dhcp4o6_port: DHCP4O6_PORT COLON INTEGER {
  1150. ElementPtr time(new IntElement($3, ctx.loc2pos(@3)));
  1151. ctx.stack_.back()->set("dhcp4o6-port", time);
  1152. };
  1153. // code says it is a string, unit test a number
  1154. version: VERSION {
  1155. ctx.enter(ctx.NO_KEYWORD);
  1156. } COLON version_value {
  1157. ctx.stack_.back()->set("version", $4);
  1158. ctx.leave();
  1159. };
  1160. version_value:
  1161. INTEGER { $$ = ElementPtr(new IntElement($1, ctx.loc2pos(@1))); }
  1162. | FLOAT { $$ = ElementPtr(new DoubleElement($1, ctx.loc2pos(@1))); }
  1163. | STRING { $$ = ElementPtr(new StringElement($1, ctx.loc2pos(@1))); }
  1164. ;
  1165. // --- control socket ----------------------------------------
  1166. control_socket: CONTROL_SOCKET {
  1167. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  1168. ctx.stack_.back()->set("control-socket", m);
  1169. ctx.stack_.push_back(m);
  1170. ctx.enter(ctx.CONTROL_SOCKET);
  1171. } COLON LCURLY_BRACKET control_socket_params RCURLY_BRACKET {
  1172. ctx.stack_.pop_back();
  1173. ctx.leave();
  1174. };
  1175. control_socket_params: control_socket_param
  1176. | control_socket_params COMMA control_socket_param
  1177. ;
  1178. control_socket_param: socket_type
  1179. | socket_name
  1180. ;
  1181. socket_type: SOCKET_TYPE {
  1182. ctx.enter(ctx.NO_KEYWORD);
  1183. } COLON STRING {
  1184. ElementPtr stype(new StringElement($4, ctx.loc2pos(@4)));
  1185. ctx.stack_.back()->set("socket-type", stype);
  1186. ctx.leave();
  1187. };
  1188. socket_name: SOCKET_NAME {
  1189. ctx.enter(ctx.NO_KEYWORD);
  1190. } COLON STRING {
  1191. ElementPtr name(new StringElement($4, ctx.loc2pos(@4)));
  1192. ctx.stack_.back()->set("socket-name", name);
  1193. ctx.leave();
  1194. };
  1195. // --- dhcp ddns ---------------------------------------------
  1196. dhcp_ddns: DHCP_DDNS {
  1197. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  1198. ctx.stack_.back()->set("dhcp-ddns", m);
  1199. ctx.stack_.push_back(m);
  1200. ctx.enter(ctx.NO_KEYWORD);
  1201. } COLON LCURLY_BRACKET not_empty_map RCURLY_BRACKET {
  1202. ctx.stack_.pop_back();
  1203. ctx.leave();
  1204. };
  1205. // JSON entries for Dhcp4 and DhcpDdns
  1206. dhcp6_json_object: DHCP6 {
  1207. ctx.enter(ctx.NO_KEYWORD);
  1208. } COLON value {
  1209. ctx.stack_.back()->set("Dhcp6", $4);
  1210. ctx.leave();
  1211. };
  1212. dhcpddns_json_object: DHCPDDNS {
  1213. ctx.enter(ctx.NO_KEYWORD);
  1214. } COLON value {
  1215. ctx.stack_.back()->set("DhcpDdns", $4);
  1216. ctx.leave();
  1217. };
  1218. // --- logging entry -----------------------------------------
  1219. // This defines the top level "Logging" object. It parses
  1220. // the following "Logging": { ... }. The ... is defined
  1221. // by logging_params
  1222. logging_object: LOGGING {
  1223. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  1224. ctx.stack_.back()->set("Logging", m);
  1225. ctx.stack_.push_back(m);
  1226. ctx.enter(ctx.LOGGING);
  1227. } COLON LCURLY_BRACKET logging_params RCURLY_BRACKET {
  1228. ctx.stack_.pop_back();
  1229. ctx.leave();
  1230. };
  1231. // This defines the list of allowed parameters that may appear
  1232. // in the top-level Logging object. It can either be a single
  1233. // parameter or several parameters separated by commas.
  1234. logging_params: logging_param
  1235. | logging_params COMMA logging_param
  1236. ;
  1237. // There's currently only one parameter defined, which is "loggers".
  1238. logging_param: loggers;
  1239. // "loggers", the only parameter currently defined in "Logging" object,
  1240. // is "Loggers": [ ... ].
  1241. loggers: LOGGERS {
  1242. ElementPtr l(new ListElement(ctx.loc2pos(@1)));
  1243. ctx.stack_.back()->set("loggers", l);
  1244. ctx.stack_.push_back(l);
  1245. ctx.enter(ctx.LOGGERS);
  1246. } COLON LSQUARE_BRACKET loggers_entries RSQUARE_BRACKET {
  1247. ctx.stack_.pop_back();
  1248. ctx.leave();
  1249. };
  1250. // These are the parameters allowed in loggers: either one logger
  1251. // entry or multiple entries separate by commas.
  1252. loggers_entries: logger_entry
  1253. | loggers_entries COMMA logger_entry
  1254. ;
  1255. // This defines a single entry defined in loggers in Logging.
  1256. logger_entry: LCURLY_BRACKET {
  1257. ElementPtr l(new MapElement(ctx.loc2pos(@1)));
  1258. ctx.stack_.back()->add(l);
  1259. ctx.stack_.push_back(l);
  1260. } logger_params RCURLY_BRACKET {
  1261. ctx.stack_.pop_back();
  1262. };
  1263. logger_params: logger_param
  1264. | logger_params COMMA logger_param
  1265. ;
  1266. logger_param: name
  1267. | output_options_list
  1268. | debuglevel
  1269. | severity
  1270. | unknown_map_entry
  1271. ;
  1272. debuglevel: DEBUGLEVEL COLON INTEGER {
  1273. ElementPtr dl(new IntElement($3, ctx.loc2pos(@3)));
  1274. ctx.stack_.back()->set("debuglevel", dl);
  1275. };
  1276. severity: SEVERITY {
  1277. ctx.enter(ctx.NO_KEYWORD);
  1278. } COLON STRING {
  1279. ElementPtr sev(new StringElement($4, ctx.loc2pos(@4)));
  1280. ctx.stack_.back()->set("severity", sev);
  1281. ctx.leave();
  1282. };
  1283. output_options_list: OUTPUT_OPTIONS {
  1284. ElementPtr l(new ListElement(ctx.loc2pos(@1)));
  1285. ctx.stack_.back()->set("output_options", l);
  1286. ctx.stack_.push_back(l);
  1287. ctx.enter(ctx.OUTPUT_OPTIONS);
  1288. } COLON LSQUARE_BRACKET output_options_list_content RSQUARE_BRACKET {
  1289. ctx.stack_.pop_back();
  1290. ctx.leave();
  1291. };
  1292. output_options_list_content: output_entry
  1293. | output_options_list_content COMMA output_entry
  1294. ;
  1295. output_entry: LCURLY_BRACKET {
  1296. ElementPtr m(new MapElement(ctx.loc2pos(@1)));
  1297. ctx.stack_.back()->add(m);
  1298. ctx.stack_.push_back(m);
  1299. } output_params RCURLY_BRACKET {
  1300. ctx.stack_.pop_back();
  1301. };
  1302. output_params: output_param
  1303. | output_params COMMA output_param
  1304. ;
  1305. output_param: OUTPUT {
  1306. ctx.enter(ctx.NO_KEYWORD);
  1307. } COLON STRING {
  1308. ElementPtr sev(new StringElement($4, ctx.loc2pos(@4)));
  1309. ctx.stack_.back()->set("output", sev);
  1310. ctx.leave();
  1311. };
  1312. %%
  1313. void
  1314. isc::dhcp::Dhcp4Parser::error(const location_type& loc,
  1315. const std::string& what)
  1316. {
  1317. ctx.error(loc, what);
  1318. }