Browse Source

[4088] Bison example integrated.

Tomek Mrugalski 9 years ago
parent
commit
28413e8258
5 changed files with 246 additions and 0 deletions
  1. 14 0
      src/lib/eval/Makefile.am
  2. 38 0
      src/lib/eval/eval_context.cc
  3. 45 0
      src/lib/eval/eval_context.h
  4. 80 0
      src/lib/eval/lexer.ll
  5. 69 0
      src/lib/eval/parser.yy

+ 14 - 0
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

+ 38 - 0
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;
+}

+ 45 - 0
src/lib/eval/eval_context.h

@@ -0,0 +1,45 @@
+#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

+ 80 - 0
src/lib/eval/lexer.ll

@@ -0,0 +1,80 @@
+%{ /* -*- 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);
+}
+

+ 69 - 0
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 <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);
+}