static isc::eval::location loc;
%}
%option noyywrap nounput batch debug noinput
-id [a-zA-Z][a-zA-Z_0-9]*
int [0-9]+
blank [ \t]
loc.step();
%}
-{blank}+ loc.step ();
-[\n]+ loc.lines (yyleng); loc.step ();
-"-" return isc::eval::EvalParser::make_MINUS(loc);
-"+" return isc::eval::EvalParser::make_PLUS(loc);
-"*" return isc::eval::EvalParser::make_STAR(loc);
-"/" return isc::eval::EvalParser::make_SLASH(loc);
-"(" return isc::eval::EvalParser::make_LPAREN(loc);
-")" return isc::eval::EvalParser::make_RPAREN(loc);
-":=" return isc::eval::EvalParser::make_ASSIGN(loc);
+{blank}+ loc.step();
+[\n]+ loc.lines(yyleng); loc.step();
+
+\"[a-zA-Z_0-9]*\" {
+ // This is a string, no need to do any conversions here.
+ return isc::eval::EvalParser::make_STRING(yytext, loc);
+}
+
+option\[{int}\] {
+ long n = strtol(yytext, NULL, 10);
+ /// @todo: Sanity check n
+ if (n<0 || n>65535) {
+ driver.error(loc, "Option code has invalid values. Allowed range: 0..65535");
+ }
+
+ return isc::eval::EvalParser::make_OPTION(n, loc);
+}
+"==" {
+ return isc::eval::EvalParser::make_EQUAL(loc);
+}
-{int} {
- errno = 0;
- long n = strtol (yytext, NULL, 10);
- if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE))
- driver.error (loc, "integer is out of range");
- return isc::eval::EvalParser::make_NUMBER(n, loc);
+"substring" {
+ return isc::eval::EvalParser::make_SUBSTRING(loc);
}
-{id} return isc::eval::EvalParser::make_IDENTIFIER(yytext, loc);
+"(" return isc::eval::EvalParser::make_LPAREN(loc);
+")" return isc::eval::EvalParser::make_RPAREN(loc);
+"," return isc::eval::EvalParser::make_COMA(loc);
+
. driver.error (loc, "invalid character");
<<EOF>> return isc::eval::EvalParser::make_END(loc);
%%
void
EvalContext::scan_begin()
{
- yy_flex_debug = trace_scanning;
- if (file.empty () || file == "-")
- yyin = stdin;
- else if (!(yyin = fopen(file.c_str (), "r")))
- {
- error ("cannot open " + file + ": " + strerror(errno));
- exit (EXIT_FAILURE);
+ yy_flex_debug = trace_scanning;
+ if (file.empty () || file == "-") {
+ yyin = stdin;
+ }
+ else if (!(yyin = fopen(file.c_str (), "r"))) {
+ error ("cannot open " + file + ": " + strerror(errno));
+ exit (EXIT_FAILURE);
}
}
void
EvalContext::scan_end()
{
- fclose (yyin);
+ fclose (yyin);
}
-
%define parse.assert
%code requires
{
-# include <string>
+#include <string>
+#include <eval/token.h>
class EvalContext;
}
// The parsing context.
-%param { EvalContext& driver }
+%param { EvalContext& ctx }
%locations
%initial-action
{
// Initialize the initial location.
- @$.begin.filename = @$.end.filename = &driver.file;
+ @$.begin.filename = @$.end.filename = &ctx.file;
};
%define parse.trace
%define parse.error verbose
%define api.token.prefix {TOKEN_}
%token
END 0 "end of file"
- ASSIGN ":="
- MINUS "-"
- PLUS "+"
- STAR "*"
- SLASH "/"
+ EQUAL "=="
+ SUBSTRING "substring"
+ COMA ","
LPAREN "("
RPAREN ")"
;
-%token <std::string> IDENTIFIER "identifier"
-%token <int> NUMBER "number"
-%type <int> exp
+%token <std::string> STRING "constant string"
+%token <int> OPTION "option code"
%printer { yyoutput << $$; } <*>;
%%
-%start unit;
-unit: assignments exp { driver.result = $2; };
-assignments:
- %empty {}
-| assignments assignment {};
+// The whole grammar starts with an expression.
+%start expression;
-assignment:
- "identifier" ":=" exp { driver.variables[$1] = $3; };
+// Expression can either be a single token or a (something == something) expression
+expression:
+token EQUAL token
+| token;
+
+token:
+STRING { /* push back TokenString */ }
+| OPTION { /* push back TokenOption */ }
+| SUBSTRING "(" token "," token "," token ")" {
+ /* push back TokenSubstring */
+ }
-%left "+" "-";
-%left "*" "/";
-exp:
- exp "+" exp { $$ = $1 + $3; }
-| exp "-" exp { $$ = $1 - $3; }
-| exp "*" exp { $$ = $1 * $3; }
-| exp "/" exp { $$ = $1 / $3; }
-| "(" exp ")" { std::swap ($$, $2); }
-| "identifier" { $$ = driver.variables[$1]; }
-| "number" { std::swap ($$, $1); };
%%
void
isc::eval::EvalParser::error(const location_type& l,
const std::string& m)
{
- driver.error (l, m);
+ ctx.error(l, m);
}