lexer.ll 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /* Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
  2. Permission to use, copy, modify, and/or distribute this software for any
  3. purpose with or without fee is hereby granted, provided that the above
  4. copyright notice and this permission notice appear in all copies.
  5. THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  6. REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  7. AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  8. INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  9. LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  10. OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  11. PERFORMANCE OF THIS SOFTWARE. */
  12. %{ /* -*- C++ -*- */
  13. #include <cerrno>
  14. #include <climits>
  15. #include <cstdlib>
  16. #include <string>
  17. #include <eval/eval_context.h>
  18. #include <eval/parser.h>
  19. #include <boost/lexical_cast.hpp>
  20. // Work around an incompatibility in flex (at least versions
  21. // 2.5.31 through 2.5.33): it generates code that does
  22. // not conform to C89. See Debian bug 333231
  23. // <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=333231>.
  24. # undef yywrap
  25. # define yywrap() 1
  26. // The location of the current token. The lexer will keep updating it. This
  27. // variable will be useful for logging errors.
  28. static isc::eval::location loc;
  29. %}
  30. /* noyywrap disables automatic rewinding for the next file to parse. Since we
  31. always parse only a single string, there's no need to do any wraps. And
  32. using yywrap requires linking with -lfl, which provides the default yywrap
  33. implementation that always returns 1 anyway. */
  34. %option noyywrap
  35. /* nounput simplifies the lexer, by removing support for putting a character
  36. back into the input stream. We never use such capability anyway. */
  37. %option nounput
  38. /* batch means that we'll never use the generated lexer interactively. */
  39. %option batch
  40. /* Enables debug mode. To see the debug messages, one needs to also set
  41. yy_flex_debug to 1, then the debug messages will be printed on stderr. */
  42. %option debug
  43. /* I have no idea what this option does, except it was specified in the bison
  44. examples and Postgres folks added it to remove gcc 4.3 warnings. Let's
  45. be on the safe side and keep it. */
  46. %option noinput
  47. /* This line tells flex to track the line numbers. It's not really that
  48. useful for client classes, which typically are one-liners, but it may be
  49. useful in more complex cases. */
  50. %option yylineno
  51. /* These are not token expressions yet, just convenience expressions that
  52. can be used during actual token definitions. */
  53. int [0-9]+
  54. hex [0-9a-fA-F]+
  55. blank [ \t]
  56. %{
  57. // This code run each time a pattern is matched. It updates the location
  58. // by moving it ahead by yyleng bytes. yyleng specifies the length of the
  59. // currently matched token.
  60. #define YY_USER_ACTION loc.columns(yyleng);
  61. %}
  62. %%
  63. %{
  64. // Code run each time yylex is called.
  65. loc.step();
  66. %}
  67. {blank}+ {
  68. // Ok, we found a with space. Let's ignore it and update loc variable.
  69. loc.step();
  70. }
  71. [\n]+ {
  72. // Newline found. Let's update the location and continue.
  73. loc.lines(yyleng);
  74. loc.step();
  75. }
  76. \'\-?{int}\' {
  77. // A string containing a number. Quotes should be removed, see below.
  78. std::string tmp(yytext+1);
  79. tmp.resize(tmp.size() - 1);
  80. return isc::eval::EvalParser::make_NUMBER(tmp, loc);
  81. }
  82. "'all'" {
  83. // A string containing the "all" keyword.
  84. return isc::eval::EvalParser::make_ALL("all", loc);
  85. }
  86. \'[^\'\n]*\' {
  87. // A string has been matched. It contains the actual string and single quotes.
  88. // We need to get those quotes out of the way and just use its content, e.g.
  89. // for 'foo' we should get foo
  90. std::string tmp(yytext+1);
  91. tmp.resize(tmp.size() - 1);
  92. return isc::eval::EvalParser::make_STRING(tmp, loc);
  93. }
  94. 0[xX]{hex} {
  95. // A hex string has been matched. It contains the '0x' or '0X' header
  96. // followed by at least one hexadecimal digit.
  97. return isc::eval::EvalParser::make_HEXSTRING(yytext, loc);
  98. }
  99. {int} {
  100. // A code (16 bit unsigned integer) was found.
  101. std::string tmp(yytext);
  102. int n;
  103. try {
  104. n = boost::lexical_cast<int>(tmp);
  105. } catch (const boost::bad_lexical_cast &) {
  106. driver.error(loc, "Failed to convert specified option code to "
  107. "number in " + tmp + ".");
  108. }
  109. // 65535 is the maximum value of the option code in DHCPv6. We want the
  110. // code to be the same for v4 and v6, so let's ignore for a moment that
  111. // max. option code in DHCPv4 is 255.
  112. if (n < 0 || n > 65535) {
  113. driver.error(loc, "Option code has invalid value in " +
  114. std::string(yytext) + ". Allowed range: 0..65535");
  115. }
  116. return isc::eval::EvalParser::make_CODE(static_cast<uint16_t>(n), loc);
  117. }
  118. "==" return isc::eval::EvalParser::make_EQUAL(loc);
  119. "option" return isc::eval::EvalParser::make_OPTION(loc);
  120. "substring" return isc::eval::EvalParser::make_SUBSTRING(loc);
  121. "untyped:" return isc::eval::EvalParser::make_UNTYPED(loc);
  122. "(" return isc::eval::EvalParser::make_LPAREN(loc);
  123. ")" return isc::eval::EvalParser::make_RPAREN(loc);
  124. "[" return isc::eval::EvalParser::make_LBRACKET(loc);
  125. "]" return isc::eval::EvalParser::make_RBRACKET(loc);
  126. "," return isc::eval::EvalParser::make_COMA(loc);
  127. . driver.error (loc, "Invalid character: " + std::string(yytext));
  128. <<EOF>> return isc::eval::EvalParser::make_END(loc);
  129. %%
  130. using namespace isc::eval;
  131. void
  132. EvalContext::scanFileBegin()
  133. {
  134. loc.initialize(&file_);
  135. yy_flex_debug = trace_scanning_;
  136. if (file_.empty () || file_ == "-") {
  137. yyin = stdin;
  138. }
  139. else if (!(yyin = fopen(file_.c_str (), "r"))) {
  140. error("cannot open " + file_ + ": " + strerror(errno));
  141. exit(EXIT_FAILURE);
  142. }
  143. }
  144. void
  145. EvalContext::scanFileEnd()
  146. {
  147. fclose(yyin);
  148. }
  149. void
  150. EvalContext::scanStringBegin()
  151. {
  152. loc.initialize(&file_);
  153. yy_flex_debug = trace_scanning_;
  154. YY_BUFFER_STATE buffer;
  155. buffer = yy_scan_bytes(string_.c_str(), string_.size());
  156. if (!buffer) {
  157. error("cannot scan string");
  158. exit(EXIT_FAILURE);
  159. }
  160. }
  161. void
  162. EvalContext::scanStringEnd()
  163. {
  164. yy_delete_buffer(YY_CURRENT_BUFFER);
  165. }