summaryrefslogtreecommitdiff
path: root/i/chuck/src/parser
diff options
context:
space:
mode:
Diffstat (limited to 'i/chuck/src/parser')
-rw-r--r--i/chuck/src/parser/Makefile.defs14
-rw-r--r--i/chuck/src/parser/parser.cc189
-rw-r--r--i/chuck/src/parser/parser.hh89
-rw-r--r--i/chuck/src/parser/test_parser.cc86
-rw-r--r--i/chuck/src/parser/yylexer.ll148
-rw-r--r--i/chuck/src/parser/yyparser.yy278
6 files changed, 804 insertions, 0 deletions
diff --git a/i/chuck/src/parser/Makefile.defs b/i/chuck/src/parser/Makefile.defs
new file mode 100644
index 0000000..61b4b97
--- /dev/null
+++ b/i/chuck/src/parser/Makefile.defs
@@ -0,0 +1,14 @@
+PROGRAMS += test_parser
+
+parser_OBJECTS = yylexer.o yyparser.o parser.o
+
+test_parser_OBJECTS = $(parser_OBJECTS) test_parser.o
+
+EXTRA_CLEAN += yyparser.hh yyparser.cc yylexer.hh yylexer.cc
+
+yyparser.hh: yyparser.cc
+$(OBJ_DIR)/yylexer.o: yyparser.hh
+
+yylexer.hh: yylexer.cc
+$(OBJ_DIR)/yyparser.o: yylexer.hh
+$(OBJ_DIR)/parser.o: yylexer.hh
diff --git a/i/chuck/src/parser/parser.cc b/i/chuck/src/parser/parser.cc
new file mode 100644
index 0000000..4981474
--- /dev/null
+++ b/i/chuck/src/parser/parser.cc
@@ -0,0 +1,189 @@
+// parser.cc
+// marvin - programme du robot 2006. {{{
+//
+// Copyright (C) 2006 Nicolas Schodet
+//
+// Robot APB Team/Efrei 2006.
+// Web: http://assos.efrei.fr/robot/
+// Email: robot AT efrei DOT fr
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// }}}
+#include "parser.hh"
+
+#include "yyparser.hh"
+#include "yylexer.hh"
+
+#include <stdexcept>
+#include <sstream>
+
+int yyparse (void *);
+
+/// Constructeur.
+Parser::Parser (void)
+{
+}
+
+/// Destructeur
+Parser::~Parser (void)
+{
+}
+
+/// Lance le parseur sur un fichier.
+void
+Parser::parseFile (const std::string &file)
+{
+ FILE *f;
+ f = fopen (file.c_str (), "r");
+ if (!f)
+ throw std::runtime_error ("can not open file \"" + file + "\"");
+ try
+ {
+ // Crée un scanner, initialise son tampon d'entré, puis parse.
+ yyscan_t scanner;
+ YY_BUFFER_STATE buf;
+ Extra e (*this, true);
+ yylex_init (&scanner);
+ yyset_extra (&e, scanner);
+ buf = yy_create_buffer (f, YY_READ_BUF_SIZE, scanner);
+ yy_switch_to_buffer (buf, scanner);
+ int ret = yyparse (scanner);
+ yy_delete_buffer (buf, scanner);
+ yylex_destroy (scanner);
+ if (ret)
+ {
+ if (!e.error_.empty ())
+ throw std::runtime_error (e.error_);
+ else
+ throw std::runtime_error ("parse error");
+ }
+ }
+ catch (const std::exception &e)
+ {
+ fclose (f);
+ throw std::runtime_error ("in file \"" + file + "\": " + e.what ());
+ }
+ fclose (f);
+}
+
+/// Lance le parseur sur une chaîne.
+void
+Parser::parseString (const std::string &s)
+{
+ try
+ {
+ // Crée un scanner, initialise son tampon d'entré, puis parse.
+ yyscan_t scanner;
+ YY_BUFFER_STATE buf;
+ Extra e (*this, false);
+ yylex_init (&scanner);
+ yyset_extra (&e, scanner);
+ buf = yy_scan_bytes (s.data (), s.size (), scanner);
+ int ret = yyparse (scanner);
+ yy_delete_buffer (buf, scanner);
+ yylex_destroy (scanner);
+ if (ret)
+ {
+ if (!e.error_.empty ())
+ throw std::runtime_error (e.error_);
+ else
+ throw std::runtime_error ("parse error");
+ }
+ }
+ catch (const std::exception &e)
+ {
+ throw std::runtime_error ("in string \"" + s + "\": " + e.what ());
+ }
+}
+
+/// Fonction appelée lors d'une affectation. VAL peut être modifié, il est
+/// détruit suite à l'appel.
+void
+Parser::assign (const std::string &id, any &val)
+{
+ throw std::runtime_error ("unexpected assignement");
+}
+
+/// Fonction appelée lors d'un appel. ARGS peut être modifié, il est
+/// détruit suite à l'appel.
+void
+Parser::call (const std::string &id, AnyList &args)
+{
+ throw std::runtime_error ("unexpected call");
+}
+
+/// Constructeur pour initialiser les références.
+Parser::Extra::Extra (Parser &parser, bool useLine)
+ : line (1), parser_ (parser), useLine_ (useLine)
+{
+}
+
+/// Recueille l'erreur de bison.
+void
+Parser::Extra::error (const std::string &e)
+{
+ if (error_.empty ())
+ {
+ error_ = e;
+ if (useLine_)
+ {
+ std::stringstream os;
+ os << line;
+ error_ += ", line ";
+ error_ += os.str ();
+ }
+ }
+}
+
+/// Fonction appelée lors d'une affectation par bison.
+bool
+Parser::Extra::assign (const std::string &id, any &val)
+{
+ try
+ {
+ parser_.assign (id, val);
+ }
+ catch (const std::exception &e)
+ {
+ error (e.what ());
+ return false;
+ }
+ return true;
+}
+
+/// Fonction appelée lors d'un appel par bison.
+bool
+Parser::Extra::call (const std::string &id, AnyList &args)
+{
+ try
+ {
+ parser_.call (id, args);
+ }
+ catch (const std::exception &e)
+ {
+ error (e.what ());
+ return false;
+ }
+ return true;
+}
+
+/* Shut up warning for this wrongly declared static function. */
+static int
+yy_init_globals (yyscan_t yyscanner)
+{
+ return yy_init_globals (yyscanner);
+}
+
diff --git a/i/chuck/src/parser/parser.hh b/i/chuck/src/parser/parser.hh
new file mode 100644
index 0000000..573d5f6
--- /dev/null
+++ b/i/chuck/src/parser/parser.hh
@@ -0,0 +1,89 @@
+#ifndef parser_hh
+#define parser_hh
+// parser.hh
+// marvin - programme du robot 2006. {{{
+//
+// Copyright (C) 2006 Nicolas Schodet
+//
+// Robot APB Team/Efrei 2006.
+// Web: http://assos.efrei.fr/robot/
+// Email: robot AT efrei DOT fr
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// }}}
+#include "utils/any.hh"
+
+#include <string>
+#include <list>
+
+/// Classe de parsing. Pour l'utiliser, dériver une classe et implémenter les
+/// méthodes que l'on veut supporter.
+class Parser
+{
+ public:
+ /// Les types supportés sont bool, char, int, double, std::string,
+ /// IntList, DoubleList, StringList.
+ typedef std::list<int> IntList;
+ typedef std::list<double> DoubleList;
+ typedef std::list<std::string> StringList;
+ typedef std::list<any> AnyList;
+ /// Cette structure est passée au parser en bison, puis au lexer en flex.
+ class Extra
+ {
+ public:
+ /// Chaîne temporaire utilisée pendant l'analyse lexicale.
+ std::string tmp;
+ /// Ligne courante.
+ int line;
+ private:
+ /// Référence vers l'instance de Parser.
+ Parser &parser_;
+ /// Permet de stocker l'erreur de bison.
+ std::string error_;
+ /// Utilise ou non le comptage de lignes.
+ bool useLine_;
+ public:
+ /// Constructeur pour initialiser les références.
+ Extra (Parser &parser, bool useLine);
+ /// Recueille l'erreur de bison.
+ void error (const std::string &e);
+ /// Fonction appelée lors d'une affectation par bison.
+ bool assign (const std::string &id, any &val);
+ /// Fonction appelée lors d'un appel par bison.
+ bool call (const std::string &id, AnyList &args);
+ /// Accés réservé pour Parser.
+ friend class Parser;
+ };
+ public:
+ /// Constructeur.
+ Parser (void);
+ /// Destructeur virtuel
+ virtual ~Parser (void);
+ /// Lance le parseur sur un fichier.
+ void parseFile (const std::string &file);
+ /// Lance le parseur sur une chaîne.
+ void parseString (const std::string &s);
+ /// Fonction appelée lors d'une affectation. VAL peut être modifié, il est
+ /// détruit suite à l'appel.
+ virtual void assign (const std::string &id, any &val);
+ /// Fonction appelée lors d'un appel. ARGS peut être modifié, il est
+ /// détruit suite à l'appel.
+ virtual void call (const std::string &id, AnyList &args);
+};
+
+#define YY_EXTRA_TYPE Parser::Extra *
+
+#endif // parser_hh
diff --git a/i/chuck/src/parser/test_parser.cc b/i/chuck/src/parser/test_parser.cc
new file mode 100644
index 0000000..dedbd83
--- /dev/null
+++ b/i/chuck/src/parser/test_parser.cc
@@ -0,0 +1,86 @@
+// test_parser.cc
+// marvin - programme du robot 2006. {{{
+//
+// Copyright (C) 2006 Nicolas Schodet
+//
+// Robot APB Team/Efrei 2006.
+// Web: http://assos.efrei.fr/robot/
+// Email: robot AT efrei DOT fr
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// }}}
+#include "parser.hh"
+
+#include <iostream>
+#include <exception>
+
+class TestParser : public Parser
+{
+ public:
+ /// Fonction appelée lors d'une affectation. VAL peut être modifié, il est
+ /// détruit suite à l'appel.
+ virtual void assign (const std::string &id, any &val)
+ {
+ std::cout << id << " = " << val << std::endl;
+ }
+ /// Fonction appelée lors d'un appel. ARGS peut être modifié, il est
+ /// détruit suite à l'appel.
+ virtual void call (const std::string &id, AnyList &args)
+ {
+ std::cout << "call " << id << ' ' << args << std::endl;
+ }
+};
+
+int
+main (int argc, char **argv)
+{
+ try
+ {
+ if (argc <= 1)
+ {
+ std::cerr << "test_parser - test le parser.\n"
+ "Utilisation: test_parser [-f FILE | STRING]\n"
+ << std::endl;
+ }
+ TestParser tp;
+ for (int i = 1; i < argc; i++)
+ {
+ try
+ {
+ if (i + 1 < argc && strcmp (argv[i], "-f") == 0)
+ {
+ tp.parseFile (argv[++i]);
+ }
+ else
+ {
+ tp.parseString (argv[i]);
+ }
+ }
+ catch (const std::exception &e)
+ {
+ // L'erreur est humaine... heu, normale, elle fait parti du
+ // test donc pas de cerr.
+ std::cout << "error: " << e.what () << std::endl;
+ }
+ }
+ }
+ catch (const std::exception &e)
+ {
+ std::cerr << e.what () << std::endl;
+ return 1;
+ }
+ return 0;
+}
diff --git a/i/chuck/src/parser/yylexer.ll b/i/chuck/src/parser/yylexer.ll
new file mode 100644
index 0000000..be8d41c
--- /dev/null
+++ b/i/chuck/src/parser/yylexer.ll
@@ -0,0 +1,148 @@
+%{
+// marvin - programme du robot 2006. {{{
+//
+// Copyright (C) 2006 Nicolas Schodet
+//
+// Robot APB Team/Efrei 2006.
+// Web: http://assos.efrei.fr/robot/
+// Email: robot AT efrei DOT fr
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// }}}
+#include "parser/parser.hh"
+#include "yyparser.hh"
+%}
+
+%option reentrant
+%option header-file="yylexer.hh"
+%option outfile="yylexer.cc"
+%option bison-bridge
+%option noyywrap nodefault nounput
+
+%x strst
+
+INTDEC [+-]?[0-9]+
+INTHEX "0x"[0-9a-fA-F]+
+INTNUM {INTDEC}|{INTHEX}
+DOUBLEEX [eE]{INTDEC}
+DOUBLE1 [+-]?\.[0-9]+{DOUBLEEX}?
+DOUBLE2 [+-]?[0-9]+\.[0-9]*{DOUBLEEX}?
+DOUBLE3 {INTDEC}{DOUBLEEX}
+DOUBLENUM {DOUBLE1}|{DOUBLE2}|{DOUBLE3}
+
+%%
+
+"true"|"on"|"yes" {
+ yylval->b = true;
+ return BOOLEAN;
+}
+
+"false"|"off"|"no" {
+ yylval->b = false;
+ return BOOLEAN;
+}
+
+"'"\\n"'" {
+ yylval->c = '\n';
+ return CHAR;
+}
+"'"\\r"'" {
+ yylval->c = '\r';
+ return CHAR;
+}
+"'"\\t"'" {
+ yylval->c = '\t';
+ return CHAR;
+}
+"'"\\."'" {
+ yylval->c = yytext[1];
+ return CHAR;
+}
+"'"\\\n"'" {
+ yyextra->line++;
+ yylval->c = yytext[1];
+ return CHAR;
+}
+"'"."'" {
+ yylval->c = yytext[1];
+ return CHAR;
+}
+
+[a-zA-Z][_a-zA-Z0-9.-]* {
+ yylval->s = new std::string (yytext);
+ return ID;
+}
+
+{DOUBLENUM} {
+ yylval->d = strtod (yytext, 0);
+ return DOUBLE;
+}
+
+{INTNUM} {
+ yylval->i = strtol (yytext, 0, 0);
+ return INT;
+}
+
+\" {
+ BEGIN(strst);
+ yyextra->tmp.clear ();
+}
+
+\n {
+ yyextra->line++;
+ return SEP;
+}
+
+; {
+ return SEP;
+}
+
+[=()] return yytext[0];
+
+[ \t]+ /* Skip. */
+#.* /* Skip comments. */
+
+. {
+ yyextra->error (std::string ("unexpected character \'") \
+ + yytext[0] + '\'');
+ return UNKNOWN;
+}
+
+<strst>\" {
+ BEGIN (INITIAL);
+ yylval->s = new std::string (yyextra->tmp);
+ return STRING;
+}
+
+<strst>\\n yyextra->tmp += '\n';
+<strst>\\r yyextra->tmp += '\r';
+<strst>\\t yyextra->tmp += '\t';
+<strst>\\. yyextra->tmp += yytext[1];
+<strst>\\\n {
+ yyextra->line++;
+ yyextra->tmp += yytext[1];
+}
+<strst>. yyextra->tmp += yytext[0];
+<strst>\n {
+ yyextra->error ("unexpected end of line inside string");
+ yyextra->line++;
+ return UNKNOWN;
+}
+
+%%
+
+/* vim:ft=lex:
+*/
diff --git a/i/chuck/src/parser/yyparser.yy b/i/chuck/src/parser/yyparser.yy
new file mode 100644
index 0000000..86db4a5
--- /dev/null
+++ b/i/chuck/src/parser/yyparser.yy
@@ -0,0 +1,278 @@
+%{
+// marvin - programme du robot 2006. {{{
+//
+// Copyright (C) 2006 Nicolas Schodet
+//
+// Robot APB Team/Efrei 2006.
+// Web: http://assos.efrei.fr/robot/
+// Email: robot AT efrei DOT fr
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// }}}
+#include "parser/parser.hh"
+
+// Fichiers d'en-tête générés.
+#include "yyparser.hh"
+#include "yylexer.hh"
+
+#undef yyextra
+#define yyextra (yyget_extra (scanner))
+
+void yyerror (void *scanner, const char *e);
+
+%}
+
+%error-verbose
+%pure-parser
+%lex-param {void *scanner}
+%parse-param {void *scanner}
+%defines
+%union {
+ bool b;
+ char c;
+ int i;
+ double d;
+ std::string *s;
+ struct {
+ any *a;
+ Parser::IntList *il;
+ } il;
+ struct {
+ any *a;
+ Parser::DoubleList *dl;
+ } dl;
+ struct {
+ any *a;
+ Parser::StringList *sl;
+ } sl;
+ Parser::AnyList *al;
+}
+
+%token SEP
+
+%token<b> BOOLEAN
+%token<c> UNKNOWN
+%token<c> CHAR
+%token<i> INT
+%token<d> DOUBLE
+%token<s> ID STRING
+
+%type<il> int_list int_list_i
+%type<dl> double_list double_list_i
+%type<sl> string_list string_list_i
+%type<al> arg_list
+
+%destructor { delete $$; } ID STRING
+%destructor { delete $$.a; } int_list int_list_i
+%destructor { delete $$.a; } double_list double_list_i
+%destructor { delete $$.a; } string_list string_list_i
+%destructor { delete $$; } arg_list
+
+%%
+
+input:
+ /* Nothing. */
+ | item
+ | input SEP item
+ | input SEP
+;
+
+item:
+ ID '=' BOOLEAN {
+ any a ($3);
+ if (!yyextra->assign (*$1, a))
+ YYERROR;
+ delete $1;
+ }
+ | ID '=' CHAR {
+ any a ($3);
+ if (!yyextra->assign (*$1, a))
+ YYERROR;
+ delete $1;
+ }
+ | ID '=' INT {
+ any a ($3);
+ if (!yyextra->assign (*$1, a))
+ YYERROR;
+ delete $1;
+ }
+ | ID '=' DOUBLE {
+ any a ($3);
+ if (!yyextra->assign (*$1, a))
+ YYERROR;
+ delete $1;
+ }
+ | ID '=' STRING {
+ any a (*$3);
+ if (!yyextra->assign (*$1, a))
+ YYERROR;
+ delete $1;
+ delete $3;
+ }
+ | ID '=' int_list {
+ if (!yyextra->assign (*$1, *$3.a))
+ YYERROR;
+ delete $1;
+ delete $3.a;
+ }
+ | ID '=' double_list {
+ if (!yyextra->assign (*$1, *$3.a))
+ YYERROR;
+ delete $1;
+ delete $3.a;
+ }
+ | ID '=' string_list {
+ if (!yyextra->assign (*$1, *$3.a))
+ YYERROR;
+ delete $1;
+ delete $3.a;
+ }
+ | ID arg_list {
+ if (!yyextra->call (*$1, *$2))
+ YYERROR;
+ delete $1;
+ delete $2;
+ }
+;
+
+int_list:
+ '(' int_list_i ')' {
+ $$ = $2;
+ }
+;
+
+int_list_i:
+ INT {
+ $$.a = new any (Parser::IntList ());
+ $$.il = any_cast<Parser::IntList> ($$.a);
+ $$.il->push_back ($1);
+ }
+ | int_list_i INT {
+ $1.il->push_back ($2);
+ $$ = $1;
+ }
+;
+
+double_list:
+ '(' double_list_i ')' {
+ $$ = $2;
+ }
+;
+
+double_list_i:
+ DOUBLE {
+ $$.a = new any (Parser::DoubleList ());
+ $$.dl = any_cast<Parser::DoubleList> ($$.a);
+ $$.dl->push_back ($1);
+ }
+ | double_list_i DOUBLE {
+ $1.dl->push_back ($2);
+ $$ = $1;
+ }
+;
+
+string_list:
+ '(' string_list_i ')' {
+ $$ = $2;
+ }
+;
+
+string_list_i:
+ STRING {
+ $$.a = new any (Parser::StringList ());
+ $$.sl = any_cast<Parser::StringList> ($$.a);
+ $$.sl->push_back (*$1);
+ delete $1;
+ }
+ | string_list_i STRING {
+ $1.sl->push_back (*$2);
+ $$ = $1;
+ delete $2;
+ }
+;
+
+arg_list:
+ /* empty */ {
+ $$ = new Parser::AnyList;
+ }
+ | arg_list BOOLEAN {
+ any a ($2);
+ $1->push_back (any ());
+ $1->back ().swap (a);
+ $$ = $1;
+ }
+ | arg_list CHAR {
+ any a ($2);
+ $1->push_back (any ());
+ $1->back ().swap (a);
+ $$ = $1;
+ }
+ | arg_list INT {
+ any a ($2);
+ $1->push_back (any ());
+ $1->back ().swap (a);
+ $$ = $1;
+ }
+ | arg_list DOUBLE {
+ any a ($2);
+ $1->push_back (any ());
+ $1->back ().swap (a);
+ $$ = $1;
+ }
+ | arg_list STRING {
+ any a (*$2);
+ $1->push_back (any ());
+ $1->back ().swap (a);
+ delete $2;
+ $$ = $1;
+ }
+ | arg_list int_list {
+ $1->push_back (any ());
+ $1->back ().swap (*$2.a);
+ delete $2.a;
+ $$ = $1;
+ }
+ | arg_list double_list {
+ $1->push_back (any ());
+ $1->back ().swap (*$2.a);
+ delete $2.a;
+ $$ = $1;
+ }
+ | arg_list string_list {
+ $1->push_back (any ());
+ $1->back ().swap (*$2.a);
+ delete $2.a;
+ $$ = $1;
+ }
+;
+%%
+
+/// Traite une erreur de Bison.
+void
+yyerror (void *scanner, const char *e)
+{
+ yyextra->error (e);
+}
+
+/* Shut up warning for this wrongly declared static function. */
+static int
+yy_init_globals (yyscan_t yyscanner)
+{
+ return yy_init_globals (yyscanner);
+}
+
+/* vim:ft=yacc:
+*/