123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- /* Copyright (C) 2015-2016 Internet Systems Consortium, Inc. ("ISC")
- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- %{ /* -*- C++ -*- */
- #include <cerrno>
- #include <climits>
- #include <cstdlib>
- #include <string>
- #include <eval/eval_context.h>
- #include <eval/parser.h>
- #include <asiolink/io_address.h>
- #include <boost/lexical_cast.hpp>
- // Work around an incompatibility in flex (at least versions
- // 2.5.31 through 2.5.33): it generates code that does
- // not conform to C89. See Debian bug 333231
- // <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=333231>.
- # undef yywrap
- # define yywrap() 1
- // The location of the current token. The lexer will keep updating it. This
- // variable will be useful for logging errors.
- static isc::eval::location loc;
- namespace {
- bool start_token_flag = false;
- isc::eval::EvalContext::ParserType start_token_value;
- };
- // To avoid the call to exit... oops!
- #define YY_FATAL_ERROR(msg) isc::eval::EvalContext::fatal(msg)
- %}
- /* noyywrap disables automatic rewinding for the next file to parse. Since we
- always parse only a single string, there's no need to do any wraps. And
- using yywrap requires linking with -lfl, which provides the default yywrap
- implementation that always returns 1 anyway. */
- %option noyywrap
- /* nounput simplifies the lexer, by removing support for putting a character
- back into the input stream. We never use such capability anyway. */
- %option nounput
- /* batch means that we'll never use the generated lexer interactively. */
- %option batch
- /* Enables debug mode. To see the debug messages, one needs to also set
- eval_flex_debug to 1, then the debug messages will be printed on stderr. */
- %option debug
- /* I have no idea what this option does, except it was specified in the bison
- examples and Postgres folks added it to remove gcc 4.3 warnings. Let's
- be on the safe side and keep it. */
- %option noinput
- /* This line tells flex to track the line numbers. It's not really that
- useful for client classes, which typically are one-liners, but it may be
- useful in more complex cases. */
- %option yylineno
- /* These are not token expressions yet, just convenience expressions that
- can be used during actual token definitions. Note some can match
- incorrect inputs (e.g., IP addresses) which must be checked. */
- int \-?[0-9]+
- hex [0-9a-fA-F]+
- blank [ \t]
- addr4 [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+
- addr6 [0-9a-fA-F]*\:[0-9a-fA-F]*\:[0-9a-fA-F:.]*
- %{
- // This code run each time a pattern is matched. It updates the location
- // by moving it ahead by yyleng bytes. yyleng specifies the length of the
- // currently matched token.
- #define YY_USER_ACTION loc.columns(evalleng);
- %}
- %%
- %{
- // Code run each time evallex is called.
- loc.step();
- if (start_token_flag) {
- start_token_flag = false;
- switch (start_token_value) {
- case EvalContext::PARSER_BOOL:
- return isc::eval::EvalParser::make_TOPLEVEL_BOOL(loc);
- default:
- case EvalContext::PARSER_STRING:
- return isc::eval::EvalParser::make_TOPLEVEL_STRING(loc);
- }
- }
- %}
- {blank}+ {
- // Ok, we found a with space. Let's ignore it and update loc variable.
- loc.step();
- }
- [\n]+ {
- // Newline found. Let's update the location and continue.
- loc.lines(evalleng);
- loc.step();
- }
- \'[^\'\n]*\' {
- // A string has been matched. It contains the actual string and single quotes.
- // We need to get those quotes out of the way and just use its content, e.g.
- // for 'foo' we should get foo
- std::string tmp(evaltext+1);
- tmp.resize(tmp.size() - 1);
- return isc::eval::EvalParser::make_STRING(tmp, loc);
- }
- 0[xX]{hex} {
- // A hex string has been matched. It contains the '0x' or '0X' header
- // followed by at least one hexadecimal digit.
- return isc::eval::EvalParser::make_HEXSTRING(evaltext, loc);
- }
- {int} {
- // An integer was found.
- std::string tmp(evaltext);
- try {
- // In substring we want to use negative values (e.g. -1).
- // In enterprise-id we need to use values up to 0xffffffff.
- // To cover both of those use cases, we need at least
- // int64_t.
- static_cast<void>(boost::lexical_cast<int64_t>(tmp));
- } catch (const boost::bad_lexical_cast &) {
- driver.error(loc, "Failed to convert " + tmp + " to an integer.");
- }
- // The parser needs the string form as double conversion is no lossless
- return isc::eval::EvalParser::make_INTEGER(tmp, loc);
- }
- [A-Za-z]([-_A-Za-z0-9]*[A-Za-z0-9])?/({blank}|\n)*] {
- // This string specifies option name starting with a letter
- // and further containing letters, digits, hyphens and
- // underscores and finishing by letters or digits.
- return isc::eval::EvalParser::make_OPTION_NAME(evaltext, loc);
- }
- {addr4}|{addr6} {
- // IPv4 or IPv6 address
- std::string tmp(evaltext);
- // Some incorrect addresses can match so we have to check.
- try {
- isc::asiolink::IOAddress ip(tmp);
- } catch (...) {
- driver.error(loc, "Failed to convert " + tmp + " to an IP address.");
- }
- return isc::eval::EvalParser::make_IP_ADDRESS(evaltext, loc);
- }
- "==" return isc::eval::EvalParser::make_EQUAL(loc);
- "option" return isc::eval::EvalParser::make_OPTION(loc);
- "relay4" return isc::eval::EvalParser::make_RELAY4(loc);
- "relay6" return isc::eval::EvalParser::make_RELAY6(loc);
- "peeraddr" return isc::eval::EvalParser::make_PEERADDR(loc);
- "linkaddr" return isc::eval::EvalParser::make_LINKADDR(loc);
- "text" return isc::eval::EvalParser::make_TEXT(loc);
- "hex" return isc::eval::EvalParser::make_HEX(loc);
- "exists" return isc::eval::EvalParser::make_EXISTS(loc);
- "pkt" return isc::eval::EvalParser::make_PKT(loc);
- "iface" return isc::eval::EvalParser::make_IFACE(loc);
- "src" return isc::eval::EvalParser::make_SRC(loc);
- "dst" return isc::eval::EvalParser::make_DST(loc);
- "len" return isc::eval::EvalParser::make_LEN(loc);
- "pkt4" return isc::eval::EvalParser::make_PKT4(loc);
- "mac" return isc::eval::EvalParser::make_CHADDR(loc);
- "hlen" return isc::eval::EvalParser::make_HLEN(loc);
- "htype" return isc::eval::EvalParser::make_HTYPE(loc);
- "ciaddr" return isc::eval::EvalParser::make_CIADDR(loc);
- "giaddr" return isc::eval::EvalParser::make_GIADDR(loc);
- "yiaddr" return isc::eval::EvalParser::make_YIADDR(loc);
- "siaddr" return isc::eval::EvalParser::make_SIADDR(loc);
- "pkt6" return isc::eval::EvalParser::make_PKT6(loc);
- "msgtype" return isc::eval::EvalParser::make_MSGTYPE(loc);
- "transid" return isc::eval::EvalParser::make_TRANSID(loc);
- "vendor" return isc::eval::EvalParser::make_VENDOR(loc);
- "vendor-class" return isc::eval::EvalParser::make_VENDOR_CLASS(loc);
- "data" return isc::eval::EvalParser::make_DATA(loc);
- "enterprise" return isc::eval::EvalParser::make_ENTERPRISE(loc);
- "substring" return isc::eval::EvalParser::make_SUBSTRING(loc);
- "all" return isc::eval::EvalParser::make_ALL(loc);
- "concat" return isc::eval::EvalParser::make_CONCAT(loc);
- "not" return isc::eval::EvalParser::make_NOT(loc);
- "and" return isc::eval::EvalParser::make_AND(loc);
- "or" return isc::eval::EvalParser::make_OR(loc);
- "." return isc::eval::EvalParser::make_DOT(loc);
- "(" return isc::eval::EvalParser::make_LPAREN(loc);
- ")" return isc::eval::EvalParser::make_RPAREN(loc);
- "[" return isc::eval::EvalParser::make_LBRACKET(loc);
- "]" return isc::eval::EvalParser::make_RBRACKET(loc);
- "," return isc::eval::EvalParser::make_COMA(loc);
- "*" return isc::eval::EvalParser::make_ANY(loc);
- . driver.error (loc, "Invalid character: " + std::string(evaltext));
- <<EOF>> return isc::eval::EvalParser::make_END(loc);
- %%
- using namespace isc::eval;
- void
- EvalContext::scanStringBegin(ParserType type)
- {
- start_token_flag = true;
- start_token_value = type;
- loc.initialize(&file_);
- eval_flex_debug = trace_scanning_;
- YY_BUFFER_STATE buffer;
- buffer = eval_scan_bytes(string_.c_str(), string_.size());
- if (!buffer) {
- fatal("cannot scan string");
- // fatal() throws an exception so this can't be reached
- }
- }
- void
- EvalContext::scanStringEnd()
- {
- eval_delete_buffer(YY_CURRENT_BUFFER);
- }
- namespace {
- /// To avoid unused function error
- class Dummy {
- // cppcheck-suppress unusedPrivateFunction
- void dummy() { yy_fatal_error("Fix me: how to disable its definition?"); }
- };
- }
|