From: Tomek Mrugalski Date: Wed, 28 Oct 2015 19:13:59 +0000 (+0100) Subject: [4088] Bison example integrated. X-Git-Tag: trac4088fd_base~21 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=28413e825867f485cb1fa7fa75861edacddf5335;p=thirdparty%2Fkea.git [4088] Bison example integrated. --- diff --git a/src/lib/eval/Makefile.am b/src/lib/eval/Makefile.am index 1fd66b96f8..a2c28afc8a 100644 --- a/src/lib/eval/Makefile.am +++ b/src/lib/eval/Makefile.am @@ -14,6 +14,10 @@ lib_LTLIBRARIES = libkea-eval.la libkea_eval_la_SOURCES = libkea_eval_la_SOURCES += token.cc token.h +libkea_eval_la_SOURCES += parser.cc parser.h +libkea_eval_la_SOURCES += lexer.cc +libkea_eval_la_SOURCES += eval_context.cc + libkea_eval_la_CXXFLAGS = $(AM_CXXFLAGS) libkea_eval_la_CPPFLAGS = $(AM_CPPFLAGS) libkea_eval_la_LIBADD = $(top_builddir)/src/lib/exceptions/libkea-exceptions.la @@ -40,3 +44,13 @@ s-messages: eval_messages.mes BUILT_SOURCES = eval_messages.h eval_messages.cc CLEANFILES = eval_messages.h eval_messages.cc + + +# --- Flex/Bison stuff below -------------------------------------------------- +parser.cc parser.h: parser.yy + bison --defines=parser.h -oparser.cc parser.yy + +lexer.cc: lexer.ll + flex -olexer.cc lexer.ll + +driver.o: driver.cc diff --git a/src/lib/eval/eval_context.cc b/src/lib/eval/eval_context.cc new file mode 100644 index 0000000000..94338b9511 --- /dev/null +++ b/src/lib/eval/eval_context.cc @@ -0,0 +1,38 @@ +#line 11104 "./doc/bison.texi" +#include "eval_context.h" +#include "parser.h" + +calcxx_driver::calcxx_driver () + : trace_scanning (false), trace_parsing (false) +{ + variables["one"] = 1; + variables["two"] = 2; +} + +calcxx_driver::~calcxx_driver () +{ +} + +int +calcxx_driver::parse (const std::string &f) +{ + file = f; + scan_begin (); + yy::calcxx_parser parser (*this); + parser.set_debug_level (trace_parsing); + int res = parser.parse (); + scan_end (); + return res; +} + +void +calcxx_driver::error (const yy::location& l, const std::string& m) +{ + std::cerr << l << ": " << m << std::endl; +} + +void +calcxx_driver::error (const std::string& m) +{ + std::cerr << m << std::endl; +} diff --git a/src/lib/eval/eval_context.h b/src/lib/eval/eval_context.h new file mode 100644 index 0000000000..1d26f04faa --- /dev/null +++ b/src/lib/eval/eval_context.h @@ -0,0 +1,45 @@ +#ifndef CALCXX_DRIVER_HH +# define CALCXX_DRIVER_HH +# include +# include +# include "parser.h" + +// Tell Flex the lexer's prototype ... +# define YY_DECL \ + yy::calcxx_parser::symbol_type yylex (calcxx_driver& driver) + +// ... and declare it for the parser's sake. +YY_DECL; + +// Conducting the whole scanning and parsing of Calc++. +class calcxx_driver +{ +public: + calcxx_driver (); + virtual ~calcxx_driver (); + + std::map variables; + + int result; + + // Handling the scanner. + void scan_begin (); + void scan_end (); + bool trace_scanning; + + // Run the parser on file F. + // Return 0 on success. + int parse (const std::string& f); + + // The name of the file being parsed. + // Used later to pass the file name to the location tracker. + + std::string file; + // Whether parser traces should be generated. + bool trace_parsing; + + // Error handling. + void error (const yy::location& l, const std::string& m); + void error (const std::string& m); +}; +#endif // ! CALCXX_DRIVER_HH diff --git a/src/lib/eval/lexer.ll b/src/lib/eval/lexer.ll new file mode 100644 index 0000000000..f48e8161cd --- /dev/null +++ b/src/lib/eval/lexer.ll @@ -0,0 +1,80 @@ +%{ /* -*- C++ -*- */ +# include +# include +# include +# include +# include "eval_context.h" +# include "parser.h" + +// 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 +// . +# undef yywrap +# define yywrap() 1 + +// The location of the current token. +static yy::location loc; +%} +%option noyywrap nounput batch debug noinput +id [a-zA-Z][a-zA-Z_0-9]* +int [0-9]+ +blank [ \t] + +%{ + // Code run each time a pattern is matched. + # define YY_USER_ACTION loc.columns (yyleng); +%} + +%% + +%{ + // Code run each time yylex is called. + loc.step (); +%} + +{blank}+ loc.step (); +[\n]+ loc.lines (yyleng); loc.step (); +"-" return yy::calcxx_parser::make_MINUS(loc); +"+" return yy::calcxx_parser::make_PLUS(loc); +"*" return yy::calcxx_parser::make_STAR(loc); +"/" return yy::calcxx_parser::make_SLASH(loc); +"(" return yy::calcxx_parser::make_LPAREN(loc); +")" return yy::calcxx_parser::make_RPAREN(loc); +":=" return yy::calcxx_parser::make_ASSIGN(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 yy::calcxx_parser::make_NUMBER(n, loc); +} + +{id} return yy::calcxx_parser::make_IDENTIFIER(yytext, loc); +. driver.error (loc, "invalid character"); +<> return yy::calcxx_parser::make_END(loc); +%% + +void +calcxx_driver::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); + } +} + + + +void +calcxx_driver::scan_end () +{ + fclose (yyin); +} + diff --git a/src/lib/eval/parser.yy b/src/lib/eval/parser.yy new file mode 100644 index 0000000000..f13542c7d6 --- /dev/null +++ b/src/lib/eval/parser.yy @@ -0,0 +1,69 @@ +%skeleton "lalr1.cc" /* -*- C++ -*- */ +%require "3.0.2" +%defines +%define parser_class_name {calcxx_parser} +%define api.token.constructor +%define api.value.type variant +%define parse.assert +%code requires +{ +# include +class calcxx_driver; +} +// The parsing context. +%param { calcxx_driver& driver } +%locations +%initial-action +{ + // Initialize the initial location. + @$.begin.filename = @$.end.filename = &driver.file; +}; +%define parse.trace +%define parse.error verbose +%code +{ +# include "eval_context.h" +} +%define api.token.prefix {TOK_} +%token + END 0 "end of file" + ASSIGN ":=" + MINUS "-" + PLUS "+" + STAR "*" + SLASH "/" + LPAREN "(" + RPAREN ")" +; +%token IDENTIFIER "identifier" +%token NUMBER "number" +%type exp +%printer { yyoutput << $$; } <*>; +%% +%start unit; +unit: assignments exp { driver.result = $2; }; + +assignments: + %empty {} +| assignments assignment {}; + +assignment: + "identifier" ":=" exp { driver.variables[$1] = $3; }; + +%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 +yy::calcxx_parser::error (const location_type& l, + const std::string& m) +{ + driver.error (l, m); +}