From 1cb15048a3da2076ea3d41b53b2791cbb8925eec Mon Sep 17 00:00:00 2001 From: schodet Date: Sun, 9 Apr 2006 13:48:55 +0000 Subject: Ajout du parser générique. Voila, j'ai résolu mes problèmes éthiques comme dit djerem. --- i/marvin/src/Makefile.defs | 1 + i/marvin/src/config/Makefile.defs | 15 +- i/marvin/src/config/config_data.cc | 17 ++- i/marvin/src/config/config_data.hh | 9 -- i/marvin/src/config/config_data.tcc | 11 -- i/marvin/src/config/config_parser.cc | 142 ------------------ i/marvin/src/config/config_parser.hh | 77 ---------- i/marvin/src/config/lexer.ll | 118 --------------- i/marvin/src/config/parser.yy | 173 --------------------- i/marvin/src/config/test_config.cc | 48 ++++++ i/marvin/src/config/test_config_data.cc | 49 ------ i/marvin/src/parser/Makefile.defs | 14 ++ i/marvin/src/parser/parser.cc | 184 +++++++++++++++++++++++ i/marvin/src/parser/parser.hh | 87 +++++++++++ i/marvin/src/parser/test_parser.cc | 86 +++++++++++ i/marvin/src/parser/yylexer.ll | 120 +++++++++++++++ i/marvin/src/parser/yyparser.yy | 258 ++++++++++++++++++++++++++++++++ 17 files changed, 817 insertions(+), 592 deletions(-) delete mode 100644 i/marvin/src/config/config_parser.cc delete mode 100644 i/marvin/src/config/config_parser.hh delete mode 100644 i/marvin/src/config/lexer.ll delete mode 100644 i/marvin/src/config/parser.yy create mode 100644 i/marvin/src/config/test_config.cc delete mode 100644 i/marvin/src/config/test_config_data.cc create mode 100644 i/marvin/src/parser/Makefile.defs create mode 100644 i/marvin/src/parser/parser.cc create mode 100644 i/marvin/src/parser/parser.hh create mode 100644 i/marvin/src/parser/test_parser.cc create mode 100644 i/marvin/src/parser/yylexer.ll create mode 100644 i/marvin/src/parser/yyparser.yy (limited to 'i/marvin') diff --git a/i/marvin/src/Makefile.defs b/i/marvin/src/Makefile.defs index 0ad5bc1..cec8951 100644 --- a/i/marvin/src/Makefile.defs +++ b/i/marvin/src/Makefile.defs @@ -20,6 +20,7 @@ endif CXXFLAGS += -fmessage-length=0 SUBDIRS = utils utils/meta \ + parser \ interpreter config tester \ log serial timer \ data scheduler \ diff --git a/i/marvin/src/config/Makefile.defs b/i/marvin/src/config/Makefile.defs index 823c9ea..a06f2a7 100644 --- a/i/marvin/src/config/Makefile.defs +++ b/i/marvin/src/config/Makefile.defs @@ -1,14 +1,5 @@ -PROGRAMS += test_config_data +PROGRAMS += test_config -config_OBJECTS = lexer.o parser.o config_data.o config_parser.o config.o +config_OBJECTS = config_data.o config.o $(parser_OBJECTS) -test_config_data_OBJECTS = $(config_OBJECTS) test_config_data.o - -EXTRA_CLEAN += parser.hh parser.cc lexer.hh lexer.cc - -parser.hh: parser.cc -$(OBJ_DIR)/lexer.o: parser.hh - -lexer.hh: lexer.cc -$(OBJ_DIR)/parser.o: lexer.hh -$(OBJ_DIR)/config_parser.o: lexer.hh +test_config_OBJECTS = $(config_OBJECTS) test_config.o diff --git a/i/marvin/src/config/config_data.cc b/i/marvin/src/config/config_data.cc index 2642e74..b126082 100644 --- a/i/marvin/src/config/config_data.cc +++ b/i/marvin/src/config/config_data.cc @@ -24,7 +24,7 @@ // }}} #include "config.hh" #include "config_data.hh" -#include "config_parser.hh" +#include "parser/parser.hh" #include @@ -75,6 +75,21 @@ ConfigData::add (const std::string &id, any &val) a.swap (val); } +/// Classe dérivé de Parser pour le parsing de conf. +class ConfigParser : public Parser +{ + ConfigData &data_; + public: + /// Constructeur. + ConfigParser (ConfigData &data) : data_ (data) { } + /// 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) + { + data_.add (id, val); + } +}; + /// Initialise (lit la ligne de commande et les fichiers de config. void ConfigData::init (int &argc, char **&argv, const std::string &file) diff --git a/i/marvin/src/config/config_data.hh b/i/marvin/src/config/config_data.hh index 8c8bf1f..51caabd 100644 --- a/i/marvin/src/config/config_data.hh +++ b/i/marvin/src/config/config_data.hh @@ -58,18 +58,9 @@ class ConfigData /// Ajoute une valeur de configuration. VAL prend l'ancienne valeur ou un /// any vide. void add (const std::string &id, any &val); - /// Ajoute une valeur de configuration, fonction générique. Attention, - /// cette fonction est plus couteuse car elle fait une copie de - /// la valeur. - template - void add (const std::string &id, const T &val); private: /// Initialise (lit la ligne de commande et les fichiers de config. void init (int &argc, char **&argv, const std::string &file); - /// 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); }; #include "config_data.tcc" diff --git a/i/marvin/src/config/config_data.tcc b/i/marvin/src/config/config_data.tcc index 7e5b905..71fa6d6 100644 --- a/i/marvin/src/config/config_data.tcc +++ b/i/marvin/src/config/config_data.tcc @@ -57,14 +57,3 @@ ConfigData::get (const std::string &id, const T &defaut) const return *v; } -/// Ajoute une valeur de configuration, fonction générique. Attention, -/// cette fonction est plus couteuse car elle fait une copie de -/// la valeur. -template -void -ConfigData::add (const std::string &id, const T &val) -{ - any a (val); - add (id, a); -} - diff --git a/i/marvin/src/config/config_parser.cc b/i/marvin/src/config/config_parser.cc deleted file mode 100644 index ee0a6e3..0000000 --- a/i/marvin/src/config/config_parser.cc +++ /dev/null @@ -1,142 +0,0 @@ -// config_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 "config_parser.hh" -#include "config.hh" - -#include "parser.hh" -#include "lexer.hh" - -#include -#include - -int yyparse (void *); - -/// Constructeur. -ConfigParser::ConfigParser (ConfigData &configData) - : configData_ (configData) -{ -} - -/// Lance le parseur sur un fichier. -void -ConfigParser::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 (configData_, *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.errorValid_) - throw std::runtime_error (e.error_); - else - throw std::runtime_error ("parse error"); - } - } - catch (const std::runtime_error &e) - { - fclose (f); - throw std::runtime_error ("in file \"" + file + "\": " + e.what ()); - } - fclose (f); -} - -/// Lance le parseur sur une chaîne. -void -ConfigParser::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 (configData_, *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.errorValid_) - throw std::runtime_error (e.error_); - else - throw std::runtime_error ("parse error"); - } - } - catch (const std::runtime_error &e) - { - throw std::runtime_error ("in config string \"" + s + "\": " - + e.what ()); - } -} - -/// Constructeur pour initialiser les références. -ConfigParser::Extra::Extra (ConfigData &configData_, ConfigParser - &configParser_, bool useLine) - : configData (configData_), configParser (configParser_), - line (1), errorValid_ (false), useLine_ (useLine) -{ -} - -/// Recueille l'erreur de bison. -void -ConfigParser::Extra::error (const std::string &e) -{ - if (!errorValid_) - { - error_ = e; - errorValid_ = true; - if (useLine_) - { - std::stringstream os; - os << line; - error_ += ", line "; - error_ += os.str (); - } - } -} - -/* 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/marvin/src/config/config_parser.hh b/i/marvin/src/config/config_parser.hh deleted file mode 100644 index abbf214..0000000 --- a/i/marvin/src/config/config_parser.hh +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef config_parser_hh -#define config_parser_hh -// config_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 - -class ConfigData; - -/// Structure d'information passée au parser. -class ConfigParser -{ - public: - struct Extra - { - public: - /// Chaîne temporaire utilisée pendant l'analyse lexicale. - std::string tmp; - /// Référence vers le ConfigData qui doit recevoir la configuration. - ConfigData &configData; - /// Référence vers l'instance de ConfigParser. - ConfigParser &configParser; - /// Ligne courante. - int line; - private: - /// Permet de stocker l'erreur de bison. - std::string error_; - /// Indique si error est significatif. - bool errorValid_; - /// Utilise ou non le comptage de lignes. - bool useLine_; - public: - /// Constructeur pour initialiser les références. - Extra (ConfigData &configData_, ConfigParser &configParser_, - bool useLine); - /// Recueille l'erreur de bison. - void error (const std::string &e); - /// Accés réservé pour ConfigParser. - friend class ConfigParser; - }; - private: - /// Référence vers le ConfigData qui doit recevoir la configuration. - ConfigData &configData_; - public: - /// Constructeur. - ConfigParser (ConfigData &configData); - /// 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); -}; - -#define YY_EXTRA_TYPE ConfigParser::Extra * - -#endif // config_parser_hh diff --git a/i/marvin/src/config/lexer.ll b/i/marvin/src/config/lexer.ll deleted file mode 100644 index 34522dc..0000000 --- a/i/marvin/src/config/lexer.ll +++ /dev/null @@ -1,118 +0,0 @@ -%{ -// 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 "config/config.hh" -#include "config/config_parser.hh" -#include "utils/any.hh" -#include "parser.hh" -%} - -%option reentrant -%option header-file="lexer.hh" -%option outfile="lexer.cc" -%option bison-bridge -%option noyywrap nodefault nounput - -%x strst - -INTDEC [+-]?[0-9]+ -INTHEX "0x"[0-9a-fA-F]+ -INTNUM {INTDEC}|{INTHEX} -FLOAT1 [+-]?\.[0-9]+ -FLOAT2 [+-]?[0-9]+\.[0-9]* -FLOATNUM {FLOAT1}|{FLOAT2} - -%% - -"true"|"on" { - yylval->b = true; - return BOOLEAN; -} - -"false"|"off" { - yylval->b = false; - return BOOLEAN; -} - -[a-zA-Z][_a-zA-Z0-9.-]* { - yylval->s = new std::string (yytext); - return ID; -} - -{FLOATNUM} { - yylval->f = strtod (yytext, 0); - return FLOAT; -} - -{INTNUM} { - yylval->i = strtol (yytext, 0, 0); - return INT; -} - -\" { - BEGIN(strst); - yyextra->tmp.clear (); -} - -\n { - yyextra->line++; - return yytext[0]; -} - -[=()] return yytext[0]; - -[ \t]+ /* Skip. */ -#.* /* Skip comments. */ - -. { - yyextra->error (std::string ("unexpected character \'") \ - + yytext[0] + '\''); - return UNKNOWN; -} - -\" { - BEGIN (INITIAL); - yylval->s = new std::string (yyextra->tmp); - return STRING; -} - -\\n yyextra->tmp += '\n'; -\\r yyextra->tmp += '\r'; -\\t yyextra->tmp += '\t'; -\\. yyextra->tmp += yytext[1]; -\\\n { - yyextra->line++; - yyextra->tmp += yytext[1]; -} -. yyextra->tmp += yytext[0]; -\n { - yyextra->error ("unexpected end of line inside string"); - yyextra->line++; - return UNKNOWN; -} - -%% - -/* vim:ft=lex: -*/ diff --git a/i/marvin/src/config/parser.yy b/i/marvin/src/config/parser.yy deleted file mode 100644 index dc2be24..0000000 --- a/i/marvin/src/config/parser.yy +++ /dev/null @@ -1,173 +0,0 @@ -%{ -// 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 "config/config.hh" -#include "config/config_data.hh" -#include "config/config_parser.hh" - -// Fichiers d'en-tête générés. -#include "parser.hh" -#include "lexer.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 { - char c; - int i; - double f; - bool b; - std::string *s; - struct { - any *a; - Config::IntList *il; - Config::FloatList *fl; - Config::StringList *sl; - } a; -} - -%token UNKNOWN -%token INT -%token FLOAT -%token ID STRING -%token BOOLEAN - -%type int_list -%type float_list -%type string_list - -%destructor { delete $$; } ID STRING -%destructor { delete $$.a; } int_list -%destructor { delete $$.a; } float_list -%destructor { delete $$.a; } string_list - -%% - -input: - /* Nothing. */ - | confitem - | input '\n' confitem - | input '\n' -; - -confitem: - ID '=' BOOLEAN { - yyextra->configData.add (*$1, $3); - delete $1; - } - | ID '=' INT { - yyextra->configData.add (*$1, $3); - delete $1; - } - | ID '=' FLOAT { - yyextra->configData.add (*$1, $3); - delete $1; - } - | ID '=' STRING { - yyextra->configData.add (*$1, *$3); - delete $1; - delete $3; - } - | ID '=' '(' int_list ')' { - yyextra->configData.add (*$1, *$4.a); - delete $1; - delete $4.a; - } - | ID '=' '(' float_list ')' { - yyextra->configData.add (*$1, *$4.a); - delete $1; - delete $4.a; - } - | ID '=' '(' string_list ')' { - yyextra->configData.add (*$1, *$4.a); - delete $1; - delete $4.a; - } -; - -int_list: - INT { - $$.a = new any (Config::IntList ()); - $$.il = any_cast ($$.a); - $$.il->push_back ($1); - } - | int_list INT { - $1.il->push_back ($2); - $$ = $1; - } -; - -float_list: - FLOAT { - $$.a = new any (Config::FloatList ()); - $$.fl = any_cast ($$.a); - $$.fl->push_back ($1); - } - | float_list FLOAT { - $1.fl->push_back ($2); - $$ = $1; - } -; - -string_list: - STRING { - $$.a = new any (Config::StringList ()); - $$.sl = any_cast ($$.a); - $$.sl->push_back (*$1); - delete $1; - } - | string_list STRING { - $1.sl->push_back (*$2); - $$ = $1; - delete $2; - } -; - -%% - -/// 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: -*/ diff --git a/i/marvin/src/config/test_config.cc b/i/marvin/src/config/test_config.cc new file mode 100644 index 0000000..3b3e368 --- /dev/null +++ b/i/marvin/src/config/test_config.cc @@ -0,0 +1,48 @@ +// test_config.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 "config.hh" + +#include +#include + +int +main (int argc, char **argv) +{ + try + { + // Create manually the instance of the config class + Config c (argc, argv); + // Example for getting the unique instance + Config &ci = Config::getInstance (); + for (int i = 1; i < argc; ++i) + std::cout << ci.get (argv[i]) << std::endl; + } + catch (const std::exception &e) + { + std::cerr << e.what () << std::endl; + return 1; + } + return 0; +} diff --git a/i/marvin/src/config/test_config_data.cc b/i/marvin/src/config/test_config_data.cc deleted file mode 100644 index 5643ce1..0000000 --- a/i/marvin/src/config/test_config_data.cc +++ /dev/null @@ -1,49 +0,0 @@ -// test_config_data.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 "config.hh" - -#include -#include - -int -main (int argc, char **argv) -{ - try - { - // Create manually the instance of the config class - Config cd (argc, argv); - // Example for getting the unique instance - //Config &confInstance = Config::getInstance (); - - for (int i = 1; i < argc; ++i) - std::cout << cd.get (argv[i]) << std::endl; - } - catch (const std::exception &e) - { - std::cerr << e.what () << std::endl; - return 1; - } - return 0; -} diff --git a/i/marvin/src/parser/Makefile.defs b/i/marvin/src/parser/Makefile.defs new file mode 100644 index 0000000..61b4b97 --- /dev/null +++ b/i/marvin/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/marvin/src/parser/parser.cc b/i/marvin/src/parser/parser.cc new file mode 100644 index 0000000..0c5a39e --- /dev/null +++ b/i/marvin/src/parser/parser.cc @@ -0,0 +1,184 @@ +// 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 +#include + +int yyparse (void *); + +/// Constructeur. +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/marvin/src/parser/parser.hh b/i/marvin/src/parser/parser.hh new file mode 100644 index 0000000..c07d645 --- /dev/null +++ b/i/marvin/src/parser/parser.hh @@ -0,0 +1,87 @@ +#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 +#include + +/// 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 IntList; + typedef std::list DoubleList; + typedef std::list StringList; + typedef std::list 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); + /// 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/marvin/src/parser/test_parser.cc b/i/marvin/src/parser/test_parser.cc new file mode 100644 index 0000000..dedbd83 --- /dev/null +++ b/i/marvin/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 +#include + +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/marvin/src/parser/yylexer.ll b/i/marvin/src/parser/yylexer.ll new file mode 100644 index 0000000..34157b9 --- /dev/null +++ b/i/marvin/src/parser/yylexer.ll @@ -0,0 +1,120 @@ +%{ +// 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} +DOUBLE1 [+-]?\.[0-9]+ +DOUBLE2 [+-]?[0-9]+\.[0-9]* +DOUBLENUM {DOUBLE1}|{DOUBLE2} + +%% + +"true"|"on" { + yylval->b = true; + return BOOLEAN; +} + +"false"|"off" { + yylval->b = false; + return BOOLEAN; +} + +[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; +} + +\" { + BEGIN (INITIAL); + yylval->s = new std::string (yyextra->tmp); + return STRING; +} + +\\n yyextra->tmp += '\n'; +\\r yyextra->tmp += '\r'; +\\t yyextra->tmp += '\t'; +\\. yyextra->tmp += yytext[1]; +\\\n { + yyextra->line++; + yyextra->tmp += yytext[1]; +} +. yyextra->tmp += yytext[0]; +\n { + yyextra->error ("unexpected end of line inside string"); + yyextra->line++; + return UNKNOWN; +} + +%% + +/* vim:ft=lex: +*/ diff --git a/i/marvin/src/parser/yyparser.yy b/i/marvin/src/parser/yyparser.yy new file mode 100644 index 0000000..e965ffd --- /dev/null +++ b/i/marvin/src/parser/yyparser.yy @@ -0,0 +1,258 @@ +%{ +// 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 BOOLEAN +%token UNKNOWN +%token INT +%token DOUBLE +%token ID STRING + +%type int_list int_list_i +%type
double_list double_list_i +%type string_list string_list_i +%type 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 '=' 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 ($$.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 ($$.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 ($$.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); + } + | arg_list INT { + any a ($2); + $1->push_back (any ()); + $1->back ().swap (a); + } + | arg_list DOUBLE { + any a ($2); + $1->push_back (any ()); + $1->back ().swap (a); + } + | arg_list STRING { + any a (*$2); + $1->push_back (any ()); + $1->back ().swap (a); + delete $2; + } + | arg_list int_list { + $1->push_back (any ()); + $1->back ().swap (*$2.a); + delete $2.a; + } + | arg_list double_list { + $1->push_back (any ()); + $1->back ().swap (*$2.a); + delete $2.a; + } + | arg_list string_list { + $1->push_back (any ()); + $1->back ().swap (*$2.a); + delete $2.a; + } +; +%% + +/// 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: +*/ -- cgit v1.2.3