parser.yy 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. /* Copyright (C) 2015-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 {EvalParser}
  9. %define api.token.constructor
  10. %define api.value.type variant
  11. %define api.namespace {isc::eval}
  12. %define parse.assert
  13. %code requires
  14. {
  15. #include <string>
  16. #include <eval/token.h>
  17. #include <eval/eval_context_decl.h>
  18. #include <dhcp/option.h>
  19. #include <boost/lexical_cast.hpp>
  20. using namespace isc::dhcp;
  21. using namespace isc::eval;
  22. }
  23. // The parsing context.
  24. %param { EvalContext& ctx }
  25. %locations
  26. %define parse.trace
  27. %define parse.error verbose
  28. %code
  29. {
  30. # include "eval_context.h"
  31. }
  32. %define api.token.prefix {TOKEN_}
  33. // Tokens in an order which makes sense and related to the intented use.
  34. %token
  35. END 0 "end of file"
  36. LPAREN "("
  37. RPAREN ")"
  38. NOT "not"
  39. AND "and"
  40. OR "or"
  41. EQUAL "=="
  42. OPTION "option"
  43. RELAY4 "relay4"
  44. RELAY6 "relay6"
  45. PEERADDR "peeraddr"
  46. LINKADDR "linkaddr"
  47. LBRACKET "["
  48. RBRACKET "]"
  49. DOT "."
  50. TEXT "text"
  51. HEX "hex"
  52. EXISTS "exists"
  53. PKT "pkt"
  54. IFACE "iface"
  55. SRC "src"
  56. DST "dst"
  57. LEN "len"
  58. PKT4 "pkt4"
  59. CHADDR "mac"
  60. HLEN "hlen"
  61. HTYPE "htype"
  62. CIADDR "ciaddr"
  63. GIADDR "giaddr"
  64. YIADDR "yiaddr"
  65. SIADDR "siaddr"
  66. PKT6 "pkt6"
  67. MSGTYPE "msgtype"
  68. TRANSID "transid"
  69. SUBSTRING "substring"
  70. ALL "all"
  71. COMA ","
  72. CONCAT "concat"
  73. ;
  74. %token <std::string> STRING "constant string"
  75. %token <std::string> INTEGER "integer"
  76. %token <std::string> HEXSTRING "constant hexstring"
  77. %token <std::string> OPTION_NAME "option name"
  78. %token <std::string> IP_ADDRESS "ip address"
  79. %type <uint16_t> option_code
  80. %type <TokenOption::RepresentationType> option_repr_type
  81. %type <TokenRelay6Field::FieldType> relay6_field
  82. %type <uint8_t> nest_level
  83. %type <TokenPkt::MetadataType> pkt_metadata
  84. %type <TokenPkt4::FieldType> pkt4_field
  85. %type <TokenPkt6::FieldType> pkt6_field
  86. %left OR
  87. %left AND
  88. %precedence NOT
  89. %printer { yyoutput << $$; } <*>;
  90. %%
  91. // The whole grammar starts with an expression.
  92. %start expression;
  93. // Expression can either be a single token or a (something == something) expression
  94. expression : bool_expr
  95. ;
  96. bool_expr : "(" bool_expr ")"
  97. | NOT bool_expr
  98. {
  99. TokenPtr neg(new TokenNot());
  100. ctx.expression.push_back(neg);
  101. }
  102. | bool_expr AND bool_expr
  103. {
  104. TokenPtr neg(new TokenAnd());
  105. ctx.expression.push_back(neg);
  106. }
  107. | bool_expr OR bool_expr
  108. {
  109. TokenPtr neg(new TokenOr());
  110. ctx.expression.push_back(neg);
  111. }
  112. | string_expr EQUAL string_expr
  113. {
  114. TokenPtr eq(new TokenEqual());
  115. ctx.expression.push_back(eq);
  116. }
  117. | OPTION "[" option_code "]" "." EXISTS
  118. {
  119. TokenPtr opt(new TokenOption($3, TokenOption::EXISTS));
  120. ctx.expression.push_back(opt);
  121. }
  122. | RELAY4 "[" option_code "]" "." EXISTS
  123. {
  124. switch (ctx.getUniverse()) {
  125. case Option::V4:
  126. {
  127. TokenPtr opt(new TokenRelay4Option($3, TokenOption::EXISTS));
  128. ctx.expression.push_back(opt);
  129. break;
  130. }
  131. case Option::V6:
  132. // We will have relay6[123] for the DHCPv6.
  133. // In a very distant future we'll possibly be able
  134. // to mix both if we have DHCPv4-over-DHCPv6, so it
  135. // has some sense to make it explicit whether we
  136. // talk about DHCPv4 relay or DHCPv6 relay. However,
  137. // for the time being relay4 can be used in DHCPv4
  138. // only.
  139. error(@1, "relay4 can only be used in DHCPv4.");
  140. }
  141. }
  142. | RELAY6 "[" nest_level "]" "." OPTION "[" option_code "]" "." EXISTS
  143. {
  144. switch (ctx.getUniverse()) {
  145. case Option::V6:
  146. {
  147. TokenPtr opt(new TokenRelay6Option($3, $8, TokenOption::EXISTS));
  148. ctx.expression.push_back(opt);
  149. break;
  150. }
  151. case Option::V4:
  152. // For now we only use relay6 in DHCPv6.
  153. error(@1, "relay6 can only be used in DHCPv6.");
  154. }
  155. }
  156. ;
  157. string_expr : STRING
  158. {
  159. TokenPtr str(new TokenString($1));
  160. ctx.expression.push_back(str);
  161. }
  162. | HEXSTRING
  163. {
  164. TokenPtr hex(new TokenHexString($1));
  165. ctx.expression.push_back(hex);
  166. }
  167. | IP_ADDRESS
  168. {
  169. TokenPtr ip(new TokenIpAddress($1));
  170. ctx.expression.push_back(ip);
  171. }
  172. | OPTION "[" option_code "]" "." option_repr_type
  173. {
  174. TokenPtr opt(new TokenOption($3, $6));
  175. ctx.expression.push_back(opt);
  176. }
  177. | RELAY4 "[" option_code "]" "." option_repr_type
  178. {
  179. switch (ctx.getUniverse()) {
  180. case Option::V4:
  181. {
  182. TokenPtr opt(new TokenRelay4Option($3, $6));
  183. ctx.expression.push_back(opt);
  184. break;
  185. }
  186. case Option::V6:
  187. // We will have relay6[123] for the DHCPv6.
  188. // In a very distant future we'll possibly be able
  189. // to mix both if we have DHCPv4-over-DHCPv6, so it
  190. // has some sense to make it explicit whether we
  191. // talk about DHCPv4 relay or DHCPv6 relay. However,
  192. // for the time being relay4 can be used in DHCPv4
  193. // only.
  194. error(@1, "relay4 can only be used in DHCPv4.");
  195. }
  196. }
  197. | RELAY6 "[" nest_level "]" "." OPTION "[" option_code "]" "." option_repr_type
  198. {
  199. switch (ctx.getUniverse()) {
  200. case Option::V6:
  201. {
  202. TokenPtr opt(new TokenRelay6Option($3, $8, $11));
  203. ctx.expression.push_back(opt);
  204. break;
  205. }
  206. case Option::V4:
  207. // For now we only use relay6 in DHCPv6.
  208. error(@1, "relay6 can only be used in DHCPv6.");
  209. }
  210. }
  211. | PKT "." pkt_metadata
  212. {
  213. TokenPtr pkt_metadata(new TokenPkt($3));
  214. ctx.expression.push_back(pkt_metadata);
  215. }
  216. | PKT4 "." pkt4_field
  217. {
  218. switch (ctx.getUniverse()) {
  219. case Option::V4:
  220. {
  221. TokenPtr pkt4_field(new TokenPkt4($3));
  222. ctx.expression.push_back(pkt4_field);
  223. break;
  224. }
  225. case Option::V6:
  226. // For now we only use pkt4 in DHCPv4.
  227. error(@1, "pkt4 can only be used in DHCPv4.");
  228. }
  229. }
  230. | PKT6 "." pkt6_field
  231. {
  232. switch (ctx.getUniverse()) {
  233. case Option::V6:
  234. {
  235. TokenPtr pkt6_field(new TokenPkt6($3));
  236. ctx.expression.push_back(pkt6_field);
  237. break;
  238. }
  239. case Option::V4:
  240. // For now we only use pkt6 in DHCPv6.
  241. error(@1, "pkt6 can only be used in DHCPv6.");
  242. }
  243. }
  244. | RELAY6 "[" nest_level "]" "." relay6_field
  245. {
  246. switch (ctx.getUniverse()) {
  247. case Option::V6:
  248. {
  249. TokenPtr relay6field(new TokenRelay6Field($3, $6));
  250. ctx.expression.push_back(relay6field);
  251. break;
  252. }
  253. case Option::V4:
  254. // For now we only use relay6 in DHCPv6.
  255. error(@1, "relay6 can only be used in DHCPv6.");
  256. }
  257. }
  258. | SUBSTRING "(" string_expr "," start_expr "," length_expr ")"
  259. {
  260. TokenPtr sub(new TokenSubstring());
  261. ctx.expression.push_back(sub);
  262. }
  263. | CONCAT "(" string_expr "," string_expr ")"
  264. {
  265. TokenPtr conc(new TokenConcat());
  266. ctx.expression.push_back(conc);
  267. }
  268. ;
  269. option_code : INTEGER
  270. {
  271. $$ = ctx.convertOptionCode($1, @1);
  272. }
  273. | OPTION_NAME
  274. {
  275. $$ = ctx.convertOptionName($1, @1);
  276. }
  277. ;
  278. option_repr_type : TEXT
  279. {
  280. $$ = TokenOption::TEXTUAL;
  281. }
  282. | HEX
  283. {
  284. $$ = TokenOption::HEXADECIMAL;
  285. }
  286. ;
  287. nest_level : INTEGER
  288. {
  289. $$ = ctx.convertNestLevelNumber($1, @1);
  290. }
  291. // Eventually we may add strings to handle different
  292. // ways of choosing from which relay we want to extract
  293. // an option or field.
  294. ;
  295. pkt_metadata : IFACE
  296. {
  297. $$ = TokenPkt::IFACE;
  298. }
  299. | SRC
  300. {
  301. $$ = TokenPkt::SRC;
  302. }
  303. | DST
  304. {
  305. $$ = TokenPkt::DST;
  306. }
  307. | LEN
  308. {
  309. $$ = TokenPkt::LEN;
  310. }
  311. ;
  312. pkt4_field : CHADDR
  313. {
  314. $$ = TokenPkt4::CHADDR;
  315. }
  316. | HLEN
  317. {
  318. $$ = TokenPkt4::HLEN;
  319. }
  320. | HTYPE
  321. {
  322. $$ = TokenPkt4::HTYPE;
  323. }
  324. | CIADDR
  325. {
  326. $$ = TokenPkt4::CIADDR;
  327. }
  328. | GIADDR
  329. {
  330. $$ = TokenPkt4::GIADDR;
  331. }
  332. | YIADDR
  333. {
  334. $$ = TokenPkt4::YIADDR;
  335. }
  336. | SIADDR
  337. {
  338. $$ = TokenPkt4::SIADDR;
  339. }
  340. ;
  341. pkt6_field : MSGTYPE
  342. {
  343. $$ = TokenPkt6::MSGTYPE;
  344. }
  345. | TRANSID
  346. {
  347. $$ = TokenPkt6::TRANSID;
  348. }
  349. ;
  350. relay6_field : PEERADDR
  351. {
  352. $$ = TokenRelay6Field::PEERADDR;
  353. }
  354. | LINKADDR
  355. {
  356. $$ = TokenRelay6Field::LINKADDR;
  357. }
  358. ;
  359. start_expr : INTEGER
  360. {
  361. TokenPtr str(new TokenString($1));
  362. ctx.expression.push_back(str);
  363. }
  364. ;
  365. length_expr : INTEGER
  366. {
  367. TokenPtr str(new TokenString($1));
  368. ctx.expression.push_back(str);
  369. }
  370. | ALL
  371. {
  372. TokenPtr str(new TokenString("all"));
  373. ctx.expression.push_back(str);
  374. }
  375. ;
  376. %%
  377. void
  378. isc::eval::EvalParser::error(const location_type& loc,
  379. const std::string& what)
  380. {
  381. ctx.error(loc, what);
  382. }