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
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
--- /dev/null
+#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;
+}
--- /dev/null
+#ifndef CALCXX_DRIVER_HH
+# define CALCXX_DRIVER_HH
+# include <string>
+# include <map>
+# 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<std::string, int> 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
--- /dev/null
+%{ /* -*- C++ -*- */
+# include <cerrno>
+# include <climits>
+# include <cstdlib>
+# include <string>
+# 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
+// <http://bugs.debian.org/cgi-bin/bugreport.cgi?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");
+<<EOF>> 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);
+}
+
--- /dev/null
+%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 <string>
+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 <std::string> IDENTIFIER "identifier"
+%token <int> NUMBER "number"
+%type <int> 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);
+}