# HG changeset patch # User Mario de Sousa # Date 1354027748 0 # Node ID 634f476cb60f04ba6d351959aae90691c6207be4 # Parent 7b90dd17f0ba7f4c6598086b4f6ca4a2dfc5e87e Insert the auto generated enum datatype conversion functions after the TYPE...END_TYPE, instead of at the end of input file. diff -r 7b90dd17f0ba -r 634f476cb60f stage1_2/create_enumtype_conversion_functions.cc --- a/stage1_2/create_enumtype_conversion_functions.cc Mon Nov 26 16:38:15 2012 +0000 +++ b/stage1_2/create_enumtype_conversion_functions.cc Tue Nov 27 14:49:08 2012 +0000 @@ -37,42 +37,48 @@ /* set to 1 to see debug info during execution */ static const int debug = 0; -/* - * functionDataType array contains all supported data type conversion. - */ -const char *create_enumtype_conversion_functions_c::functionDataType[] = { - "STRING", - "SINT" , - "INT" , - "DINT" , - "LINT" , - "USINT" , - "UINT" , - "UDINT" , - "ULINT" , - NULL -}; - -create_enumtype_conversion_functions_c::create_enumtype_conversion_functions_c(symbol_c *ignore) { - -} - -create_enumtype_conversion_functions_c::~create_enumtype_conversion_functions_c(void) { - -} - -std::string &create_enumtype_conversion_functions_c::get_declaration(symbol_c *root) { - text = ""; - if (NULL != root) { - root->accept(*this); - } - - return text; -} + +/* + * The create_enumtype_conversion_functions_c class generates ST source code! + * This code is in actual fact datatype conversion functions between user defined + * enumerated datatypes, and some basic datatypes. + * + * These conversion functions cannot be implemented the normal way (i.e. in the standard library) + * since they convert from/to a datatype that is defined by the user. So, we generate these conversions + * functions on the fly! + * (to get an idea of what the generated code looks like, see the comments in create_enumtype_conversion_functions.cc) + * + * Currently, we support conversion between the user defined enumerated datatype and STRING, + * SINT, INT, DINT, LINT, USINT, UINT, UDINT, ULINT (basically the ANY_INT) + * + * ST source code is generated when the method get_declaration() is called. since the + * create_enumtype_conversion_functions_c inherits from the iterator visitor, this method may be + * passed either the root of an abstract syntax tree, or sub-tree of the AST. + * + * This class will iterate through that AST, and for each enumerated type declaration, will + * create the apropriate conversion functions. + */ + +create_enumtype_conversion_functions_c *create_enumtype_conversion_functions_c::singleton = NULL; + +create_enumtype_conversion_functions_c:: create_enumtype_conversion_functions_c(symbol_c *ignore) {} +create_enumtype_conversion_functions_c::~create_enumtype_conversion_functions_c(void) {} + + +std::string &create_enumtype_conversion_functions_c::get_declaration(symbol_c *symbol) { + if (NULL == singleton) singleton = new create_enumtype_conversion_functions_c(NULL); + if (NULL == singleton) ERROR_MSG("Out of memory. Bailing out!\n"); + + singleton->text = ""; + if (NULL != symbol) + symbol->accept(*singleton); + + return singleton->text; +} + void *create_enumtype_conversion_functions_c::visit(identifier_c *symbol) { currentToken = symbol->value; - return NULL; } diff -r 7b90dd17f0ba -r 634f476cb60f stage1_2/create_enumtype_conversion_functions.hh --- a/stage1_2/create_enumtype_conversion_functions.hh Mon Nov 26 16:38:15 2012 +0000 +++ b/stage1_2/create_enumtype_conversion_functions.hh Tue Nov 27 14:49:08 2012 +0000 @@ -47,12 +47,13 @@ class create_enumtype_conversion_functions_c: public iterator_visitor_c { + private: + static create_enumtype_conversion_functions_c *singleton; + public: explicit create_enumtype_conversion_functions_c(symbol_c *ignore); virtual ~create_enumtype_conversion_functions_c(void); - std::string &get_declaration(symbol_c *root); - - const static char *functionDataType []; + static std::string &get_declaration(symbol_c *symbol); void *visit(identifier_c *symbol); /**********************/ diff -r 7b90dd17f0ba -r 634f476cb60f stage1_2/iec_bison.yy --- a/stage1_2/iec_bison.yy Mon Nov 26 16:38:15 2012 +0000 +++ b/stage1_2/iec_bison.yy Tue Nov 27 14:49:08 2012 +0000 @@ -237,10 +237,7 @@ int last_column, const char *last_filename, long int last_order, - const char *additional_error_msg); - -/* Create entry in symbol table for function conversion data type*/ -void add_enumtype_conversion_functions(const char * dname); + const char *additional_error_msg); %} @@ -2509,7 +2506,7 @@ data_type_declaration: TYPE type_declaration_list END_TYPE - {$$ = new data_type_declaration_c($2, locloc(@$));} + {$$ = new data_type_declaration_c($2, locloc(@$)); include_string((create_enumtype_conversion_functions_c::get_declaration($$)).c_str());} /* ERROR_CHECK_BEGIN */ | TYPE END_TYPE {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no data type declared in data type(s) declaration."); yynerrs++;} @@ -2712,13 +2709,7 @@ * and include the library_element_symtable.insert(...) code in the rule actions! */ identifier ':' enumerated_specification {library_element_symtable.insert($1, prev_declared_enumerated_type_name_token);} - { - $$ = new enumerated_type_declaration_c($1, new enumerated_spec_init_c($3, NULL, locloc(@3)), locloc(@$)); - if (conversion_functions_) { - const char *name = ((identifier_c *)$1)->value; - add_enumtype_conversion_functions(name); - } - } + {$$ = new enumerated_type_declaration_c($1, new enumerated_spec_init_c($3, NULL, locloc(@3)), locloc(@$));} | identifier ':' enumerated_specification {library_element_symtable.insert($1, prev_declared_enumerated_type_name_token);} ASSIGN enumerated_value {$$ = new enumerated_type_declaration_c($1, new enumerated_spec_init_c($3, $6, locf(@3), locl(@6)), locloc(@$));} /* ERROR_CHECK_BEGIN */ @@ -8338,8 +8329,8 @@ {int res; if ((res = yyparse()) != 0) { fprintf (stderr, "\nParsing failed because of too many consecutive syntax errors. Bailing out!\n"); - exit(EXIT_FAILURE); - } + exit(EXIT_FAILURE); + } } if (yynerrs > 0) { @@ -8354,84 +8345,16 @@ return 0; } -/* Create a tmp file from a char buffer. */ -FILE *ftmpopen (void *buf, size_t size, const char *opentype) -{ - FILE *f; - f = tmpfile(); - fwrite(buf, 1, size, f); - rewind(f); - return f; -} - -/* sstage2__ function allow to parse a ST code inside a string. - * We use this function to add into AST auto generated code like enum conversion functions. - * This appoach allow us to write future changes code indipendetly and to check generate code - * during developing. - */ -int sstage2__(const char *text, - symbol_c **tree_root_ref, - bool full_token_loc_ /* error messages specify full token location */ - ) { - - FILE *in_file = NULL; - - if((in_file = ftmpopen((void *)text, strlen(text), "r")) == NULL) { - perror("Error creating temp file."); - return -1; - } - - /* now parse the input file... */ - #if YYDEBUG - yydebug = 1; - #endif - yyin = in_file; - - /* We turn on "allow_function_overloading" flag to disable some checks. - * In detail when we add to symboltable a symbol already processed we - * don't want to get any error. - */ - - allow_function_overloading = true; - allow_extensible_function_parameters = false; - full_token_loc = full_token_loc_; - current_filename = "built-in"; - current_tracking = GetNewTracking(yyin); - {int res; - if ((res = yyparse()) != 0) { - fprintf (stderr, "\nParsing failed because of too many consecutive syntax errors. Bailing out!\n"); - exit(EXIT_FAILURE); - } - } - - if (yynerrs > 0) { - fprintf (stderr, "\n%d error(s) found. Bailing out!\n", yynerrs /* global variable */); - exit(EXIT_FAILURE); - } - - if (tree_root_ref != NULL) - *tree_root_ref = tree_root; - - fclose(in_file); - return 0; -} - - -/* Create entry in symbol table for function conversion data type*/ -void add_enumtype_conversion_functions(const char * dname) { - std::string strname; - std::string tmp; - - strname = dname; - for (int i = 0; create_enumtype_conversion_functions_c::functionDataType[i] != NULL; i++) { - tmp = strname + std::string("_TO_") + create_enumtype_conversion_functions_c::functionDataType[i]; - library_element_symtable.insert(tmp.c_str(), prev_declared_derived_function_name_token); - - tmp = create_enumtype_conversion_functions_c::functionDataType[i] + std::string("_TO_") + strname; - library_element_symtable.insert(tmp.c_str(), prev_declared_derived_function_name_token); - } -} - - - - + + + + + + + + + + + + + diff -r 7b90dd17f0ba -r 634f476cb60f stage1_2/iec_flex.ll --- a/stage1_2/iec_flex.ll Mon Nov 26 16:38:15 2012 +0000 +++ b/stage1_2/iec_flex.ll Tue Nov 27 14:49:08 2012 +0000 @@ -247,6 +247,8 @@ * but first return to the stream an additional character to mark the end of the token. */ void unput_and_mark(const char c); + +void include_file(const char *include_filename); %} @@ -867,38 +869,8 @@ {file_include_pragma_beg} BEGIN(include_filename); {file_include_pragma_filename} { - /* got the include file name */ - int i; - - if (include_stack_ptr >= MAX_INCLUDE_DEPTH) { - fprintf(stderr, "Includes nested too deeply\n"); - exit( 1 ); - } - include_stack[include_stack_ptr].buffer_state = YY_CURRENT_BUFFER; - include_stack[include_stack_ptr].env = current_tracking; - include_stack[include_stack_ptr].filename = current_filename; - - for (i = 0, yyin = NULL; (INCLUDE_DIRECTORIES[i] != NULL) && (yyin == NULL); i++) { - char *full_name = strdup3(INCLUDE_DIRECTORIES[i], "/", yytext); - if (full_name == NULL) { - fprintf(stderr, "Out of memory!\n"); - exit( 1 ); - } - yyin = fopen(full_name, "r"); - free(full_name); - } - - if (!yyin) { - fprintf(stderr, "Error opening included file %s\n", yytext); - exit( 1 ); - } - - current_filename = strdup(yytext); - current_tracking = GetNewTracking(yyin); - include_stack_ptr++; - - /* switch input buffer to new file... */ - yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); + /* set the internal state variables of lexical analyser to process a new include file */ + include_file(yytext); /* switch to whatever state was active before the include file */ yy_pop_state(); /* now process the new file... */ @@ -947,6 +919,8 @@ } {file_include_pragma_end} yy_pop_state(); + /* handle the artificial file includes created by include_string(), which do not end with a '}' */ +. unput_text(0); yy_pop_state(); /*********************************/ @@ -1690,6 +1664,79 @@ } + +/* set the internal state variables of lexical analyser to process a new include file */ +void handle_include_file_(FILE *filehandle, const char *filename) { + if (include_stack_ptr >= MAX_INCLUDE_DEPTH) { + fprintf(stderr, "Includes nested too deeply\n"); + exit( 1 ); + } + + yyin = filehandle; + + include_stack[include_stack_ptr].buffer_state = YY_CURRENT_BUFFER; + include_stack[include_stack_ptr].env = current_tracking; + include_stack[include_stack_ptr].filename = current_filename; + + current_filename = strdup(filename); + current_tracking = GetNewTracking(yyin); + include_stack_ptr++; + + /* switch input buffer to new file... */ + yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); +} + + + +/* insert the code (in ) into the source code we are parsing. + * This is done by creating an artificial file with that new source code, and then 'including' the file + */ +void include_string(const char *source_code) { + FILE *tmp_file = tmpfile(); + + if(tmp_file == NULL) { + perror("Error creating temp file."); + exit(EXIT_FAILURE); + } + + fwrite((void *)source_code, 1, strlen(source_code), tmp_file); + rewind(tmp_file); + + /* now parse the tmp file, by asking flex to handle it as if it had been included with the (*#include ... *) pragma... */ + handle_include_file_(tmp_file, ""); +//fclose(tmp_file); /* do NOT close file. It must only be closed when we finish reading from it! */ +} + + + +/* Open an include file, and set the internal state variables of lexical analyser to process a new include file */ +void include_file(const char *filename) { + FILE *filehandle = NULL; + + for (int i = 0; (INCLUDE_DIRECTORIES[i] != NULL) && (filehandle == NULL); i++) { + char *full_name; + full_name = strdup3(INCLUDE_DIRECTORIES[i], "/", filename); + if (full_name == NULL) { + fprintf(stderr, "Out of memory!\n"); + exit( 1 ); + } + filehandle = fopen(full_name, "r"); + free(full_name); + } + + if (NULL == filehandle) { + fprintf(stderr, "Error opening included file %s\n", filename); + exit( 1 ); + } + + /* now process the new file... */ + handle_include_file_(filehandle, filename); +} + + + + + /* return all the text in the current token back to the input stream, except the first n chars. */ void unput_text(unsigned int n) { /* it seems that flex has a bug in that it will not correctly count the line numbers diff -r 7b90dd17f0ba -r 634f476cb60f stage1_2/stage1_2.cc --- a/stage1_2/stage1_2.cc Mon Nov 26 16:38:15 2012 +0000 +++ b/stage1_2/stage1_2.cc Tue Nov 27 14:49:08 2012 +0000 @@ -292,11 +292,6 @@ bool full_token_loc /* error messages specify full token location */ ); -int sstage2__(const char *text, - symbol_c **tree_root_ref, - bool full_token_loc /* error messages specify full token location */ - ); - int stage1_2(const char *filename, symbol_c **tree_root_ref, stage1_2_options_t options) { /* NOTE: we only call stage2 (bison - syntax analysis) directly, as stage 2 will itself call stage1 (flex - lexical analysis) @@ -312,13 +307,6 @@ safe_extensions_ = options.safe_extensions; conversion_functions_ = options.conversion_functions; - int ret = stage2__(filename, options.includedir, tree_root_ref, options.full_token_loc); - - if (conversion_functions_) { - create_enumtype_conversion_functions_c create_enumtype_conversion_functions_c(*tree_root_ref); - std::string source_code = create_enumtype_conversion_functions_c.get_declaration(*tree_root_ref); - ret = sstage2__(source_code.c_str(), tree_root_ref, false); - } - return ret; -} - + return stage2__(filename, options.includedir, tree_root_ref, options.full_token_loc); +} + diff -r 7b90dd17f0ba -r 634f476cb60f stage1_2/stage1_2_priv.hh --- a/stage1_2/stage1_2_priv.hh Mon Nov 26 16:38:15 2012 +0000 +++ b/stage1_2/stage1_2_priv.hh Tue Nov 27 14:49:08 2012 +0000 @@ -105,6 +105,18 @@ /* This is a service that flex provides to bison... */ void print_include_stack(void); +/*****************************************************/ +/* Ask flex to include the source code in the string */ +/*****************************************************/ +/* This is a service that flex provides to bison... */ +/* The string should contain valid IEC 61131-3 source code. Bison will ask flex to insert source + * code into the input stream of IEC code being parsed. The code to be inserted is typically + * generated automatically. + * Currently this is used to insert conversion functions ***_TO_*** (as defined by the standard) + * between user defined (i.e. derived) enumerated datatypes, and some basic datatypes + * (e.g. INT, STRING, etc...) + */ +void include_string(const char *source_code); /**************************************/ /* The name of the file being parsed. */