dhcp6_lexer.ll 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  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. %{ /* -*- C++ -*- */
  6. #include <cerrno>
  7. #include <climits>
  8. #include <cstdlib>
  9. #include <string>
  10. #include <dhcp6/parser_context.h>
  11. #include <asiolink/io_address.h>
  12. #include <boost/lexical_cast.hpp>
  13. #include <exceptions/exceptions.h>
  14. // Work around an incompatibility in flex (at least versions
  15. // 2.5.31 through 2.5.33): it generates code that does
  16. // not conform to C89. See Debian bug 333231
  17. // <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=333231>.
  18. # undef yywrap
  19. # define yywrap() 1
  20. // The location of the current token. The lexer will keep updating it. This
  21. // variable will be useful for logging errors.
  22. static isc::dhcp::location loc;
  23. static bool start_token_flag = false;
  24. static isc::dhcp::Parser6Context::ParserType start_token_value;
  25. // To avoid the call to exit... oops!
  26. #define YY_FATAL_ERROR(msg) isc::dhcp::Parser6Context::fatal(msg)
  27. %}
  28. /* noyywrap disables automatic rewinding for the next file to parse. Since we
  29. always parse only a single string, there's no need to do any wraps. And
  30. using yywrap requires linking with -lfl, which provides the default yywrap
  31. implementation that always returns 1 anyway. */
  32. %option noyywrap
  33. /* nounput simplifies the lexer, by removing support for putting a character
  34. back into the input stream. We never use such capability anyway. */
  35. %option nounput
  36. /* batch means that we'll never use the generated lexer interactively. */
  37. %option batch
  38. /* Enables debug mode. To see the debug messages, one needs to also set
  39. yy_flex_debug to 1, then the debug messages will be printed on stderr. */
  40. %option debug
  41. /* I have no idea what this option does, except it was specified in the bison
  42. examples and Postgres folks added it to remove gcc 4.3 warnings. Let's
  43. be on the safe side and keep it. */
  44. %option noinput
  45. /* This line tells flex to track the line numbers. It's not really that
  46. useful for client classes, which typically are one-liners, but it may be
  47. useful in more complex cases. */
  48. %option yylineno
  49. %x COMMENT
  50. /* These are not token expressions yet, just convenience expressions that
  51. can be used during actual token definitions. Note some can match
  52. incorrect inputs (e.g., IP addresses) which must be checked. */
  53. int \-?[0-9]+
  54. blank [ \t]
  55. UnicodeEscapeSequence u[0-9A-Fa-f]{4}
  56. JSONEscapeCharacter ["\\/bfnrt]
  57. JSONEscapeSequence {JSONEscapeCharacter}|{UnicodeEscapeSequence}
  58. JSONStringCharacter [^"\\]|\\{JSONEscapeSequence}
  59. JSONString \"{JSONStringCharacter}*\"
  60. %{
  61. // This code run each time a pattern is matched. It updates the location
  62. // by moving it ahead by yyleng bytes. yyleng specifies the length of the
  63. // currently matched token.
  64. #define YY_USER_ACTION loc.columns(yyleng);
  65. %}
  66. %%
  67. %{
  68. // This part of the code is copied over to the verbatim to the top
  69. // of the generated yylex function. Explanation:
  70. // http://www.gnu.org/software/bison/manual/html_node/Multiple-start_002dsymbols.html
  71. // Code run each time yylex is called.
  72. loc.step();
  73. int comment_start_line = 0;
  74. if (start_token_flag) {
  75. start_token_flag = false;
  76. switch (start_token_value) {
  77. case Parser6Context::PARSER_DHCP6:
  78. return isc::dhcp::Dhcp6Parser::make_TOPLEVEL_DHCP6(loc);
  79. case Parser6Context::PARSER_GENERIC_JSON:
  80. default:
  81. return isc::dhcp::Dhcp6Parser::make_TOPLEVEL_GENERIC_JSON(loc);
  82. }
  83. }
  84. %}
  85. #.* ;
  86. "//"(.*) ;
  87. "/*" {
  88. BEGIN(COMMENT);
  89. comment_start_line = yylineno;
  90. }
  91. <COMMENT>"*/" BEGIN(INITIAL);
  92. <COMMENT>. ;
  93. <COMMENT><<EOF>> {
  94. isc_throw(isc::BadValue, "Comment not closed. (/* in line " << comment_start_line);
  95. }
  96. {blank}+ {
  97. // Ok, we found a with space. Let's ignore it and update loc variable.
  98. loc.step();
  99. }
  100. [\n]+ {
  101. // Newline found. Let's update the location and continue.
  102. loc.lines(yyleng);
  103. loc.step();
  104. }
  105. \"Dhcp6\" { return isc::dhcp::Dhcp6Parser::make_DHCP6(loc); }
  106. \"interfaces-config\" { return isc::dhcp::Dhcp6Parser::make_INTERFACES_CONFIG(loc); }
  107. \"interfaces\" { return isc::dhcp::Dhcp6Parser::make_INTERFACES(loc); }
  108. \"lease-database\" { return isc::dhcp::Dhcp6Parser::make_LEASE_DATABASE(loc); }
  109. \"hosts-database\" { return isc::dhcp::Dhcp6Parser::make_HOSTS_DATABASE(loc); }
  110. \"type\" { return isc::dhcp::Dhcp6Parser::make_TYPE(loc); }
  111. \"user\" { return isc::dhcp::Dhcp6Parser::make_USER(loc); }
  112. \"password\" { return isc::dhcp::Dhcp6Parser::make_PASSWORD(loc); }
  113. \"host\" { return isc::dhcp::Dhcp6Parser::make_HOST(loc); }
  114. \"persist\" { return isc::dhcp::Dhcp6Parser::make_PERSIST(loc); }
  115. \"lfc-interval\" { return isc::dhcp::Dhcp6Parser::make_LFC_INTERVAL(loc); }
  116. \"preferred-lifetime\" { return isc::dhcp::Dhcp6Parser::make_PREFERRED_LIFETIME(loc); }
  117. \"valid-lifetime\" { return isc::dhcp::Dhcp6Parser::make_VALID_LIFETIME(loc); }
  118. \"renew-timer\" { return isc::dhcp::Dhcp6Parser::make_RENEW_TIMER(loc); }
  119. \"rebind-timer\" { return isc::dhcp::Dhcp6Parser::make_REBIND_TIMER(loc); }
  120. \"subnet6\" { return isc::dhcp::Dhcp6Parser::make_SUBNET6(loc); }
  121. \"option-data\" { return isc::dhcp::Dhcp6Parser::make_OPTION_DATA(loc); }
  122. \"name\" { return isc::dhcp::Dhcp6Parser::make_NAME(loc); }
  123. \"data\" { return isc::dhcp::Dhcp6Parser::make_DATA(loc); }
  124. \"pools\" { return isc::dhcp::Dhcp6Parser::make_POOLS(loc); }
  125. \"pd-pools\" { return isc::dhcp::Dhcp6Parser::make_PD_POOLS(loc); }
  126. \"prefix\" { return isc::dhcp::Dhcp6Parser::make_PREFIX(loc); }
  127. \"prefix-len\" { return isc::dhcp::Dhcp6Parser::make_PREFIX_LEN(loc); }
  128. \"delegated-len\" { return isc::dhcp::Dhcp6Parser::make_DELEGATED_LEN(loc); }
  129. \"pool\" { return isc::dhcp::Dhcp6Parser::make_POOL(loc); }
  130. \"subnet\" { return isc::dhcp::Dhcp6Parser::make_SUBNET(loc); }
  131. \"interface\" { return isc::dhcp::Dhcp6Parser::make_INTERFACE(loc); }
  132. \"id\" { return isc::dhcp::Dhcp6Parser::make_ID(loc); }
  133. \"code\" { return isc::dhcp::Dhcp6Parser::make_CODE(loc); }
  134. \"mac-sources\" { return isc::dhcp::Dhcp6Parser::make_MAC_SOURCES(loc); }
  135. \"relay-supplied-options\" { return isc::dhcp::Dhcp6Parser::make_RELAY_SUPPLIED_OPTIONS(loc); }
  136. \"host-reservation-identifiers\" { return isc::dhcp::Dhcp6Parser::make_HOST_RESERVATION_IDENTIFIERS(loc); }
  137. \"Logging\" { return isc::dhcp::Dhcp6Parser::make_LOGGING(loc); }
  138. \"loggers\" { return isc::dhcp::Dhcp6Parser::make_LOGGERS(loc); }
  139. \"output_options\" { return isc::dhcp::Dhcp6Parser::make_OUTPUT_OPTIONS(loc); }
  140. \"output\" { return isc::dhcp::Dhcp6Parser::make_OUTPUT(loc); }
  141. \"debuglevel\" { return isc::dhcp::Dhcp6Parser::make_DEBUGLEVEL(loc); }
  142. \"severity\" { return isc::dhcp::Dhcp6Parser::make_SEVERITY(loc); }
  143. \"client-classes\" { return isc::dhcp::Dhcp6Parser::make_CLIENT_CLASSES(loc); }
  144. \"client-class\" { return isc::dhcp::Dhcp6Parser::make_CLIENT_CLASS(loc); }
  145. \"test\" { return isc::dhcp::Dhcp6Parser::make_TEST(loc); }
  146. \"reservations\" { return isc::dhcp::Dhcp6Parser::make_RESERVATIONS(loc); }
  147. \"ip-addresses\" { return isc::dhcp::Dhcp6Parser::make_IP_ADDRESSES(loc); }
  148. \"prefixes\" { return isc::dhcp::Dhcp6Parser::make_PREFIXES(loc); }
  149. \"duid\" { return isc::dhcp::Dhcp6Parser::make_DUID(loc); }
  150. \"hw-address\" { return isc::dhcp::Dhcp6Parser::make_HW_ADDRESS(loc); }
  151. \"hostname\" { return isc::dhcp::Dhcp6Parser::make_HOSTNAME(loc); }
  152. \"space\" { return isc::dhcp::Dhcp6Parser::make_SPACE(loc); }
  153. \"csv-format\" { return isc::dhcp::Dhcp6Parser::make_CSV_FORMAT(loc); }
  154. \"hooks-libraries\" { return isc::dhcp::Dhcp6Parser::make_HOOKS_LIBRARIES(loc); }
  155. \"library\" { return isc::dhcp::Dhcp6Parser::make_LIBRARY(loc); }
  156. \"server-id\" { return isc::dhcp::Dhcp6Parser::make_SERVER_ID(loc); }
  157. \"identifier\" { return isc::dhcp::Dhcp6Parser::make_IDENTIFIER(loc); }
  158. \"htype\" { return isc::dhcp::Dhcp6Parser::make_HTYPE(loc); }
  159. \"time\" { return isc::dhcp::Dhcp6Parser::make_TIME(loc); }
  160. \"enterprise-id\" { return isc::dhcp::Dhcp6Parser::make_ENTERPRISE_ID(loc); }
  161. \"expired-leases-processing\" { return isc::dhcp::Dhcp6Parser::make_EXPIRED_LEASES_PROCESSING(loc); }
  162. \"dhcp4o6-port\" { return isc::dhcp::Dhcp6Parser::make_DHCP4O6_PORT(loc); }
  163. {JSONString} {
  164. // A string has been matched. It contains the actual string and single quotes.
  165. // We need to get those quotes out of the way and just use its content, e.g.
  166. // for 'foo' we should get foo
  167. std::string tmp(yytext+1);
  168. tmp.resize(tmp.size() - 1);
  169. return isc::dhcp::Dhcp6Parser::make_STRING(tmp, loc);
  170. }
  171. "[" { return isc::dhcp::Dhcp6Parser::make_LSQUARE_BRACKET(loc); }
  172. "]" { return isc::dhcp::Dhcp6Parser::make_RSQUARE_BRACKET(loc); }
  173. "{" { return isc::dhcp::Dhcp6Parser::make_LCURLY_BRACKET(loc); }
  174. "}" { return isc::dhcp::Dhcp6Parser::make_RCURLY_BRACKET(loc); }
  175. "," { return isc::dhcp::Dhcp6Parser::make_COMMA(loc); }
  176. ":" { return isc::dhcp::Dhcp6Parser::make_COLON(loc); }
  177. {int} {
  178. // An integer was found.
  179. std::string tmp(yytext);
  180. int64_t integer = 0;
  181. try {
  182. // In substring we want to use negative values (e.g. -1).
  183. // In enterprise-id we need to use values up to 0xffffffff.
  184. // To cover both of those use cases, we need at least
  185. // int64_t.
  186. integer = boost::lexical_cast<int64_t>(tmp);
  187. } catch (const boost::bad_lexical_cast &) {
  188. driver.error(loc, "Failed to convert " + tmp + " to an integer.");
  189. }
  190. // The parser needs the string form as double conversion is no lossless
  191. return isc::dhcp::Dhcp6Parser::make_INTEGER(integer, loc);
  192. }
  193. [-+]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)? {
  194. // A floating point was found.
  195. std::string tmp(yytext);
  196. double fp = 0.0;
  197. try {
  198. // In substring we want to use negative values (e.g. -1).
  199. // In enterprise-id we need to use values up to 0xffffffff.
  200. // To cover both of those use cases, we need at least
  201. // int64_t.
  202. fp = boost::lexical_cast<double>(tmp);
  203. } catch (const boost::bad_lexical_cast &) {
  204. driver.error(loc, "Failed to convert " + tmp + " to a floating point.");
  205. }
  206. return isc::dhcp::Dhcp6Parser::make_FLOAT(fp, loc);
  207. }
  208. true|false {
  209. string tmp(yytext);
  210. return isc::dhcp::Dhcp6Parser::make_BOOLEAN(tmp == "true", loc);
  211. }
  212. null {
  213. return isc::dhcp::Dhcp6Parser::make_NULL_TYPE(loc);
  214. }
  215. . driver.error (loc, "Invalid character: " + std::string(yytext));
  216. <<EOF>> return isc::dhcp::Dhcp6Parser::make_END(loc);
  217. %%
  218. using namespace isc::dhcp;
  219. void
  220. Parser6Context::scanStringBegin(ParserType parser_type)
  221. {
  222. start_token_flag = true;
  223. start_token_value = parser_type;
  224. loc.initialize(&file_);
  225. yy_flex_debug = trace_scanning_;
  226. YY_BUFFER_STATE buffer;
  227. buffer = yy_scan_bytes(string_.c_str(), string_.size());
  228. if (!buffer) {
  229. fatal("cannot scan string");
  230. // fatal() throws an exception so this can't be reached
  231. }
  232. }
  233. void
  234. Parser6Context::scanStringEnd()
  235. {
  236. yy_delete_buffer(YY_CURRENT_BUFFER);
  237. }
  238. void
  239. Parser6Context::scanFileBegin(FILE * f, ParserType parser_type) {
  240. start_token_flag = true;
  241. start_token_value = parser_type;
  242. loc.initialize(&file_);
  243. yy_flex_debug = trace_scanning_;
  244. YY_BUFFER_STATE buffer;
  245. // See dhcp6_lexer.cc header for available definitions
  246. buffer = parser6__create_buffer(f, 65536 /*buffer size*/);
  247. if (!buffer) {
  248. fatal("cannot scan file " + file_);
  249. }
  250. }
  251. void
  252. Parser6Context::scanFileEnd(FILE * f) {
  253. fclose(f);
  254. yy_delete_buffer(YY_CURRENT_BUFFER);
  255. }
  256. namespace {
  257. /// To avoid unused function error
  258. class Dummy {
  259. // cppcheck-suppress unusedPrivateFunction
  260. void dummy() { yy_fatal_error("Fix me: how to disable its definition?"); }
  261. };
  262. }