diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index be08dcbbb1aac8a2f1f6a043470af52e55030cc8..3279187dab352f9ebe3655c643e587e2145dfb71 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,10 +1,15 @@ +ADD_SUBDIRECTORY(parser) # locate the necessary dependencies # add the necessary include directories -INCLUDE_DIRECTORIES(.) +INCLUDE_DIRECTORIES(. ./parser) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/parser) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) # application source files -SET(sources bioloid_motion_pages.cpp) +SET(sources bioloid_motion_pages.cpp ${motion_parser_SRCS}) # application header files SET(headers bioloid_motion_pages.h) # create the executable file ADD_EXECUTABLE(bioloid_motion_pages ${sources}) +TARGET_LINK_LIBRARIES(bioloid_motion_pages motion_parser) # link necessary libraries +ADD_DEPENDENCIES(bioloid_motion_pages motion_parser) diff --git a/src/bioloid_motion_pages.cpp b/src/bioloid_motion_pages.cpp index 8f611b2f67a4cfcca3a3c3facb01f29f493c8533..85265b8f36e013f8a4d388ad603cbe41e49cde31 100755 --- a/src/bioloid_motion_pages.cpp +++ b/src/bioloid_motion_pages.cpp @@ -1,5 +1,15 @@ -int main(int argc,char *argv[]) -{ +#include <iostream> +#include <cstdlib> + +#include "mc_driver.hpp" +int main(const int argc,char *argv[]) +{ + if(argc!=2) + return (EXIT_FAILURE); + MC::MC_Driver driver; + driver.parse(argv[1]); + return(EXIT_SUCCESS); } + diff --git a/src/parser/CMakeLists.txt b/src/parser/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..3accc88df5755a92769747e7c501bc475d4e8bc9 --- /dev/null +++ b/src/parser/CMakeLists.txt @@ -0,0 +1,31 @@ +# Create target for the parser +FIND_PACKAGE(BISON REQUIRED) +FIND_PACKAGE(FLEX REQUIRED) + +SET(BisonOutput motion_parser.cpp) +IF(BISON_FOUND) + ADD_CUSTOM_COMMAND( + OUTPUT ${BisonOutput} + COMMAND ${BISON_EXECUTABLE} + --output=${BisonOutput} + ${CMAKE_CURRENT_SOURCE_DIR}/motion_file.y + COMMENT "Generating motion_parser.cpp" + ) +ENDIF() + +FIND_PACKAGE(FLEX REQUIRED) +SET(FlexOutput motion_scanner.cpp) +IF(FLEX_FOUND) + ADD_CUSTOM_COMMAND( + OUTPUT ${FlexOutput} + COMMAND ${FLEX_EXECUTABLE} + --outfile=${FlexOutput} + ${CMAKE_CURRENT_SOURCE_DIR}/motion_file.l + COMMENT "Generating motion_scanner.cpp" + ) +ENDIF() + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) +add_library(motion_parser SHARED ${BisonOutput} ${FlexOutput} mc_driver.cpp) + diff --git a/src/parser/Makefile b/src/parser/Makefile index fa61c49cd6fb095a64808bcf97e8037c60995b46..4d8ea2f8b00651a13747b329880a0b48472d4312 100644 --- a/src/parser/Makefile +++ b/src/parser/Makefile @@ -1,19 +1,46 @@ -LEXOR = motion_file -PARSER = motion_file +CC ?= clang +CXX ?= clang++ -all: $(PARSER) +EXE = motion_file_parser -$(PARSER): $(PARSER).tab.c $(LEXOR).yy.c - gcc -o $(PARSER) $(PARSER).tab.c $(LEXOR).yy.c -ly -ll -lm - -$(PARSER).tab.c: $(PARSER).y - bison -vd $(PARSER).y +CDEBUG = -g -Wall -$(LEXOR).yy.c: $(LEXOR).l - flex -o $(LEXOR).yy.c $(LEXOR).l - +CXXDEBUG = -g -Wall + +CSTD = -std=c99 + +CFLAGS = -O0 $(CDEBUG) $(CSTD) +CXXFLAGS = -O0 $(CXXDEBUG) + +CPPOBJ = main mc_driver +SOBJ = parser lexer + +FILES = $(addsuffix .cpp, $(CPPOBJ)) + +OBJS = $(addsuffix .o, $(CPPOBJ)) + +CLEANLIST = $(addsuffix .o, $(OBJ)) $(OBJS) \ +motion_file.tab.c motion_file.tab.h \ +location.hh position.hh \ +stack.hh mc_parser.output parser.o \ +lexer.o mc_lexer.yy.cc $(EXE)\ + +.PHONY: all +all: motion_file_parser + +motion_file_parser: $(FILES) + $(MAKE) $(SOBJ) + $(MAKE) $(OBJS) + $(CXX) $(CXXFLAGS) -o $(EXE) $(OBJS) parser.o lexer.o $(LIBS) + +parser: motion_file.y + bison -d -v motion_file.y + $(CXX) $(CXXFLAGS) -c -o parser.o motion_file.tab.c + +lexer: motion_file.l + flex --outfile=motion_file.yy.cc $< + $(CXX) $(CXXFLAGS) -c motion_file.yy.cc -o lexer.o + +.PHONY: clean clean: - rm -f $(LEXOR).yy.c - rm -f $(PARSER).output - rm -f $(PARSER).tab.* - rm -f $(PARSER) + rm -rf $(CLEANLIST) diff --git a/src/parser/mc_driver.cpp b/src/parser/mc_driver.cpp new file mode 100644 index 0000000000000000000000000000000000000000..64fb3665f32109c8650f3ed70d5ee6a7d1393789 --- /dev/null +++ b/src/parser/mc_driver.cpp @@ -0,0 +1,55 @@ +#include <cctype> +#include <fstream> +#include <cassert> + +#include "mc_driver.hpp" + +MC::MC_Driver::MC_Driver() +{ + this->scanner=NULL; + this->parser=NULL; +} + +MC::MC_Driver::~MC_Driver() +{ + if(this->scanner!=NULL) + { + delete this->scanner; + this->scanner=NULL; + } + if(this->parser!=NULL) + { + delete this->parser; + this->parser=NULL; + } +} + +void MC::MC_Driver::parse(const char *filename) +{ + std::ifstream in_file(filename); + if(!in_file.good()) + exit( EXIT_FAILURE ); + if(this->scanner!=NULL) + delete this->scanner; + try + { + scanner=new MC::MC_Scanner(&in_file); + }catch(std::bad_alloc &ba){ + std::cerr << "Failed to allocate scanner: (" << ba.what() << "), exiting!!\n"; + exit( EXIT_FAILURE ); + } + if(this->parser!=NULL) + delete this->parser; + try + { + parser = new MC::MC_Parser((*scanner),(*this)); + }catch(std::bad_alloc &ba){ + std::cerr << "Failed to allocate parser: (" << ba.what() << "), exiting!!\n"; + exit( EXIT_FAILURE ); + } + const int accept(0); + if(parser->parse()!=accept) + { + std::cerr << "Parse failed!!\n"; + } +} diff --git a/src/parser/mc_driver.hpp b/src/parser/mc_driver.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8fbe4991287aefb4f05cc7da27673d24a3fbfccd --- /dev/null +++ b/src/parser/mc_driver.hpp @@ -0,0 +1,21 @@ +#ifndef _MC_DRIVER_HPP +#define _MC_DRIVER_HPP + +#include <string> +#include "mc_scanner.hpp" + +namespace MC +{ + class MC_Driver + { + public: + MC_Driver(); + void parse(const char *filename); + virtual ~MC_Driver(); + + private: + MC::MC_Parser *parser; + MC::MC_Scanner *scanner; + }; +} +#endif diff --git a/src/parser/mc_scanner.hpp b/src/parser/mc_scanner.hpp new file mode 100644 index 0000000000000000000000000000000000000000..11adceafd6fd74f74bc503facc51cdab0b337fd4 --- /dev/null +++ b/src/parser/mc_scanner.hpp @@ -0,0 +1,35 @@ +#ifndef _MC_SCANNER_HPP +#define _MC_SCANNER_HPP + +#if !defined(yyFlexLexerOnce) +#include <FlexLexer.h> +#endif + +#undef YY_DECL +#define YY_DECL int MC::MC_Scanner::yylex() + +#include "motion_parser.hpp" + +namespace MC +{ + class MC_Scanner : public yyFlexLexer + { + public: + MC_Scanner(std::istream *in) : yyFlexLexer(in), yylval( NULL ) + { + }; + int yylex(MC::MC_Parser::semantic_type *lval) + { + yylval = lval; + return( yylex() ); + } + + private: + /* hide this one from public view */ + int yylex(); + /* yyval ptr */ + MC::MC_Parser::semantic_type *yylval; + }; +} /* end namespace MC */ + +#endif diff --git a/src/parser/motion_file.l b/src/parser/motion_file.l index a1c1447f5aff45451263d6aedd096fa9b43ab028..b8ee93e9174b4bc73103d386eb456cddfa409448 100644 --- a/src/parser/motion_file.l +++ b/src/parser/motion_file.l @@ -1,33 +1,37 @@ %{ -#include "motion_file.tab.h" -/* Here we recoginze the various letters that are part of your language. -*/ -void yyerror(char *s) -{ - printf("Parse error: %s\n",s); - // might as well halt now: - exit(-1); -} +/* Implementation of yyFlexScanner */ +#include "mc_scanner.hpp" +#include "motion_parser.hpp" + +/* typedef to make the returns for the tokens shorter */ +typedef MC::MC_Parser::token token; + %} + +%option debug +%option nodefault +%option yyclass="MC_Scanner" +%option noyywrap +%option c++ +%option yylineno + %% -[ \t] ; -type { return TYPE; } -version { return VERSION; } -enable { return ENABLE; } -motor_type { return MOTOR_TYPE; } -page_begin { return BEGIN_PAGE; } -name { return NAME; } -compliance { return COMPLIANCE; } -play_param { return PLAY_PARAMS; } -step { return STEP; } -page_end { return END_PAGE; } -= { return EQUAL; } -[0-9]+\.[0-9]+ { yylval.fval=atof(yytext); return FLOAT; } -[0-9]+ { yylval.ival=atoi(yytext); return INT; } -[a-zA-Z0-9]+ { char *res=(char *)malloc(strlen(yytext)+1); - strcpy(res,yytext); - yylval.sval=res; - return STRING; } -. ; +[ \t\n] ; +"type" { return token::TYPE; } +"version" { return token::VERSION; } +"enable" { return token::ENABLE; } +"motor_type" { return token::MOTOR_TYPE; } +"page_begin" { return token::BEGIN_PAGE; } +"name" { return token::NAME; } +"compliance" { return token::COMPLIANCE; } +"play_param" { return token::PLAY_PARAMS; } +"step" { return token::STEP; } +"page_end" { return token::END_PAGE; } +"=" { return token::EQUAL; } +[0-9]+"."[0-9]+ { yylval->fval=atof(yytext); return token::FLOAT; } +[0-9]+ { yylval->ival=atoi(yytext); return token::INT; } +[a-zA-Z0-9]+|_ { yylval->sval=new std::string(yytext); + return token::STRING; } +. { printf("bad input character '%s' at line %d\n", yytext, yylineno); } %% diff --git a/src/parser/motion_file.y b/src/parser/motion_file.y index 0b56369335083b7f5e090b8a01db32210ebfd1f4..3bbfdff994e61d1ae1a43f748798fd3102365d78 100644 --- a/src/parser/motion_file.y +++ b/src/parser/motion_file.y @@ -1,120 +1,131 @@ -%{ -#include <stdio.h> - -int num_servos=0; -int num_pages=0; -int num_steps=0; -%} -%token TYPE VERSION ENABLE MOTOR_TYPE BEGIN_PAGE END_PAGE -%token NAME COMPLIANCE PLAY_PARAMS STEP -%token EQUAL - +%skeleton "lalr1.cc" +%require "2.5" +%debug +%defines +%define namespace "MC" +%define parser_class_name "MC_Parser" + +%code requires +{ + namespace MC + { + class MC_Driver; + class MC_Scanner; + } +} + +%lex-param { MC_Scanner &scanner } +%parse-param { MC_Scanner &scanner } + +%lex-param { MC_Driver &driver } +%parse-param { MC_Driver &driver } + +%code +{ + #include <iostream> + #include <cstdlib> + #include <fstream> + /* include for all driver functions */ + #include "mc_driver.hpp" + /* this is silly, but I can't figure out a way around */ + static int yylex(MC::MC_Parser::semantic_type *yylval,MC::MC_Scanner &scanner,MC::MC_Driver &driver); +} + +/* token types */ %union { int ival; float fval; - char *sval; + std::string *sval; } +%token TYPE VERSION ENABLE MOTOR_TYPE BEGIN_PAGE END_PAGE +%token NAME COMPLIANCE PLAY_PARAMS STEP +%token EQUAL %token <ival> INT %token <fval> FLOAT %token <sval> STRING + +/* destructor rule for <sval> objects */ +%destructor { if ($$) { delete ($$); ($$) = NULL; } } <sval> + %% -motion_file: type version enables motor_types pages { printf("Processed %d pages\n",num_pages); } +motion_file: type version enables motor_types pages ; -type: TYPE EQUAL STRING { printf("Type: %s\n",$3); } +type: TYPE EQUAL STRING { std::cout << "Type: " << *($3) << std::endl; } ; -version: VERSION EQUAL FLOAT { printf("version: %f\n",$3); } +version: VERSION EQUAL FLOAT { std::cout << "version: " << $3 << std::endl; } ; -enables: ENABLE EQUAL enable { printf("num servos (enable): %d\n",num_servos); - num_servos=0; } +enables: ENABLE EQUAL enable ; -enable: enable INT { num_servos++; } - | INT { num_servos++; } +enable: enable INT + | INT ; motor_types: - | MOTOR_TYPE EQUAL motor_type { printf("num servos (motor_type): %d\n",num_servos); - num_servos=0; } + | MOTOR_TYPE EQUAL motor_type ; -motor_type: motor_type INT { num_servos++; } - | INT { num_servos++; } +motor_type: motor_type INT + | INT ; -pages: pages page { num_pages++; } - | page { num_pages++; } +pages: pages page + | page ; -page: BEGIN_PAGE name compliances params steps END_PAGE { printf("page %d num steps %d\n",num_pages,num_steps); - num_steps=0; - num_servos=0; } - | BEGIN_PAGE name compliances params END_PAGE { printf("page %d with no steps\n",num_pages); - num_steps=0; - num_servos=0; } +page: BEGIN_PAGE name compliances params steps END_PAGE + | BEGIN_PAGE name compliances params END_PAGE ; -name: NAME EQUAL { printf("page %d has no name\n",num_pages); } - | NAME EQUAL strings { printf("page %d name:\n", num_pages); } +name: NAME EQUAL + | NAME EQUAL strings ; strings: strings STRING | STRING ; -compliances: COMPLIANCE EQUAL compliance { printf("page %d num servos (compliance): %d\n",num_pages,num_servos); - num_servos++; } +compliances: COMPLIANCE EQUAL compliance ; -compliance: compliance INT { num_servos++; } - | INT { num_servos++; } +compliance: compliance INT + | INT ; -params: PLAY_PARAMS EQUAL INT INT INT FLOAT INT { printf("page %d next motion: %d\n",num_pages,$3); - printf("page %d exit motion: %d\n",num_pages,$4); - printf("page %d repetitions: %d\n",num_pages,$5); - printf("page %d speed rate: %f\n",num_pages,$6); - printf("page %d inertial force: %d\n",num_pages,$7); } +params: PLAY_PARAMS EQUAL INT INT INT FLOAT INT { std::cout << "next motion: " << $3 << std::endl; + std::cout << "exit motion: " << $4 << std::endl; + std::cout << "repetitions: " << $5 << std::endl; + std::cout << "speed rate: " << $6 << std::endl; + std::cout << "inertial force: " << $7 << std::endl; } ; -steps: steps step { num_steps++; } - | step { num_steps++; } +steps: steps step + | step ; -step: STEP EQUAL angles FLOAT FLOAT { printf("page %d step %d pause time: %f\n",num_pages,num_steps,$4); - printf("page %d step %d step time: %f\n",num_pages,num_steps,$5); } +step: STEP EQUAL angles FLOAT FLOAT { std::cout << "pause time: " << $4 << std::endl; + std::cout << "step time: " << $5 << std::endl; } ; angles: angles INT | INT ; %% -extern FILE *yyin; - -int main(int argc, char *argv[]) +void +MC::MC_Parser::error(const MC::MC_Parser::location_type &l,const std::string &err_message ) { - FILE *file; - - printf("parsing example.\n"); - if(argc!=2) - { - printf("A motion file mist be provided as an argument.\n"); - return -1; - } - file=fopen(argv[1],"r"); - if(file==NULL) - { - printf("Impossible to open the file %s\n",argv[1]); - return -1; - } - yyin=file; - do { - yyparse (); - }while(!feof(yyin)); - return 0; + std::cerr << "Error: " << err_message << "\n"; } + +/* include for access to scanner.yylex */ +#include "mc_scanner.hpp" +static int yylex( MC::MC_Parser::semantic_type *yylval,MC::MC_Scanner &scanner,MC::MC_Driver &driver ) +{ + return( scanner.yylex(yylval) ); +}