lexer.ll 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  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 <eval/eval_context.h>
  11. #include <eval/parser.h>
  12. #include <boost/lexical_cast.hpp>
  13. // Work around an incompatibility in flex (at least versions
  14. // 2.5.31 through 2.5.33): it generates code that does
  15. // not conform to C89. See Debian bug 333231
  16. // <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=333231>.
  17. # undef yywrap
  18. # define yywrap() 1
  19. // The location of the current token. The lexer will keep updating it. This
  20. // variable will be useful for logging errors.
  21. static isc::eval::location loc;
  22. // To avoid the call to exit... oops!
  23. #define YY_FATAL_ERROR(msg) isc::eval::EvalContext::fatal(msg)
  24. %}
  25. /* noyywrap disables automatic rewinding for the next file to parse. Since we
  26. always parse only a single string, there's no need to do any wraps. And
  27. using yywrap requires linking with -lfl, which provides the default yywrap
  28. implementation that always returns 1 anyway. */
  29. %option noyywrap
  30. /* nounput simplifies the lexer, by removing support for putting a character
  31. back into the input stream. We never use such capability anyway. */
  32. %option nounput
  33. /* batch means that we'll never use the generated lexer interactively. */
  34. %option batch
  35. /* Enables debug mode. To see the debug messages, one needs to also set
  36. yy_flex_debug to 1, then the debug messages will be printed on stderr. */
  37. %option debug
  38. /* I have no idea what this option does, except it was specified in the bison
  39. examples and Postgres folks added it to remove gcc 4.3 warnings. Let's
  40. be on the safe side and keep it. */
  41. %option noinput
  42. /* This line tells flex to track the line numbers. It's not really that
  43. useful for client classes, which typically are one-liners, but it may be
  44. useful in more complex cases. */
  45. %option yylineno
  46. /* These are not token expressions yet, just convenience expressions that
  47. can be used during actual token definitions. */
  48. int \-?[0-9]+
  49. hex [0-9a-fA-F]+
  50. blank [ \t]
  51. %{
  52. // This code run each time a pattern is matched. It updates the location
  53. // by moving it ahead by yyleng bytes. yyleng specifies the length of the
  54. // currently matched token.
  55. #define YY_USER_ACTION loc.columns(yyleng);
  56. %}
  57. %%
  58. %{
  59. // Code run each time yylex is called.
  60. loc.step();
  61. %}
  62. {blank}+ {
  63. // Ok, we found a with space. Let's ignore it and update loc variable.
  64. loc.step();
  65. }
  66. [\n]+ {
  67. // Newline found. Let's update the location and continue.
  68. loc.lines(yyleng);
  69. loc.step();
  70. }
  71. \'[^\'\n]*\' {
  72. // A string has been matched. It contains the actual string and single quotes.
  73. // We need to get those quotes out of the way and just use its content, e.g.
  74. // for 'foo' we should get foo
  75. std::string tmp(yytext+1);
  76. tmp.resize(tmp.size() - 1);
  77. return isc::eval::EvalParser::make_STRING(tmp, loc);
  78. }
  79. 0[xX]{hex} {
  80. // A hex string has been matched. It contains the '0x' or '0X' header
  81. // followed by at least one hexadecimal digit.
  82. return isc::eval::EvalParser::make_HEXSTRING(yytext, loc);
  83. }
  84. {int} {
  85. // An integer was found.
  86. std::string tmp(yytext);
  87. try {
  88. static_cast<void>(boost::lexical_cast<int>(tmp));
  89. } catch (const boost::bad_lexical_cast &) {
  90. driver.error(loc, "Failed to convert " + tmp + " to an integer.");
  91. }
  92. // The parser needs the string form as double conversion is no lossless
  93. return isc::eval::EvalParser::make_INTEGER(tmp, loc);
  94. }
  95. [A-Za-z]([-_A-Za-z0-9]*[A-Za-z0-9])?/({blank}|\n)*] {
  96. // This string specifies option name starting with a letter
  97. // and further containing letters, digits, hyphens and
  98. // underscores and finishing by letters or digits.
  99. return isc::eval::EvalParser::make_OPTION_NAME(yytext, loc);
  100. }
  101. "==" return isc::eval::EvalParser::make_EQUAL(loc);
  102. "option" return isc::eval::EvalParser::make_OPTION(loc);
  103. "text" return isc::eval::EvalParser::make_TEXT(loc);
  104. "hex" return isc::eval::EvalParser::make_HEX(loc);
  105. "exists" return isc::eval::EvalParser::make_EXISTS(loc);
  106. "substring" return isc::eval::EvalParser::make_SUBSTRING(loc);
  107. "relay4" return isc::eval::EvalParser::make_RELAY4(loc);
  108. "all" return isc::eval::EvalParser::make_ALL(loc);
  109. "not" return isc::eval::EvalParser::make_NOT(loc);
  110. "and" return isc::eval::EvalParser::make_AND(loc);
  111. "or" return isc::eval::EvalParser::make_OR(loc);
  112. "." return isc::eval::EvalParser::make_DOT(loc);
  113. "(" return isc::eval::EvalParser::make_LPAREN(loc);
  114. ")" return isc::eval::EvalParser::make_RPAREN(loc);
  115. "[" return isc::eval::EvalParser::make_LBRACKET(loc);
  116. "]" return isc::eval::EvalParser::make_RBRACKET(loc);
  117. "," return isc::eval::EvalParser::make_COMA(loc);
  118. . driver.error (loc, "Invalid character: " + std::string(yytext));
  119. <<EOF>> return isc::eval::EvalParser::make_END(loc);
  120. %%
  121. using namespace isc::eval;
  122. void
  123. EvalContext::scanStringBegin()
  124. {
  125. loc.initialize(&file_);
  126. yy_flex_debug = trace_scanning_;
  127. YY_BUFFER_STATE buffer;
  128. buffer = yy_scan_bytes(string_.c_str(), string_.size());
  129. if (!buffer) {
  130. fatal("cannot scan string");
  131. // fatal() throws an exception so this can't be reached
  132. }
  133. }
  134. void
  135. EvalContext::scanStringEnd()
  136. {
  137. yy_delete_buffer(YY_CURRENT_BUFFER);
  138. }
  139. namespace {
  140. /// To avoid unused function error
  141. class Dummy {
  142. // cppcheck-suppress unusedPrivateFunction
  143. void dummy() { yy_fatal_error("Fix me: how to disable its definition?"); }
  144. };
  145. }