From 8f486613be58ced269db1d437e560c16558604e8 Mon Sep 17 00:00:00 2001 From: becquet Date: Thu, 10 May 2007 18:49:20 +0000 Subject: Création de chuck, le programme du robot 2007. --- i/chuck/src/parser/Makefile.defs | 14 ++ i/chuck/src/parser/parser.cc | 189 ++++++++++++++++++++++++++ i/chuck/src/parser/parser.hh | 89 ++++++++++++ i/chuck/src/parser/test_parser.cc | 86 ++++++++++++ i/chuck/src/parser/yylexer.ll | 148 ++++++++++++++++++++ i/chuck/src/parser/yyparser.yy | 278 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 804 insertions(+) create mode 100644 i/chuck/src/parser/Makefile.defs create mode 100644 i/chuck/src/parser/parser.cc create mode 100644 i/chuck/src/parser/parser.hh create mode 100644 i/chuck/src/parser/test_parser.cc create mode 100644 i/chuck/src/parser/yylexer.ll create mode 100644 i/chuck/src/parser/yyparser.yy (limited to 'i/chuck/src/parser') 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 +#include + +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 +#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); + /// 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 +#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/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; +} + +\" { + 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/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 BOOLEAN +%token UNKNOWN +%token CHAR +%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 '=' 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 ($$.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); + $$ = $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: +*/ -- cgit v1.2.3