lexer.ll 5.54 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")

   Permission to use, copy, modify, and/or distribute this software for any
   purpose with or without fee is hereby granted, provided that the above
   copyright notice and this permission notice appear in all copies.

   THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
   REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
   AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
   INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
   LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
   OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
   PERFORMANCE OF THIS SOFTWARE. */

15
%{ /* -*- C++ -*- */
16
17
18
19
20
21
22
#include <cerrno>
#include <climits>
#include <cstdlib>
#include <string>
#include <eval/eval_context.h>
#include <eval/parser.h>
#include <boost/lexical_cast.hpp>
23
24
25
26
27
28
29
30

// 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

31
32
// The location of the current token. The lexer will keep updating it. This
// variable will be useful for logging errors.
33
static isc::eval::location loc;
34
35
36

// To avoid the call to exit... oops!
#define YY_FATAL_ERROR(msg) isc::eval::EvalContext::fatal(msg)
37
%}
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

/* 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
   yy_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. */
68
int   \-?[0-9]+
69
hex   [0-9a-fA-F]+
70
71
72
blank [ \t]

%{
73
74
75
// 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.
76
#define YY_USER_ACTION  loc.columns(yyleng);
77
78
79
80
81
%}

%%

%{
82
83
    // Code run each time yylex is called.
    loc.step();
84
85
%}

86
87
88
89
90
91
92
93
94
{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(yyleng);
    loc.step();
}
95

96
\'[^\'\n]*\' {
97
98
99
    // 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
100
101
102
103
    std::string tmp(yytext+1);
    tmp.resize(tmp.size() - 1);

    return isc::eval::EvalParser::make_STRING(tmp, loc);
104
105
}

106
107
108
109
110
111
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(yytext, loc);
}

112
{int} {
113
    // An integer was found.
114
115
116
    std::string tmp(yytext);

    try {
117
        static_cast<void>(boost::lexical_cast<int>(tmp));
118
    } catch (const boost::bad_lexical_cast &) {
119
        driver.error(loc, "Failed to convert " + tmp + " to an integer.");
120
    }
121

122
123
    // The parser needs the string form as double conversion is no lossless
    return isc::eval::EvalParser::make_INTEGER(tmp, loc);
124
125
}

126
"=="        return isc::eval::EvalParser::make_EQUAL(loc);
127
"option"    return isc::eval::EvalParser::make_OPTION(loc);
128
129
"text"      return isc::eval::EvalParser::make_TEXT(loc);
"hex"       return isc::eval::EvalParser::make_HEX(loc);
130
"substring" return isc::eval::EvalParser::make_SUBSTRING(loc);
131
"all"       return isc::eval::EvalParser::make_ALL(loc);
132
"."         return isc::eval::EvalParser::make_DOT(loc);
133
134
"("         return isc::eval::EvalParser::make_LPAREN(loc);
")"         return isc::eval::EvalParser::make_RPAREN(loc);
135
136
"["         return isc::eval::EvalParser::make_LBRACKET(loc);
"]"         return isc::eval::EvalParser::make_RBRACKET(loc);
137
","         return isc::eval::EvalParser::make_COMA(loc);
138

139
.          driver.error (loc, "Invalid character: " + std::string(yytext));
140
<<EOF>>    return isc::eval::EvalParser::make_END(loc);
141
142
%%

143
144
using namespace isc::eval;

145
146
147
void
EvalContext::scanStringBegin()
{
Francis Dupont's avatar
Francis Dupont committed
148
    loc.initialize(&file_);
149
    yy_flex_debug = trace_scanning_;
Francis Dupont's avatar
Francis Dupont committed
150
    YY_BUFFER_STATE buffer;
151
152
    buffer = yy_scan_bytes(string_.c_str(), string_.size());
    if (!buffer) {
153
154
        fatal("cannot scan string");
	// fatal() throws an exception so this can't be reached
155
156
157
158
159
160
161
162
    }
}

void
EvalContext::scanStringEnd()
{
    yy_delete_buffer(YY_CURRENT_BUFFER);
}
163
164
165
166
167
168
169

namespace {
/// To avoid unused function error
class Dummy {
    void dummy() { yy_fatal_error("Fix me: how to disable its definition?"); }
};
}