summaryrefslogtreecommitdiffstats
path: root/src/lib/eval/lexer.ll
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lib/eval/lexer.ll277
1 files changed, 277 insertions, 0 deletions
diff --git a/src/lib/eval/lexer.ll b/src/lib/eval/lexer.ll
new file mode 100644
index 0000000..3c376c2
--- /dev/null
+++ b/src/lib/eval/lexer.ll
@@ -0,0 +1,277 @@
+/* Copyright (C) 2015-2022 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++ -*- */
+
+/* Generated files do not make clang static analyser so happy */
+#ifndef __clang_analyzer__
+
+#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>
+
+/* Please avoid C++ style comments (// ... eol) as they break flex 2.6.2 */
+
+/* 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. */
+ /* Moved from a variable trailing context to C++ code as it was too slow */
+ std::string tmp(evaltext);
+ /* remove possible trailing blanks or newlines */
+ while (tmp.size() > 1) {
+ char last = tmp[tmp.size() - 1];
+ if ((last != ' ') && (last != '\t') && (last != '\n')) {
+ break;
+ }
+ if (last == '\n') {
+ /* Take embedded newlines into account */
+ /* Can make it more complex to handle spaces after the last
+ newline but currently keep it simple... */
+ loc.lines();
+ loc.step();
+ }
+ tmp.resize(tmp.size() - 1);
+ }
+ return isc::eval::EvalParser::make_OPTION_NAME(tmp, 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);
+"split" return isc::eval::EvalParser::make_SPLIT(loc);
+"all" return isc::eval::EvalParser::make_ALL(loc);
+"concat" return isc::eval::EvalParser::make_CONCAT(loc);
+"ifelse" return isc::eval::EvalParser::make_IFELSE(loc);
+"hexstring" return isc::eval::EvalParser::make_TOHEXSTRING(loc);
+"addrtotext" return isc::eval::EvalParser::make_ADDRTOTEXT(loc);
+"int8totext" return isc::eval::EvalParser::make_INT8TOTEXT(loc);
+"int16totext" return isc::eval::EvalParser::make_INT16TOTEXT(loc);
+"int32totext" return isc::eval::EvalParser::make_INT32TOTEXT(loc);
+"uint8totext" return isc::eval::EvalParser::make_UINT8TOTEXT(loc);
+"uint16totext" return isc::eval::EvalParser::make_UINT16TOTEXT(loc);
+"uint32totext" return isc::eval::EvalParser::make_UINT32TOTEXT(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);
+"member" return isc::eval::EvalParser::make_MEMBER(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);
+"+" return isc::eval::EvalParser::make_PLUS(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?"); }
+};
+}
+#endif /* !__clang_analyzer__ */