# HG changeset patch # User Mario de Sousa # Date 1333226797 -3600 # Node ID 0bb88139e4716e92bb9b42bcfe6cdd5075f9295c # Parent 58d0c3b3c53b74acf4e6aa48a8a9ffab0b597e74# Parent 34a5571c859c704f158fdf2ca9213a2dd01c2a47 merging with Lauren't changeset. diff -r 34a5571c859c -r 0bb88139e471 absyntax/absyntax.cc --- a/absyntax/absyntax.cc Thu Mar 22 00:22:48 2012 +0100 +++ b/absyntax/absyntax.cc Sat Mar 31 21:46:37 2012 +0100 @@ -61,6 +61,7 @@ this->last_line = last_line; this->last_column = last_column; this->last_order = last_order; + this->datatype = NULL; } @@ -130,18 +131,27 @@ /* To insert into the begining of list, call with pos=0 */ /* To insert into the end of list, call with pos=list->n */ void list_c::insert_element(symbol_c *elem, int pos) { - int i; if (pos > n) ERROR; /* add new element to end of list. Basically alocate required memory... */ /* will also increment n by 1 ! */ add_element(elem); /* if not inserting into end position, shift all elements up one position, to open up a slot in pos for new element */ - if (pos < (n-1)) for (i = n-2; i >= pos; i--) elements[i+1] = elements[i]; + if (pos < (n-1)) for (int i = n-2; i >= pos; i--) elements[i+1] = elements[i]; elements[pos] = elem; } +/* remove element at position pos. */ +void list_c::remove_element(int pos) { + if (pos > n) ERROR; + + /* Shift all elements down one position, starting at the entry to delete. */ + for (int i = pos; i < n-1; i++) elements[i] = elements[i+1]; + /* corrent the new size, and free unused memory */ + n--; + elements = (symbol_c **)realloc(elements, n * sizeof(symbol_c *)); +} #define SYM_LIST(class_name_c, ...) \ class_name_c::class_name_c( \ diff -r 34a5571c859c -r 0bb88139e471 absyntax/absyntax.def --- a/absyntax/absyntax.def Thu Mar 22 00:22:48 2012 +0100 +++ b/absyntax/absyntax.def Sat Mar 31 21:46:37 2012 +0100 @@ -97,6 +97,12 @@ SYM_REF0(eno_param_c) */ +/* A class used to identify an entry (literal, variable, etc...) in the abstract syntax tree with an invalid data type */ +/* This is only used from stage3 onwards. Stages 1 and 2 will never create any instances of invalid_type_name_c */ +SYM_REF0(invalid_type_name_c) + + + /********************/ /* 2.1.6 - Pragmas */ /********************/ @@ -158,34 +164,15 @@ * OR * neg_literal_c -> real_literal_c * - * In the semantic verification and code generation stages of the compiler, - * the integer_c is treated as a basic (undefined) data type, since an integer - * constant may be used as a BYTE, BOOLEAN, REAL, etc..., depending on the - * context in which it is used. - * However, an integer_c that is preceded by a '-' may not be used - * as an ANY_BIT data type (BYTE, BOOLEAN, WORD, ...). - * We must therefore be able to determine, holding a simple pointer - * to an integer_c, if that integer_c value is preceded by a '-'. - * However, since the neg_literal_c points to the integer_c, and not - * vice-versa, we can't determine that. - * There are 3 simple ways of working around this: - * - change the order of the pointers: - * have the integer_c and real_c point to the neg_literal_c - * - maintain the order of the pointers, and - * add redundant info to the integer_c and real_c + * However, this has since been changed to... * - replace the neg_literal_c with two distinc classes * (neg_integer_c and neg_real_c), one for each - * lietral type. This means that we can now treat - * each of these classes as an unknown data type - * just as we do with the integer_c and real_c. - * - * The second option is simply ugly. - * and the first has a serious drawback: when generating code it is - * easier to encapsulate the real or integer values inside prefix - * and postfix symbols (e.g. NEG() - with postfix ')' ) - * if we keep the pointer order as is. - * - * For the above reasoning, we use the third option. + * lietral type. + * + * This change was done in order to ease the writing of semantic verification (stage3) code. + * However, that version of the code has since been replaced by a newer and better algoritm. + * This means the above change can now be undone, but there is really no need to undo it, + * so we leave it as it is. */ SYM_REF1(neg_real_c, exp) SYM_REF1(neg_integer_c, exp) @@ -913,18 +900,22 @@ SYM_LIST(instruction_list_c) /* | label ':' [il_incomplete_instruction] eol_list */ -SYM_REF2(il_instruction_c, label, il_instruction) +/* NOTE: The parameter 'prev_il_instruction' is used to point to all previous il instructions that may be executed imedaitely before this instruction. + * In case of an il instruction preceded by a label, this will include all IL instructions that jump to this label! + * It is filled in by the flow_control_analysis_c during stage 3. + */ +SYM_REF2(il_instruction_c, label, il_instruction, std::vector prev_il_instruction;) /* | il_simple_operator [il_operand] */ SYM_REF2(il_simple_operation_c, il_simple_operator, il_operand) /* | function_name [il_operand_list] */ -/* NOTE: The parameters 'called_function_declaration' is used to pass +/* NOTE: The parameter 'called_function_declaration', 'extensible_param_count' and 'candidate_functions' are used to pass data between the stage 3 and stage 4. * data between the stage 3 and stage 4. * See the comment above function_invocation_c for more details */ -SYM_REF2(il_function_call_c, function_name, il_operand_list, symbol_c *called_function_declaration; int extensible_param_count;) +SYM_REF2(il_function_call_c, function_name, il_operand_list, symbol_c *called_function_declaration; int extensible_param_count; std::vector candidate_functions;) /* | il_expr_operator '(' [il_operand] eol_list [simple_instr_list] ')' */ @@ -939,15 +930,15 @@ * | il_call_operator prev_declared_fb_name '(' il_operand_list ')' * | il_call_operator prev_declared_fb_name '(' eol_list il_param_list ')' */ -SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list) +/* NOTE: The parameter 'called_fb_declaration'is used to pass data between stage 3 and stage4 (although currently it is not used in stage 4 */ +SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list, symbol_c *called_fb_declaration;) /* | function_name '(' eol_list [il_param_list] ')' */ -/* NOTE: The parameters 'called_function_declaration' is used to pass - * data between the stage 3 and stage 4. - * See the comment above function_invocation_c for more details - */ -SYM_REF2(il_formal_funct_call_c, function_name, il_param_list, symbol_c *called_function_declaration; int extensible_param_count;) +/* NOTE: The parameter 'called_function_declaration', 'extensible_param_count' and 'candidate_functions' are used to pass data between the stage 3 and stage 4. + * See the comment above function_invocation_c for more details. + */ +SYM_REF2(il_formal_funct_call_c, function_name, il_param_list, symbol_c *called_function_declaration; int extensible_param_count; std::vector candidate_functions;) /* | il_operand_list ',' il_operand */ SYM_LIST(il_operand_list_c) @@ -955,6 +946,15 @@ /* | simple_instr_list il_simple_instruction */ SYM_LIST(simple_instr_list_c) + +/* il_simple_instruction: + * il_simple_operation eol_list + * | il_expression eol_list + * | il_formal_funct_call eol_list + */ +/* NOTE: The parameter 'prev_il_instruction' is used to point to all previous il instructions that may be executed imedaitely before this instruction. */ +SYM_REF1(il_simple_instruction_c, il_simple_instruction, std::vector prev_il_instruction;) + /* | il_initial_param_list il_param_instruction */ SYM_LIST(il_param_list_c) @@ -971,31 +971,36 @@ /*******************/ /* B 2.2 Operators */ /*******************/ +/* NOTE: The parameter 'called_fb_declaration' is used to pass data between stage 3 and stage4 (although currently it is not used in stage 4 */ +/* NOTE: The parameter 'deprecated_operation' indicates that the operation, with the specific data types being used, is currently defined + * in the standard as being deprecated. This variable is filled in with the correct value in stage 3 (narrow_candidate_datatypes_c) + * and currently only used in stage 3 (print_datatypes_error_c). + */ SYM_REF0(LD_operator_c) SYM_REF0(LDN_operator_c) SYM_REF0(ST_operator_c) SYM_REF0(STN_operator_c) SYM_REF0(NOT_operator_c) -SYM_REF0(S_operator_c) -SYM_REF0(R_operator_c) -SYM_REF0(S1_operator_c) -SYM_REF0(R1_operator_c) -SYM_REF0(CLK_operator_c) -SYM_REF0(CU_operator_c) -SYM_REF0(CD_operator_c) -SYM_REF0(PV_operator_c) -SYM_REF0(IN_operator_c) -SYM_REF0(PT_operator_c) +SYM_REF0(S_operator_c, symbol_c *called_fb_declaration;) +SYM_REF0(R_operator_c, symbol_c *called_fb_declaration;) +SYM_REF0(S1_operator_c, symbol_c *called_fb_declaration;) +SYM_REF0(R1_operator_c, symbol_c *called_fb_declaration;) +SYM_REF0(CLK_operator_c, symbol_c *called_fb_declaration;) +SYM_REF0(CU_operator_c, symbol_c *called_fb_declaration;) +SYM_REF0(CD_operator_c, symbol_c *called_fb_declaration;) +SYM_REF0(PV_operator_c, symbol_c *called_fb_declaration;) +SYM_REF0(IN_operator_c, symbol_c *called_fb_declaration;) +SYM_REF0(PT_operator_c, symbol_c *called_fb_declaration;) SYM_REF0(AND_operator_c) SYM_REF0(OR_operator_c) SYM_REF0(XOR_operator_c) SYM_REF0(ANDN_operator_c) SYM_REF0(ORN_operator_c) SYM_REF0(XORN_operator_c) -SYM_REF0(ADD_operator_c) -SYM_REF0(SUB_operator_c) -SYM_REF0(MUL_operator_c) -SYM_REF0(DIV_operator_c) +SYM_REF0(ADD_operator_c, bool deprecated_operation;) +SYM_REF0(SUB_operator_c, bool deprecated_operation;) +SYM_REF0(MUL_operator_c, bool deprecated_operation;) +SYM_REF0(DIV_operator_c, bool deprecated_operation;) SYM_REF0(MOD_operator_c) SYM_REF0(GT_operator_c) SYM_REF0(GE_operator_c) @@ -1036,10 +1041,10 @@ SYM_REF2(gt_expression_c, l_exp, r_exp) SYM_REF2(le_expression_c, l_exp, r_exp) SYM_REF2(ge_expression_c, l_exp, r_exp) -SYM_REF2(add_expression_c, l_exp, r_exp) -SYM_REF2(sub_expression_c, l_exp, r_exp) -SYM_REF2(mul_expression_c, l_exp, r_exp) -SYM_REF2(div_expression_c, l_exp, r_exp) +SYM_REF2(add_expression_c, l_exp, r_exp, bool deprecated_operation;) +SYM_REF2(sub_expression_c, l_exp, r_exp, bool deprecated_operation;) +SYM_REF2(mul_expression_c, l_exp, r_exp, bool deprecated_operation;) +SYM_REF2(div_expression_c, l_exp, r_exp, bool deprecated_operation;) SYM_REF2(mod_expression_c, l_exp, r_exp) SYM_REF2(power_expression_c, l_exp, r_exp) SYM_REF1(neg_expression_c, exp) @@ -1047,18 +1052,36 @@ /* formal_param_list -> may be NULL ! */ /* nonformal_param_list -> may be NULL ! */ -/* NOTE: The parameters 'called_function_declaration' is used to pass - * data between the stage 3 and stage 4. +/* NOTES: + * The parameter 'called_function_declaration'... + * ...is used to pass data between the stage 3 and stage 4. * The IEC 61131-3 standard allows for overloaded standard functions. This means that some - * function calls are not compeletely defined by the name of the function being called, + * function calls are not completely defined by the name of the function being called, * and need to be disambiguated with using the data types of the parameters being passed. - * Stage 3 does this to verify semantic correctnes. + * Stage 3 does this to verify semantic correctness. * Stage 4 also needs to do this in order to determine which function to call. * It does not make sense to determine the exact function being called twice (once in stage 3, - * and again in stage 4), so stage 3 will store this infor in the parameter called_function_declaration + * and again in stage 4), so stage 3 will store this info in the parameter called_function_declaration * for stage 4 to use it later on. - */ -SYM_REF3(function_invocation_c, function_name, formal_param_list, nonformal_param_list, symbol_c *called_function_declaration; int extensible_param_count;) + * The parameter 'candidate_functions'... + * ...is used to pass data between two passes within stage 3 + * (actually between fill_candidate_datatypes_c and narrow_candidate_datatypes_c). + * It is used to store all the functions that may be legally called with the current parameters + * being used in this function invocation. Note that the standard includes some standard functions + * that have the exact same input parameter types, but return different data types. + * In order to determine which of these functions should be called, we first create a list + * of all possible functions, and then narrow down the list (hopefully down to 1 function) + * once we know the data type that the function invocation must return (this will take into + * account the expression in which the function invocation is inserted/occurs). + * The 'called_function_declaration' will eventually be set (in stage 3) to one of + * the functions in the 'candidate_functions' list! + * The parameter 'extensible_param_count'... + * ...is used to pass data between the stage 3 and stage 4. + * The IEC 61131-3 standard allows for extensible standard functions. This means that some + * standard functions may be called with a variable number of paramters. Stage 3 will store + * in extensible_param_count the number of parameters being passed to the extensible parameter. + */ +SYM_REF3(function_invocation_c, function_name, formal_param_list, nonformal_param_list, symbol_c *called_function_declaration; int extensible_param_count; std::vector candidate_functions;) /********************/ @@ -1083,7 +1106,8 @@ /* fb_name '(' [param_assignment_list] ')' */ /* formal_param_list -> may be NULL ! */ /* nonformal_param_list -> may be NULL ! */ -SYM_REF3(fb_invocation_c, fb_name, formal_param_list, nonformal_param_list) +/* NOTE: The parameter 'called_fb_declaration'is used to pass data between stage 3 and stage4 (although currently it is not used in stage 4 */ +SYM_REF3(fb_invocation_c, fb_name, formal_param_list, nonformal_param_list, symbol_c *called_fb_declaration;) /* helper symbol for fb_invocation */ /* param_assignment_list ',' param_assignment */ diff -r 34a5571c859c -r 0bb88139e471 absyntax/absyntax.hh --- a/absyntax/absyntax.hh Thu Mar 22 00:22:48 2012 +0100 +++ b/absyntax/absyntax.hh Sat Mar 31 21:46:37 2012 +0100 @@ -47,6 +47,7 @@ #include // required for NULL +#include /* Forward declaration of the visitor interface * dclared in the visitor.hh file @@ -76,6 +77,14 @@ int last_column; const char *last_file; /* filename referenced by last line/column */ long int last_order; /* relative order in which it is read by lexcial analyser */ + std::vector candidate_datatypes; /* All possible data types the expression/literal/etc. may take. Filled in stage3 by fill_candidate_datatypes_c class */ + /* Data type of the expression/literal/etc. Filled in stage3 by narrow_candidate_datatypes_c + * If set to NULL, it means it has not yet been evaluated. + * If it points to an object of type invalid_type_name_c, it means it is invalid. + * Otherwise, it points to an object of the apropriate data type (e.g. int_type_name_c, bool_type_name_c, ...) + */ + symbol_c *datatype; + public: /* default constructor */ @@ -125,6 +134,8 @@ /* To insert into the begining of list, call with pos=0 */ /* To insert into the end of list, call with pos=list->n */ virtual void insert_element(symbol_c *elem, int pos = 0); + /* remove element at position pos. */ + virtual void remove_element(int pos = 0); }; diff -r 34a5571c859c -r 0bb88139e471 absyntax/visitor.cc --- a/absyntax/visitor.cc Thu Mar 22 00:22:48 2012 +0100 +++ b/absyntax/visitor.cc Sat Mar 31 21:46:37 2012 +0100 @@ -73,13 +73,13 @@ #define SYM_LIST(class_name_c) \ void *null_visitor_c::visit(class_name_c *symbol) {return NULL;} -#define SYM_TOKEN(class_name_c) \ - void *null_visitor_c::visit(class_name_c *symbol) {return NULL;} - -#define SYM_REF0(class_name_c) \ - void *null_visitor_c::visit(class_name_c *symbol) {return NULL;} - -#define SYM_REF1(class_name_c, ref1) \ +#define SYM_TOKEN(class_name_c, ...) \ + void *null_visitor_c::visit(class_name_c *symbol) {return NULL;} + +#define SYM_REF0(class_name_c, ...) \ + void *null_visitor_c::visit(class_name_c *symbol) {return NULL;} + +#define SYM_REF1(class_name_c, ref1, ...) \ void *null_visitor_c::visit(class_name_c *symbol) {return NULL;} #define SYM_REF2(class_name_c, ref1, ref2, ...) \ @@ -136,13 +136,13 @@ #define SYM_LIST(class_name_c) \ void *iterator_visitor_c::visit(class_name_c *symbol) {return visit_list(symbol);} -#define SYM_TOKEN(class_name_c) \ +#define SYM_TOKEN(class_name_c, ...) \ void *iterator_visitor_c::visit(class_name_c *symbol) {return NULL;} -#define SYM_REF0(class_name_c) \ +#define SYM_REF0(class_name_c, ...) \ void *iterator_visitor_c::visit(class_name_c *symbol) {return NULL;} -#define SYM_REF1(class_name_c, ref1) \ +#define SYM_REF1(class_name_c, ref1, ...) \ void *iterator_visitor_c::visit(class_name_c *symbol) { \ if (symbol->ref1!=NULL) symbol->ref1->accept(*this); \ return NULL; \ @@ -238,13 +238,13 @@ #define SYM_LIST(class_name_c) \ void *search_visitor_c::visit(class_name_c *symbol) {return visit_list(symbol);} -#define SYM_TOKEN(class_name_c) \ +#define SYM_TOKEN(class_name_c, ...) \ void *search_visitor_c::visit(class_name_c *symbol) {return NULL;} -#define SYM_REF0(class_name_c) \ +#define SYM_REF0(class_name_c, ...) \ void *search_visitor_c::visit(class_name_c *symbol) {return NULL;} -#define SYM_REF1(class_name_c, ref1) \ +#define SYM_REF1(class_name_c, ref1, ...) \ void *search_visitor_c::visit(class_name_c *symbol) { \ if (symbol->ref1) return symbol->ref1->accept(*this); \ return NULL; \ diff -r 34a5571c859c -r 0bb88139e471 absyntax_utils/Makefile.am --- a/absyntax_utils/Makefile.am Thu Mar 22 00:22:48 2012 +0100 +++ b/absyntax_utils/Makefile.am Sat Mar 31 21:46:37 2012 +0100 @@ -13,6 +13,7 @@ function_param_iterator.cc \ get_function_type.cc \ get_sizeof_datatype.cc \ + search_il_label.cc \ search_base_type.cc \ search_constant_type.cc \ search_expression_type.cc \ diff -r 34a5571c859c -r 0bb88139e471 absyntax_utils/Makefile.in --- a/absyntax_utils/Makefile.in Thu Mar 22 00:22:48 2012 +0100 +++ b/absyntax_utils/Makefile.in Sat Mar 31 21:46:37 2012 +0100 @@ -78,8 +78,8 @@ function_call_iterator.$(OBJEXT) \ function_call_param_iterator.$(OBJEXT) \ function_param_iterator.$(OBJEXT) get_function_type.$(OBJEXT) \ - get_sizeof_datatype.$(OBJEXT) search_base_type.$(OBJEXT) \ - search_constant_type.$(OBJEXT) \ + get_sizeof_datatype.$(OBJEXT) search_il_label.$(OBJEXT) \ + search_base_type.$(OBJEXT) search_constant_type.$(OBJEXT) \ search_expression_type.$(OBJEXT) \ search_fb_instance_decl.$(OBJEXT) search_fb_typedecl.$(OBJEXT) \ search_varfb_instance_type.$(OBJEXT) \ @@ -213,6 +213,7 @@ function_param_iterator.cc \ get_function_type.cc \ get_sizeof_datatype.cc \ + search_il_label.cc \ search_base_type.cc \ search_constant_type.cc \ search_expression_type.cc \ @@ -319,6 +320,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/search_expression_type.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/search_fb_instance_decl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/search_fb_typedecl.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/search_il_label.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/search_var_instance_decl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/search_varfb_instance_type.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spec_init_separator.Po@am__quote@ diff -r 34a5571c859c -r 0bb88139e471 absyntax_utils/absyntax_utils.cc --- a/absyntax_utils/absyntax_utils.cc Thu Mar 22 00:22:48 2012 +0100 +++ b/absyntax_utils/absyntax_utils.cc Sat Mar 31 21:46:37 2012 +0100 @@ -294,7 +294,17 @@ } - + /* string_type_name ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init */ + // SYM_REF4(string_type_declaration_c, string_type_name, + // elementary_string_type_name, + // string_type_declaration_size, + // string_type_declaration_init) /* may be == NULL! */ + void *visit(string_type_declaration_c *symbol) { + TRACE("string_type_declaration_c"); + type_symtable.insert(symbol->string_type_name, symbol); + return NULL; +} + /*********************/ /* B 1.4 - Variables */ /*********************/ diff -r 34a5571c859c -r 0bb88139e471 absyntax_utils/absyntax_utils.hh --- a/absyntax_utils/absyntax_utils.hh Thu Mar 22 00:22:48 2012 +0100 +++ b/absyntax_utils/absyntax_utils.hh Sat Mar 31 21:46:37 2012 +0100 @@ -120,7 +120,7 @@ #include "add_en_eno_param_decl.hh" #include "get_sizeof_datatype.hh" #include "get_function_type.h" - +#include "search_il_label.hh" /***********************************************************************/ /***********************************************************************/ diff -r 34a5571c859c -r 0bb88139e471 absyntax_utils/function_call_param_iterator.cc --- a/absyntax_utils/function_call_param_iterator.cc Thu Mar 22 00:22:48 2012 +0100 +++ b/absyntax_utils/function_call_param_iterator.cc Sat Mar 31 21:46:37 2012 +0100 @@ -184,6 +184,7 @@ */ symbol_c *function_call_param_iterator_c::next_f(void) { current_value = NULL; + current_assign_direction = assign_none; param_count = 0; iterate_f_next_param++; current_operation = function_call_param_iterator_c::iterate_f_op; @@ -201,6 +202,7 @@ */ symbol_c *function_call_param_iterator_c::next_nf(void) { current_value = NULL; + current_assign_direction = assign_none; param_count = 0; iterate_nf_next_param++; current_operation = function_call_param_iterator_c::iterate_nf_op; @@ -212,6 +214,7 @@ /* Search for the value passed to the parameter named ... */ symbol_c *function_call_param_iterator_c::search_f(symbol_c *param_name) { current_value = NULL; + current_assign_direction = assign_none; if (NULL == param_name) ERROR; search_param_name = dynamic_cast(param_name); if (NULL == search_param_name) ERROR; @@ -233,6 +236,12 @@ return current_value; } +/* Returns the value being passed to the current parameter. */ +function_call_param_iterator_c::assign_direction_t function_call_param_iterator_c::get_assign_direction(void) { + return current_assign_direction; +} + + /********************************/ /* B 1.7 Configuration elements */ /********************************/ @@ -339,6 +348,7 @@ if (NULL == symb_var) ERROR; + current_assign_direction = assign_in; return handle_parameter_assignment(symb_var->var_name, symbol->prog_data_source); } @@ -355,6 +365,7 @@ if (NULL == symb_var) ERROR; + current_assign_direction = assign_out; return handle_parameter_assignment(symb_var->var_name, symbol->data_sink); } @@ -459,6 +470,7 @@ // since we do not yet support it, it is best to simply stop than to fail silently... if (NULL != symbol->simple_instr_list) ERROR; + current_assign_direction = assign_in; return handle_parameter_assignment((symbol_c *)symbol->il_assign_operator->accept(*this), symbol->il_operand); } @@ -466,6 +478,7 @@ // SYM_REF2(il_param_out_assignment_c, il_assign_out_operator, variable); void *function_call_param_iterator_c::visit(il_param_out_assignment_c *symbol) { TRACE("il_param_out_assignment_c"); + current_assign_direction = assign_out; return handle_parameter_assignment((symbol_c *)symbol->il_assign_out_operator->accept(*this), symbol->variable); } @@ -564,6 +577,7 @@ // SYM_REF2(input_variable_param_assignment_c, variable_name, expression) void *function_call_param_iterator_c::visit(input_variable_param_assignment_c *symbol) { TRACE("input_variable_param_assignment_c"); + current_assign_direction = assign_in; return handle_parameter_assignment(symbol->variable_name, symbol->expression); } @@ -574,6 +588,7 @@ // TODO : Handle not_param !!! if (NULL != symbol->not_param) ERROR; // we do not yet support it, so it is best to simply stop than to fail silently... + current_assign_direction = assign_out; return handle_parameter_assignment(symbol->variable_name, symbol->variable); } diff -r 34a5571c859c -r 0bb88139e471 absyntax_utils/function_call_param_iterator.hh --- a/absyntax_utils/function_call_param_iterator.hh Thu Mar 22 00:22:48 2012 +0100 +++ b/absyntax_utils/function_call_param_iterator.hh Sat Mar 31 21:46:37 2012 +0100 @@ -51,6 +51,58 @@ class function_call_param_iterator_c : public null_visitor_c { private: + void *search_list(list_c *list); + void *handle_parameter_assignment(symbol_c *variable_name, symbol_c *expression) ; + + + public: + /* start off at the first parameter once again... */ + void reset(void); + + /* initialise the iterator object. + * We must be given a reference to the function/program/function block call + * that will be analysed... + */ + function_call_param_iterator_c(symbol_c *f_call); + + /* Skip to the next formal parameter. After object creation, + * the object references on parameter _before_ the first, so + * this function must be called once to get the object to + * reference the first parameter... + * + * Returns the paramater name to which a value is being passed! + * You can determine the value being passed by calling + * function_call_param_iterator_c::search_f() + */ + symbol_c *next_f(void); + + /* Skip to the next non-formal parameter. After object creation, + * the object references on parameter _before_ the first, so + * this function must be called once to get the object to + * reference the first parameter... + * + * Returns whatever is being passed to the parameter! + */ + symbol_c *next_nf(void); + + /* Search for the value passed to the parameter named ... */ + symbol_c *search_f(symbol_c *param_name); + symbol_c *search_f(const char *param_name); + + /* Returns the value being passed to the current parameter. */ + symbol_c *get_current_value(void); + + /* A type to specify how the current parameter was assigned. + * param_name := var -> assign_in + * param_name => var -> assign_out + * -> assign_none (used when handling non formal calls, when no assignment type is used) + */ + typedef enum {assign_in, assign_out, assign_none} assign_direction_t ; + /* Returns the assignment direction of the current parameter. */ + assign_direction_t get_assign_direction(void); + + + private: /* a pointer to the function call * (or function block or program call!) */ @@ -58,6 +110,7 @@ int iterate_f_next_param, iterate_nf_next_param, param_count; identifier_c *search_param_name; symbol_c *current_value; + assign_direction_t current_assign_direction; /* Which operation of the class was called: * - iterate to the next non-formal parameter. @@ -67,49 +120,7 @@ typedef enum {iterate_nf_op, iterate_f_op, search_f_op} operation_t; operation_t current_operation; - private: - void *search_list(list_c *list); - void *handle_parameter_assignment(symbol_c *variable_name, symbol_c *expression) ; - - - public: - /* start off at the first parameter once again... */ - void reset(void); - - /* initialise the iterator object. - * We must be given a reference to the function/program/function block call - * that will be analysed... - */ - function_call_param_iterator_c(symbol_c *f_call); - - /* Skip to the next formal parameter. After object creation, - * the object references on parameter _before_ the first, so - * this function must be called once to get the object to - * reference the first parameter... - * - * Returns the paramater name to which a value is being passed! - * You can determine the value being passed by calling - * function_call_param_iterator_c::search_f() - */ - symbol_c *next_f(void); - - /* Skip to the next non-formal parameter. After object creation, - * the object references on parameter _before_ the first, so - * this function must be called once to get the object to - * reference the first parameter... - * - * Returns whatever is being passed to the parameter! - */ - symbol_c *next_nf(void); - - /* Search for the value passed to the parameter named ... */ - symbol_c *search_f(symbol_c *param_name); - symbol_c *search_f(const char *param_name); - - /* Returns the value being passed to the current parameter. */ - symbol_c *get_current_value(void); - - + private: /********************************/ /* B 1.7 Configuration elements */ diff -r 34a5571c859c -r 0bb88139e471 absyntax_utils/function_param_iterator.cc --- a/absyntax_utils/function_param_iterator.cc Thu Mar 22 00:22:48 2012 +0100 +++ b/absyntax_utils/function_param_iterator.cc Sat Mar 31 21:46:37 2012 +0100 @@ -206,7 +206,9 @@ _first_extensible_param_index = -1; current_param_is_extensible = false; current_param_name = NULL; - current_param_type = current_param_default_value = NULL; + current_param_type = NULL; + current_param_default_value = NULL; + last_returned_parameter = NULL; /* the last parameter returned by search() or next() */ } @@ -223,7 +225,8 @@ function_block_declaration_c *fb_decl = dynamic_cast(pou_decl); program_declaration_c * p_decl = dynamic_cast(pou_decl); - if ((NULL == f_decl) && (NULL == fb_decl) && (NULL == p_decl)) ERROR; + if ((NULL == f_decl) && (NULL == fb_decl) && (NULL == p_decl)) + ERROR; /* OK. Now initialise this object... */ this->f_decl = pou_decl; @@ -248,6 +251,7 @@ return current_param_name; } + last_returned_parameter = NULL; param_count = 0; en_eno_param_implicit = false; next_param++; @@ -268,6 +272,7 @@ if (identifier == NULL) ERROR; current_param_name = identifier; + last_returned_parameter = current_param_name; return current_param_name; } @@ -281,35 +286,53 @@ current_operation = function_param_iterator_c::search_op; void *res = f_decl->accept(*this); identifier_c *res_param_name = dynamic_cast((symbol_c *)res); + last_returned_parameter = res_param_name; return res_param_name; } +identifier_c *function_param_iterator_c::search(const char *param_name) { + identifier_c param_name_id(param_name); + return search(¶m_name_id); +} + + + /* Returns the currently referenced parameter's default value, * or NULL if none is specified in the function declrataion itself. */ symbol_c *function_param_iterator_c::default_value(void) { + if (NULL == last_returned_parameter) + return NULL; return current_param_default_value; } /* Returns the currently referenced parameter's type name. */ symbol_c *function_param_iterator_c::param_type(void) { + if (NULL == last_returned_parameter) + return NULL; return current_param_type; } /* Returns if currently referenced parameter is an implicit defined EN/ENO parameter. */ bool function_param_iterator_c::is_en_eno_param_implicit(void) { + if (NULL == last_returned_parameter) + ERROR; return en_eno_param_implicit; } /* Returns if currently referenced parameter is an extensible parameter. */ /* extensible paramters only occur in some standard functions, e.g. AND(word#34, word#44, word#65); */ bool function_param_iterator_c::is_extensible_param(void) { + if (NULL == last_returned_parameter) + ERROR; return current_param_is_extensible; } /* Returns the index of the current extensible parameter. */ /* If the current parameter is not an extensible paramter, returns -1 */ int function_param_iterator_c::extensible_param_index(void) { + if (NULL == last_returned_parameter) + ERROR; return (current_param_is_extensible? current_extensible_param_index : -1); } @@ -323,6 +346,8 @@ * i.e. VAR_INPUT, VAR_OUTPUT or VAR_INOUT */ function_param_iterator_c::param_direction_t function_param_iterator_c::param_direction(void) { + if (NULL == last_returned_parameter) + ERROR; return current_param_direction; } diff -r 34a5571c859c -r 0bb88139e471 absyntax_utils/function_param_iterator.hh --- a/absyntax_utils/function_param_iterator.hh Thu Mar 22 00:22:48 2012 +0100 +++ b/absyntax_utils/function_param_iterator.hh Sat Mar 31 21:46:37 2012 +0100 @@ -105,7 +105,10 @@ */ typedef enum {iterate_op, search_op} operation_t; operation_t current_operation; - + + /* the last parameter/value returned by search() or next() */ + symbol_c *last_returned_parameter; + private: int cmp_extparam_names(const char* s1, const char* s2); void* handle_param_list(list_c *list); @@ -143,6 +146,7 @@ * of the found parameter. */ identifier_c *search(symbol_c *param_name); + identifier_c *search(const char *param_name); /* Returns the currently referenced parameter's default value, * or NULL if none is specified in the function declrataion itself. diff -r 34a5571c859c -r 0bb88139e471 absyntax_utils/get_sizeof_datatype.cc --- a/absyntax_utils/get_sizeof_datatype.cc Thu Mar 22 00:22:48 2012 +0100 +++ b/absyntax_utils/get_sizeof_datatype.cc Sat Mar 31 21:46:37 2012 +0100 @@ -80,6 +80,7 @@ /* tell stdint.h we want the definition of UINT64_MAX */ #define __STDC_LIMIT_MACROS #include // get definition of uint64_t and UINT64_MAX +#include #define ERROR error_exit(__FILE__,__LINE__) @@ -158,8 +159,60 @@ /* NOTE: all integer_c and real_c tokens will always be positive (i.e. no leading '-') * due to the way the source code is parsed by iec.flex. */ + +/* + * IEC6113-3 and C++ use IEC 60559 to rappresent floating point data types + * REAL => float => single precision 32 bit + * LREAL => double => double precision 64 bit + * ????? => long double => quadruple precision 128 bit + */ void *get_sizeof_datatype_c::visit(real_c *symbol) { - return _encode_int(32); + char *endp; + long double ld_test; + double d_test; + float f_test; + + /* copy the original string, but leave out any underscores... */ + char *sval, *oval; + const char *pval; + oval = sval = (char *)malloc(strlen(symbol->value)+1); + if (NULL == sval) ERROR; + + for (pval = symbol->value, sval = oval; *pval != '\0'; pval++) { + if ('_' != *pval) {*sval = *pval; sval++;} + } + *sval = '\0'; + + sval = oval; + if ('\0' == *sval) ERROR; + + /* now do the conversion using the new string... */ + f_test = strtof(sval, &endp); + if (*endp != '\0') ERROR; + if (ERANGE != errno) { + /* No overflow/underflow! => It fits in a float! */ + free(oval); + return _encode_int(32); + } + + d_test = strtod(sval, &endp); + if (*endp != '\0') ERROR; + if (ERANGE != errno) { + /* No overflow/underflow! => It fits in a double! */ + free(oval); + return _encode_int(64); + } + + ld_test = strtold(sval, &endp); + if (*endp != '\0') ERROR; + if (ERANGE != errno) { + /* No overflow/underflow! => It fits in a long double! */ + free(oval); + return _encode_int(128); + } + + free(oval); + return _encode_int(65535); /* a very large number!!! */ } void *get_sizeof_datatype_c::visit(neg_real_c *symbol) { @@ -282,7 +335,7 @@ if (('0' != *sval) && ('1' != *sval) && ('_' != *sval)) ERROR; - if ('_' != *sval) bitsize ++; /* 1 bits per binary digit */ + if ('_' != *sval) bitsize++; /* 1 bits per binary digit */ } /* special case... if (value == 0) <=> (bitsize == 0), return bit size of 1 ! */ diff -r 34a5571c859c -r 0bb88139e471 absyntax_utils/search_base_type.cc --- a/absyntax_utils/search_base_type.cc Thu Mar 22 00:22:48 2012 +0100 +++ b/absyntax_utils/search_base_type.cc Sat Mar 31 21:46:37 2012 +0100 @@ -1,7 +1,7 @@ /* * matiec - a compiler for the programming languages defined in IEC 61131-3 * - * Copyright (C) 2003-2011 Mario de Sousa (msousa@fe.up.pt) + * Copyright (C) 2003-2012 Mario de Sousa (msousa@fe.up.pt) * Copyright (C) 2007-2011 Laurent Bessard and Edouard Tisserant * * This program is free software: you can redistribute it and/or modify @@ -55,16 +55,29 @@ search_base_type_c::search_base_type_c(void) {current_type_name = NULL;} -void *search_base_type_c::visit(identifier_c *type_name) { - this->current_type_name = type_name; - /* look up the type declaration... */ - symbol_c *type_decl = type_symtable.find_value(type_name); - if (type_decl == type_symtable.end_value()) - /* Type declaration not found!! */ - ERROR; - - return type_decl->accept(*this); -} + + + +symbol_c *search_base_type_c::get_basetype_decl(symbol_c *symbol) { + if (NULL == symbol) + return NULL; + + return (symbol_c *)symbol->accept(*this); +} + +symbol_c *search_base_type_c::get_basetype_id (symbol_c *symbol) { + if (NULL == symbol) + return NULL; + + current_type_name = NULL; /* just to be on the safe side... */ + symbol->accept(*this); + return (symbol_c *)current_type_name; +} + + +/* Note by MJS: The following two functions definately do not belong in this class!! Maybe create a new utility class? + * I will need to clean this up when the opportunity arises! + */ bool search_base_type_c::type_is_subrange(symbol_c* type_decl) { this->is_subrange = false; @@ -78,6 +91,35 @@ return this->is_enumerated; } + +/*************************/ +/* B.1 - Common elements */ +/*************************/ + +/*******************************************/ +/* B 1.1 - Letters, digits and identifiers */ +/*******************************************/ +void *search_base_type_c::visit(identifier_c *type_name) { + symbol_c *type_decl; + + this->current_type_name = type_name; + + /* look up the type declaration... */ + type_decl = type_symtable.find_value(type_name); + if (type_decl != type_symtable.end_value()) + return type_decl->accept(*this); + + type_decl = function_block_type_symtable.find_value(type_name); + if (type_decl != function_block_type_symtable.end_value()) + return type_decl->accept(*this); + + /* Type declaration not found!! */ + ERROR; + + return NULL; +} + + /*********************/ /* B 1.2 - Constants */ /*********************/ @@ -205,8 +247,7 @@ /* helper symbol for enumerated_specification->enumerated_spec_init */ /* enumerated_value_list ',' enumerated_value */ void *search_base_type_c::visit(enumerated_value_list_c *symbol) { - if (NULL == this->current_type_name) ERROR; - return (void *)this->current_type_name; + return (void *)symbol; } /* enumerated_type_name '#' identifier */ @@ -222,14 +263,16 @@ /* array_specification [ASSIGN array_initialization} */ /* array_initialization may be NULL ! */ void *search_base_type_c::visit(array_spec_init_c *symbol) { + /* Note that the 'array_specification' may be either an identifier of a previsously defined array type, + * or an array_specification_c, so we can not stop here and simply return a array_spec_init_c, + * especially if we are looking for the base class! + */ return symbol->array_specification->accept(*this); } /* ARRAY '[' array_subrange_list ']' OF non_generic_type_name */ void *search_base_type_c::visit(array_specification_c *symbol) { - if (NULL == this->current_type_name) - this->current_type_name = symbol->non_generic_type_name; - return symbol->non_generic_type_name->accept(*this); + return symbol; } /* helper symbol for array_specification */ diff -r 34a5571c859c -r 0bb88139e471 absyntax_utils/search_base_type.hh --- a/absyntax_utils/search_base_type.hh Thu Mar 22 00:22:48 2012 +0100 +++ b/absyntax_utils/search_base_type.hh Sat Mar 31 21:46:37 2012 +0100 @@ -1,7 +1,7 @@ /* * matiec - a compiler for the programming languages defined in IEC 61131-3 * - * Copyright (C) 2003-2011 Mario de Sousa (msousa@fe.up.pt) + * Copyright (C) 2003-2012 Mario de Sousa (msousa@fe.up.pt) * Copyright (C) 2007-2011 Laurent Bessard and Edouard Tisserant * * This program is free software: you can redistribute it and/or modify @@ -60,18 +60,27 @@ search_base_type_c(void); public: - void *visit(identifier_c *type_name); + symbol_c *get_basetype_decl(symbol_c *symbol); + symbol_c *get_basetype_id (symbol_c *symbol); bool type_is_subrange(symbol_c* type_decl); bool type_is_enumerated(symbol_c* type_decl); public: - /*********************/ - /* B 1.2 - Constants */ - /*********************/ - - /******************************/ - /* B 1.2.1 - Numeric Literals */ - /******************************/ + /*************************/ + /* B.1 - Common elements */ + /*************************/ + /*******************************************/ + /* B 1.1 - Letters, digits and identifiers */ + /*******************************************/ + void *visit(identifier_c *type_name); + + + /*********************/ + /* B 1.2 - Constants */ + /*********************/ + /******************************/ + /* B 1.2.1 - Numeric Literals */ + /******************************/ /* Numeric literals without any explicit type cast have unknown data type, * so we continue considering them as their own basic data types until * they can be resolved (for example, when using '30+x' where 'x' is a LINT variable, the diff -r 34a5571c859c -r 0bb88139e471 absyntax_utils/search_constant_type.cc --- a/absyntax_utils/search_constant_type.cc Thu Mar 22 00:22:48 2012 +0100 +++ b/absyntax_utils/search_constant_type.cc Sat Mar 31 21:46:37 2012 +0100 @@ -133,6 +133,12 @@ return (void *)value_type; } + + + +invalid_type_name_c search_constant_type_c::invalid_type_name; + + real_type_name_c search_constant_type_c::real_type_name; sint_type_name_c search_constant_type_c::sint_type_name; lint_type_name_c search_constant_type_c::lint_type_name; @@ -155,17 +161,26 @@ time_type_name_c search_constant_type_c::time_type_name; int_type_name_c search_constant_type_c::int_type_name; -// safebool_type_name_c search_constant_type_c::safebool_type_name; - /* The following is required because the expression (TOD_var - TOD_var) will result in a data type - * (in this case, TIME) that is neither of the expression elements... - */ safetime_type_name_c search_constant_type_c::safetime_type_name; safetod_type_name_c search_constant_type_c::safetod_type_name; safedt_type_name_c search_constant_type_c::safedt_type_name; +safedate_type_name_c search_constant_type_c::safedate_type_name; +safereal_type_name_c search_constant_type_c::safereal_type_name; +safesint_type_name_c search_constant_type_c::safesint_type_name; +safelint_type_name_c search_constant_type_c::safelint_type_name; +safedint_type_name_c search_constant_type_c::safedint_type_name; +safedword_type_name_c search_constant_type_c::safedword_type_name; +safeudint_type_name_c search_constant_type_c::safeudint_type_name; +safeword_type_name_c search_constant_type_c::safeword_type_name; +safewstring_type_name_c search_constant_type_c::safewstring_type_name; +safestring_type_name_c search_constant_type_c::safestring_type_name; +safelword_type_name_c search_constant_type_c::safelword_type_name; +safeuint_type_name_c search_constant_type_c::safeuint_type_name; +safelreal_type_name_c search_constant_type_c::safelreal_type_name; +safebyte_type_name_c search_constant_type_c::safebyte_type_name; +safeusint_type_name_c search_constant_type_c::safeusint_type_name; +safeulint_type_name_c search_constant_type_c::safeulint_type_name; +safebool_type_name_c search_constant_type_c::safebool_type_name; +safeint_type_name_c search_constant_type_c::safeint_type_name; - -/* temporarily here until we remove the st_code_gen.c and il_code_gen.c files... */ -/* It should then move to search_expression_type_c */ -integer_c search_constant_type_c::integer("1"); -real_c search_constant_type_c::real("1.0"); diff -r 34a5571c859c -r 0bb88139e471 absyntax_utils/search_constant_type.hh --- a/absyntax_utils/search_constant_type.hh Thu Mar 22 00:22:48 2012 +0100 +++ b/absyntax_utils/search_constant_type.hh Sat Mar 31 21:46:37 2012 +0100 @@ -30,6 +30,14 @@ * */ +/* NOTE: The use of this visitor class is now deprecated. + * The new version of stage3 data type checking adds an entry to + * every relevant object in the abstract syntax tree defining + * the data type of that object. Please use that instead! + */ + + + /* Determine the data type of a specific constant or variable. * A reference to the relevant type definition is returned. * @@ -49,6 +57,10 @@ class search_constant_type_c: public search_visitor_c { public: + /* object used to identify an entry in the abstract syntax tree with an invalid data type */ + /* This is only used from stage3 onwards. Stages 1 and 2 will never create any instances of invalid_type_name_c */ + static invalid_type_name_c invalid_type_name; + /**********************/ /* B.1.3 - Data types */ /**********************/ @@ -79,7 +91,6 @@ /* temporarily here until we remove the st_code_gen.c and il_code_gen.c files... */ static integer_c integer; - static real_c real; /******************************************************/ /* Extensions to the base standard as defined in */ @@ -96,8 +107,24 @@ static safetime_type_name_c safetime_type_name; static safetod_type_name_c safetod_type_name; static safedt_type_name_c safedt_type_name; - - + static safedate_type_name_c safedate_type_name; + static safereal_type_name_c safereal_type_name; + static safesint_type_name_c safesint_type_name; + static safelint_type_name_c safelint_type_name; + static safedint_type_name_c safedint_type_name; + static safedword_type_name_c safedword_type_name; + static safeudint_type_name_c safeudint_type_name; + static safeword_type_name_c safeword_type_name; + static safewstring_type_name_c safewstring_type_name; + static safestring_type_name_c safestring_type_name; + static safelword_type_name_c safelword_type_name; + static safeuint_type_name_c safeuint_type_name; + static safelreal_type_name_c safelreal_type_name; + static safebyte_type_name_c safebyte_type_name; + static safeusint_type_name_c safeusint_type_name; + static safeulint_type_name_c safeulint_type_name; + static safebool_type_name_c safebool_type_name; + static safeint_type_name_c safeint_type_name; public: symbol_c *get_type(symbol_c *constant); @@ -164,5 +191,4 @@ }; // search_constant_type_c - #endif /* ifndef _SEARCH_CONSTANT_TYPE_HH */ diff -r 34a5571c859c -r 0bb88139e471 absyntax_utils/search_il_label.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/absyntax_utils/search_il_label.cc Sat Mar 31 21:46:37 2012 +0100 @@ -0,0 +1,97 @@ +/* + * matiec - a compiler for the programming languages defined in IEC 61131-3 + * + * Copyright (C) 2012 Mario de Sousa (msousa@fe.up.pt) + * + * 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 3 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, see . + * + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + */ + +/* + * An IEC 61131-3 compiler. + * + * Based on the + * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) + * + */ + + +/* + * Search for a specific label in an IL list. + * + * when instantiated, must be given a pointer to one of the following + * - function_declaration_c + * - function_block_declaration_c + * - program_declaration_c + * - instruction_list_c + * + * which is where all calls to search for a specific label will look for said label. + */ + + + +#include "absyntax_utils.hh" + + + +/* set to 1 to see debug info during execution */ +static int debug = 0; + +search_il_label_c::search_il_label_c(symbol_c *search_scope) { + this->search_scope = search_scope; + this->search_label = NULL; +} + +search_il_label_c::~search_il_label_c(void) { +} + + +il_instruction_c *search_il_label_c::find_label(const char *label) { + return find_label(new identifier_c(label)); +} + + +il_instruction_c *search_il_label_c::find_label(symbol_c *label) { + search_label = label; + il_instruction_c *res = (il_instruction_c *)search_scope->accept(*this); + search_label = NULL; + return res; +} + + +/****************************************/ +/* B.2 - Language IL (Instruction List) */ +/****************************************/ +/***********************************/ +/* B 2.1 Instructions and Operands */ +/***********************************/ + +/* | label ':' [il_incomplete_instruction] eol_list */ +// SYM_REF2(il_instruction_c, label, il_instruction) +// void *visit(instruction_list_c *symbol); +void *search_il_label_c::visit(il_instruction_c *symbol) { +// printf("search_il_label_c::visit(il_instruction_c *symbol): searching for %s\n", ((identifier_c *)search_label)->value); + if (NULL != symbol->label) + if (compare_identifiers(search_label, symbol->label) == 0) + return symbol; + + return NULL; +} + + + + diff -r 34a5571c859c -r 0bb88139e471 absyntax_utils/search_il_label.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/absyntax_utils/search_il_label.hh Sat Mar 31 21:46:37 2012 +0100 @@ -0,0 +1,95 @@ +/* + * matiec - a compiler for the programming languages defined in IEC 61131-3 + * + * Copyright (C) 2012 Mario de Sousa (msousa@fe.up.pt) + * + * + * 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 3 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, see . + * + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + */ + +/* + * An IEC 61131-3 compiler. + * + * Based on the + * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) + * + */ + + +/* + * Search for a specific label in an IL list. + * + * when instantiated, must be given a pointer to one of the following + * - function_declaration_c + * - function_block_declaration_c + * - program_declaration_c + * - instruction_list_c + * + * which is where all calls to search for a specific label will look for said label. + */ + + + +#include "../absyntax_utils/absyntax_utils.hh" + + +class search_il_label_c: public search_visitor_c { + + private: + search_varfb_instance_type_c *search_varfb_instance_type; + symbol_c *search_scope; + symbol_c *search_label; + + public: + search_il_label_c(symbol_c *search_scope); + virtual ~search_il_label_c(void); + + il_instruction_c *find_label(const char *label); + il_instruction_c *find_label(symbol_c *label); + + + /****************************************/ + /* B.2 - Language IL (Instruction List) */ + /****************************************/ + /***********************************/ + /* B 2.1 Instructions and Operands */ + /***********************************/ +// void *visit(instruction_list_c *symbol); + void *visit(il_instruction_c *symbol); +// void *visit(il_simple_operation_c *symbol); +// void *visit(il_function_call_c *symbol); +// void *visit(il_expression_c *symbol); +// void *visit(il_fb_call_c *symbol); +// void *visit(il_formal_funct_call_c *symbol); +// void *visit(il_operand_list_c *symbol); +// void *visit(simple_instr_list_c *symbol); +// void *visit(il_simple_instruction_c*symbol); +// void *visit(il_param_list_c *symbol); +// void *visit(il_param_assignment_c *symbol); +// void *visit(il_param_out_assignment_c *symbol); + + +}; // search_il_label_c + + + + + + + + diff -r 34a5571c859c -r 0bb88139e471 absyntax_utils/search_var_instance_decl.cc --- a/absyntax_utils/search_var_instance_decl.cc Thu Mar 22 00:22:48 2012 +0100 +++ b/absyntax_utils/search_var_instance_decl.cc Sat Mar 31 21:46:37 2012 +0100 @@ -77,10 +77,14 @@ return (symbol_c *)search_scope->accept(*this); } -unsigned int search_var_instance_decl_c::get_vartype(void) { +unsigned int search_var_instance_decl_c::get_vartype(symbol_c *variable_instance_name) { + this->current_vartype = none_vt; + this->search_name = variable_instance_name; + search_scope->accept(*this); return current_vartype; } + /***************************/ /* B 0 - Programming Model */ /***************************/ diff -r 34a5571c859c -r 0bb88139e471 absyntax_utils/search_var_instance_decl.hh --- a/absyntax_utils/search_var_instance_decl.hh Thu Mar 22 00:22:48 2012 +0100 +++ b/absyntax_utils/search_var_instance_decl.hh Sat Mar 31 21:46:37 2012 +0100 @@ -77,7 +77,8 @@ public: search_var_instance_decl_c(symbol_c *search_scope); symbol_c *get_decl(symbol_c *variable_instance_name); - unsigned int get_vartype(void); + + unsigned int get_vartype(symbol_c *variable_instance_name); public: diff -r 34a5571c859c -r 0bb88139e471 absyntax_utils/search_varfb_instance_type.cc --- a/absyntax_utils/search_varfb_instance_type.cc Thu Mar 22 00:22:48 2012 +0100 +++ b/absyntax_utils/search_varfb_instance_type.cc Sat Mar 31 21:46:37 2012 +0100 @@ -1,7 +1,7 @@ /* * matiec - a compiler for the programming languages defined in IEC 61131-3 * - * Copyright (C) 2003-2011 Mario de Sousa (msousa@fe.up.pt) + * Copyright (C) 2003-2012 Mario de Sousa (msousa@fe.up.pt) * Copyright (C) 2007-2011 Laurent Bessard and Edouard Tisserant * * This program is free software: you can redistribute it and/or modify @@ -75,225 +75,155 @@ * * Member functions: * ================ + * get_basetype_id() ---> returns 2A (implemented, although currently it is not needed! ) * get_basetype_decl() ---> returns 2B * get_type_id() ---> returns 1A * - * Since we haven't yet needed them, we don't yet implement - * get_basetype_id() ----> would return 2A - * get_type_decl() ----> would return 1B + * Since we haven't yet needed it, we don't yet implement + * get_type_decl() ---> returns 1B */ -/* - * TODO: this code has a memory leak... - * We call 'new' in several locations, but bever get to 'delete' the object instances... - */ + #include "absyntax_utils.hh" +void search_varfb_instance_type_c::init(void) { + this->current_type_id = NULL; + this->current_basetype_id = NULL; + this->current_basetype_decl = NULL; + this->current_field_selector = NULL; + this->is_complex = false; +} + + search_varfb_instance_type_c::search_varfb_instance_type_c(symbol_c *search_scope): search_var_instance_decl(search_scope) { - this->decompose_var_instance_name = NULL; - this->current_structelement_name = NULL; - this->current_typeid = NULL; - this->current_basetypeid = NULL; -} - -symbol_c *search_varfb_instance_type_c::get_type_decl(symbol_c *variable_name) { - this->current_structelement_name = NULL; - this->current_typeid = NULL; - this->current_basetypeid = NULL; - this->decompose_var_instance_name = new decompose_var_instance_name_c(variable_name); - if (NULL == decompose_var_instance_name) ERROR; - - /* find the part of the variable name that will appear in the - * variable declaration, for e.g., in window.point.x, this would be - * window! - */ - symbol_c *var_name_part = decompose_var_instance_name->next_part(); - if (NULL == var_name_part) ERROR; - - /* Now we try to find the variable instance declaration, to determine its type... */ - symbol_c *var_decl = search_var_instance_decl.get_decl(var_name_part); - if (NULL == var_decl) ERROR; - - /* if it is a struct or function block, we must search the type - * of the struct or function block member. - * This is done by this class visiting the var_decl. - * This class, while visiting, will recursively call - * decompose_var_instance_name->get_next() when and if required... - */ - symbol_c *res = (symbol_c *)var_decl->accept(*this); - /* NOTE: A Null result is not really an internal compiler error, but rather an error in - * the IEC 61131-3 source code being compiled. This means we cannot just abort the compiler with ERROR. - * // if (NULL == res) ERROR; - */ - if (NULL == res) return NULL; - - /* make sure that we have decomposed all structure elements of the variable name */ - symbol_c *var_name = decompose_var_instance_name->next_part(); - /* NOTE: A non-NULL result is not really an internal compiler error, but rather an error in - * the IEC 61131-3 source code being compiled. - * (for example, 'int_var.struct_elem' in the source code, when 'int_var' is a simple integer, - * and not a structure, will result in this result being non-NULL!) - * This means we cannot just abort the compiler with ERROR. - * // if (NULL != var_name) ERROR; - */ - if (NULL != var_name) return NULL; - - return res; + this->init(); +} + + +/* We expect to be passed a symbolic_variable_c */ +symbol_c *search_varfb_instance_type_c::get_type_id(symbol_c *variable_name) { + this->init(); + variable_name->accept(*this); + return current_type_id; +} + + +symbol_c *search_varfb_instance_type_c::get_basetype_id(symbol_c *variable_name) { + this->init(); + variable_name->accept(*this); + return current_basetype_id; } symbol_c *search_varfb_instance_type_c::get_basetype_decl(symbol_c *variable_name) { - symbol_c *res = get_type_decl(variable_name); - if (NULL == res) return NULL; - return (symbol_c *)base_type(res); + this->init(); + variable_name->accept(*this); + return current_basetype_decl; } + + + unsigned int search_varfb_instance_type_c::get_vartype(symbol_c *variable_name) { - this->current_structelement_name = NULL; - this->current_typeid = NULL; - this->current_basetypeid = NULL; - this->is_complex = false; - this->decompose_var_instance_name = new decompose_var_instance_name_c(variable_name); - if (NULL == decompose_var_instance_name) ERROR; - - /* find the part of the variable name that will appear in the - * variable declaration, for e.g., in window.point.x, this would be - * window! - */ - symbol_c *var_name_part = decompose_var_instance_name->next_part(); - if (NULL == var_name_part) ERROR; - - /* Now we try to find the variable instance declaration, to determine its type... */ - symbol_c *var_decl = search_var_instance_decl.get_decl(var_name_part); - if (NULL == var_decl) { - /* variable instance declaration not found! */ - return 0; - } - - /* if it is a struct or function block, we must search the type - * of the struct or function block member. - * This is done by this class visiting the var_decl. - * This class, while visiting, will recursively call - * decompose_var_instance_name->get_next() when and if required... - */ - var_decl->accept(*this); - unsigned int res = search_var_instance_decl.get_vartype(); - - /* make sure that we have decomposed all structure elements of the variable name */ - symbol_c *var_name = decompose_var_instance_name->next_part(); - if (NULL != var_name) ERROR; - - return res; -} - -symbol_c *search_varfb_instance_type_c::get_type_id(symbol_c *variable_name) { - this->current_typeid = NULL; - symbol_c *vartype = this->get_type_decl(variable_name); - if (this->current_typeid != NULL) - return this->current_typeid; - else - return vartype; -} + this->init(); + return search_var_instance_decl.get_vartype(variable_name); +} + + bool search_varfb_instance_type_c::type_is_complex(void) { return this->is_complex; } -/* a helper function... */ -void *search_varfb_instance_type_c::visit_list(list_c *list) { - if (NULL == current_structelement_name) ERROR; - - for(int i = 0; i < list->n; i++) { - void *res = list->elements[i]->accept(*this); - if (res != NULL) - return res; - } - /* not found! */ - return NULL; -} - -/* a helper function... */ -void *search_varfb_instance_type_c::base_type(symbol_c *symbol) { - search_base_type_c search_base_type; - return symbol->accept(search_base_type); -} - -/* We override the base class' visitor to identifier_c. - * This is so because the base class does not consider a function block - * to be a type, unlike this class that allows a variable instance - * of a function block type... - */ -void *search_varfb_instance_type_c::visit(identifier_c *type_name) { - /* we only store the new type id if none had been found yet. - * Since we will recursively carry on looking at the base type - * to determine the base type declaration and id, we must only set this variable - * the first time. - * e.g. TYPE myint1_t : int := 1; - * myint2_t : int1_t := 2; - * myint3_t : int2_t := 3; - * END_TYPE; - * VAR - * myint1 : myint1_t; - * myint2 : myint2_t; - * myint3 : myint3_t; - * END_VAR - * - * If we ask for typeid of myint3, it must return myint3_t - * If we ask for basetypeid of myint3, it must return int - * - * When determining the data type of myint3, we will recursively go all the way - * down to int, but we must still only store myint3_t as the base type id. + + + +/*************************/ +/* B.1 - Common elements */ +/*************************/ +/*******************************************/ +/* B 1.1 - Letters, digits and identifiers */ +/*******************************************/ +// SYM_TOKEN(identifier_c) +void *search_varfb_instance_type_c::visit(identifier_c *variable_name) { + /* symbol should be a variable name!! */ + /* Note: although the method is called get_decl(), it is getting the declaration of the variable, which for us is the type_id of that variable! */ + current_type_id = search_var_instance_decl.get_decl (variable_name); + current_basetype_decl = search_base_type.get_basetype_decl(current_type_id); + current_basetype_id = search_base_type.get_basetype_id (current_type_id); + + /* What if the variable has not been declared? Then this should not be a compiler error! + * However, currently stage 2 of the compiler already detects when variables have not been delcared, + * so if the variable's declaration is not found, then that means that we have an internal compiler error! */ - if (NULL == this->current_typeid) - this->current_typeid = type_name; - this->current_basetypeid = type_name; - - /* look up the type declaration... */ - symbol_c *fb_decl = function_block_type_symtable.find_value(type_name); - if (fb_decl != function_block_type_symtable.end_value()) - /* Type declaration found!! */ - return fb_decl->accept(*this); - - /* No. It is not a function block, so we let - * the base class take care of it... - */ - return search_base_type_c::visit(type_name); -} + if (NULL == current_type_id) ERROR; + + return NULL; +} + + + + /********************************/ /* B 1.3.3 - Derived data types */ /********************************/ - /* identifier ':' array_spec_init */ +/* NOTE: I don't think this will ever get called, since in the visit method for array_variable_c + * we use the basetype_decl for recursively calling this class, and the base type should never be a + * array_type_declaration_c, but for now, let's leave it in... + */ void *search_varfb_instance_type_c::visit(array_type_declaration_c *symbol) { - return symbol->array_spec_init->accept(*this); + ERROR; + return NULL; } /* array_specification [ASSIGN array_initialization] */ /* array_initialization may be NULL ! */ +/* NOTE: I don't think this will ever get called, since in the visit method for array_variable_c + * we use the basetype_decl for recursively calling this class, and the base type should never be a + * array_spec_init_c, but for now, let's leave it in... + */ void *search_varfb_instance_type_c::visit(array_spec_init_c *symbol) { - return symbol->array_specification->accept(*this); + /* Note that the 'array_specification' may be either an identifier of a previsously defined array type, + * or an array_specification_c, so we can not stop here and simply return a array_spec_init_c, + * especially if we are looking for the base class! + */ + ERROR; + return NULL; } /* ARRAY '[' array_subrange_list ']' OF non_generic_type_name */ +/* NOTE: This method will be reached after being called from the + * search_varfb_instance_type_c::visit(array_variable_c *symbol) + * method, so we must return the data type of the data stored in the array, + * and not the data type of the array itself! + */ void *search_varfb_instance_type_c::visit(array_specification_c *symbol) { - this->is_complex = true; - this->current_typeid = symbol; - return symbol->non_generic_type_name->accept(*this); -} + /* found the type of the element we were looking for! */ + current_type_id = symbol->non_generic_type_name; + current_basetype_decl = search_base_type.get_basetype_decl(current_type_id); + current_basetype_id = search_base_type.get_basetype_id (current_type_id); + + return NULL; +} + /* structure_type_name ':' structure_specification */ /* NOTE: this is only used inside a TYPE ... END_TYPE declaration. * It is never used directly when declaring a new variable! */ +/* NOTE: I don't think this will ever get called, since in the visit method for structured_variable_c + * we use the basetype_decl for recursively calling this class, and the base type should never be a + * structure_type_declaration_c, but for now, let's leave it in... + */ void *search_varfb_instance_type_c::visit(structure_type_declaration_c *symbol) { - this->is_complex = true; - - if (NULL == current_structelement_name) ERROR; - return symbol->structure_specification->accept(*this); + if (NULL == current_field_selector) ERROR; + symbol->structure_specification->accept(*this); + return NULL; /* NOTE: structure_specification will point to either a * initialized_structure_c * OR A @@ -304,51 +234,42 @@ /* structure_type_name ASSIGN structure_initialization */ /* structure_initialization may be NULL ! */ // SYM_REF2(initialized_structure_c, structure_type_name, structure_initialization) -/* NOTE: only the initialized structure is ever used when declaring a new variable instance */ +/* NOTE: only the initialized structure is never used when declaring a new variable instance */ +/* NOTE: I don't think this will ever get called, since in the visit method for structured_variable_c + * we use the basetype_decl for recursively calling this class, and the base type should never be a + * initialized_structure_c, but for now, let's leave it in... + */ void *search_varfb_instance_type_c::visit(initialized_structure_c *symbol) { - this->is_complex = true; - if (NULL != current_structelement_name) ERROR; - - /* make sure that we have decomposed all structure elements of the variable name */ - symbol_c *var_name = decompose_var_instance_name->next_part(); - if (NULL == var_name) { - /* this is it... ! - * No need to look any further... - * Note also that, unlike for the struct types, a function block may - * not be defined based on another (i.e. no inheritance is allowed), - * so this function block is already the most base type. - * We simply return it. - */ - return (void *)symbol; - } - - /* reset current_type_id because of new structure element part */ - this->current_typeid = NULL; - - /* look for the var_name in the structure declaration */ - current_structelement_name = var_name; - - /* recursively find out the data type of current_structelement_name... */ - return symbol->structure_type_name->accept(*this); + if (NULL != current_field_selector) ERROR; + + /* recursively find out the data type of current_field_selector... */ + symbol->structure_type_name->accept(*this); + return NULL; } /* helper symbol for structure_declaration */ /* structure_declaration: STRUCT structure_element_declaration_list END_STRUCT */ /* structure_element_declaration_list structure_element_declaration ';' */ void *search_varfb_instance_type_c::visit(structure_element_declaration_list_c *symbol) { - if (NULL == current_structelement_name) ERROR; + if (NULL == current_field_selector) ERROR; + /* now search the structure declaration */ - return visit_list(symbol); + for(int i = 0; i < symbol->n; i++) { + symbol->elements[i]->accept(*this); + } + + return NULL; } /* structure_element_name ':' spec_init */ void *search_varfb_instance_type_c::visit(structure_element_declaration_c *symbol) { - if (NULL == current_structelement_name) ERROR; - - if (compare_identifiers(symbol->structure_element_name, current_structelement_name) == 0) { - current_structelement_name = NULL; + if (NULL == current_field_selector) ERROR; + + if (compare_identifiers(symbol->structure_element_name, current_field_selector) == 0) { /* found the type of the element we were looking for! */ - return symbol->spec_init->accept(*this); + current_type_id = symbol->spec_init; + current_basetype_decl = search_base_type.get_basetype_decl(current_type_id); + current_basetype_id = search_base_type.get_basetype_id (current_type_id); } /* Did not find the type of the element we were looking for! */ @@ -364,6 +285,73 @@ void *search_varfb_instance_type_c::visit(structure_element_initialization_c *symbol) {ERROR; return NULL;} /* should never get called... */ +/*********************/ +/* B 1.4 - Variables */ +/*********************/ +// SYM_REF1(symbolic_variable_c, var_name) +void *search_varfb_instance_type_c::visit(symbolic_variable_c *symbol) { + symbol->var_name->accept(*this); + return NULL; +} + +/********************************************/ +/* B.1.4.1 Directly Represented Variables */ +/********************************************/ +// SYM_TOKEN(direct_variable_c) +/* We do not yet handle this. Will we ever need to handle it, as the data type of the direct variable is + * directly obtainable from the syntax of the direct variable itself? + */ + +/*************************************/ +/* B 1.4.2 - Multi-element variables */ +/*************************************/ +/* subscripted_variable '[' subscript_list ']' */ +// SYM_REF2(array_variable_c, subscripted_variable, subscript_list) +/* NOTE: when passed a array_variable_c, which represents some IEC61131-3 code similar to X[42] + * we must return the data type of the value _stored_ in the array. + * If you want to get the data type of the array itself (i.e. just the X variable, without the [42]) + * then this class must be called with the identifier_c 'X'. + */ +void *search_varfb_instance_type_c::visit(array_variable_c *symbol) { + this->is_complex = true; + + /* determine the data type of the subscripted_variable... + * This should be an array_specification_c + * ARRAY [xx..yy] OF Stored_Data_Type + */ + symbol->subscripted_variable->accept(*this); + + /* Now we determine the 'Stored_Data_Type', i.e. the data type of the variable stored in the array. */ + if (NULL != current_basetype_decl) { + current_basetype_decl->accept(*this); + } + + return NULL; +} + + +/* record_variable '.' field_selector */ +/* WARNING: input and/or output variables of function blocks + * may be accessed as fields of a structured variable! + * Code handling a structured_variable_c must take + * this into account! + */ +// SYM_REF2(structured_variable_c, record_variable, field_selector) +void *search_varfb_instance_type_c::visit(structured_variable_c *symbol) { + this->is_complex = true; + symbol->record_variable->accept(*this); + + /* Now we search for the data type of the field... But only if we were able to determine the data type of the variable */ + if (NULL != current_basetype_decl) { + current_field_selector = symbol->field_selector; + current_basetype_decl->accept(*this); + current_field_selector = NULL; + } + + return NULL; +} + + /**************************************/ /* B.1.5 - Program organization units */ @@ -371,46 +359,18 @@ /*****************************/ /* B 1.5.2 - Function Blocks */ /*****************************/ + /* FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */ // SYM_REF4(function_block_declaration_c, fblock_name, var_declarations, fblock_body, unused) void *search_varfb_instance_type_c::visit(function_block_declaration_c *symbol) { - /* make sure that we have decomposed all structure elements of the variable name */ - symbol_c *var_name = decompose_var_instance_name->next_part(); - if (NULL == var_name) { - /* this is it... ! - * No need to look any further... - * Note also that, unlike for the struct types, a function block may - * not be defined based on another (i.e. no inheritance is allowed), - * so this function block is already the most base type. - * We simply return it. - */ - return (void *)symbol; - } - - /* reset current_type_id because of new structure element part */ - this->current_typeid = NULL; - - /* now search the function block declaration for the variable... */ - search_var_instance_decl_c search_decl(symbol); - symbol_c *var_decl = search_decl.get_decl(var_name); - if (NULL == var_decl) { - /* variable instance declaration not found! */ - return NULL; - } -#if 0 - /* We have found the declaration. - * Should we look any further? - */ - var_name = decompose_var_instance_name->next_part(); - if (NULL == var_name) { - /* this is it... ! */ - return base_type(var_decl); - } - - current_structelement_name = var_name; - /* recursively find out the data type of var_name... */ - return symbol->var_declarations->accept(*this); -#endif - /* carry on recursively, in case the variable has more elements to be decomposed... */ - return var_decl->accept(*this); -} + if (NULL == current_field_selector) ERROR; + + /* now search the function block declaration for the variable... */ + /* If not found, these pointers will all be set to NULL!! */ + search_var_instance_decl_c search_decl(symbol); + current_type_id = search_decl.get_decl(current_field_selector); + current_basetype_decl = search_base_type.get_basetype_decl(current_type_id); + current_basetype_id = search_base_type.get_basetype_id (current_type_id); + + return NULL; +} diff -r 34a5571c859c -r 0bb88139e471 absyntax_utils/search_varfb_instance_type.hh --- a/absyntax_utils/search_varfb_instance_type.hh Thu Mar 22 00:22:48 2012 +0100 +++ b/absyntax_utils/search_varfb_instance_type.hh Sat Mar 31 21:46:37 2012 +0100 @@ -1,7 +1,7 @@ /* * matiec - a compiler for the programming languages defined in IEC 61131-3 * - * Copyright (C) 2003-2011 Mario de Sousa (msousa@fe.up.pt) + * Copyright (C) 2003-2012 Mario de Sousa (msousa@fe.up.pt) * Copyright (C) 2007-2011 Laurent Bessard and Edouard Tisserant * * This program is free software: you can redistribute it and/or modify @@ -77,41 +77,44 @@ * * Member functions: * ================ + * get_basetype_id() ---> returns 2A (implemented, although currently it is not needed! ) * get_basetype_decl() ---> returns 2B * get_type_id() ---> returns 1A * - * Since we haven't yet needed them, we don't yet implement - * get_basetype_id() ----> would return 2A - * get_type_decl() ----> would return 1B + * Since we haven't yet needed it, we don't yet implement + * get_type_decl() ---> returns 1B */ -class search_varfb_instance_type_c: public search_base_type_c { +class search_varfb_instance_type_c : null_visitor_c { private: search_var_instance_decl_c search_var_instance_decl; - decompose_var_instance_name_c *decompose_var_instance_name; - symbol_c *current_structelement_name; - symbol_c *current_typeid; - symbol_c *current_basetypeid; + search_base_type_c search_base_type; + +// symbol_c *current_type_decl; + symbol_c *current_type_id; + symbol_c *current_basetype_decl; + symbol_c *current_basetype_id; + + symbol_c *current_field_selector; + bool is_complex; + + /* sets all the above variables to NULL, or false */ + void init(void); public: search_varfb_instance_type_c(symbol_c *search_scope); symbol_c *get_basetype_decl(symbol_c *variable_name); - symbol_c *get_type_decl(symbol_c *variable_name); + symbol_c *get_basetype_id (symbol_c *variable_name); +// symbol_c *get_type_decl(symbol_c *variable_name); symbol_c *get_type_id(symbol_c *variable_name); - /* NOTE: this function should be remvoed/deleted. + /* NOTE: I have a feeling that this function should be remvoed/deleted. * However, it is currently used in stage 4, and before deleting it * requires that the stage4 code be analysed and fixed (i.e. replace by * a call to one of the above functions get_basetype_decl(), * get_type_decl(), get_type_id(). - * - * At the moment, I have a feeling that this whole class search_varfb_instance_type_c - * will not be needed in the future (i.e. when we finish implementing type checking - * in stage 3 correctly, where we store on each symbol in the abstract syntax - * tree it's data type, so stage4 implementations will not need to deduce the data - * types again), so it does not make much sense to spend more time on it. */ unsigned int get_vartype(symbol_c *variable_name); bool type_is_complex(void); @@ -125,17 +128,17 @@ private: - /* We override the base class' visitor to identifier_c. - * This is so because the base class does not consider a function block - * to be a type, unlike this class that allows a variable instance - * of a function block type... - */ - void *visit(identifier_c *type_name); - + /*************************/ + /* B.1 - Common elements */ + /*************************/ + /*******************************************/ + /* B 1.1 - Letters, digits and identifiers */ + /*******************************************/ + void *visit(identifier_c *variable_name); + /********************************/ /* B 1.3.3 - Derived data types */ /********************************/ - /* identifier ':' array_spec_init */ void *visit(array_type_declaration_c *symbol); @@ -170,7 +173,20 @@ void *visit(structure_element_initialization_c *symbol); /* should never get called... */ - + /*********************/ + /* B 1.4 - Variables */ + /*********************/ + void *visit(symbolic_variable_c *symbol); + + /********************************************/ + /* B.1.4.1 Directly Represented Variables */ + /********************************************/ + /*************************************/ + /* B 1.4.2 - Multi-element variables */ + /*************************************/ + void *visit(array_variable_c *symbol); + void *visit(structured_variable_c *symbol); + /**************************************/ /* B.1.5 - Program organization units */ /**************************************/ diff -r 34a5571c859c -r 0bb88139e471 absyntax_utils/type_initial_value.cc --- a/absyntax_utils/type_initial_value.cc Thu Mar 22 00:22:48 2012 +0100 +++ b/absyntax_utils/type_initial_value.cc Sat Mar 31 21:46:37 2012 +0100 @@ -366,13 +366,13 @@ * as would be expected! */ /* string_type_name ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init */ -#if 0 -SYM_REF4(string_type_declaration_c, string_type_name, - elementary_string_type_name, - string_type_declaration_size, - string_type_declaration_init) /* may be == NULL! */ -#endif -void *type_initial_value_c::visit(string_type_declaration_c *symbol) {return NULL;} +// SYM_REF4(string_type_declaration_c, string_type_name, +// elementary_string_type_name, +// string_type_declaration_size, +// string_type_declaration_init) /* may be == NULL! */ +void *type_initial_value_c::visit(string_type_declaration_c *symbol) { + return handle_type_spec(symbol->elementary_string_type_name, symbol->string_type_declaration_init); +} type_initial_value_c *type_initial_value_c::_instance = NULL; diff -r 34a5571c859c -r 0bb88139e471 absyntax_utils/type_initial_value.hh --- a/absyntax_utils/type_initial_value.hh Thu Mar 22 00:22:48 2012 +0100 +++ b/absyntax_utils/type_initial_value.hh Sat Mar 31 21:46:37 2012 +0100 @@ -279,12 +279,10 @@ * as would be expected! */ /* string_type_name ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init */ -#if 0 -SYM_REF4(string_type_declaration_c, string_type_name, - elementary_string_type_name, - string_type_declaration_size, - string_type_declaration_init) /* may be == NULL! */ -#endif + // SYM_REF4(string_type_declaration_c, string_type_name, + // elementary_string_type_name, + // string_type_declaration_size, + // string_type_declaration_init) /* may be == NULL! */ void *visit(string_type_declaration_c *symbol); }; // type_initial_value_c diff -r 34a5571c859c -r 0bb88139e471 lib/create_standard_function_txt.sh --- a/lib/create_standard_function_txt.sh Thu Mar 22 00:22:48 2012 +0100 +++ b/lib/create_standard_function_txt.sh Sat Mar 31 21:46:37 2012 +0100 @@ -711,6 +711,13 @@ /**************/ /* Should be for: ANY_ELEMENTARY, but we currently do not support WSTRING yet... */ /* However, we can call __ANY_ELEMENTARY since the __ANY_STRING macro does not call DO(WSTRING) */ +/* NOTE (by mjs) : The following declaration is worng, as it assumes that only 2 parameter may be used! + * The NE function is actually an extensible function, that may be called with more than 2 parameters! + * This needs to be fixed!! + * The correct definition is: + * __function_1e(NE, BOOL, IN, TYPENAME, 1) + * __function_1e(NE_##TYPENAME, BOOL, IN, TYPENAME, 1) + */ #define __iec_(TYPENAME) \ __function_2p(NE, BOOL, IN1, TYPENAME, IN2, TYPENAME) /* overloaded function */ \ __function_2p(NE_##TYPENAME, BOOL, IN1, TYPENAME, IN2, TYPENAME) /* explicitly typed function */ diff -r 34a5571c859c -r 0bb88139e471 lib/iec_std_lib.h --- a/lib/iec_std_lib.h Thu Mar 22 00:22:48 2012 +0100 +++ b/lib/iec_std_lib.h Sat Mar 31 21:46:37 2012 +0100 @@ -1753,6 +1753,10 @@ /* NE */ /**************/ +/* NOTE (by mjs) : The following declaration is worng, as it assumes that only 2 parameter may be used! + * The NE function is actually an extensible function, that may be called with more than 2 parameters! + * This needs to be fixed!! + */ #define __ne_num(fname, TYPENAME) \ static inline BOOL fname(EN_ENO_PARAMS, TYPENAME op1, TYPENAME op2){\ TEST_EN(BOOL)\ diff -r 34a5571c859c -r 0bb88139e471 readme --- a/readme Thu Mar 22 00:22:48 2012 +0100 +++ b/readme Sat Mar 31 21:46:37 2012 +0100 @@ -8,7 +8,64 @@ FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) - Copyright (C) 2003-2011 Mario de Sousa (msousa@fe.up.pt) + Copyright (C) 2003-2012 Mario de Sousa (msousa@fe.up.pt) + + +**************************************************************** +**************************************************************** +**************************************************************** +********* ********* +********* ********* +********* O V E R A L L G O A L S ********* +********* ********* +********* ********* +**************************************************************** +**************************************************************** +**************************************************************** + + + + This project has the goal of producing an open source compiler for the programming languages defined +in the IEC 61131-3 standard. These programming languages are mostly used in the industrial automation +domain, to program PLCs (Programmable Logic Controllers). + + This standard defines 5 programming languages: + - IL : Instructtion List + A textual programming language, somewhat similar to assembly. + - ST : Structured Text + A textual programming language, somewhat similar to Pascal. + - FBD: Function Block Diagram + A graphical programming language, somewhat similar to an electrical circuit diagram based on small + scale integration ICs (Integrated Circuits) (counters, AND/OR/XOR/... logic gates, timers, ...). + - LD : Ladder Diagram + A graphical programming language, somewhat similar to an electrical circuit diagram based on + relays (used for basic cabled logic controllers). + - SFC: Sequential Function Chart + A graphical programming language, that defines a state machine, based largely on Grafcet. + (may also be expressed in textual format). + + Of the above 5 languages, the standard defines textual representations for IL, ST and SFC. +It is these 3 languages that we target, and we currently support all three, as long as they are +expressed in the textual format as defined in the standard. + + Currently the matiec project generates two compilers (more correctly, code translaters, but we like +to call them compilers :-O ): iec2c, and iec2iec + + Both compilers accept the same input: a text file with ST, IL and/or SFC code. + + The iec2c compiler generates ANSI C code which is equivalent to the IEC 61131-3 code expressed in the input file. + + The iec2iec compiler generates IEC61131-3 code which is equivalent to the IEC 61131-3 code expressed in the input file. +This last compiler should generate and output file which should be almost identical to the input file (some formating +may change, as well as the case of letters, etc.). This 'compiler' is mostly used by the matiec project contributors +to help debug the lexical and syntax portions of the compilers. + + + + To compile/build these compilers, just +$./configure; make + + @@ -25,26 +82,111 @@ **************************************************************** The compiler works in 4(+1) stages: - Stage 1 - Lexical analyser - implemented with flex (iec.flex) - Stage 2 - Syntax parser - implemented with bison (iec.y) - Stage 3 - Semantics analyser - currently in its early stages - Stage 4 - Code generator - implemented in C++ - Stage 4+1 - Binary code generator - gcc, javac, etc... + ================================== + Stage 1 - Lexical analyser - implemented with flex (stage1_2/iec_flex.ll) + Stage 2 - Syntax parser - implemented with bison (stage1_2/iec_bison.yy) + Stage pre3 - Populate symbol tables - Symbol tables that will ease searching for symbols in the abstract symbol tree. + Stage 3 - Semantics analyser - currently does type checking only + Stage 4 - Code generator - generates ANSI C code + + Stage 5 - Binary code generator - gcc, javac, etc... (Not integrated into matiec compiler. Must be called explicitly by the user.) + Data structures passed between stages, in global variables: - 1->2 : tokens (int), and token values (char *) - 2->1 : symbol tables (defined in symtable.hh) - 2->3 : abstract syntax tree (tree of C++ classes, in absyntax.hh file) - 3->4 : Same as 2->3 - 4->4+1 : file with program in c, java, etc... + ========================================================== + 1->2 : tokens (int), and token values (char *) (defined in stage1_2/stage1_2_priv.hh) + 2->1 : symbol tables (implemented in util/symtable.[hh|cc], and defined in stage1_2/stage1_2_priv.hh) + 2->3 : abstract syntax tree (tree of C++ objects, whose classes are defined in absyntax/absyntax.hh) +pre3->3,4 : global symbol tables (defined in util/[d]symtable.[hh|cc] and declared in absyntax_utils/absyntax_utils.hh) + 3->4 : abstract syntax tree (same as 2->3), but now annotated (i.e. some extra data inserted into the absyntax tree) + + 4->5 : file with program in c, java, etc... + + The compiler works in several passes: - Pass 1: executes stages 1 and 2 simultaneously - Pass 2: executes stage 3 - Pass 3: executes stage 4 - Pass 4: executes stage 4+1 + ==================================== + +Stage 1 and Stage 2 +------------------- + Executed in one single pass. This pass will: + - Do lexical analysis + - Do syntax analysis + - Execute the absyntax_utils/add_en_eno_param_decl_c visitor class + This class will add the EN and ENO parameter declarations to all + functions that do not have them already explicitly declared by the user. + This will let us handle these parameters in the remaining compiler just as if + they were standard input/output parameters. + + +Stage Pre3 +---------- + Executed in one single pass. This pass will populate the following symbol tables: + - function_symtable; /* A symbol table with all globally declared functions POUs. */ + - function_block_type_symtable; /* A symbol table with all globally declared functions block POUs. */ + - program_type_symtable; /* A symbol table with all globally declared program POUs. */ + - type_symtable; /* A symbol table with all user declared (non elementary) datat type definitions. */ + - enumerated_value_symtable; /* A symbol table with all identifiers (values) declared for enumerated types. */ + + +Stage 3 +------- + Executes two algorithms (flow control analysis, and data type analysis) in several passes. + + Flow control: + Pass 1: Does flow control analysis (for now only of IL code) + Implemented in -> stage3/flow_control_analysis_c + This will anotate the abstract syntax tree + (Every object of the class il_instruction_c that is in the abstract syntax tree will have the variable 'prev_il_instruction' correctly filled in.) + + Data Type Analysis + Pass 1: Analyses the possible data types each expression/literal/IL instruction/etc. may take + Implemented in -> stage3/fill_candidate_datatypes_c + This will anotate the abstract syntax tree + (Every object of in the abstract syntax tree that may have a data type, will have the variable 'candidate_datatypes' correctly filled in. + Additionally, objects in the abstract syntax tree that represen function invocations will have the variable + 'candidate_functions' correctly filled in.) +Pass 2: Narrows all the possible data types each expression/literal/IL instruction/etc. may take down to a single data type + Implemented in -> stage3/narrow_candidate_datatypes_c + This will anotate the abstract syntax tree + (Every object of in the abstract syntax tree that may have a data type, will have the variable 'datatype' correctly filled in. + Additionally, objects in the abstract syntax tree that represen function invocations will have the variables + 'called_function_declaration' and 'extensible_param_count' correctly filled in. + Additionally, objects in the abstract syntax tree that represen function block (FB) invocations will have the variable + 'called_fb_declaration' correctly filled in.) + Pass 2: Prints error messages in the event of the IEC 61131-3 source code being analysed contains semantic data type incompatibility errors. + Implemented in -> stage3/print_datatype_errors_c + + +Stage 4 +------- + Has 2 possible implementations. + + iec2c : Generates C source code in a single pass (stage4/generate_c). + iec2iec: Generates IEC61131 source code in a single pass (stage4/generate_iec). + + + + + + +**************************************************************** +**************************************************************** +**************************************************************** +********* ********* +********* ********* +********* N O T E S ********* +********* ********* +********* ********* +**************************************************************** +**************************************************************** +**************************************************************** + + + + NOTE 1 @@ -388,4 +530,4 @@ ************************************************************************** - Copyright (C) 2003-2011 Mario de Sousa (msousa@fe.up.pt) + Copyright (C) 2003-2012 Mario de Sousa (msousa@fe.up.pt) diff -r 34a5571c859c -r 0bb88139e471 stage1_2/iec_bison.yy --- a/stage1_2/iec_bison.yy Thu Mar 22 00:22:48 2012 +0100 +++ b/stage1_2/iec_bison.yy Sat Mar 31 21:46:37 2012 +0100 @@ -250,17 +250,9 @@ * declared twice. * We therefore use the #if !defined YYLTYPE ... * to make sure only the first declaration is parsed by the C++ compiler. - * - * At first glance it seems that what we really should do is delcare the - * YYLTYPE directly as an anonymous struct, thus: - * #define YYLTYPE struct{ ...} - * however, this also results in compilation errors. - * - * I (Mario) think this is kind of a hack. If you know how to - * do this re-declaration of YYLTYPE properly, please let me know! */ #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED - typedef struct { +typedef struct YYLTYPE { int first_line; int first_column; const char *first_file; @@ -269,9 +261,11 @@ int last_column; const char *last_file; long int last_order; - } yyltype__local; - #define YYLTYPE yyltype__local +} YYLTYPE; +#define YYLTYPE_IS_DECLARED 1 +#define YYLTYPE_IS_TRIVIAL 1 #endif + } @@ -2797,7 +2791,7 @@ | signed_integer DOTDOT error {$$ = NULL; if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for upper bound in subrange definition.");} - else {print_err_msg(locf(@3), locl(@3), "invalid value for upper bound in subrange definition."); yyclearin;} + else {print_err_msg(locf(@3), locl(@3), "invalid value for lower bound in subrange definition."); yyclearin;} yyerrok; } /* ERROR_CHECK_END */ @@ -3407,7 +3401,7 @@ record_variable '.' field_selector {$$ = new structured_variable_c($1, $3, locloc(@$));} | record_variable '.' il_simple_operator_clash3 - {$$ = new structured_variable_c($1, $3, locloc(@$));} + {$$ = new structured_variable_c($1, il_operator_c_2_identifier_c($3), locloc(@$));} ; @@ -6643,8 +6637,11 @@ il_simple_instruction: il_simple_operation eol_list + {$$ = new il_simple_instruction_c($1, locloc(@$));} | il_expression eol_list + {$$ = new il_simple_instruction_c($1, locloc(@$));} | il_formal_funct_call eol_list + {$$ = new il_simple_instruction_c($1, locloc(@$));} /* ERROR_CHECK_BEGIN */ | il_expression error {$$ = NULL; print_err_msg(locl(@1), locf(@2), "EOL missing after expression IL instruction."); yyerrok;} diff -r 34a5571c859c -r 0bb88139e471 stage1_2/iec_flex.ll --- a/stage1_2/iec_flex.ll Thu Mar 22 00:22:48 2012 +0100 +++ b/stage1_2/iec_flex.ll Sat Mar 31 21:46:37 2012 +0100 @@ -171,8 +171,9 @@ * track of the locations, in order to give * more meaningful error messages! */ -extern YYLTYPE yylloc; - +/* + *extern YYLTYPE yylloc; +b*/ #define YY_INPUT(buf,result,max_size) {\ result = GetNextChar(buf, max_size);\ if ( result <= 0 )\ @@ -208,7 +209,6 @@ current_order++; \ } - /* Since this lexical parser we defined only works in ASCII based * systems, we might as well make sure it is being compiled on * one... diff -r 34a5571c859c -r 0bb88139e471 stage3/Makefile.am --- a/stage3/Makefile.am Thu Mar 22 00:22:48 2012 +0100 +++ b/stage3/Makefile.am Sat Mar 31 21:46:37 2012 +0100 @@ -4,5 +4,9 @@ libstage3_a_SOURCES = \ stage3.cc \ - visit_expression_type.cc + flow_control_analysis.cc \ + fill_candidate_datatypes.cc \ + narrow_candidate_datatypes.cc \ + print_datatypes_error.cc \ + datatype_functions.cc diff -r 34a5571c859c -r 0bb88139e471 stage3/Makefile.in --- a/stage3/Makefile.in Thu Mar 22 00:22:48 2012 +0100 +++ b/stage3/Makefile.in Sat Mar 31 21:46:37 2012 +0100 @@ -33,7 +33,7 @@ PRE_UNINSTALL = : POST_UNINSTALL = : DIST_COMMON = $(srcdir)/../common.mk $(srcdir)/Makefile.am \ - $(srcdir)/Makefile.in + $(srcdir)/Makefile.in TODO subdir = stage3 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac @@ -71,7 +71,10 @@ libstage3_a_AR = $(AR) $(ARFLAGS) libstage3_a_LIBADD = am_libstage3_a_OBJECTS = stage3.$(OBJEXT) \ - visit_expression_type.$(OBJEXT) + flow_control_analysis.$(OBJEXT) \ + fill_candidate_datatypes.$(OBJEXT) \ + narrow_candidate_datatypes.$(OBJEXT) \ + print_datatypes_error.$(OBJEXT) datatype_functions.$(OBJEXT) libstage3_a_OBJECTS = $(am_libstage3_a_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/config depcomp = $(SHELL) $(top_srcdir)/config/depcomp @@ -188,7 +191,11 @@ lib_LIBRARIES = libstage3.a libstage3_a_SOURCES = \ stage3.cc \ - visit_expression_type.cc + flow_control_analysis.cc \ + fill_candidate_datatypes.cc \ + narrow_candidate_datatypes.cc \ + print_datatypes_error.cc \ + datatype_functions.cc all: all-am @@ -267,8 +274,12 @@ distclean-compile: -rm -f *.tab.c +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/datatype_functions.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fill_candidate_datatypes.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flow_control_analysis.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/narrow_candidate_datatypes.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/print_datatypes_error.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stage3.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/visit_expression_type.Po@am__quote@ .cc.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff -r 34a5571c859c -r 0bb88139e471 stage3/TODO --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stage3/TODO Sat Mar 31 21:46:37 2012 +0100 @@ -0,0 +1,13 @@ + + + Things that we must still check for in stage 3: + + +1) Handling of CONSTANTs: + + 1.a) "Any program organization unit attempts to modify the value of a variable that has been declared with the CONSTANT qualifier;" + 1.b) From table 16.a "The CONSTANT qualifier shall not be used in the declaration of function block instances as described in 2.5.2.1." + + + + diff -r 34a5571c859c -r 0bb88139e471 stage3/datatype_functions.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stage3/datatype_functions.cc Sat Mar 31 21:46:37 2012 +0100 @@ -0,0 +1,790 @@ +/* + * matiec - a compiler for the programming languages defined in IEC 61131-3 + * + * Copyright (C) 2009-2012 Mario de Sousa (msousa@fe.up.pt) + * Copyright (C) 2012 Manuele Conti (conti.ma@alice.it) + * + * 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 3 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, see . + * + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + */ + +#include "datatype_functions.hh" +#include "../absyntax_utils/absyntax_utils.hh" +#include +// #include + + + + + +elementary_type_c *elementary_type_c::singleton = NULL; + +const char *elementary_type_c::to_string(symbol_c *symbol) { + if (NULL == singleton) singleton = new elementary_type_c; + if (NULL == singleton) ERROR; + const char *res = (const char *)symbol->accept(*singleton); + if (NULL == res) { + int i = 1; + } + return res; +} + + + + + +/* Macro that expand to subtypes */ +/* copied from matiec/lib/create_standard_functions_txt.sh */ +#define __ANY(DO) __ANY_DERIVED(DO) __ANY_ELEMENTARY(DO) +#define __ANY_DERIVED(DO) +#define __ANY_ELEMENTARY(DO) __ANY_MAGNITUDE(DO) __ANY_BIT(DO) __ANY_STRING(DO) __ANY_DATE(DO) +#define __ANY_MAGNITUDE(DO) __ANY_NUM(DO) DO(time) +#define __ANY_BIT(DO) __ANY_NBIT(DO) DO(bool) +#define __ANY_NBIT(DO) DO(byte) DO(word) DO(dword) DO(lword) +//#define __ANY_STRING(DO) DO(string) DO(wstring) +#define __ANY_STRING(DO) DO(string) +#define __ANY_DATE(DO) DO(date) DO(tod) DO(dt) +#define __ANY_NUM(DO) __ANY_REAL(DO) __ANY_INT(DO) +#define __ANY_REAL(DO) DO(real) DO(lreal) +#define __ANY_INT(DO) __ANY_SINT(DO) __ANY_UINT(DO) +#define __ANY_SINT(DO) DO(sint) DO(int) DO(dint) DO(lint) +#define __ANY_UINT(DO) DO(usint) DO(uint) DO(udint) DO(ulint) + +#define __ANY_1(DO,P1) __ANY_DERIVED_1(DO,P1) __ANY_ELEMENTARY_1(DO,P1) +#define __ANY_DERIVED_1(DO,P1) +#define __ANY_ELEMENTARY_1(DO,P1) __ANY_MAGNITUDE_1(DO,P1) __ANY_BIT_1(DO,P1) __ANY_STRING_1(DO,P1) __ANY_DATE_1(DO,P1) +#define __ANY_MAGNITUDE_1(DO,P1) __ANY_NUM_1(DO,P1) DO(time,P1) +#define __ANY_BIT_1(DO,P1) __ANY_NBIT_1(DO,P1) DO(bool,P1) +#define __ANY_NBIT_1(DO,P1) DO(byte,P1) DO(word,P1) DO(dword,P1) DO(lword,P1) +// #define __ANY_STRING_1(DO,P1) DO(string,P1) DO(wstring,P1) +#define __ANY_STRING_1(DO,P1) DO(string,P1) +#define __ANY_DATE_1(DO,P1) DO(date,P1) DO(tod,P1) DO(dt,P1) +#define __ANY_NUM_1(DO,P1) __ANY_REAL_1(DO,P1) __ANY_INT_1(DO,P1) +#define __ANY_REAL_1(DO,P1) DO(real,P1) DO(lreal,P1) +#define __ANY_INT_1(DO,P1) __ANY_SINT_1(DO,P1) __ANY_UINT_1(DO,P1) +#define __ANY_SINT_1(DO,P1) DO(sint,P1) DO(int,P1) DO(dint,P1) DO(lint,P1) +#define __ANY_UINT_1(DO,P1) DO(usint,P1) DO(uint,P1) DO(udint,P1) DO(ulint,P1) + + +/**************************************************************/ +/**************************************************************/ +/**************************************************************/ +/******* TABLE 24: Standard arithmetic functions *******/ +/******* merged with *******/ +/******* TABLE 30: Functions of time data types *******/ +/**************************************************************/ +/**************************************************************/ +/**************************************************************/ + + +const struct widen_entry widen_ADD_table[] = { +#define __add(TYPE) \ + { &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, widen_entry::ok }, + __ANY_NUM(__add) +#undef __add + + /*******************************************/ + /*******************************************/ + /*** Operations with TIME, DT and TOD... ***/ + /*******************************************/ + /*******************************************/ + { &search_constant_type_c::time_type_name, &search_constant_type_c::time_type_name, &search_constant_type_c::time_type_name, widen_entry::ok }, + { &search_constant_type_c::tod_type_name, &search_constant_type_c::time_type_name, &search_constant_type_c::tod_type_name, widen_entry::deprecated }, + /* NOTE: the standard des not explicitly support the following semantics. However, since 'addition' is supposed to be commutative, we add it anyway... */ + /* not currently supported by stage4, so it is best no tto add it for now... */ +// { &search_constant_type_c::time_type_name, &search_constant_type_c::tod_type_name, &search_constant_type_c::tod_type_name, widen_entry::deprecated }, + { &search_constant_type_c::dt_type_name, &search_constant_type_c::time_type_name, &search_constant_type_c::dt_type_name, widen_entry::deprecated }, + /* NOTE: the standard des not explicitly support the following semantics. However, since 'addition' is supposed to be commutative, we add it anyway... */ + /* not currently supported by stage4, so it is best no tto add it for now... */ +// { &search_constant_type_c::time_type_name, &search_constant_type_c::dt_type_name, &search_constant_type_c::dt_type_name, widen_entry::deprecated }, + + /*******************************/ + /* SAFE version on the left... */ + /*******************************/ + { &search_constant_type_c::safetime_type_name, &search_constant_type_c::time_type_name, &search_constant_type_c::time_type_name, widen_entry::ok }, + { &search_constant_type_c::safetod_type_name, &search_constant_type_c::time_type_name, &search_constant_type_c::tod_type_name, widen_entry::deprecated }, + /* NOTE: the standard des not explicitly support the following semantics. However, since 'addition' is supposed to be commutative, we add it anyway... */ + /* not currently supported by stage4, so it is best no tto add it for now... */ +// { &search_constant_type_c::safetime_type_name, &search_constant_type_c::tod_type_name, &search_constant_type_c::tod_type_name, widen_entry::deprecated }, + { &search_constant_type_c::safedt_type_name, &search_constant_type_c::time_type_name, &search_constant_type_c::dt_type_name, widen_entry::deprecated }, + /* NOTE: the standard des not explicitly support the following semantics. However, since 'addition' is supposed to be commutative, we add it anyway... */ + /* not currently supported by stage4, so it is best no tto add it for now... */ +// { &search_constant_type_c::safetime_type_name, &search_constant_type_c::dt_type_name, &search_constant_type_c::dt_type_name, widen_entry::deprecated }, + + /********************************/ + /* SAFE version on the right... */ + /********************************/ + { &search_constant_type_c::time_type_name, &search_constant_type_c::safetime_type_name, &search_constant_type_c::time_type_name, widen_entry::ok }, + { &search_constant_type_c::tod_type_name, &search_constant_type_c::safetime_type_name, &search_constant_type_c::tod_type_name, widen_entry::deprecated }, + /* NOTE: the standard des not explicitly support the following semantics. However, since 'addition' is supposed to be commutative, we add it anyway... */ + /* not currently supported by stage4, so it is best no tto add it for now... */ +// { &search_constant_type_c::time_type_name, &search_constant_type_c::safetod_type_name, &search_constant_type_c::tod_type_name, widen_entry::deprecated }, + { &search_constant_type_c::dt_type_name, &search_constant_type_c::safetime_type_name, &search_constant_type_c::dt_type_name, widen_entry::deprecated }, + /* NOTE: the standard des not explicitly support the following semantics. However, since 'addition' is supposed to be commutative, we add it anyway... */ + /* not currently supported by stage4, so it is best no tto add it for now... */ +// { &search_constant_type_c::time_type_name, &search_constant_type_c::safedt_type_name, &search_constant_type_c::dt_type_name, widen_entry::deprecated }, + + /*************************************/ + /* SAFE version on left and right... */ + /*************************************/ + { &search_constant_type_c::safetime_type_name, &search_constant_type_c::safetime_type_name, &search_constant_type_c::safetime_type_name, widen_entry::ok }, + { &search_constant_type_c::safetod_type_name, &search_constant_type_c::safetime_type_name, &search_constant_type_c::safetod_type_name, widen_entry::deprecated }, + /* NOTE: the standard des not explicitly support the following semantics. However, since 'addition' is supposed to be commutative, we add it anyway... */ + /* not currently supported by stage4, so it is best no tto add it for now... */ +// { &search_constant_type_c::safetime_type_name, &search_constant_type_c::safetod_type_name, &search_constant_type_c::safetod_type_name, widen_entry::deprecated }, + { &search_constant_type_c::safedt_type_name, &search_constant_type_c::safetime_type_name, &search_constant_type_c::safedt_type_name, widen_entry::deprecated }, + /* NOTE: the standard des not explicitly support the following semantics. However, since 'addition' is supposed to be commutative, we add it anyway... */ + /* not currently supported by stage4, so it is best no tto add it for now... */ +// { &search_constant_type_c::safetime_type_name, &search_constant_type_c::safedt_type_name, &search_constant_type_c::safedt_type_name, widen_entry::deprecated }, + + { NULL, NULL, NULL, widen_entry::ok }, +}; + + + + + + + +const struct widen_entry widen_SUB_table[] = { +#define __sub(TYPE) \ + { &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, widen_entry::ok }, + __ANY_NUM(__sub) +#undef __sub + + /*******************************************/ + /*******************************************/ + /*** Operations with TIME, DT and TOD... ***/ + /*******************************************/ + /*******************************************/ + { &search_constant_type_c::time_type_name, &search_constant_type_c::time_type_name, &search_constant_type_c::time_type_name, widen_entry::ok }, + { &search_constant_type_c::date_type_name, &search_constant_type_c::date_type_name, &search_constant_type_c::time_type_name, widen_entry::deprecated }, + { &search_constant_type_c::tod_type_name, &search_constant_type_c::time_type_name, &search_constant_type_c::tod_type_name, widen_entry::deprecated }, + { &search_constant_type_c::tod_type_name, &search_constant_type_c::tod_type_name, &search_constant_type_c::time_type_name, widen_entry::deprecated }, + { &search_constant_type_c::dt_type_name, &search_constant_type_c::time_type_name, &search_constant_type_c::dt_type_name, widen_entry::deprecated }, + { &search_constant_type_c::dt_type_name, &search_constant_type_c::dt_type_name, &search_constant_type_c::time_type_name, widen_entry::deprecated }, + + /*******************************/ + /* SAFE version on the left... */ + /*******************************/ + { &search_constant_type_c::safetime_type_name, &search_constant_type_c::time_type_name, &search_constant_type_c::time_type_name, widen_entry::ok }, + { &search_constant_type_c::safedate_type_name, &search_constant_type_c::date_type_name, &search_constant_type_c::time_type_name, widen_entry::deprecated }, + { &search_constant_type_c::safetod_type_name, &search_constant_type_c::time_type_name, &search_constant_type_c::tod_type_name, widen_entry::deprecated }, + { &search_constant_type_c::safetod_type_name, &search_constant_type_c::tod_type_name, &search_constant_type_c::time_type_name, widen_entry::deprecated }, + { &search_constant_type_c::safedt_type_name, &search_constant_type_c::time_type_name, &search_constant_type_c::dt_type_name, widen_entry::deprecated }, + { &search_constant_type_c::safedt_type_name, &search_constant_type_c::dt_type_name, &search_constant_type_c::time_type_name, widen_entry::deprecated }, + + /********************************/ + /* SAFE version on the right... */ + /********************************/ + { &search_constant_type_c::time_type_name, &search_constant_type_c::safetime_type_name, &search_constant_type_c::time_type_name, widen_entry::ok }, + { &search_constant_type_c::date_type_name, &search_constant_type_c::safedate_type_name, &search_constant_type_c::time_type_name, widen_entry::deprecated }, + { &search_constant_type_c::tod_type_name, &search_constant_type_c::safetime_type_name, &search_constant_type_c::tod_type_name, widen_entry::deprecated }, + { &search_constant_type_c::tod_type_name, &search_constant_type_c::safetod_type_name, &search_constant_type_c::time_type_name, widen_entry::deprecated }, + { &search_constant_type_c::dt_type_name, &search_constant_type_c::safetime_type_name, &search_constant_type_c::dt_type_name, widen_entry::deprecated }, + { &search_constant_type_c::dt_type_name, &search_constant_type_c::safedt_type_name, &search_constant_type_c::time_type_name, widen_entry::deprecated }, + + /*************************************/ + /* SAFE version on left and right... */ + /*************************************/ + { &search_constant_type_c::safetime_type_name, &search_constant_type_c::safetime_type_name, &search_constant_type_c::safetime_type_name, widen_entry::ok }, + { &search_constant_type_c::safedate_type_name, &search_constant_type_c::safedate_type_name, &search_constant_type_c::safetime_type_name, widen_entry::deprecated }, + { &search_constant_type_c::safetod_type_name, &search_constant_type_c::safetime_type_name, &search_constant_type_c::safetod_type_name, widen_entry::deprecated }, + { &search_constant_type_c::safetod_type_name, &search_constant_type_c::safetod_type_name, &search_constant_type_c::safetime_type_name, widen_entry::deprecated }, + { &search_constant_type_c::safedt_type_name, &search_constant_type_c::safetime_type_name, &search_constant_type_c::safedt_type_name, widen_entry::deprecated }, + { &search_constant_type_c::safedt_type_name, &search_constant_type_c::safedt_type_name, &search_constant_type_c::safetime_type_name, widen_entry::deprecated }, + + { NULL, NULL, NULL, widen_entry::ok }, +}; + + + + + + + +const struct widen_entry widen_MUL_table[] = { +#define __mul(TYPE) \ + { &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, widen_entry::ok }, + __ANY_NUM(__mul) +#undef __mul + + /*******************************************/ + /*******************************************/ + /*** Operations with TIME, DT and TOD... ***/ + /*******************************************/ + /*******************************************/ +#define __multime(TYPE) \ + { &search_constant_type_c::time_type_name, &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::time_type_name, widen_entry::deprecated }, \ + { &search_constant_type_c::safetime_type_name, &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::time_type_name, widen_entry::deprecated }, \ + { &search_constant_type_c::time_type_name, &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::time_type_name, widen_entry::deprecated }, \ + { &search_constant_type_c::safetime_type_name, &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::safetime_type_name, widen_entry::deprecated }, \ + /* NOTE: the standard des not explicitly support the following semantics. However, since 'multiplication' is supposed to be commutative, we add it anyway... */ \ + { &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::time_type_name, &search_constant_type_c::time_type_name, widen_entry::deprecated }, \ + { &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::time_type_name, &search_constant_type_c::time_type_name, widen_entry::deprecated }, \ + { &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::safetime_type_name, &search_constant_type_c::time_type_name, widen_entry::deprecated }, \ + { &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::safetime_type_name, &search_constant_type_c::safetime_type_name, widen_entry::deprecated }, + __ANY_NUM(__multime) +#undef __multime + + { NULL, NULL, NULL, widen_entry::ok }, +}; + + + + + +const struct widen_entry widen_DIV_table[] = { +#define __div(TYPE) \ + { &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, widen_entry::ok }, + __ANY_NUM(__div) +#undef __div + + /*******************************************/ + /*******************************************/ + /*** Operations with TIME, DT and TOD... ***/ + /*******************************************/ + /*******************************************/ +#define __divtime(TYPE) \ + { &search_constant_type_c::time_type_name, &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::time_type_name, widen_entry::deprecated }, \ + { &search_constant_type_c::safetime_type_name, &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::time_type_name, widen_entry::deprecated }, \ + { &search_constant_type_c::time_type_name, &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::time_type_name, widen_entry::deprecated }, \ + { &search_constant_type_c::safetime_type_name, &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::safetime_type_name, widen_entry::deprecated }, + __ANY_NUM(__divtime) +#undef __divtime + + { NULL, NULL, NULL, widen_entry::ok }, + }; + + + + +const struct widen_entry widen_MOD_table[] = { +#define __mod(TYPE) \ + { &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, widen_entry::ok }, + __ANY_NUM(__mod) +#undef __mod + + { NULL, NULL, NULL, widen_entry::ok }, +}; + + + + +const struct widen_entry widen_EXPT_table[] = { +#define __expt(IN2TYPE, IN1TYPE) \ + { &search_constant_type_c::IN1TYPE##_type_name, &search_constant_type_c::IN2TYPE##_type_name, &search_constant_type_c::IN1TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::safe##IN1TYPE##_type_name, &search_constant_type_c::IN2TYPE##_type_name, &search_constant_type_c::IN1TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::IN1TYPE##_type_name, &search_constant_type_c::safe##IN2TYPE##_type_name, &search_constant_type_c::IN1TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::safe##IN1TYPE##_type_name, &search_constant_type_c::safe##IN2TYPE##_type_name, &search_constant_type_c::safe##IN1TYPE##_type_name, widen_entry::ok }, +#define __IN2_anynum_(IN1_TYPENAME) __ANY_NUM_1(__expt,IN1_TYPENAME) + __ANY_REAL(__IN2_anynum_) +#undef __expt +#undef __IN2_anynum_ + { NULL, NULL, NULL, widen_entry::ok }, +}; + + + +/**************************************************************/ +/**************************************************************/ +/**************************************************************/ +/******* *******/ +/******* TABLE 26: Standard bitwise Boolean functions *******/ +/******* *******/ +/**************************************************************/ +/**************************************************************/ +/**************************************************************/ +/* table used by AND and ANDN operators, and and_expression */ +const struct widen_entry widen_AND_table[] = { +#define __and(TYPE) \ + { &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, widen_entry::ok }, + __ANY_BIT(__and) +#undef __and + + { NULL, NULL, NULL, widen_entry::ok }, +}; + +/* table used by OR and ORN operators, and or_expression */ +const struct widen_entry widen_OR_table[] = { +#define __or(TYPE) \ + { &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, widen_entry::ok }, + __ANY_BIT(__or) +#undef __or + + { NULL, NULL, NULL, widen_entry::ok }, +}; + + +/* table used by XOR and XORN operators, and xor_expression */ +const struct widen_entry widen_XOR_table[] = { +#define __xor(TYPE) \ + { &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, widen_entry::ok }, \ + { &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, widen_entry::ok }, + __ANY_BIT(__xor) +#undef __xor + + { NULL, NULL, NULL, widen_entry::ok }, +}; + +/**************************************************************/ +/**************************************************************/ +/**************************************************************/ +/******* *******/ +/******* TABLE 28: Standard comparison functions *******/ +/******* *******/ +/**************************************************************/ +/**************************************************************/ +/**************************************************************/ +/* table used by GT, GE, EQ, LE, LT, and NE operators, and equivalent ST expressions. */ +const struct widen_entry widen_CMP_table[] = { +#define __cmp(TYPE) \ + { &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::bool_type_name, widen_entry::ok }, \ + { &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::bool_type_name, widen_entry::ok }, \ + { &search_constant_type_c::TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::bool_type_name, widen_entry::ok }, \ + { &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::safe##TYPE##_type_name, &search_constant_type_c::safebool_type_name, widen_entry::ok }, + __ANY_ELEMENTARY(__cmp) +#undef __cmp + + { NULL, NULL, NULL, widen_entry::ok }, +}; + + +/* Search for a datatype inside a candidate_datatypes list. + * Returns: position of datatype in the list, or -1 if not found. + */ +int search_in_candidate_datatype_list(symbol_c *datatype, std::vector candidate_datatypes) { + if (NULL == datatype) + return -1; + + for(unsigned int i = 0; i < candidate_datatypes.size(); i++) + if (is_type_equal(datatype, candidate_datatypes[i])) + return i; + /* Not found ! */ + return -1; +} + + + + + + + +/* Intersect two candidate_datatype_lists. + * Remove from list1 (origin, dest.) all elements that are not found in list2 (with). + * In essence, list1 will contain the result of the intersection of list1 with list2. + * In other words, modify list1 so it only contains the elelements that are simultaneously in list1 and list2! + */ +void intersect_candidate_datatype_list(symbol_c *list1 /*origin, dest.*/, symbol_c *list2 /*with*/) { + if ((NULL == list1) || (NULL == list2)) + /* In principle, we should never call it with NULL values. Best to abort the compiler just in case! */ + return; + + for(std::vector::iterator i = list1->candidate_datatypes.begin(); i < list1->candidate_datatypes.end(); ) { + /* Note that we do _not_ increment i in the for() loop! + * When we erase an element from position i, a new element will take it's place, that must also be tested! + */ + if (search_in_candidate_datatype_list(*i, list2->candidate_datatypes) < 0) + /* remove this element! This will change the value of candidate_datatypes.size() */ + list1->candidate_datatypes.erase(i); + else i++; + } +} + + + + +/* intersect the candidate_datatype lists of all prev_il_intructions, and set the local candidate_datatype list to the result! */ +void intersect_prev_candidate_datatype_lists(il_instruction_c *symbol) { + if (symbol->prev_il_instruction.empty()) + return; + + symbol->candidate_datatypes = symbol->prev_il_instruction[0]->candidate_datatypes; + for (unsigned int i = 1; i < symbol->prev_il_instruction.size(); i++) { + intersect_candidate_datatype_list(symbol /*origin, dest.*/, symbol->prev_il_instruction[i] /*with*/); + } +} + + + + +/* A helper function... */ +bool is_ANY_ELEMENTARY_type(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + return is_ANY_MAGNITUDE_type(type_symbol) + || is_ANY_BIT_type (type_symbol) + || is_ANY_STRING_type (type_symbol) + || is_ANY_DATE_type (type_symbol); +} + +/* A helper function... */ +bool is_ANY_SAFEELEMENTARY_type(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + return is_ANY_SAFEMAGNITUDE_type(type_symbol) + || is_ANY_SAFEBIT_type (type_symbol) + || is_ANY_SAFESTRING_type (type_symbol) + || is_ANY_SAFEDATE_type (type_symbol); +} + +/* A helper function... */ +bool is_ANY_ELEMENTARY_compatible(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + /* NOTE: doing + * return is_ANY_SAFEELEMENTARY_type() || is_ANY_ELEMENTARY_type() + * is incorrect, as the literals would never be considered compatible... + */ + return is_ANY_MAGNITUDE_compatible(type_symbol) + || is_ANY_BIT_compatible (type_symbol) + || is_ANY_STRING_compatible (type_symbol) + || is_ANY_DATE_compatible (type_symbol); +} + + +/* A helper function... */ +bool is_ANY_MAGNITUDE_type(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (typeid(*type_symbol) == typeid(time_type_name_c)) {return true;} + return is_ANY_NUM_type(type_symbol); +} + +/* A helper function... */ +bool is_ANY_signed_MAGNITUDE_type(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (typeid(*type_symbol) == typeid(time_type_name_c)) {return true;} + return is_ANY_signed_NUM_type(type_symbol); +} + +/* A helper function... */ +bool is_ANY_SAFEMAGNITUDE_type(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (typeid(*type_symbol) == typeid(safetime_type_name_c)) {return true;} + return is_ANY_SAFENUM_type(type_symbol); +} + +/* A helper function... */ +bool is_ANY_signed_SAFEMAGNITUDE_type(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (typeid(*type_symbol) == typeid(safetime_type_name_c)) {return true;} + return is_ANY_signed_SAFENUM_type(type_symbol); +} + +/* A helper function... */ +bool is_ANY_MAGNITUDE_compatible(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (is_ANY_MAGNITUDE_type (type_symbol)) {return true;} + if (is_ANY_SAFEMAGNITUDE_type(type_symbol)) {return true;} + return is_ANY_NUM_compatible(type_symbol); +} + +/* A helper function... */ +bool is_ANY_signed_MAGNITUDE_compatible(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (is_ANY_signed_MAGNITUDE_type (type_symbol)) {return true;} + if (is_ANY_signed_SAFEMAGNITUDE_type(type_symbol)) {return true;} + return is_ANY_signed_NUM_compatible(type_symbol); +} + +/* A helper function... */ +bool is_ANY_NUM_type(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (is_ANY_REAL_type(type_symbol)) {return true;} + if (is_ANY_INT_type(type_symbol)) {return true;} + return false; +} + +/* A helper function... */ +bool is_ANY_signed_NUM_type(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (is_ANY_REAL_type(type_symbol)) {return true;} + if (is_ANY_signed_INT_type(type_symbol)) {return true;} + return false; +} + +/* A helper function... */ +bool is_ANY_SAFENUM_type(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + return is_ANY_SAFEREAL_type(type_symbol) + || is_ANY_SAFEINT_type (type_symbol); +} + +/* A helper function... */ +bool is_ANY_signed_SAFENUM_type(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + return is_ANY_SAFEREAL_type(type_symbol) + || is_ANY_signed_SAFEINT_type (type_symbol); +} + +/* A helper function... */ +bool is_ANY_NUM_compatible(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (is_ANY_REAL_compatible(type_symbol)) {return true;} + if (is_ANY_INT_compatible(type_symbol)) {return true;} + return false; +} + +/* A helper function... */ +bool is_ANY_signed_NUM_compatible(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (is_ANY_REAL_compatible(type_symbol)) {return true;} + if (is_ANY_signed_INT_compatible(type_symbol)) {return true;} + return false; +} + +/* A helper function... */ +bool is_ANY_DATE_type(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (typeid(*type_symbol) == typeid(date_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(tod_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(dt_type_name_c)) {return true;} + return false; +} + +/* A helper function... */ +bool is_ANY_SAFEDATE_type(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (typeid(*type_symbol) == typeid(safedate_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(safetod_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(safedt_type_name_c)) {return true;} + return false; +} + +/* A helper function... */ +bool is_ANY_DATE_compatible(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (is_ANY_DATE_type (type_symbol)) {return true;} + if (is_ANY_SAFEDATE_type(type_symbol)) {return true;} + return false; +} + +/* A helper function... */ +bool is_ANY_STRING_type(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (typeid(*type_symbol) == typeid(string_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(wstring_type_name_c)) {return true;} + return false; +} + +/* A helper function... */ +bool is_ANY_SAFESTRING_type(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (typeid(*type_symbol) == typeid(safestring_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(safewstring_type_name_c)) {return true;} + return false; +} + +/* A helper function... */ +bool is_ANY_STRING_compatible(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (is_ANY_STRING_type (type_symbol)) {return true;} + if (is_ANY_SAFESTRING_type(type_symbol)) {return true;} + return false; +} + +/* A helper function... */ +bool is_ANY_INT_type(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (typeid(*type_symbol) == typeid(sint_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(int_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(dint_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(lint_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(usint_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(uint_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(udint_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(ulint_type_name_c)) {return true;} + return false; +} + +/* A helper function... */ +bool is_ANY_signed_INT_type(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (typeid(*type_symbol) == typeid(sint_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(int_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(dint_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(lint_type_name_c)) {return true;} + return false; +} + +/* A helper function... */ +bool is_ANY_signed_SAFEINT_type(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (typeid(*type_symbol) == typeid(safesint_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(safeint_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(safedint_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(safelint_type_name_c)) {return true;} + return false; +} + +/* A helper function... */ +bool is_ANY_SAFEINT_type(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (typeid(*type_symbol) == typeid(safesint_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(safeint_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(safedint_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(safelint_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(safeusint_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(safeuint_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(safeudint_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(safeulint_type_name_c)) {return true;} + return false; +} + +/* A helper function... */ +bool is_ANY_signed_INT_compatible(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (is_ANY_signed_INT_type (type_symbol)) {return true;} + if (is_ANY_signed_SAFEINT_type(type_symbol)) {return true;} + return false; +} + +/* A helper function... */ +bool is_ANY_INT_compatible(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (is_ANY_INT_type (type_symbol)) {return true;} + if (is_ANY_SAFEINT_type(type_symbol)) {return true;} + return false; +} + +/* A helper function... */ +bool is_ANY_REAL_type(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (typeid(*type_symbol) == typeid(real_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(lreal_type_name_c)) {return true;} + return false; +} + +/* A helper function... */ +bool is_ANY_SAFEREAL_type(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (typeid(*type_symbol) == typeid(safereal_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(safelreal_type_name_c)) {return true;} + return false; +} + +/* A helper function... */ +bool is_ANY_REAL_compatible(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (is_ANY_REAL_type (type_symbol)) {return true;} + if (is_ANY_SAFEREAL_type(type_symbol)) {return true;} + return false; +} + +/* A helper function... */ +bool is_ANY_BIT_type(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (typeid(*type_symbol) == typeid(bool_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(byte_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(word_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(dword_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(lword_type_name_c)) {return true;} + return false; +} + +/* A helper function... */ +bool is_ANY_SAFEBIT_type(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (typeid(*type_symbol) == typeid(safebool_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(safebyte_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(safeword_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(safedword_type_name_c)) {return true;} + if (typeid(*type_symbol) == typeid(safelword_type_name_c)) {return true;} + return false; +} + +/* A helper function... */ +bool is_ANY_BIT_compatible(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (is_ANY_BIT_type (type_symbol)) {return true;} + if (is_ANY_SAFEBIT_type(type_symbol)) {return true;} + return false; +} + +/* A helper function... */ +bool is_BOOL_type(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (typeid(*type_symbol) == typeid(bool_type_name_c)) {return true;} + return false; +} + +/* A helper function... */ +bool is_SAFEBOOL_type(symbol_c *type_symbol){ + if (type_symbol == NULL) {return false;} + if (typeid(*type_symbol) == typeid(safebool_type_name_c)) {return true;} + return false; +} + +/* A helper function... */ +bool is_ANY_BOOL_compatible(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (is_BOOL_type (type_symbol)) {return true;} + if (is_SAFEBOOL_type(type_symbol)) {return true;} + return false; +} + + + + + +bool is_type_equal(symbol_c *first_type, symbol_c *second_type) { + if ((NULL == first_type) || (NULL == second_type)) + return false; + if (typeid(* first_type) == typeid(invalid_type_name_c)) + return false; + if (typeid(*second_type) == typeid(invalid_type_name_c)) + return false; + + if (is_ANY_ELEMENTARY_type(first_type)) { + if (typeid(*first_type) == typeid(*second_type)) + return true; + } else /* ANY_DERIVED */ + return (first_type == second_type); + + return false; +} + + + +bool is_type_valid(symbol_c *type) { + if (NULL == type) + return false; + if (typeid(*type) == typeid(invalid_type_name_c)) + return false; + + return true; +} diff -r 34a5571c859c -r 0bb88139e471 stage3/datatype_functions.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stage3/datatype_functions.hh Sat Mar 31 21:46:37 2012 +0100 @@ -0,0 +1,215 @@ +/* + * matiec - a compiler for the programming languages defined in IEC 61131-3 + * + * Copyright (C) 2009-2012 Mario de Sousa (msousa@fe.up.pt) + * Copyright (C) 2012 Manuele Conti (conti.ma@alice.it) + * + * 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 3 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, see . + * + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + */ + +#ifndef _HELPER_FUNCTIONS_HH_ +#define _HELPER_FUNCTIONS_HH_ + +#include "../absyntax/visitor.hh" +#include + + + + + +typedef struct { + symbol_c *function_name; + symbol_c *nonformal_operand_list; + symbol_c * formal_operand_list; + + enum {POU_FB, POU_function} POU_type; +//symbol_c &*datatype; +//std::vector &candidate_datatypes; + std::vector &candidate_functions; + symbol_c *&called_function_declaration; + int &extensible_param_count; +} generic_function_call_t; + + + +/* A small helper class, to transform elementary data type to string. + * this allows us to generate more relevant error messages... + */ + +class elementary_type_c: public null_visitor_c { + protected: + elementary_type_c(void) {}; + ~elementary_type_c(void) {}; + + private: + /* singleton class! */ + static elementary_type_c *singleton; + + public: + static const char * to_string(symbol_c *symbol); + + + /***********************************/ + /* B 1.3.1 - Elementary Data Types */ + /***********************************/ + void *visit(time_type_name_c *symbol) {return (void *)"TIME"; }; + void *visit(bool_type_name_c *symbol) {return (void *)"BOOL"; }; + void *visit(sint_type_name_c *symbol) {return (void *)"SINT"; }; + void *visit(int_type_name_c *symbol) {return (void *)"INT"; }; + void *visit(dint_type_name_c *symbol) {return (void *)"DINT"; }; + void *visit(lint_type_name_c *symbol) {return (void *)"LINT"; }; + void *visit(usint_type_name_c *symbol) {return (void *)"USINT"; }; + void *visit(uint_type_name_c *symbol) {return (void *)"UINT"; }; + void *visit(udint_type_name_c *symbol) {return (void *)"UDINT"; }; + void *visit(ulint_type_name_c *symbol) {return (void *)"ULINT"; }; + void *visit(real_type_name_c *symbol) {return (void *)"REAL"; }; + void *visit(lreal_type_name_c *symbol) {return (void *)"LREAL"; }; + void *visit(date_type_name_c *symbol) {return (void *)"DATE"; }; + void *visit(tod_type_name_c *symbol) {return (void *)"TOD"; }; + void *visit(dt_type_name_c *symbol) {return (void *)"DT"; }; + void *visit(byte_type_name_c *symbol) {return (void *)"BYTE"; }; + void *visit(word_type_name_c *symbol) {return (void *)"WORD"; }; + void *visit(lword_type_name_c *symbol) {return (void *)"LWORD"; }; + void *visit(dword_type_name_c *symbol) {return (void *)"DWORD"; }; + void *visit(string_type_name_c *symbol) {return (void *)"STRING"; }; + void *visit(wstring_type_name_c *symbol) {return (void *)"WSTRING"; }; + + void *visit(safetime_type_name_c *symbol) {return (void *)"SAFETIME"; }; + void *visit(safebool_type_name_c *symbol) {return (void *)"SAFEBOOL"; }; + void *visit(safesint_type_name_c *symbol) {return (void *)"SAFESINT"; }; + void *visit(safeint_type_name_c *symbol) {return (void *)"SAFEINT"; }; + void *visit(safedint_type_name_c *symbol) {return (void *)"SAFEDINT"; }; + void *visit(safelint_type_name_c *symbol) {return (void *)"SAFELINT"; }; + void *visit(safeusint_type_name_c *symbol) {return (void *)"SAFEUSINT"; }; + void *visit(safeuint_type_name_c *symbol) {return (void *)"SAFEUINT"; }; + void *visit(safeudint_type_name_c *symbol) {return (void *)"SAFEUDINT"; }; + void *visit(safeulint_type_name_c *symbol) {return (void *)"SAFEULINT"; }; + void *visit(safereal_type_name_c *symbol) {return (void *)"SAFEREAL"; }; + void *visit(safelreal_type_name_c *symbol) {return (void *)"SAFELREAL"; }; + void *visit(safedate_type_name_c *symbol) {return (void *)"SAFEDATE"; }; + void *visit(safetod_type_name_c *symbol) {return (void *)"SAFETOD"; }; + void *visit(safedt_type_name_c *symbol) {return (void *)"SAFEDT"; }; + void *visit(safebyte_type_name_c *symbol) {return (void *)"SAFEBYTE"; }; + void *visit(safeword_type_name_c *symbol) {return (void *)"SAFEWORD"; }; + void *visit(safelword_type_name_c *symbol) {return (void *)"SAFELWORD"; }; + void *visit(safedword_type_name_c *symbol) {return (void *)"SAFEDWORD"; }; + void *visit(safestring_type_name_c *symbol) {return (void *)"SAFESTRING"; }; + void *visit(safewstring_type_name_c *symbol) {return (void *)"SAFEWSTRING"; }; +}; + + + + + + +/* Widening Primitive Conversion */ +struct widen_entry { + symbol_c *left; + symbol_c *right; + symbol_c *result; + enum {ok, deprecated} status; +}; +/* + * 2.5.1.5.6 Functions of time data types + * Table 30 - page 64 + */ +extern const struct widen_entry widen_ADD_table[]; +extern const struct widen_entry widen_SUB_table[]; +extern const struct widen_entry widen_MUL_table[]; +extern const struct widen_entry widen_DIV_table[]; +extern const struct widen_entry widen_MOD_table[]; +extern const struct widen_entry widen_EXPT_table[]; +extern const struct widen_entry widen_AND_table[]; +extern const struct widen_entry widen_OR_table[]; +extern const struct widen_entry widen_XOR_table[]; +extern const struct widen_entry widen_CMP_table[]; + +/* Search for a datatype inside a candidate_datatypes list. + * Returns: position of datatype in the list, or -1 if not found. + */ +int search_in_candidate_datatype_list(symbol_c *datatype, std::vector candidate_datatypes); + +/* Intersect two candidate_datatype_lists. + * Remove from list1 (origin, dest.) all elements that are not found in list2 (with). + * In essence, list1 will contain the result of the intersection of list1 with list2. + * In other words, modify list1 so it only contains the elelements that are simultaneously in list1 and list2! + */ +void intersect_candidate_datatype_list(symbol_c *list1 /*origin, dest.*/, symbol_c *list2 /*with*/); + +/* intersect the candidate_datatype lists of all prev_il_intructions, and set the local candidate_datatype list to the result! */ +void intersect_prev_candidate_datatype_lists(il_instruction_c *symbol); + + + +/* A helper function... */ +bool is_ANY_ELEMENTARY_type (symbol_c *type_symbol); +bool is_ANY_SAFEELEMENTARY_type (symbol_c *type_symbol); +bool is_ANY_ELEMENTARY_compatible (symbol_c *type_symbol); + +bool is_ANY_MAGNITUDE_type (symbol_c *type_symbol); +bool is_ANY_SAFEMAGNITUDE_type (symbol_c *type_symbol); +bool is_ANY_MAGNITUDE_compatible (symbol_c *type_symbol); + +bool is_ANY_signed_MAGNITUDE_type (symbol_c *type_symbol); +bool is_ANY_signed_SAFEMAGNITUDE_type (symbol_c *type_symbol); +bool is_ANY_signed_MAGNITUDE_compatible (symbol_c *type_symbol); + +bool is_ANY_DATE_type (symbol_c *type_symbol); +bool is_ANY_SAFEDATE_type (symbol_c *type_symbol); +bool is_ANY_DATE_compatible (symbol_c *type_symbol); + +bool is_ANY_STRING_type (symbol_c *type_symbol); +bool is_ANY_SAFESTRING_type (symbol_c *type_symbol); +bool is_ANY_STRING_compatible (symbol_c *type_symbol); + +bool is_ANY_INT_type (symbol_c *type_symbol); +bool is_ANY_SAFEINT_type (symbol_c *type_symbol); +bool is_ANY_INT_compatible (symbol_c *type_symbol); + +bool is_ANY_signed_INT_type (symbol_c *type_symbol); +bool is_ANY_signed_SAFEINT_type (symbol_c *type_symbol); +bool is_ANY_signed_INT_compatible (symbol_c *type_symbol); + +bool is_ANY_REAL_type (symbol_c *type_symbol); +bool is_ANY_SAFEREAL_type (symbol_c *type_symbol); +bool is_ANY_REAL_compatible (symbol_c *type_symbol); + +bool is_ANY_NUM_type (symbol_c *type_symbol); +bool is_ANY_SAFENUM_type (symbol_c *type_symbol); +bool is_ANY_NUM_compatible (symbol_c *type_symbol); + +bool is_ANY_signed_NUM_type (symbol_c *type_symbol); +bool is_ANY_signed_SAFENUM_type (symbol_c *type_symbol); +bool is_ANY_signed_NUM_compatible (symbol_c *type_symbol); + +bool is_ANY_BIT_type (symbol_c *type_symbol); +bool is_ANY_SAFEBIT_type (symbol_c *type_symbol); +bool is_ANY_BIT_compatible (symbol_c *type_symbol); + +bool is_BOOL_type (symbol_c *type_symbol); +bool is_SAFEBOOL_type (symbol_c *type_symbol); +bool is_ANY_BOOL_compatible (symbol_c *type_symbol); + + +bool is_type_equal(symbol_c *first_type, symbol_c *second_type); +bool is_type_valid(symbol_c *type); + + + + +#endif /* _HELPER_FUNCTIONS_HH_ */ diff -r 34a5571c859c -r 0bb88139e471 stage3/fill_candidate_datatypes.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stage3/fill_candidate_datatypes.cc Sat Mar 31 21:46:37 2012 +0100 @@ -0,0 +1,1391 @@ +/* + * matiec - a compiler for the programming languages defined in IEC 61131-3 + * + * Copyright (C) 2009-2012 Mario de Sousa (msousa@fe.up.pt) + * Copyright (C) 2012 Manuele Conti (manuele.conti@sirius-es.it) + * Copyright (C) 2012 Matteo Facchinetti (matteo.facchinetti@sirius-es.it) + * + * 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 3 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, see . + * + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + */ + +/* + * An IEC 61131-3 compiler. + * + * Based on the + * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) + * + */ + + +/* + * Fill candidate list of data types for all symbols + */ + +#include "fill_candidate_datatypes.hh" +#include "datatype_functions.hh" +#include +#include +#include +#include +#include + +/* set to 1 to see debug info during execution */ +static int debug = 0; + +fill_candidate_datatypes_c::fill_candidate_datatypes_c(symbol_c *ignore) { +} + +fill_candidate_datatypes_c::~fill_candidate_datatypes_c(void) { +} + +symbol_c *fill_candidate_datatypes_c::widening_conversion(symbol_c *left_type, symbol_c *right_type, const struct widen_entry widen_table[]) { + int k; + /* find a widening table entry compatible */ + for (k = 0; NULL != widen_table[k].left; k++) + if ((typeid(*left_type) == typeid(*widen_table[k].left)) && (typeid(*right_type) == typeid(*widen_table[k].right))) + return widen_table[k].result; + return NULL; +} + + +/* add a data type to a candidate data type list, while guaranteeing no duplicate entries! */ +/* Returns true if it really did add the datatype to the list, or false if it was already present in the list! */ +bool fill_candidate_datatypes_c::add_datatype_to_candidate_list(symbol_c *symbol, symbol_c *datatype) { + /* If it is an invalid data type, do not insert! + * NOTE: it reduces overall code size to do this test here, instead of doing every time before calling the add_datatype_to_candidate_list() function. + */ + if (!is_type_valid(datatype)) /* checks for NULL and invalid_type_name_c */ + return false; + + if (search_in_candidate_datatype_list(datatype, symbol->candidate_datatypes) >= 0) + /* already in the list, Just return! */ + return false; + + /* not yet in the candidate data type list, so we insert it now! */ + symbol->candidate_datatypes.push_back(datatype); + return true; +} + + +bool fill_candidate_datatypes_c::add_2datatypes_to_candidate_list(symbol_c *symbol, symbol_c *datatype1, symbol_c *datatype2) { + add_datatype_to_candidate_list(symbol, datatype1); + add_datatype_to_candidate_list(symbol, datatype2); + return true; +} + + +/* returns true if compatible function/FB invocation, otherwise returns false */ +/* Assumes that the candidate_datatype lists of all the parameters being passed haved already been filled in */ +/* + * All parameters being passed to the called function MUST be in the parameter list to which f_call points to! + * This means that, for non formal function calls in IL, de current (default value) must be artificially added to the + * beginning of the parameter list BEFORE calling handle_function_call(). + */ +bool fill_candidate_datatypes_c::match_nonformal_call(symbol_c *f_call, symbol_c *f_decl) { + symbol_c *call_param_value, *param_datatype; + identifier_c *param_name; + function_param_iterator_c fp_iterator(f_decl); + function_call_param_iterator_c fcp_iterator(f_call); + int extensible_parameter_highest_index = -1; + unsigned int i; + + /* Iterating through the non-formal parameters of the function call */ + while((call_param_value = fcp_iterator.next_nf()) != NULL) { + /* Iterate to the next parameter of the function being called. + * Get the name of that parameter, and ignore if EN or ENO. + */ + do { + param_name = fp_iterator.next(); + /* If there is no other parameter declared, then we are passing too many parameters... */ + if(param_name == NULL) return false; + } while ((strcmp(param_name->value, "EN") == 0) || (strcmp(param_name->value, "ENO") == 0)); + + /* TODO: verify if it is lvalue when INOUT or OUTPUT parameters! */ + /* Get the parameter type */ + param_datatype = base_type(fp_iterator.param_type()); + + /* check whether one of the candidate_data_types of the value being passed is the same as the param_type */ + if (search_in_candidate_datatype_list(param_datatype, call_param_value->candidate_datatypes) < 0) + return false; /* return false if param_type not in the list! */ + } + /* call is compatible! */ + return true; +} + + + +/* returns true if compatible function/FB invocation, otherwise returns false */ +/* Assumes that the candidate_datatype lists of all the parameters being passed haved already been filled in */ +bool fill_candidate_datatypes_c::match_formal_call(symbol_c *f_call, symbol_c *f_decl, symbol_c **first_param_datatype) { + symbol_c *call_param_value, *call_param_name, *param_datatype; + symbol_c *verify_duplicate_param; + identifier_c *param_name; + function_param_iterator_c fp_iterator(f_decl); + function_call_param_iterator_c fcp_iterator(f_call); + int extensible_parameter_highest_index = -1; + identifier_c *extensible_parameter_name; + unsigned int i; + bool is_first_param = true; + + /* Iterating through the formal parameters of the function call */ + while((call_param_name = fcp_iterator.next_f()) != NULL) { + /* Obtaining the value being passed in the function call */ + call_param_value = fcp_iterator.get_current_value(); + /* the following should never occur. If it does, then we have a bug in our code... */ + if (NULL == call_param_value) ERROR; + + /* Obtaining the assignment direction: := (assign_in) or => (assign_out) */ + function_call_param_iterator_c::assign_direction_t call_param_dir = fcp_iterator.get_assign_direction(); + + /* Checking if there are duplicated parameter values */ + verify_duplicate_param = fcp_iterator.search_f(call_param_name); + if(verify_duplicate_param != call_param_value) + return false; + + /* Obtaining the type of the value being passed in the function call */ + std::vector &call_param_types = call_param_value->candidate_datatypes; + + /* Find the corresponding parameter in function declaration */ + param_name = fp_iterator.search(call_param_name); + if(param_name == NULL) return false; + /* Get the parameter data type */ + param_datatype = base_type(fp_iterator.param_type()); + /* Get the parameter direction: IN, OUT, IN_OUT */ + function_param_iterator_c::param_direction_t param_dir = fp_iterator.param_direction(); + + /* check whether direction (IN, OUT, IN_OUT) and assignment types (:= , =>) are compatible !!! */ + if (function_call_param_iterator_c::assign_in == call_param_dir) { + if ((function_param_iterator_c::direction_in != param_dir) && + (function_param_iterator_c::direction_inout != param_dir)) + return false; + } else if (function_call_param_iterator_c::assign_out == call_param_dir) { + if ((function_param_iterator_c::direction_out != param_dir)) + return false; + } else ERROR; + + /* check whether one of the candidate_data_types of the value being passed is the same as the param_type */ + if (search_in_candidate_datatype_list(param_datatype, call_param_types) < 0) + return false; /* return false if param_type not in the list! */ + + /* If this is the first parameter, then copy the datatype to *first_param_datatype */ + if (is_first_param) + if (NULL != first_param_datatype) + *first_param_datatype = param_datatype; + is_first_param = false; + } + /* call is compatible! */ + return true; +} + + + + +/* Handle a generic function call! + * Assumes that the parameter_list containing the values being passed in this function invocation + * has already had all the candidate_datatype lists filled in! + * + * All parameters being passed to the called function MUST be in the parameter list to which f_call points to! + * This means that, for non formal function calls in IL, de current (default value) must be artificially added to the + * beginning of the parameter list BEFORE calling handle_function_call(). + */ +/* +typedef struct { + symbol_c *function_name, + symbol_c *nonformal_operand_list, + symbol_c * formal_operand_list, + + std::vector &candidate_functions, + symbol_c &*called_function_declaration, + int &extensible_param_count +} generic_function_call_t; +*/ +/* +void narrow_candidate_datatypes_c::narrow_function_invocation(symbol_c *fcall, generic_function_call_t fcall_data) { +void *fill_candidate_datatypes_c::handle_function_call(symbol_c *f_call, symbol_c *function_name, invocation_type_t invocation_type, + std::vector *candidate_datatypes, + std::vector *candidate_functions) { + */ +void fill_candidate_datatypes_c::handle_function_call(symbol_c *fcall, generic_function_call_t fcall_data) { + function_declaration_c *f_decl; + list_c *parameter_list; + list_c *parameter_candidate_datatypes; + symbol_c *returned_parameter_type; + + if (debug) std::cout << "function()\n"; + + function_symtable_t::iterator lower = function_symtable.lower_bound(fcall_data.function_name); + function_symtable_t::iterator upper = function_symtable.upper_bound(fcall_data.function_name); + /* If the name of the function being called is not found in the function symbol table, then this is an invalid call */ + /* Since the lexical parser already checks for this, then if this occurs then we have an internal compiler error. */ + if (lower == function_symtable.end()) ERROR; + + /* Look for all compatible function declarations, and add their return datatypes + * to the candidate_datatype list of this function invocation. + * + * If only one function exists, we add its return datatype to the candidate_datatype list, + * even if the parameters passed to it are invalid. + * This guarantees that the remainder of the expression in which the function call is inserted + * is treated as if the function call returns correctly, and therefore does not generate + * spurious error messages. + * Even if the parameters to the function call are invalid, doing this is still safe, as the + * expressions inside the function call will themselves have erros and will guarantee that + * compilation is aborted in stage3 (in print_datatypes_error_c). + */ + if (function_symtable.multiplicity(fcall_data.function_name) == 1) { + f_decl = function_symtable.get_value(lower); + returned_parameter_type = base_type(f_decl->type_name); + if (add_datatype_to_candidate_list(fcall, returned_parameter_type)) + /* we only add it to the function declaration list if this entry was not already present in the candidate datatype list! */ + fcall_data.candidate_functions.push_back(f_decl); + + } + for(; lower != upper; lower++) { + bool compatible = false; + + f_decl = function_symtable.get_value(lower); + /* Check if function declaration in symbol_table is compatible with parameters */ + if (NULL != fcall_data.nonformal_operand_list) compatible=match_nonformal_call(fcall, f_decl); + if (NULL != fcall_data. formal_operand_list) compatible= match_formal_call(fcall, f_decl); + if (compatible) { + /* Add the data type returned by the called functions. + * However, only do this if this data type is not already present in the candidate_datatypes list_c + */ + returned_parameter_type = base_type(f_decl->type_name); + if (add_datatype_to_candidate_list(fcall, returned_parameter_type)) + /* we only add it to the function declaration list if this entry was not already present in the candidate datatype list! */ + fcall_data.candidate_functions.push_back(f_decl); + } + } + if (debug) std::cout << "end_function() [" << fcall->candidate_datatypes.size() << "] result.\n"; + return; +} + + +/* handle implicit FB call in IL. + * e.g. CLK ton_var + * CU counter_var + */ +void *fill_candidate_datatypes_c::handle_implicit_il_fb_call(symbol_c *il_instruction, const char *param_name, symbol_c *&called_fb_declaration) { + symbol_c *fb_type_id = search_varfb_instance_type->get_basetype_id(il_operand); + /* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */ + if (NULL == fb_type_id) ERROR; + + function_block_declaration_c *fb_decl = function_block_type_symtable.find_value(fb_type_id); + if (function_block_type_symtable.end_value() == fb_decl) + /* The il_operand is not the name of a FB instance. Most probably it is the name of a variable of some other type. + * this is a semantic error. + */ + fb_decl = NULL; + + /* The narrow_candidate_datatypes_c does not rely on this called_fb_declaration pointer being == NULL to conclude that + * we have a datatype incompatibility error, so we set it to fb_decl to allow the print_datatype_error_c to print out + * more informative error messages! + */ + called_fb_declaration = fb_decl; + + /* This implicit FB call does not change the value stored in the current/default IL variable */ + /* It does, however, require that the datatype be compatible with the input parameter of the FB being called. + * If we were to follow the filling & narrowing algorithm correctly (implemented in fill_candidate_datatypes_c + * & narrow_candidate_datatypes_c respectively), we should be restricting the candidate_datatpes to the datatypes + * that are compatible to the FB call. + * However, doing the above will often result in some very confusing error messages for the user, especially in the case + * in which the FB call is wrong, so the resulting cadidate datatypes is an empty list. In this case, the user would see + * many error messages related to the IL instructions that follow the FB call, even though those IL instructions may be perfectly + * correct. + * For now, we will simply let the narrow_candidate_datatypes_c verify if the datatypes are compatible (something that should be done + * here). + */ + if (NULL != prev_il_instruction) + il_instruction->candidate_datatypes = prev_il_instruction->candidate_datatypes; + + if (debug) std::cout << "handle_implicit_il_fb_call() [" << prev_il_instruction->candidate_datatypes.size() << "] ==> " << il_instruction->candidate_datatypes.size() << " result.\n"; + return NULL; +} + + + + +/* handle a binary IL operator, like ADD, SUB, etc... */ +void *fill_candidate_datatypes_c::handle_binary_operator(const struct widen_entry widen_table[], symbol_c *symbol, symbol_c *l_expr, symbol_c *r_expr) { + if (NULL == l_expr) /* if no prev_il_instruction */ + return NULL; + + for(unsigned int i = 0; i < l_expr->candidate_datatypes.size(); i++) + for(unsigned int j = 0; j < r_expr->candidate_datatypes.size(); j++) + /* NOTE: add_datatype_to_candidate_list() will only really add the datatype if it is != NULL !!! */ + add_datatype_to_candidate_list(symbol, widening_conversion(l_expr->candidate_datatypes[i], r_expr->candidate_datatypes[j], widen_table)); + + if (debug) std::cout << "[" << l_expr->candidate_datatypes.size() << "," << r_expr->candidate_datatypes.size() << "] ==> " << symbol->candidate_datatypes.size() << " result.\n"; + return NULL; +} + + +/* handle a binary ST expression, like '+', '-', etc... */ +void *fill_candidate_datatypes_c::handle_binary_expression(const struct widen_entry widen_table[], symbol_c *symbol, symbol_c *l_expr, symbol_c *r_expr) { + l_expr->accept(*this); + r_expr->accept(*this); + return handle_binary_operator(widen_table, symbol, l_expr, r_expr); +} + + + + +/* a helper function... */ +symbol_c *fill_candidate_datatypes_c::base_type(symbol_c *symbol) { + /* NOTE: symbol == NULL is valid. It will occur when, for e.g., an undefined/undeclared symbolic_variable is used + * in the code. + */ + if (symbol == NULL) return NULL; + return (symbol_c *)symbol->accept(search_base_type); +} + +/*********************/ +/* B 1.2 - Constants */ +/*********************/ +/******************************/ +/* B 1.2.1 - Numeric Literals */ +/******************************/ +#define sizeoftype(symbol) get_sizeof_datatype_c::getsize(symbol) + +void *fill_candidate_datatypes_c::handle_any_integer(symbol_c *symbol) { + int calc_size = sizeoftype(symbol); + + if (calc_size <= sizeoftype(&search_constant_type_c::bool_type_name)) + add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::bool_type_name, &search_constant_type_c::safebool_type_name); + if (calc_size <= sizeoftype(&search_constant_type_c::byte_type_name)) + add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::byte_type_name, &search_constant_type_c::safebyte_type_name); + if (calc_size <= sizeoftype(&search_constant_type_c::word_type_name)) + add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::word_type_name, &search_constant_type_c::safeword_type_name); + if (calc_size <= sizeoftype(&search_constant_type_c::dword_type_name)) + add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::dword_type_name, &search_constant_type_c::safedword_type_name); + if (calc_size <= sizeoftype(&search_constant_type_c::lword_type_name)) + add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::lword_type_name, &search_constant_type_c::safelword_type_name); + + if (calc_size < sizeoftype(&search_constant_type_c::sint_type_name)) + add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::sint_type_name, &search_constant_type_c::safesint_type_name); + if (calc_size < sizeoftype(&search_constant_type_c::int_type_name)) + add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::int_type_name, &search_constant_type_c::safeint_type_name); + if (calc_size < sizeoftype(&search_constant_type_c::dint_type_name)) + add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::dint_type_name, &search_constant_type_c::safedint_type_name); + if (calc_size < sizeoftype(&search_constant_type_c::lint_type_name)) + add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::lint_type_name, &search_constant_type_c::safelint_type_name); + if (calc_size <= sizeoftype(&search_constant_type_c::usint_type_name)) + add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::usint_type_name, &search_constant_type_c::safeusint_type_name); + if (calc_size <= sizeoftype(&search_constant_type_c::uint_type_name)) + add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::uint_type_name, &search_constant_type_c::safeuint_type_name); + if (calc_size <= sizeoftype(&search_constant_type_c::udint_type_name)) + add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::udint_type_name, &search_constant_type_c::safeudint_type_name); + if (calc_size <= sizeoftype(&search_constant_type_c::ulint_type_name)) + add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::ulint_type_name, &search_constant_type_c::safeulint_type_name); + + if (debug) std::cout << "ANY_INT [" << symbol->candidate_datatypes.size()<< "]" << std::endl; + return NULL; +} + + + +void *fill_candidate_datatypes_c::handle_any_real(symbol_c *symbol) { + int calc_size = sizeoftype(symbol); + + if (calc_size <= sizeoftype(&search_constant_type_c::real_type_name)) + add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::real_type_name, &search_constant_type_c::safereal_type_name); + if (calc_size <= sizeoftype(&search_constant_type_c::lreal_type_name)) + add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::lreal_type_name, &search_constant_type_c::safelreal_type_name); + if (debug) std::cout << "ANY_REAL [" << symbol->candidate_datatypes.size() << "]" << std::endl; + return NULL; +} + + + +void *fill_candidate_datatypes_c::handle_any_literal(symbol_c *symbol, symbol_c *symbol_value, symbol_c *symbol_type) { + symbol_value->accept(*this); + if (search_in_candidate_datatype_list(symbol_type, symbol_value->candidate_datatypes) >= 0) + add_datatype_to_candidate_list(symbol, symbol_type); + if (debug) std::cout << "XXX_LITERAL [" << symbol->candidate_datatypes.size() << "]\n"; + return NULL; +} + + + +void *fill_candidate_datatypes_c::visit( real_c *symbol) {return handle_any_real(symbol);} +void *fill_candidate_datatypes_c::visit(neg_real_c *symbol) {return handle_any_real(symbol);} + + + +void *fill_candidate_datatypes_c::visit(neg_integer_c *symbol) { + int calc_size = sizeoftype(symbol); + + if (calc_size <= sizeoftype(&search_constant_type_c::int_type_name)) + add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::int_type_name, &search_constant_type_c::safeint_type_name); + if (calc_size <= sizeoftype(&search_constant_type_c::sint_type_name)) + add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::sint_type_name, &search_constant_type_c::safesint_type_name); + if (calc_size <= sizeoftype(&search_constant_type_c::dint_type_name)) + add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::dint_type_name, &search_constant_type_c::safedint_type_name); + if (calc_size <= sizeoftype(&search_constant_type_c::lint_type_name)) + add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::lint_type_name, &search_constant_type_c::safelint_type_name); + if (debug) std::cout << "neg ANY_INT [" << symbol->candidate_datatypes.size() << "]" << std::endl; + return NULL; +} + + + +void *fill_candidate_datatypes_c::visit(integer_c *symbol) {return handle_any_integer(symbol);} +void *fill_candidate_datatypes_c::visit(binary_integer_c *symbol) {return handle_any_integer(symbol);} +void *fill_candidate_datatypes_c::visit(octal_integer_c *symbol) {return handle_any_integer(symbol);} +void *fill_candidate_datatypes_c::visit(hex_integer_c *symbol) {return handle_any_integer(symbol);} + + + +// SYM_REF2(integer_literal_c, type, value) +/* + * integer_literal: + * integer_type_name '#' signed_integer + * | integer_type_name '#' binary_integer + * | integer_type_name '#' octal_integer + * | integer_type_name '#' hex_integer + */ +void *fill_candidate_datatypes_c::visit( integer_literal_c *symbol) {return handle_any_literal(symbol, symbol->value, symbol->type);} +void *fill_candidate_datatypes_c::visit( real_literal_c *symbol) {return handle_any_literal(symbol, symbol->value, symbol->type);} +void *fill_candidate_datatypes_c::visit(bit_string_literal_c *symbol) {return handle_any_literal(symbol, symbol->value, symbol->type);} + +void *fill_candidate_datatypes_c::visit( boolean_literal_c *symbol) { + if (NULL != symbol->type) return handle_any_literal(symbol, symbol->value, symbol->type); + + symbol->value->accept(*this); + symbol->candidate_datatypes = symbol->value->candidate_datatypes; + return NULL; +} + + +void *fill_candidate_datatypes_c::visit(boolean_true_c *symbol) { + add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::bool_type_name, &search_constant_type_c::safebool_type_name); + return NULL; +} + +void *fill_candidate_datatypes_c::visit(boolean_false_c *symbol) { + add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::bool_type_name, &search_constant_type_c::safebool_type_name); + return NULL; +} + +/*******************************/ +/* B.1.2.2 Character Strings */ +/*******************************/ +void *fill_candidate_datatypes_c::visit(double_byte_character_string_c *symbol) { + add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::wstring_type_name, &search_constant_type_c::safewstring_type_name); + return NULL; +} + +void *fill_candidate_datatypes_c::visit(single_byte_character_string_c *symbol) { + add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::string_type_name, &search_constant_type_c::safestring_type_name); + return NULL; +} + +/***************************/ +/* B 1.2.3 - Time Literals */ +/***************************/ +/************************/ +/* B 1.2.3.1 - Duration */ +/************************/ +void *fill_candidate_datatypes_c::visit(duration_c *symbol) { + /* TODO: check whether the literal follows the rules specified in section '2.2.3.1 Duration' of the standard! */ + + add_datatype_to_candidate_list(symbol, symbol->type_name); + if (debug) std::cout << "TIME_LITERAL [" << symbol->candidate_datatypes.size() << "]\n"; + return NULL; +} + +/************************************/ +/* B 1.2.3.2 - Time of day and Date */ +/************************************/ +void *fill_candidate_datatypes_c::visit(time_of_day_c *symbol) {add_datatype_to_candidate_list(symbol, symbol->type_name); return NULL;} +void *fill_candidate_datatypes_c::visit(date_c *symbol) {add_datatype_to_candidate_list(symbol, symbol->type_name); return NULL;} +void *fill_candidate_datatypes_c::visit(date_and_time_c *symbol) {add_datatype_to_candidate_list(symbol, symbol->type_name); return NULL;} + +/**********************/ +/* B 1.3 - Data types */ +/**********************/ +/********************************/ +/* B 1.3.3 - Derived data types */ +/********************************/ +/* signed_integer DOTDOT signed_integer */ +// SYM_REF2(subrange_c, lower_limit, upper_limit) +void *fill_candidate_datatypes_c::visit(subrange_c *symbol) { + symbol->lower_limit->accept(*this); + symbol->upper_limit->accept(*this); + + for (unsigned int u = 0; u < symbol->upper_limit->candidate_datatypes.size(); u++) { + for(unsigned int l = 0; l < symbol->lower_limit->candidate_datatypes.size(); l++) { + if (is_type_equal(symbol->upper_limit->candidate_datatypes[u], symbol->lower_limit->candidate_datatypes[l])) + add_datatype_to_candidate_list(symbol, symbol->lower_limit->candidate_datatypes[l]); + } + } + return NULL; +} + +/* TYPE type_declaration_list END_TYPE */ +// SYM_REF1(data_type_declaration_c, type_declaration_list) +/* NOTE: Not required. already handled by iterator_visitor_c base class */ +/* +void *fill_candidate_datatypes_c::visit(data_type_declaration_c *symbol) { + symbol->type_declaration_list->accept(*this); + return NULL; +} +*/ + +void *fill_candidate_datatypes_c::visit(enumerated_value_c *symbol) { + symbol_c *enumerated_type; + + if (NULL != symbol->type) + enumerated_type = symbol->type; + else { + enumerated_type = enumerated_value_symtable.find_value(symbol->value); + if (enumerated_type == enumerated_value_symtable.end_value()) + enumerated_type = NULL; + } + enumerated_type = base_type(enumerated_type); + if (NULL != enumerated_type) + add_datatype_to_candidate_list(symbol, enumerated_type); + + if (debug) std::cout << "ENUMERATE [" << symbol->candidate_datatypes.size() << "]\n"; + return NULL; +} + + +/*********************/ +/* B 1.4 - Variables */ +/*********************/ +void *fill_candidate_datatypes_c::visit(symbolic_variable_c *symbol) { + add_datatype_to_candidate_list(symbol, search_varfb_instance_type->get_basetype_decl(symbol)); /* will only add if non NULL */ + if (debug) std::cout << "VAR [" << symbol->candidate_datatypes.size() << "]\n"; + return NULL; +} + +/********************************************/ +/* B 1.4.1 - Directly Represented Variables */ +/********************************************/ +void *fill_candidate_datatypes_c::visit(direct_variable_c *symbol) { + /* Comment added by mario: + * The following code is safe, actually, as the lexical parser guarantees the correct IEC61131-3 syntax was used. + */ + /* However, we should probably add an assertion in case we later change the lexical parser! */ + /* if (symbol->value == NULL) ERROR; + * if (symbol->value[0] == '\0') ERROR; + * if (symbol->value[1] == '\0') ERROR; + */ + switch (symbol->value[2]) { + case 'X': /* bit - 1 bit */ add_datatype_to_candidate_list(symbol, &search_constant_type_c::bool_type_name); break; + case 'B': /* byte - 8 bits */ add_datatype_to_candidate_list(symbol, &search_constant_type_c::byte_type_name); break; + case 'W': /* word - 16 bits */ add_datatype_to_candidate_list(symbol, &search_constant_type_c::word_type_name); break; + case 'D': /* dword - 32 bits */ add_datatype_to_candidate_list(symbol, &search_constant_type_c::dword_type_name); break; + case 'L': /* lword - 64 bits */ add_datatype_to_candidate_list(symbol, &search_constant_type_c::lword_type_name); break; + /* if none of the above, then the empty string was used <=> boolean */ + default: add_datatype_to_candidate_list(symbol, &search_constant_type_c::bool_type_name); break; + } + return NULL; +} + +/*************************************/ +/* B 1.4.2 - Multi-element variables */ +/*************************************/ +/* subscripted_variable '[' subscript_list ']' */ +// SYM_REF2(array_variable_c, subscripted_variable, subscript_list) +void *fill_candidate_datatypes_c::visit(array_variable_c *symbol) { + /* get the declaration of the data type __stored__ in the array... */ + /* if we were to want the data type of the array itself, then we should call_param_name + * search_varfb_instance_type->get_basetype_decl(symbol->subscripted_variable) + */ + symbol_c *result = search_varfb_instance_type->get_basetype_decl(symbol); + if (NULL != result) add_datatype_to_candidate_list(symbol, result); + + /* recursively call the subscript list, so we can check the data types of the expressions used for the subscripts */ + symbol->subscript_list->accept(*this); + + if (debug) std::cout << "ARRAY_VAR [" << symbol->candidate_datatypes.size() << "]\n"; + return NULL; +} + + +/* subscript_list ',' subscript */ +// SYM_LIST(subscript_list_c) +/* NOTE: we inherit from iterator visitor, so we do not need to implement this method... */ +// void *fill_candidate_datatypes_c::visit(subscript_list_c *symbol) + + +/* record_variable '.' field_selector */ +/* WARNING: input and/or output variables of function blocks + * may be accessed as fields of a structured variable! + * Code handling a structured_variable_c must take + * this into account! + */ +// SYM_REF2(structured_variable_c, record_variable, field_selector) +/* NOTE: We do not need to recursively determine the data types of each field_selector, as the search_varfb_instance_type + * will do that for us. So we determine the candidate datatypes only for the full structured_variable. + */ +void *fill_candidate_datatypes_c::visit(structured_variable_c *symbol) { + add_datatype_to_candidate_list(symbol, search_varfb_instance_type->get_basetype_decl(symbol)); /* will only add if non NULL */ + return NULL; +} + +/************************************/ +/* B 1.5 Program organization units */ +/************************************/ +/*********************/ +/* B 1.5.1 Functions */ +/*********************/ +void *fill_candidate_datatypes_c::visit(function_declaration_c *symbol) { + if (debug) printf("Filling candidate data types list of function %s\n", ((token_c *)(symbol->derived_function_name))->value); + search_varfb_instance_type = new search_varfb_instance_type_c(symbol); + symbol->var_declarations_list->accept(*this); + symbol->function_body->accept(*this); + delete search_varfb_instance_type; + search_varfb_instance_type = NULL; + return NULL; +} + +/***************************/ +/* B 1.5.2 Function blocks */ +/***************************/ +void *fill_candidate_datatypes_c::visit(function_block_declaration_c *symbol) { + if (debug) printf("Filling candidate data types list of FB %s\n", ((token_c *)(symbol->fblock_name))->value); + search_varfb_instance_type = new search_varfb_instance_type_c(symbol); + symbol->var_declarations->accept(*this); + symbol->fblock_body->accept(*this); + delete search_varfb_instance_type; + search_varfb_instance_type = NULL; + return NULL; +} + +/**********************/ +/* B 1.5.3 - Programs */ +/**********************/ +void *fill_candidate_datatypes_c::visit(program_declaration_c *symbol) { + if (debug) printf("Filling candidate data types list in program %s\n", ((token_c *)(symbol->program_type_name))->value); + search_varfb_instance_type = new search_varfb_instance_type_c(symbol); + symbol->var_declarations->accept(*this); + symbol->function_block_body->accept(*this); + delete search_varfb_instance_type; + search_varfb_instance_type = NULL; + return NULL; +} + + + +/********************************/ +/* B 1.7 Configuration elements */ +/********************************/ +void *fill_candidate_datatypes_c::visit(configuration_declaration_c *symbol) { + // TODO !!! + /* for the moment we must return NULL so semantic analysis of remaining code is not interrupted! */ + return NULL; +} + +/****************************************/ +/* B.2 - Language IL (Instruction List) */ +/****************************************/ +/***********************************/ +/* B 2.1 Instructions and Operands */ +/***********************************/ + +/*| instruction_list il_instruction */ +// SYM_LIST(instruction_list_c) +void *fill_candidate_datatypes_c::visit(instruction_list_c *symbol) { + /* In order to fill the data type candidates correctly + * in IL instruction lists containing JMPs to labels that come before the JMP instruction + * itself, we need to run the fill candidate datatypes algorithm twice on the Instruction List. + * e.g.: ... + * ld 23 + * label1:st byte_var + * ld 34 + * JMP label1 + * + * Note that the second time we run the algorithm, most of the candidate datatypes are already filled + * in, so it will be able to produce tha correct candidate datatypes for the IL instruction referenced + * by the label, as in the 2nd pass we already know the candidate datatypes of the JMP instruction! + */ + for(int j = 0; j < 2; j++) { + for(int i = 0; i < symbol->n; i++) { + symbol->elements[i]->accept(*this); + } + } + return NULL; +} + + + +/* | label ':' [il_incomplete_instruction] eol_list */ +// SYM_REF2(il_instruction_c, label, il_instruction) +// void *visit(instruction_list_c *symbol); +void *fill_candidate_datatypes_c::visit(il_instruction_c *symbol) { + if (NULL == symbol->il_instruction) { + /* This empty/null il_instruction does not change the value of the current/default IL variable. + * So it inherits the candidate_datatypes from it's previous IL instructions! + */ + intersect_prev_candidate_datatype_lists(symbol); + } else { + il_instruction_c fake_prev_il_instruction = *symbol; + intersect_prev_candidate_datatype_lists(&fake_prev_il_instruction); + + if (symbol->prev_il_instruction.size() == 0) prev_il_instruction = NULL; + else prev_il_instruction = &fake_prev_il_instruction; + symbol->il_instruction->accept(*this); + prev_il_instruction = NULL; + + /* This object has (inherits) the same candidate datatypes as the il_instruction */ + symbol->candidate_datatypes = symbol->il_instruction->candidate_datatypes; + } + + return NULL; +} + + + +void *fill_candidate_datatypes_c::visit(il_simple_operation_c *symbol) { + /* determine the data type of the operand */ + if (NULL != symbol->il_operand) { + symbol->il_operand->accept(*this); + } + /* recursive call to fill the candidate data types list */ + il_operand = symbol->il_operand; + symbol->il_simple_operator->accept(*this); + il_operand = NULL; + /* This object has (inherits) the same candidate datatypes as the il_simple_operator */ + symbol->candidate_datatypes = symbol->il_simple_operator->candidate_datatypes; + return NULL; +} + + +/* | function_name [il_operand_list] */ +/* NOTE: The parameters 'called_function_declaration' and 'extensible_param_count' are used to pass data between the stage 3 and stage 4. */ +// SYM_REF2(il_function_call_c, function_name, il_operand_list, symbol_c *called_function_declaration; int extensible_param_count;) +void *fill_candidate_datatypes_c::visit(il_function_call_c *symbol) { + /* The first parameter of a non formal function call in IL will be the 'current value' (i.e. the prev_il_instruction) + * In order to be able to handle this without coding special cases, we will simply prepend that symbol + * to the il_operand_list, and remove it after calling handle_function_call(). + * + * However, if no further paramters are given, then il_operand_list will be NULL, and we will + * need to create a new object to hold the pointer to prev_il_instruction. + */ + if (NULL == symbol->il_operand_list) symbol->il_operand_list = new il_operand_list_c; + if (NULL == symbol->il_operand_list) ERROR; + + symbol->il_operand_list->accept(*this); + + if (NULL != prev_il_instruction) { + ((list_c *)symbol->il_operand_list)->insert_element(prev_il_instruction, 0); + + generic_function_call_t fcall_param = { + /* fcall_param.function_name = */ symbol->function_name, + /* fcall_param.nonformal_operand_list = */ symbol->il_operand_list, + /* fcall_param.formal_operand_list = */ NULL, + /* enum {POU_FB, POU_function} POU_type = */ generic_function_call_t::POU_function, + /* fcall_param.candidate_functions = */ symbol->candidate_functions, + /* fcall_param.called_function_declaration = */ symbol->called_function_declaration, + /* fcall_param.extensible_param_count = */ symbol->extensible_param_count + }; + handle_function_call(symbol, fcall_param); + + /* Undo the changes to the abstract syntax tree we made above... */ + ((list_c *)symbol->il_operand_list)->remove_element(0); + } + + /* Undo the changes to the abstract syntax tree we made above... */ + if (((list_c *)symbol->il_operand_list)->n == 0) { + /* if the list becomes empty, then that means that it did not exist before we made these changes, so we delete it! */ + delete symbol->il_operand_list; + symbol->il_operand_list = NULL; + } + + if (debug) std::cout << "il_function_call_c [" << symbol->candidate_datatypes.size() << "] result.\n"; + return NULL; +} + + +/* | il_expr_operator '(' [il_operand] eol_list [simple_instr_list] ')' */ +// SYM_REF3(il_expression_c, il_expr_operator, il_operand, simple_instr_list); +void *fill_candidate_datatypes_c::visit(il_expression_c *symbol) { + symbol_c *prev_il_instruction_backup = prev_il_instruction; + + if (NULL != symbol->il_operand) + symbol->il_operand->accept(*this); + + if(symbol->simple_instr_list != NULL) + symbol->simple_instr_list->accept(*this); + + /* Now check the if the data type semantics of operation are correct, */ + il_operand = symbol->simple_instr_list; + prev_il_instruction = prev_il_instruction_backup; + symbol->il_expr_operator->accept(*this); + il_operand = NULL; + + /* This object has the same candidate datatypes as the il_expr_operator. */ + symbol->candidate_datatypes = symbol->il_expr_operator->candidate_datatypes; + return NULL; +} + + +void *fill_candidate_datatypes_c::visit(il_jump_operation_c *symbol) { + /* recursive call to fill the candidate data types list */ + il_operand = NULL; + symbol->il_jump_operator->accept(*this); + il_operand = NULL; + /* This object has the same candidate datatypes as the il_jump_operator. */ + symbol->candidate_datatypes = symbol->il_jump_operator->candidate_datatypes; + return NULL; +} + + +/* il_call_operator prev_declared_fb_name + * | il_call_operator prev_declared_fb_name '(' ')' + * | il_call_operator prev_declared_fb_name '(' eol_list ')' + * | il_call_operator prev_declared_fb_name '(' il_operand_list ')' + * | il_call_operator prev_declared_fb_name '(' eol_list il_param_list ')' + */ +/* NOTE: The parameter 'called_fb_declaration'is used to pass data between stage 3 and stage4 (although currently it is not used in stage 4 */ +// SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list, symbol_c *called_fb_declaration) +void *fill_candidate_datatypes_c::visit(il_fb_call_c *symbol) { + /* We do not call + * fb_decl = search_varfb_instance_type->get_basetype_decl(symbol->fb_name); + * because we want to make sure it is a FB instance, and not some other data type... + */ + symbol_c *fb_type_id = search_varfb_instance_type->get_basetype_id(symbol->fb_name); + /* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */ + if (NULL == fb_type_id) ERROR; + + function_block_declaration_c *fb_decl = function_block_type_symtable.find_value(fb_type_id); + if (function_block_type_symtable.end_value() == fb_decl) + /* The fb_name not the name of a FB instance. Most probably it is the name of a variable of some other type. */ + fb_decl = NULL; + + /* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */ + if (NULL == fb_decl) ERROR; + + if (symbol-> il_param_list != NULL) symbol->il_param_list->accept(*this); + if (symbol->il_operand_list != NULL) symbol->il_operand_list->accept(*this); + + /* The print_datatypes_error_c does not rely on this called_fb_declaration pointer being != NULL to conclude that + * we have a datat type incompatibility error, so setting it to the correct fb_decl is actually safe, + * as the compiler will never reach the compilation stage! + */ + symbol->called_fb_declaration = fb_decl; + + /* Let the il_call_operator (CAL, CALC, or CALCN) determine the candidate datatypes of the il_fb_call_c... */ + /* NOTE: We ignore whether the call is 'compatible' or not when filling in the candidate datatypes list. + * Even if it is not compatible, we fill in the candidate datatypes list correctly so that the following + * IL instructions may be handled correctly and debuged. + * Doing this is actually safe, as the parameter_list will still contain errors that will be found by + * print_datatypes_error_c, so the code will never reach stage 4! + */ + symbol->il_call_operator->accept(*this); + symbol->candidate_datatypes = symbol->il_call_operator->candidate_datatypes; + + if (debug) std::cout << "FB [] ==> " << symbol->candidate_datatypes.size() << " result.\n"; + return NULL; +} + + +/* | function_name '(' eol_list [il_param_list] ')' */ +/* NOTE: The parameter 'called_function_declaration' is used to pass data between the stage 3 and stage 4. */ +// SYM_REF2(il_formal_funct_call_c, function_name, il_param_list, symbol_c *called_function_declaration; int extensible_param_count;) +void *fill_candidate_datatypes_c::visit(il_formal_funct_call_c *symbol) { + symbol->il_param_list->accept(*this); + + generic_function_call_t fcall_param = { + /* fcall_param.function_name = */ symbol->function_name, + /* fcall_param.nonformal_operand_list = */ NULL, + /* fcall_param.formal_operand_list = */ symbol->il_param_list, + /* enum {POU_FB, POU_function} POU_type = */ generic_function_call_t::POU_function, + /* fcall_param.candidate_functions = */ symbol->candidate_functions, + /* fcall_param.called_function_declaration = */ symbol->called_function_declaration, + /* fcall_param.extensible_param_count = */ symbol->extensible_param_count + }; + handle_function_call(symbol, fcall_param); + + if (debug) std::cout << "il_formal_funct_call_c [" << symbol->candidate_datatypes.size() << "] result.\n"; + return NULL; +} + + +// void *visit(il_operand_list_c *symbol); + + +/* | simple_instr_list il_simple_instruction */ +/* This object is referenced by il_expression_c objects */ +void *fill_candidate_datatypes_c::visit(simple_instr_list_c *symbol) { + if (symbol->n <= 0) + return NULL; /* List is empty! Nothing to do. */ + + for(int i = 0; i < symbol->n; i++) + symbol->elements[i]->accept(*this); + + /* This object has (inherits) the same candidate datatypes as the last il_instruction */ + symbol->candidate_datatypes = symbol->elements[symbol->n-1]->candidate_datatypes; + + if (debug) std::cout << "simple_instr_list_c [" << symbol->candidate_datatypes.size() << "] result.\n"; + return NULL; +} + + + + +// SYM_REF1(il_simple_instruction_c, il_simple_instruction, symbol_c *prev_il_instruction;) +void *fill_candidate_datatypes_c::visit(il_simple_instruction_c *symbol) { + if (symbol->prev_il_instruction.size() > 1) ERROR; /* There should be no labeled insructions inside an IL expression! */ + if (symbol->prev_il_instruction.size() == 0) prev_il_instruction = NULL; + else prev_il_instruction = symbol->prev_il_instruction[0]; + symbol->il_simple_instruction->accept(*this); + prev_il_instruction = NULL; + + /* This object has (inherits) the same candidate datatypes as the il_simple_instruction it points to */ + symbol->candidate_datatypes = symbol->il_simple_instruction->candidate_datatypes; + return NULL; +} + + +/* + void *visit(il_param_list_c *symbol); + void *visit(il_param_assignment_c *symbol); + void *visit(il_param_out_assignment_c *symbol); +*/ + +/*******************/ +/* B 2.2 Operators */ +/*******************/ +void *fill_candidate_datatypes_c::visit(LD_operator_c *symbol) { + for(unsigned int i = 0; i < il_operand->candidate_datatypes.size(); i++) { + add_datatype_to_candidate_list(symbol, il_operand->candidate_datatypes[i]); + } + if (debug) std::cout << "LD [" << il_operand->candidate_datatypes.size() << "] ==> " << symbol->candidate_datatypes.size() << " result.\n"; + return NULL; +} + +void *fill_candidate_datatypes_c::visit(LDN_operator_c *symbol) { + for(unsigned int i = 0; i < il_operand->candidate_datatypes.size(); i++) { + if (is_ANY_BIT_compatible(il_operand->candidate_datatypes[i])) + add_datatype_to_candidate_list(symbol, il_operand->candidate_datatypes[i]); + } + if (debug) std::cout << "LDN [" << il_operand->candidate_datatypes.size() << "] ==> " << symbol->candidate_datatypes.size() << " result.\n"; + return NULL; +} + +void *fill_candidate_datatypes_c::visit(ST_operator_c *symbol) { + symbol_c *prev_instruction_type, *operand_type; + + if (NULL == prev_il_instruction) return NULL; + for (unsigned int i = 0; i < prev_il_instruction->candidate_datatypes.size(); i++) { + for(unsigned int j = 0; j < il_operand->candidate_datatypes.size(); j++) { + prev_instruction_type = prev_il_instruction->candidate_datatypes[i]; + operand_type = il_operand->candidate_datatypes[j]; + if (is_type_equal(prev_instruction_type, operand_type)) + add_datatype_to_candidate_list(symbol, prev_instruction_type); + } + } + if (debug) std::cout << "ST [" << prev_il_instruction->candidate_datatypes.size() << "," << il_operand->candidate_datatypes.size() << "] ==> " << symbol->candidate_datatypes.size() << " result.\n"; + return NULL; +} + +void *fill_candidate_datatypes_c::visit(STN_operator_c *symbol) { + symbol_c *prev_instruction_type, *operand_type; + + if (NULL == prev_il_instruction) return NULL; + for (unsigned int i = 0; i < prev_il_instruction->candidate_datatypes.size(); i++) { + for(unsigned int j = 0; j < il_operand->candidate_datatypes.size(); j++) { + prev_instruction_type = prev_il_instruction->candidate_datatypes[i]; + operand_type = il_operand->candidate_datatypes[j]; + if (is_type_equal(prev_instruction_type,operand_type) && is_ANY_BIT_compatible(operand_type)) + add_datatype_to_candidate_list(symbol, prev_instruction_type); + } + } + if (debug) std::cout << "STN [" << prev_il_instruction->candidate_datatypes.size() << "," << il_operand->candidate_datatypes.size() << "] ==> " << symbol->candidate_datatypes.size() << " result.\n"; + return NULL; +} + +void *fill_candidate_datatypes_c::visit(NOT_operator_c *symbol) { + /* NOTE: the standard allows syntax in which the NOT operator is followed by an optional + * NOT [] + * However, it does not define the semantic of the NOT operation when the is specified. + * We therefore consider it an error if an il_operand is specified! + */ + if (NULL == prev_il_instruction) return NULL; + for (unsigned int i = 0; i < prev_il_instruction->candidate_datatypes.size(); i++) { + if (is_ANY_BIT_compatible(prev_il_instruction->candidate_datatypes[i])) + add_datatype_to_candidate_list(symbol, prev_il_instruction->candidate_datatypes[i]); + } + if (debug) std::cout << "NOT_operator [" << prev_il_instruction->candidate_datatypes.size() << "] ==> " << symbol->candidate_datatypes.size() << " result.\n"; + return NULL; +} + + +void *fill_candidate_datatypes_c::visit(S_operator_c *symbol) { + /* TODO: what if this is a FB call ?? */ + symbol_c *prev_instruction_type, *operand_type; + + if (NULL == prev_il_instruction) return NULL; + for (unsigned int i = 0; i < prev_il_instruction->candidate_datatypes.size(); i++) { + for(unsigned int j = 0; j < il_operand->candidate_datatypes.size(); j++) { + prev_instruction_type = prev_il_instruction->candidate_datatypes[i]; + operand_type = il_operand->candidate_datatypes[j]; + /* TODO: I believe the following is wrong! The data types of prev_instruction_type and operand_type DO NOT have to be equal. + * the prev_instruction_type MUST be BOOL compatible. + * I am not too sure about operand_type, does it have to be BOOL compatible, or can it be ANY_BIT compatible? Must check! + */ + if (is_type_equal(prev_instruction_type,operand_type) && is_ANY_BOOL_compatible(operand_type)) + add_datatype_to_candidate_list(symbol, prev_instruction_type); + } + } + if (debug) std::cout << "S [" << prev_il_instruction->candidate_datatypes.size() << "," << il_operand->candidate_datatypes.size() << "] ==> " << symbol->candidate_datatypes.size() << " result.\n"; + return NULL; +} + + +void *fill_candidate_datatypes_c::visit(R_operator_c *symbol) { + /* TODO: what if this is a FB call ?? */ + symbol_c *prev_instruction_type, *operand_type; + + if (NULL == prev_il_instruction) return NULL; + for (unsigned int i = 0; i < prev_il_instruction->candidate_datatypes.size(); i++) { + for(unsigned int j = 0; j < il_operand->candidate_datatypes.size(); j++) { + prev_instruction_type = prev_il_instruction->candidate_datatypes[i]; + operand_type = il_operand->candidate_datatypes[j]; + /* TODO: I believe the following is wrong! The data types of prev_instruction_type and operand_type DO NOT have to be equal. + * the prev_instruction_type MUST be BOOL compatible. + * I am not too sure about operand_type, does it have to be BOOL compatible, or can it be ANY_BIT compatible? Must check! + */ + if (is_type_equal(prev_instruction_type,operand_type) && is_ANY_BOOL_compatible(operand_type)) + add_datatype_to_candidate_list(symbol, prev_instruction_type); + } + } + if (debug) std::cout << "R [" << prev_il_instruction->candidate_datatypes.size() << "," << il_operand->candidate_datatypes.size() << "] ==> " << symbol->candidate_datatypes.size() << " result.\n"; + return NULL; +} + + +void *fill_candidate_datatypes_c::visit( S1_operator_c *symbol) {return handle_implicit_il_fb_call(symbol, "S1", symbol->called_fb_declaration);} +void *fill_candidate_datatypes_c::visit( R1_operator_c *symbol) {return handle_implicit_il_fb_call(symbol, "R1", symbol->called_fb_declaration);} +void *fill_candidate_datatypes_c::visit( CLK_operator_c *symbol) {return handle_implicit_il_fb_call(symbol, "CLK", symbol->called_fb_declaration);} +void *fill_candidate_datatypes_c::visit( CU_operator_c *symbol) {return handle_implicit_il_fb_call(symbol, "CU", symbol->called_fb_declaration);} +void *fill_candidate_datatypes_c::visit( CD_operator_c *symbol) {return handle_implicit_il_fb_call(symbol, "CD", symbol->called_fb_declaration);} +void *fill_candidate_datatypes_c::visit( PV_operator_c *symbol) {return handle_implicit_il_fb_call(symbol, "PV", symbol->called_fb_declaration);} +void *fill_candidate_datatypes_c::visit( IN_operator_c *symbol) {return handle_implicit_il_fb_call(symbol, "IN", symbol->called_fb_declaration);} +void *fill_candidate_datatypes_c::visit( PT_operator_c *symbol) {return handle_implicit_il_fb_call(symbol, "PT", symbol->called_fb_declaration);} + +void *fill_candidate_datatypes_c::visit( AND_operator_c *symbol) {return handle_binary_operator(widen_AND_table, symbol, prev_il_instruction, il_operand);} +void *fill_candidate_datatypes_c::visit( OR_operator_c *symbol) {return handle_binary_operator( widen_OR_table, symbol, prev_il_instruction, il_operand);} +void *fill_candidate_datatypes_c::visit( XOR_operator_c *symbol) {return handle_binary_operator(widen_XOR_table, symbol, prev_il_instruction, il_operand);} +void *fill_candidate_datatypes_c::visit(ANDN_operator_c *symbol) {return handle_binary_operator(widen_AND_table, symbol, prev_il_instruction, il_operand);} +void *fill_candidate_datatypes_c::visit( ORN_operator_c *symbol) {return handle_binary_operator( widen_OR_table, symbol, prev_il_instruction, il_operand);} +void *fill_candidate_datatypes_c::visit(XORN_operator_c *symbol) {return handle_binary_operator(widen_XOR_table, symbol, prev_il_instruction, il_operand);} + +void *fill_candidate_datatypes_c::visit( ADD_operator_c *symbol) {return handle_binary_operator(widen_ADD_table, symbol, prev_il_instruction, il_operand);} +void *fill_candidate_datatypes_c::visit( SUB_operator_c *symbol) {return handle_binary_operator(widen_SUB_table, symbol, prev_il_instruction, il_operand);} +void *fill_candidate_datatypes_c::visit( MUL_operator_c *symbol) {return handle_binary_operator(widen_MUL_table, symbol, prev_il_instruction, il_operand);} +void *fill_candidate_datatypes_c::visit( DIV_operator_c *symbol) {return handle_binary_operator(widen_DIV_table, symbol, prev_il_instruction, il_operand);} +void *fill_candidate_datatypes_c::visit( MOD_operator_c *symbol) {return handle_binary_operator(widen_MOD_table, symbol, prev_il_instruction, il_operand);} + +void *fill_candidate_datatypes_c::visit( GT_operator_c *symbol) {return handle_binary_operator(widen_CMP_table, symbol, prev_il_instruction, il_operand);} +void *fill_candidate_datatypes_c::visit( GE_operator_c *symbol) {return handle_binary_operator(widen_CMP_table, symbol, prev_il_instruction, il_operand);} +void *fill_candidate_datatypes_c::visit( EQ_operator_c *symbol) {return handle_binary_operator(widen_CMP_table, symbol, prev_il_instruction, il_operand);} +void *fill_candidate_datatypes_c::visit( LT_operator_c *symbol) {return handle_binary_operator(widen_CMP_table, symbol, prev_il_instruction, il_operand);} +void *fill_candidate_datatypes_c::visit( LE_operator_c *symbol) {return handle_binary_operator(widen_CMP_table, symbol, prev_il_instruction, il_operand);} +void *fill_candidate_datatypes_c::visit( NE_operator_c *symbol) {return handle_binary_operator(widen_CMP_table, symbol, prev_il_instruction, il_operand);} + + + +void *fill_candidate_datatypes_c::handle_conditional_il_flow_control_operator(symbol_c *symbol) { + if (NULL == prev_il_instruction) return NULL; + for (unsigned int i = 0; i < prev_il_instruction->candidate_datatypes.size(); i++) { + if (is_ANY_BOOL_compatible(prev_il_instruction->candidate_datatypes[i])) + add_datatype_to_candidate_list(symbol, prev_il_instruction->candidate_datatypes[i]); + } + return NULL; +} + +void *fill_candidate_datatypes_c::visit( CAL_operator_c *symbol) {if (NULL != prev_il_instruction) symbol->candidate_datatypes = prev_il_instruction->candidate_datatypes; return NULL;} +void *fill_candidate_datatypes_c::visit( RET_operator_c *symbol) {if (NULL != prev_il_instruction) symbol->candidate_datatypes = prev_il_instruction->candidate_datatypes; return NULL;} +void *fill_candidate_datatypes_c::visit( JMP_operator_c *symbol) {if (NULL != prev_il_instruction) symbol->candidate_datatypes = prev_il_instruction->candidate_datatypes; return NULL;} +void *fill_candidate_datatypes_c::visit( CALC_operator_c *symbol) {return handle_conditional_il_flow_control_operator(symbol);} +void *fill_candidate_datatypes_c::visit(CALCN_operator_c *symbol) {return handle_conditional_il_flow_control_operator(symbol);} +void *fill_candidate_datatypes_c::visit( RETC_operator_c *symbol) {return handle_conditional_il_flow_control_operator(symbol);} +void *fill_candidate_datatypes_c::visit(RETCN_operator_c *symbol) {return handle_conditional_il_flow_control_operator(symbol);} +void *fill_candidate_datatypes_c::visit( JMPC_operator_c *symbol) {return handle_conditional_il_flow_control_operator(symbol);} +void *fill_candidate_datatypes_c::visit(JMPCN_operator_c *symbol) {return handle_conditional_il_flow_control_operator(symbol);} + + + + +/* Symbol class handled together with function call checks */ +// void *visit(il_assign_operator_c *symbol, variable_name); +/* Symbol class handled together with function call checks */ +// void *visit(il_assign_operator_c *symbol, option, variable_name); + +/***************************************/ +/* B.3 - Language ST (Structured Text) */ +/***************************************/ +/***********************/ +/* B 3.1 - Expressions */ +/***********************/ +void *fill_candidate_datatypes_c::visit( or_expression_c *symbol) {return handle_binary_expression(widen_OR_table, symbol, symbol->l_exp, symbol->r_exp);} +void *fill_candidate_datatypes_c::visit( xor_expression_c *symbol) {return handle_binary_expression(widen_XOR_table, symbol, symbol->l_exp, symbol->r_exp);} +void *fill_candidate_datatypes_c::visit( and_expression_c *symbol) {return handle_binary_expression(widen_AND_table, symbol, symbol->l_exp, symbol->r_exp);} + +void *fill_candidate_datatypes_c::visit( equ_expression_c *symbol) {return handle_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);} +void *fill_candidate_datatypes_c::visit(notequ_expression_c *symbol) {return handle_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);} +void *fill_candidate_datatypes_c::visit( lt_expression_c *symbol) {return handle_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);} +void *fill_candidate_datatypes_c::visit( gt_expression_c *symbol) {return handle_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);} +void *fill_candidate_datatypes_c::visit( le_expression_c *symbol) {return handle_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);} +void *fill_candidate_datatypes_c::visit( ge_expression_c *symbol) {return handle_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);} + + +/* The following code is correct when handling the addition of 2 symbolic_variables + * In this case, adding two variables (e.g. USINT_var1 + USINT_var2) will always yield + * the same data type, even if the result of the adition could not fit inside the same + * data type (due to overflowing) + * + * However, when adding two literals (e.g. USINT#42 + USINT#3) + * we should be able to detect overflows of the result, and therefore not consider + * that the result may be of type USINT. + * Currently we do not yet detect these overflows, and allow handling the sum of two USINTs + * as always resulting in an USINT, even in the following expression + * (USINT#65535 + USINT#2). + * + * In the future we can add some code to reduce + * all the expressions that are based on literals into the resulting literal + * value (maybe some visitor class that will run before or after data type + * checking). Since this class will have to be very careful to make sure it implements the same mathematical + * details (e.g. how to round and truncate numbers) as defined in IEC 61131-3, we will leave this to the future. + * Also, the question will arise if we should also replace calls to standard + * functions if the input parameters are all literals (e.g. ADD(42, 42)). This + * means this class will be more difficult than it appears at first. + */ +void *fill_candidate_datatypes_c::visit( add_expression_c *symbol) {return handle_binary_expression(widen_ADD_table, symbol, symbol->l_exp, symbol->r_exp);} +void *fill_candidate_datatypes_c::visit( sub_expression_c *symbol) {return handle_binary_expression(widen_SUB_table, symbol, symbol->l_exp, symbol->r_exp);} +void *fill_candidate_datatypes_c::visit( mul_expression_c *symbol) {return handle_binary_expression(widen_MUL_table, symbol, symbol->l_exp, symbol->r_exp);} +void *fill_candidate_datatypes_c::visit( div_expression_c *symbol) {return handle_binary_expression(widen_DIV_table, symbol, symbol->l_exp, symbol->r_exp);} +void *fill_candidate_datatypes_c::visit( mod_expression_c *symbol) {return handle_binary_expression(widen_MOD_table, symbol, symbol->l_exp, symbol->r_exp);} +void *fill_candidate_datatypes_c::visit(power_expression_c *symbol) {return handle_binary_expression(widen_EXPT_table, symbol, symbol->l_exp, symbol->r_exp);} + + +void *fill_candidate_datatypes_c::visit(neg_expression_c *symbol) { + /* NOTE: The standard defines the syntax for this 'negation' operation, but + * does not define the its semantics. + * + * We could be tempted to consider that the semantics of the + * 'negation' operation are similar/identical to the semantics of the + * SUB expression/operation. This would include assuming that the + * possible datatypes for the 'negation' operation is also + * the same as those for the SUB expression/operation, namely ANY_MAGNITUDE. + * + * However, this would then mean that the following ST code would be + * syntactically and semantically correct: + * uint_var := - (uint_var); + * + * According to the standard, the above code should result in a + * runtime error, when we try to apply a negative value to the + * UINT typed variable 'uint_var'. + * + * It is much easier for the compiler to detect this at compile time, + * and it is probably safer to the resulting code too. + * + * To detect these tyes of errors at compile time, the easisest solution + * is to only allow ANY_NUM datatytpes that are signed. + * So, that is what we do here! + */ + symbol->exp->accept(*this); + for (unsigned int i = 0; i < symbol->exp->candidate_datatypes.size(); i++) { + if (is_ANY_signed_MAGNITUDE_compatible(symbol->exp->candidate_datatypes[i])) + add_datatype_to_candidate_list(symbol, symbol->exp->candidate_datatypes[i]); + } + if (debug) std::cout << "neg [" << symbol->exp->candidate_datatypes.size() << "] ==> " << symbol->candidate_datatypes.size() << " result.\n"; + return NULL; +} + + +void *fill_candidate_datatypes_c::visit(not_expression_c *symbol) { + symbol->exp->accept(*this); + for (unsigned int i = 0; i < symbol->exp->candidate_datatypes.size(); i++) { + if (is_ANY_BIT_compatible(symbol->exp->candidate_datatypes[i])) + add_datatype_to_candidate_list(symbol, symbol->exp->candidate_datatypes[i]); + } + if (debug) std::cout << "not [" << symbol->exp->candidate_datatypes.size() << "] ==> " << symbol->candidate_datatypes.size() << " result.\n"; + return NULL; +} + + +void *fill_candidate_datatypes_c::visit(function_invocation_c *symbol) { + if (NULL != symbol->formal_param_list) symbol-> formal_param_list->accept(*this); + else if (NULL != symbol->nonformal_param_list) symbol->nonformal_param_list->accept(*this); + else ERROR; + + generic_function_call_t fcall_param = { + /* fcall_param.function_name = */ symbol->function_name, + /* fcall_param.nonformal_operand_list = */ symbol->nonformal_param_list, + /* fcall_param.formal_operand_list = */ symbol->formal_param_list, + /* enum {POU_FB, POU_function} POU_type = */ generic_function_call_t::POU_function, + /* fcall_param.candidate_functions = */ symbol->candidate_functions, + /* fcall_param.called_function_declaration = */ symbol->called_function_declaration, + /* fcall_param.extensible_param_count = */ symbol->extensible_param_count + }; + handle_function_call(symbol, fcall_param); + + if (debug) std::cout << "function_invocation_c [" << symbol->candidate_datatypes.size() << "] result.\n"; + return NULL; +} + + + +/********************/ +/* B 3.2 Statements */ +/********************/ +// SYM_LIST(statement_list_c) +/* The visitor of the base class search_visitor_c will handle calling each instruction in the list. + * We do not need to do anything here... + */ +// void *fill_candidate_datatypes_c::visit(statement_list_c *symbol) + + +/*********************************/ +/* B 3.2.1 Assignment Statements */ +/*********************************/ +void *fill_candidate_datatypes_c::visit(assignment_statement_c *symbol) { + symbol_c *left_type, *right_type; + + symbol->l_exp->accept(*this); + symbol->r_exp->accept(*this); + for (unsigned int i = 0; i < symbol->l_exp->candidate_datatypes.size(); i++) { + for(unsigned int j = 0; j < symbol->r_exp->candidate_datatypes.size(); j++) { + left_type = symbol->l_exp->candidate_datatypes[i]; + right_type = symbol->r_exp->candidate_datatypes[j]; + if (is_type_equal(left_type, right_type)) + add_datatype_to_candidate_list(symbol, left_type); + } + } + if (debug) std::cout << ":= [" << symbol->l_exp->candidate_datatypes.size() << "," << symbol->r_exp->candidate_datatypes.size() << "] ==> " << symbol->candidate_datatypes.size() << " result.\n"; + return NULL; +} + +/*****************************************/ +/* B 3.2.2 Subprogram Control Statements */ +/*****************************************/ +void *fill_candidate_datatypes_c::visit(fb_invocation_c *symbol) { + symbol_c *fb_type_id = search_varfb_instance_type->get_basetype_id(symbol->fb_name); + /* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */ + if (NULL == fb_type_id) ERROR; + + function_block_declaration_c *fb_decl = function_block_type_symtable.find_value(fb_type_id); + if (function_block_type_symtable.end_value() == fb_decl) + /* The fb_name not the name of a FB instance. Most probably it is the name of a variable of some other type. */ + fb_decl = NULL; + + /* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */ + if (NULL == fb_decl) ERROR; + + if (symbol-> formal_param_list != NULL) symbol->formal_param_list->accept(*this); + if (symbol->nonformal_param_list != NULL) symbol->nonformal_param_list->accept(*this); + + /* The print_datatypes_error_c does not rely on this called_fb_declaration pointer being != NULL to conclude that + * we have a datat type incompatibility error, so setting it to the correct fb_decl is actually safe, + * as the compiler will never reach the compilation stage! + */ + symbol->called_fb_declaration = fb_decl; + + if (debug) std::cout << "FB [] ==> " << symbol->candidate_datatypes.size() << " result.\n"; + return NULL; +} + + + +/********************************/ +/* B 3.2.3 Selection Statements */ +/********************************/ +void *fill_candidate_datatypes_c::visit(if_statement_c *symbol) { + symbol->expression->accept(*this); + if (NULL != symbol->statement_list) + symbol->statement_list->accept(*this); + if (NULL != symbol->elseif_statement_list) + symbol->elseif_statement_list->accept(*this); + if (NULL != symbol->else_statement_list) + symbol->else_statement_list->accept(*this); + return NULL; +} + + +void *fill_candidate_datatypes_c::visit(elseif_statement_c *symbol) { + symbol->expression->accept(*this); + if (NULL != symbol->statement_list) + symbol->statement_list->accept(*this); + return NULL; +} + +/* CASE expression OF case_element_list ELSE statement_list END_CASE */ +// SYM_REF3(case_statement_c, expression, case_element_list, statement_list) +void *fill_candidate_datatypes_c::visit(case_statement_c *symbol) { + symbol->expression->accept(*this); + if (NULL != symbol->case_element_list) + symbol->case_element_list->accept(*this); + if (NULL != symbol->statement_list) + symbol->statement_list->accept(*this); + return NULL; +} + + +/* helper symbol for case_statement */ +// SYM_LIST(case_element_list_c) +/* NOTE: visitor method for case_element_list_c is not required since we inherit from iterator_visitor_c */ + +/* case_list ':' statement_list */ +// SYM_REF2(case_element_c, case_list, statement_list) +/* NOTE: visitor method for case_element_c is not required since we inherit from iterator_visitor_c */ + +// SYM_LIST(case_list_c) +/* NOTE: visitor method for case_list_c is not required since we inherit from iterator_visitor_c */ + +/********************************/ +/* B 3.2.4 Iteration Statements */ +/********************************/ + +void *fill_candidate_datatypes_c::visit(for_statement_c *symbol) { + symbol->control_variable->accept(*this); + symbol->beg_expression->accept(*this); + symbol->end_expression->accept(*this); + if (NULL != symbol->by_expression) + symbol->by_expression->accept(*this); + if (NULL != symbol->statement_list) + symbol->statement_list->accept(*this); + return NULL; +} + + +void *fill_candidate_datatypes_c::visit(while_statement_c *symbol) { + symbol->expression->accept(*this); + if (NULL != symbol->statement_list) + symbol->statement_list->accept(*this); + return NULL; +} + + +void *fill_candidate_datatypes_c::visit(repeat_statement_c *symbol) { + symbol->expression->accept(*this); + if (NULL != symbol->statement_list) + symbol->statement_list->accept(*this); + return NULL; +} + + + + + + diff -r 34a5571c859c -r 0bb88139e471 stage3/fill_candidate_datatypes.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stage3/fill_candidate_datatypes.hh Sat Mar 31 21:46:37 2012 +0100 @@ -0,0 +1,335 @@ +/* + * matiec - a compiler for the programming languages defined in IEC 61131-3 + * + * Copyright (C) 2009-2012 Mario de Sousa (msousa@fe.up.pt) + * Copyright (C) 2012 Manuele Conti (manuele.conti@sirius-es.it) + * Copyright (C) 2012 Matteo Facchinetti (matteo.facchinetti@sirius-es.it) + * + * + * 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 3 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, see . + * + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + */ + +/* + * An IEC 61131-3 compiler. + * + * Based on the + * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) + * + */ + + +#include "../absyntax_utils/absyntax_utils.hh" +#include "datatype_functions.hh" + +class fill_candidate_datatypes_c: public iterator_visitor_c { + + private: + search_varfb_instance_type_c *search_varfb_instance_type; + search_base_type_c search_base_type; + /* When calling a function block, we must first find it's type, + * by searching through the declarations of the variables currently + * in scope. + * This class does just that... + * A new object instance is instantiated whenever we start checking semantics + * for a function block type declaration, or a program declaration. + * This object instance will then later be called while the + * function block's or the program's body is being handled. + * + * Note that functions cannot contain calls to function blocks, + * so we do not create an object instance when handling + * a function declaration. + */ + // search_var_instance_decl_c *search_var_instance_decl; + + /* This variable was created to pass information from + * fill_candidate_datatypes_c::visit(case_statement_c *symbol) function to + * fill_candidate_datatypes_c::visit(case_list_c *symbol) function. + */ +// symbol_c *case_expression_type; + + /* In IL code, once we find a type mismatch error, it is best to + * ignore any further errors until the end of the logical operation, + * i.e. until the next LD. + * However, we cannot clear the il_error flag on all LD operations, + * as these may also be used within parenthesis. LD operations + * within parenthesis may not clear the error flag. + * We therefore need a counter to know how deep inside a parenthesis + * structure we are. + */ +// int il_parenthesis_level; +// bool error_found; + + /* the current data type of the data stored in the IL stack, i.e. the default variable */ + symbol_c *prev_il_instruction; + /* the current IL operand being analyzed - its symbol and its data type */ + symbol_c *il_operand_type; + symbol_c *il_operand; + symbol_c *widening_conversion(symbol_c *left_type, symbol_c *right_type, const struct widen_entry widen_table[]); + + /* Match a function declaration with a function call through their parameters.*/ + /* returns true if compatible function/FB invocation, otherwise returns false */ + bool match_nonformal_call(symbol_c *f_call, symbol_c *f_decl); + bool match_formal_call (symbol_c *f_call, symbol_c *f_decl, symbol_c **first_param_datatype = NULL); + void handle_function_call(symbol_c *fcall, generic_function_call_t fcall_data); + void *handle_implicit_il_fb_call(symbol_c *il_instruction, const char *param_name, symbol_c *&called_fb_declaration); + void *handle_binary_expression(const struct widen_entry widen_table[], symbol_c *symbol, symbol_c *l_expr, symbol_c *r_expr); + void *handle_binary_operator (const struct widen_entry widen_table[], symbol_c *symbol, symbol_c *l_expr, symbol_c *r_expr); + void *handle_conditional_il_flow_control_operator(symbol_c *symbol); + + /* a helper function... */ + symbol_c *base_type(symbol_c *symbol); + + /* add a data type to a candidate data type list, while guaranteeing no duplicate entries! */ + /* Returns true if it really did add the datatype to the list, or false if it was already present in the list! */ + bool add_datatype_to_candidate_list (symbol_c *symbol, symbol_c *datatype); + bool add_2datatypes_to_candidate_list(symbol_c *symbol, symbol_c *datatype1, symbol_c *datatype2); + + + public: + fill_candidate_datatypes_c(symbol_c *ignore); + virtual ~fill_candidate_datatypes_c(void); + + + /*********************/ + /* B 1.2 - Constants */ + /*********************/ + /******************************/ + /* B 1.2.1 - Numeric Literals */ + /******************************/ + void *handle_any_integer(symbol_c *symbol); + void *handle_any_real (symbol_c *symbol); + void *handle_any_literal(symbol_c *symbol, symbol_c *symbol_value, symbol_c *symbol_type); + + void *visit(real_c *symbol); + void *visit(integer_c *symbol); + void *visit(neg_real_c *symbol); + void *visit(neg_integer_c *symbol); + void *visit(binary_integer_c *symbol); + void *visit(octal_integer_c *symbol); + void *visit(hex_integer_c *symbol); + void *visit(integer_literal_c *symbol); + void *visit(real_literal_c *symbol); + void *visit(bit_string_literal_c *symbol); + void *visit(boolean_literal_c *symbol); + void *visit(boolean_true_c *symbol); + void *visit(boolean_false_c *symbol); + + /*******************************/ + /* B.1.2.2 Character Strings */ + /*******************************/ + void *visit(double_byte_character_string_c *symbol); + void *visit(single_byte_character_string_c *symbol); + + /***************************/ + /* B 1.2.3 - Time Literals */ + /***************************/ + /************************/ + /* B 1.2.3.1 - Duration */ + /************************/ + void *visit(duration_c *symbol); + + /************************************/ + /* B 1.2.3.2 - Time of day and Date */ + /************************************/ + void *visit(time_of_day_c *symbol); + void *visit(date_c *symbol); + void *visit(date_and_time_c *symbol); + + + /**********************/ + /* B 1.3 - Data types */ + /**********************/ + /********************************/ + /* B 1.3.3 - Derived data types */ + /********************************/ + void *visit(subrange_c *symbol); +// void *visit(data_type_declaration_c *symbol); + void *visit(enumerated_value_c *symbol); + + /*********************/ + /* B 1.4 - Variables */ + /*********************/ + void *visit(symbolic_variable_c *symbol); + + /********************************************/ + /* B 1.4.1 - Directly Represented Variables */ + /********************************************/ + void *visit(direct_variable_c *symbol); + + /*************************************/ + /* B 1.4.2 - Multi-element variables */ + /*************************************/ + void *visit(array_variable_c *symbol); + void *visit(structured_variable_c *symbol); + + /**************************************/ + /* B 1.5 - Program organization units */ + /**************************************/ + /***********************/ + /* B 1.5.1 - Functions */ + /***********************/ + void *visit(function_declaration_c *symbol); + + /*****************************/ + /* B 1.5.2 - Function blocks */ + /*****************************/ + void *visit(function_block_declaration_c *symbol); + + /**********************/ + /* B 1.5.3 - Programs */ + /**********************/ + void *visit(program_declaration_c *symbol); + + /********************************/ + /* B 1.7 Configuration elements */ + /********************************/ + void *visit(configuration_declaration_c *symbol); + + /****************************************/ + /* B.2 - Language IL (Instruction List) */ + /****************************************/ + /***********************************/ + /* B 2.1 Instructions and Operands */ + /***********************************/ + void *visit(instruction_list_c *symbol); + void *visit(il_instruction_c *symbol); + void *visit(il_simple_operation_c *symbol); + void *visit(il_function_call_c *symbol); + void *visit(il_expression_c *symbol); + void *visit(il_jump_operation_c *symbol); + void *visit(il_fb_call_c *symbol); + void *visit(il_formal_funct_call_c *symbol); +// void *visit(il_operand_list_c *symbol); + void *visit(simple_instr_list_c *symbol); + void *visit(il_simple_instruction_c*symbol); +// void *visit(il_param_list_c *symbol); +// void *visit(il_param_assignment_c *symbol); +// void *visit(il_param_out_assignment_c *symbol); + + /*******************/ + /* B 2.2 Operators */ + /*******************/ + void *visit(LD_operator_c *symbol); + void *visit(LDN_operator_c *symbol); + void *visit(ST_operator_c *symbol); + void *visit(STN_operator_c *symbol); + void *visit(NOT_operator_c *symbol); + void *visit(S_operator_c *symbol); + void *visit(R_operator_c *symbol); + void *visit(S1_operator_c *symbol); + void *visit(R1_operator_c *symbol); + void *visit(CLK_operator_c *symbol); + void *visit(CU_operator_c *symbol); + void *visit(CD_operator_c *symbol); + void *visit(PV_operator_c *symbol); + void *visit(IN_operator_c *symbol); + void *visit(PT_operator_c *symbol); + void *visit(AND_operator_c *symbol); + void *visit(OR_operator_c *symbol); + void *visit(XOR_operator_c *symbol); + void *visit(ANDN_operator_c *symbol); + void *visit(ORN_operator_c *symbol); + void *visit(XORN_operator_c *symbol); + void *visit(ADD_operator_c *symbol); + void *visit(SUB_operator_c *symbol); + void *visit(MUL_operator_c *symbol); + void *visit(DIV_operator_c *symbol); + void *visit(MOD_operator_c *symbol); + void *visit(GT_operator_c *symbol); + void *visit(GE_operator_c *symbol); + void *visit(EQ_operator_c *symbol); + void *visit(LT_operator_c *symbol); + void *visit(LE_operator_c *symbol); + void *visit(NE_operator_c *symbol); + void *visit(CAL_operator_c *symbol); + void *visit(CALC_operator_c *symbol); + void *visit(CALCN_operator_c *symbol); + void *visit(RET_operator_c *symbol); + void *visit(RETC_operator_c *symbol); + void *visit(RETCN_operator_c *symbol); + void *visit(JMP_operator_c *symbol); + void *visit(JMPC_operator_c *symbol); + void *visit(JMPCN_operator_c *symbol); + /* Symbol class handled together with function call checks */ + // void *visit(il_assign_operator_c *symbol, variable_name); + /* Symbol class handled together with function call checks */ + // void *visit(il_assign_operator_c *symbol, option, variable_name); + + + /***************************************/ + /* B.3 - Language ST (Structured Text) */ + /***************************************/ + /***********************/ + /* B 3.1 - Expressions */ + /***********************/ + void *visit(or_expression_c *symbol); + void *visit(xor_expression_c *symbol); + void *visit(and_expression_c *symbol); + void *visit(equ_expression_c *symbol); + void *visit(notequ_expression_c *symbol); + void *visit(lt_expression_c *symbol); + void *visit(gt_expression_c *symbol); + void *visit(le_expression_c *symbol); + void *visit(ge_expression_c *symbol); + void *visit(add_expression_c *symbol); + void *visit(sub_expression_c *symbol); + void *visit(mul_expression_c *symbol); + void *visit(div_expression_c *symbol); + void *visit(mod_expression_c *symbol); + void *visit(power_expression_c *symbol); + void *visit(neg_expression_c *symbol); + void *visit(not_expression_c *symbol); + void *visit(function_invocation_c *symbol); + + /*********************************/ + /* B 3.2.1 Assignment Statements */ + /*********************************/ + void *visit(assignment_statement_c *symbol); + + /*****************************************/ + /* B 3.2.2 Subprogram Control Statements */ + /*****************************************/ + void *visit(fb_invocation_c *symbol); + + /********************************/ + /* B 3.2.3 Selection Statements */ + /********************************/ + void *visit(if_statement_c *symbol); + // void *visit(elseif_statement_list_c *symbol); + void *visit(elseif_statement_c *symbol); + void *visit(case_statement_c *symbol); + + /********************************/ + /* B 3.2.4 Iteration Statements */ + /********************************/ + void *visit(for_statement_c *symbol); + void *visit(while_statement_c *symbol); + void *visit(repeat_statement_c *symbol); + +}; // fill_candidate_datatypes_c + + + + + + + + + + + diff -r 34a5571c859c -r 0bb88139e471 stage3/flow_control_analysis.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stage3/flow_control_analysis.cc Sat Mar 31 21:46:37 2012 +0100 @@ -0,0 +1,373 @@ +/* + * matiec - a compiler for the programming languages defined in IEC 61131-3 + * + * Copyright (C) 2012 Mario de Sousa (msousa@fe.up.pt) + * + * 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 3 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, see . + * + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + */ + +/* + * An IEC 61131-3 compiler. + * + * Based on the + * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) + * + */ + + +/* + * Do flow control analysis of the IEC 61131-3 code. + * + * We currently only do this for IL code. + * This class will annotate the abstract syntax tree, by filling in the + * prev_il_instruction variable in the il_instruction_c, so it points to + * the previous il_instruction_c object in the instruction list instruction_list_c. + * + * Since IL code can contain jumps (JMP), the same il_instruction may effectively have + * several previous il_instructions. In order to accommodate this, each il_instruction + * will maintain a vector (i..e an array) of pointers to all the previous il_instructions. + * We do however attempt to guarantee that the first element in the vector (array) will preferentially + * point to the il instruction that is right before / imediately preceding the current il instructions, + * i.e. the first element in the array will tend to point to the previous il_instruction + * that is not a jump JMP IL instruction! + * + * The result will essentially be a graph of il_instruction_c objects, each + * pointing to the previous il_instruction_c object. + * + * The reality is we will get several independent and isolated linked lists + * (actually, since we now process labels correctly, this is really a graph): + * one for each block of IL code (e.g. inside a Function, FB or Program). + * Additionally, when the IL code has an expression (expression_c object), we will actually + * have one more isolated linked list for the IL code inside that expression. + * + * e.g. + * line_1: LD 1 + * line_2: ADD (42 + * line_3: ADD B + * line_4: ADD C + * line_5: ) + * line_6: ADD D + * line_7: ST E + * + * will result in two independent linked lists: + * main list: line_7 -> line_6 -> line2 -> line_1 + * expr list: lin4_4 -> line_3 -> (operand of line_2, i.e. '42') + * + * + * In the main list, each: + * line_x: IL_operation IL_operand + * is encoded as + * il_instruction_c(label, il_incomplete_instruction) + * these il_instruction_c objects will point back to the previous il_instruction_c object. + * + * In the expr list, each + * line_x: IL_operation IL_operand + * is encoded as + * il_simple_instruction_c(il_simple_instruction) + * these il_simple_instruction_c objects will point back to the previous il_simple_instruction_c object, + * except the for the first il_simple_instruction_c object in the list, which will point back to + * the first il_operand (in the above example, '42'), or NULL is it does not exist. + * + * + * label: + * identifier_c + * + * il_incomplete_instruction: + * il_simple_operation (il_simple_operation_c, il_function_call_c) + * | il_expression (il_expression_c) + * | il_jump_operation (il_jump_operation_c) + * | il_fb_call (il_fb_call_c) + * | il_formal_funct_call (il_formal_funct_call_c) + * | il_return_operator (RET_operator_c, RETC_operator_c, RETCN_operator_c) + * + * + * il_expression_c(il_expr_operator, il_operand, simple_instr_list) + * + * il_operand: + * variable (symbolic_variable_c, direct_variable_c, array_variable_c, structured_variable_c) + * | enumerated_value (enumerated_value_c) + * | constant (lots of literal classes _c) + * + * simple_instr_list: + * list of il_simple_instruction + * + * il_simple_instruction: + * il_simple_operation (il_simple_operation_c, il_function_call_c) + * | il_expression (il_expression_c) + * | il_formal_funct_call (il_formal_funct_call_c) + * + */ + +#include "flow_control_analysis.hh" + + + +/* set to 1 to see debug info during execution */ +static int debug = 0; + +flow_control_analysis_c::flow_control_analysis_c(symbol_c *ignore) { + prev_il_instruction = NULL; + curr_il_instruction = NULL; +} + +flow_control_analysis_c::~flow_control_analysis_c(void) { +} + + + +/************************************/ +/* B 1.5 Program organization units */ +/************************************/ +/*********************/ +/* B 1.5.1 Functions */ +/*********************/ +void *flow_control_analysis_c::visit(function_declaration_c *symbol) { + search_il_label = new search_il_label_c(symbol); + if (debug) printf("Doing flow control analysis in body of function %s\n", ((token_c *)(symbol->derived_function_name))->value); + symbol->function_body->accept(*this); + delete search_il_label; + search_il_label = NULL; + return NULL; +} + +/***************************/ +/* B 1.5.2 Function blocks */ +/***************************/ +void *flow_control_analysis_c::visit(function_block_declaration_c *symbol) { + search_il_label = new search_il_label_c(symbol); + if (debug) printf("Doing flow control analysis in body of FB %s\n", ((token_c *)(symbol->fblock_name))->value); + symbol->fblock_body->accept(*this); + delete search_il_label; + search_il_label = NULL; + return NULL; +} + +/********************/ +/* B 1.5.3 Programs */ +/********************/ +void *flow_control_analysis_c::visit(program_declaration_c *symbol) { + search_il_label = new search_il_label_c(symbol); + if (debug) printf("Doing flow control analysis in body of program %s\n", ((token_c *)(symbol->program_type_name))->value); + symbol->function_block_body->accept(*this); + delete search_il_label; + search_il_label = NULL; + return NULL; +} + + +/********************************/ +/* B 1.7 Configuration elements */ +/********************************/ +void *flow_control_analysis_c::visit(configuration_declaration_c *symbol) { + return NULL; +} + + +/****************************************/ +/* B.2 - Language IL (Instruction List) */ +/****************************************/ +/***********************************/ +/* B 2.1 Instructions and Operands */ +/***********************************/ + +/*| instruction_list il_instruction */ +// SYM_LIST(instruction_list_c) +void *flow_control_analysis_c::visit(instruction_list_c *symbol) { + prev_il_instruction_is_JMP_or_RET = false; + for(int i = 0; i < symbol->n; i++) { + prev_il_instruction = NULL; + if (i > 0) prev_il_instruction = symbol->elements[i-1]; + curr_il_instruction = symbol->elements[i]; + curr_il_instruction->accept(*this); + curr_il_instruction = NULL; + } + return NULL; +} + +/* | label ':' [il_incomplete_instruction] eol_list */ +// SYM_REF2(il_instruction_c, label, il_instruction) +// void *visit(instruction_list_c *symbol); +void *flow_control_analysis_c::visit(il_instruction_c *symbol) { + if ((NULL != prev_il_instruction) && (!prev_il_instruction_is_JMP_or_RET)) + /* We try to guarantee that the previous il instruction that is in the previous line, will occupy the first element of the vector. + * In order to do that, we use insert() instead of push_back() + */ + symbol->prev_il_instruction.insert(symbol->prev_il_instruction.begin() , prev_il_instruction); + + /* check if it is an il_expression_c, a JMP[C[N]], or a RET, and if so, handle it correctly */ + prev_il_instruction_is_JMP_or_RET = false; + if (NULL != symbol->il_instruction) + symbol->il_instruction->accept(*this); + return NULL; +} + + + +/* | il_simple_operator [il_operand] */ +// SYM_REF2(il_simple_operation_c, il_simple_operator, il_operand) +// void *flow_control_analysis_c::visit(il_simple_operation_c *symbol) + + + +/* | function_name [il_operand_list] */ +/* NOTE: The parameters 'called_function_declaration' and 'extensible_param_count' are used to pass data between the stage 3 and stage 4. */ +// SYM_REF2(il_function_call_c, function_name, il_operand_list, symbol_c *called_function_declaration; int extensible_param_count;) +// void *flow_control_analysis_c::visit(il_function_call_c *symbol) + + +/* | il_expr_operator '(' [il_operand] eol_list [simple_instr_list] ')' */ +// SYM_REF3(il_expression_c, il_expr_operator, il_operand, simple_instr_list); +void *flow_control_analysis_c::visit(il_expression_c *symbol) { + if(NULL == symbol->simple_instr_list) + /* nothing to do... */ + return NULL; + + symbol_c *save_prev_il_instruction = prev_il_instruction; + prev_il_instruction = symbol->il_operand; + symbol->simple_instr_list->accept(*this); + prev_il_instruction = save_prev_il_instruction; + return NULL; +} + + +/* il_jump_operator label */ +// SYM_REF2(il_jump_operation_c, il_jump_operator, label) +void *flow_control_analysis_c::visit(il_jump_operation_c *symbol) { + /* search for the il_instruction_c containing the label */ + il_instruction_c *destination = search_il_label->find_label(symbol->label); + + /* give the visit(JMP_operator *) an oportunity to set the prev_il_instruction_is_JMP_or_RET flag! */ + symbol->il_jump_operator->accept(*this); + /* add, to that il_instruction's list of prev_il_intsructions, the curr_il_instruction */ + if (NULL != destination) + destination->prev_il_instruction.push_back(curr_il_instruction); + return NULL; +} + + +/* il_call_operator prev_declared_fb_name + * | il_call_operator prev_declared_fb_name '(' ')' + * | il_call_operator prev_declared_fb_name '(' eol_list ')' + * | il_call_operator prev_declared_fb_name '(' il_operand_list ')' + * | il_call_operator prev_declared_fb_name '(' eol_list il_param_list ')' + */ +/* NOTE: The parameter 'called_fb_declaration'is used to pass data between stage 3 and stage4 (although currently it is not used in stage 4 */ +// SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list, symbol_c *called_fb_declaration) +// void *flow_control_analysis_c::visit(il_fb_call_c *symbol) + + +/* | function_name '(' eol_list [il_param_list] ')' */ +/* NOTE: The parameter 'called_function_declaration' is used to pass data between the stage 3 and stage 4. */ +// SYM_REF2(il_formal_funct_call_c, function_name, il_param_list, symbol_c *called_function_declaration; int extensible_param_count;) +// void *flow_control_analysis_c::visit(il_formal_funct_call_c *symbol) + + + +// void *visit(il_operand_list_c *symbol); +void *flow_control_analysis_c::visit(simple_instr_list_c *symbol) { + for(int i = 0; i < symbol->n; i++) { + /* The prev_il_instruction for element[0] was set in visit(il_expression_c *) */ + if (i>0) prev_il_instruction = symbol->elements[i-1]; + symbol->elements[i]->accept(*this); + } + return NULL; +} + + +// SYM_REF1(il_simple_instruction_c, il_simple_instruction, symbol_c *prev_il_instruction;) +void *flow_control_analysis_c::visit(il_simple_instruction_c*symbol) { + if (NULL != prev_il_instruction) + /* We try to guarantee that the previous il instruction that is in the previous line, will occupy the first element of the vector. + * In order to do that, we use insert() instead of push_back() + */ + symbol->prev_il_instruction.insert(symbol->prev_il_instruction.begin() , prev_il_instruction); + return NULL; +} + + +/* + void *visit(il_param_list_c *symbol); + void *visit(il_param_assignment_c *symbol); + void *visit(il_param_out_assignment_c *symbol); + */ + + + + +/*******************/ +/* B 2.2 Operators */ +/*******************/ +// void *visit( LD_operator_c *symbol); +// void *visit( LDN_operator_c *symbol); +// void *visit( ST_operator_c *symbol); +// void *visit( STN_operator_c *symbol); +// void *visit( NOT_operator_c *symbol); +// void *visit( S_operator_c *symbol); +// void *visit( R_operator_c *symbol); +// void *visit( S1_operator_c *symbol); +// void *visit( R1_operator_c *symbol); +// void *visit( CLK_operator_c *symbol); +// void *visit( CU_operator_c *symbol); +// void *visit( CD_operator_c *symbol); +// void *visit( PV_operator_c *symbol); +// void *visit( IN_operator_c *symbol); +// void *visit( PT_operator_c *symbol); +// void *visit( AND_operator_c *symbol); +// void *visit( OR_operator_c *symbol); +// void *visit( XOR_operator_c *symbol); +// void *visit( ANDN_operator_c *symbol); +// void *visit( ORN_operator_c *symbol); +// void *visit( XORN_operator_c *symbol); +// void *visit( ADD_operator_c *symbol); +// void *visit( SUB_operator_c *symbol); +// void *visit( MUL_operator_c *symbol); +// void *visit( DIV_operator_c *symbol); +// void *visit( MOD_operator_c *symbol); +// void *visit( GT_operator_c *symbol); +// void *visit( GE_operator_c *symbol); +// void *visit( EQ_operator_c *symbol); +// void *visit( LT_operator_c *symbol); +// void *visit( LE_operator_c *symbol); +// void *visit( NE_operator_c *symbol); +// void *visit( CAL_operator_c *symbol); +// void *visit( CALC_operator_c *symbol); +// void *visit(CALCN_operator_c *symbol); + +/* this next visit function will be called directly from visit(il_instruction_c *) */ +void *flow_control_analysis_c::visit( RET_operator_c *symbol) { + prev_il_instruction_is_JMP_or_RET = true; + return NULL; +} + +// void *visit( RETC_operator_c *symbol); +// void *visit(RETCN_operator_c *symbol); + +/* this next visit function will be called from visit(il_jump_operation_c *) */ +void *flow_control_analysis_c::visit( JMP_operator_c *symbol) { + prev_il_instruction_is_JMP_or_RET = true; + return NULL; +} + +// void *visit( JMPC_operator_c *symbol); +// void *visit(JMPCN_operator_c *symbol); + +/* Symbol class handled together with function call checks */ +// void *visit(il_assign_operator_c *symbol, variable_name); +/* Symbol class handled together with function call checks */ +// void *visit(il_assign_operator_c *symbol, option, variable_name); + diff -r 34a5571c859c -r 0bb88139e471 stage3/flow_control_analysis.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stage3/flow_control_analysis.hh Sat Mar 31 21:46:37 2012 +0100 @@ -0,0 +1,162 @@ +/* + * matiec - a compiler for the programming languages defined in IEC 61131-3 + * + * Copyright (C) 2012 Mario de Sousa (msousa@fe.up.pt) + * + * + * 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 3 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, see . + * + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + */ + +/* + * An IEC 61131-3 compiler. + * + * Based on the + * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) + * + */ + + +/* + * Do flow control analysis of the IEC 61131-3 code. + * + * We currently only do this for IL code. + * This class will annotate the abstract syntax tree, by filling in the + * prev_il_instruction variable in the il_instruction_c, so it points to + * the previous il_instruction_c object in the instruction list instruction_list_c. + */ + + + +#include "../absyntax_utils/absyntax_utils.hh" + + +class flow_control_analysis_c: public iterator_visitor_c { + + private: + search_il_label_c *search_il_label; + symbol_c *prev_il_instruction; + symbol_c *curr_il_instruction; + bool prev_il_instruction_is_JMP_or_RET; + + public: + flow_control_analysis_c(symbol_c *ignore); + virtual ~flow_control_analysis_c(void); + + /**************************************/ + /* B 1.5 - Program organization units */ + /**************************************/ + /***********************/ + /* B 1.5.1 - Functions */ + /***********************/ + void *visit(function_declaration_c *symbol); + + /*****************************/ + /* B 1.5.2 - Function blocks */ + /*****************************/ + void *visit(function_block_declaration_c *symbol); + + /**********************/ + /* B 1.5.3 - Programs */ + /**********************/ + void *visit(program_declaration_c *symbol); + + /********************************/ + /* B 1.7 Configuration elements */ + /********************************/ + void *visit(configuration_declaration_c *symbol); + + /****************************************/ + /* B.2 - Language IL (Instruction List) */ + /****************************************/ + /***********************************/ + /* B 2.1 Instructions and Operands */ + /***********************************/ + void *visit(instruction_list_c *symbol); + void *visit(il_instruction_c *symbol); +// void *visit(il_simple_operation_c *symbol); +// void *visit(il_function_call_c *symbol); + void *visit(il_expression_c *symbol); + void *visit(il_jump_operation_c *symbol); +// void *visit(il_fb_call_c *symbol); +// void *visit(il_formal_funct_call_c *symbol); +// void *visit(il_operand_list_c *symbol); + void *visit(simple_instr_list_c *symbol); + void *visit(il_simple_instruction_c*symbol); +// void *visit(il_param_list_c *symbol); +// void *visit(il_param_assignment_c *symbol); +// void *visit(il_param_out_assignment_c *symbol); + + /*******************/ + /* B 2.2 Operators */ + /*******************/ +// void *visit( LD_operator_c *symbol); +// void *visit( LDN_operator_c *symbol); +// void *visit( ST_operator_c *symbol); +// void *visit( STN_operator_c *symbol); +// void *visit( NOT_operator_c *symbol); +// void *visit( S_operator_c *symbol); +// void *visit( R_operator_c *symbol); +// void *visit( S1_operator_c *symbol); +// void *visit( R1_operator_c *symbol); +// void *visit( CLK_operator_c *symbol); +// void *visit( CU_operator_c *symbol); +// void *visit( CD_operator_c *symbol); +// void *visit( PV_operator_c *symbol); +// void *visit( IN_operator_c *symbol); +// void *visit( PT_operator_c *symbol); +// void *visit( AND_operator_c *symbol); +// void *visit( OR_operator_c *symbol); +// void *visit( XOR_operator_c *symbol); +// void *visit( ANDN_operator_c *symbol); +// void *visit( ORN_operator_c *symbol); +// void *visit( XORN_operator_c *symbol); +// void *visit( ADD_operator_c *symbol); +// void *visit( SUB_operator_c *symbol); +// void *visit( MUL_operator_c *symbol); +// void *visit( DIV_operator_c *symbol); +// void *visit( MOD_operator_c *symbol); +// void *visit( GT_operator_c *symbol); +// void *visit( GE_operator_c *symbol); +// void *visit( EQ_operator_c *symbol); +// void *visit( LT_operator_c *symbol); +// void *visit( LE_operator_c *symbol); +// void *visit( NE_operator_c *symbol); +// void *visit( CAL_operator_c *symbol); +// void *visit( CALC_operator_c *symbol); +// void *visit(CALCN_operator_c *symbol); + void *visit( RET_operator_c *symbol); +// void *visit( RETC_operator_c *symbol); +// void *visit(RETCN_operator_c *symbol); + void *visit( JMP_operator_c *symbol); +// void *visit( JMPC_operator_c *symbol); +// void *visit(JMPCN_operator_c *symbol); + + /* Symbol class handled together with function call checks */ + // void *visit(il_assign_operator_c *symbol, variable_name); + /* Symbol class handled together with function call checks */ + // void *visit(il_assign_operator_c *symbol, option, variable_name); + +}; // flow_control_analysis_c + + + + + + + + diff -r 34a5571c859c -r 0bb88139e471 stage3/narrow_candidate_datatypes.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stage3/narrow_candidate_datatypes.cc Sat Mar 31 21:46:37 2012 +0100 @@ -0,0 +1,1257 @@ +/* + * matiec - a compiler for the programming languages defined in IEC 61131-3 + * + * Copyright (C) 2009-2012 Mario de Sousa (msousa@fe.up.pt) + * Copyright (C) 2012 Manuele Conti (manuele.conti@sirius-es.it) + * Copyright (C) 2012 Matteo Facchinetti (matteo.facchinetti@sirius-es.it) + * + * 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 3 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, see . + * + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + */ + +/* + * An IEC 61131-3 compiler. + * + * Based on the + * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) + * + */ + + +/* + * Narrow class select and store a data type from candidate data types list for all symbols + */ + +#include "narrow_candidate_datatypes.hh" +#include "datatype_functions.hh" +#include +#include +#include +#include +#include + + +/* set to 1 to see debug info during execution */ +static int debug = 0; + +narrow_candidate_datatypes_c::narrow_candidate_datatypes_c(symbol_c *ignore) { +} + +narrow_candidate_datatypes_c::~narrow_candidate_datatypes_c(void) { +} + + +/* Only set the symbol's desired datatype to 'datatype' if that datatype is in the candidate_datatype list */ +static void set_datatype(symbol_c *datatype, symbol_c *symbol) { + + /* If we are trying to set to the undefined type, and the symbol's datatype has already been set to something else, + * we abort the compoiler as I don't think this should ever occur. + * NOTE: In order to handle JMPs to labels that come before the JMP itself, we run the narrow algorithm twice. + * This means that this situation may legally occur, so we cannot abort the compiler here! + */ +// if ((NULL == datatype) && (NULL != symbol->datatype)) ERROR; + if ((NULL == datatype) && (NULL != symbol->datatype)) return; + if ((NULL == datatype) && (NULL == symbol->datatype)) return; + + if (search_in_candidate_datatype_list(datatype, symbol->candidate_datatypes) < 0) + symbol->datatype = &(search_constant_type_c::invalid_type_name); + else { + if (NULL == symbol->datatype) + /* not yet set to anything, so we set it to the requested data type */ + symbol->datatype = datatype; + else { + /* had already been set previously to some data type. Let's check if they are the same! */ + if (!is_type_equal(symbol->datatype, datatype)) + symbol->datatype = &(search_constant_type_c::invalid_type_name); +// else + /* we leave it unchanged, as it is the same as the requested data type! */ + } + } +} + + + +/* Only set the symbol's desired datatype to 'datatype' if that datatype is in the candidate_datatype list */ +// static void set_datatype_in_prev_il_instructions(symbol_c *datatype, std::vector prev_il_instructions) { +static void set_datatype_in_prev_il_instructions(symbol_c *datatype, il_instruction_c *symbol) { + if (NULL == symbol) ERROR; + for (unsigned int i = 0; i < symbol->prev_il_instruction.size(); i++) + set_datatype(datatype, symbol->prev_il_instruction[i]); +} + + + +bool narrow_candidate_datatypes_c::is_widening_compatible(const struct widen_entry widen_table[], symbol_c *left_type, symbol_c *right_type, symbol_c *result_type, bool *deprecated_status) { + for (int k = 0; NULL != widen_table[k].left; k++) { + if ((typeid(*left_type) == typeid(*widen_table[k].left)) + && (typeid(*right_type) == typeid(*widen_table[k].right)) + && (typeid(*result_type) == typeid(*widen_table[k].result))) { + if (NULL != deprecated_status) + *deprecated_status = (widen_table[k].status == widen_entry::deprecated); + return true; + } + } + return false; +} + +/* + * All parameters being passed to the called function MUST be in the parameter list to which f_call points to! + * This means that, for non formal function calls in IL, de current (default value) must be artificially added to the + * beginning of the parameter list BEFORE calling handle_function_call(). + */ +void narrow_candidate_datatypes_c::narrow_nonformal_call(symbol_c *f_call, symbol_c *f_decl, int *ext_parm_count) { + symbol_c *call_param_value, *param_type; + identifier_c *param_name; + function_param_iterator_c fp_iterator(f_decl); + function_call_param_iterator_c fcp_iterator(f_call); + int extensible_parameter_highest_index = -1; + unsigned int i; + + if (NULL != ext_parm_count) *ext_parm_count = -1; + + /* Iterating through the non-formal parameters of the function call */ + while((call_param_value = fcp_iterator.next_nf()) != NULL) { + /* Obtaining the type of the value being passed in the function call */ + /* Iterate to the next parameter of the function being called. + * Get the name of that parameter, and ignore if EN or ENO. + */ + do { + param_name = fp_iterator.next(); + /* If there is no other parameter declared, then we are passing too many parameters... */ + /* This error should have been caught in fill_candidate_datatypes_c, but may occur here again when we handle FB invocations! + * In this case, we carry on analysing the code in order to be able to provide relevant error messages + * for that code too! + */ + if(param_name == NULL) break; + } while ((strcmp(param_name->value, "EN") == 0) || (strcmp(param_name->value, "ENO") == 0)); + + /* Set the desired datatype for this parameter, and call it recursively. */ + /* Note that if the call has more parameters than those declared in the function/FB declaration, + * we may be setting this to NULL! + */ + symbol_c *desired_datatype = base_type(fp_iterator.param_type()); + if ((NULL != param_name) && (NULL == desired_datatype)) ERROR; + if ((NULL == param_name) && (NULL != desired_datatype)) ERROR; + + /* NOTE: When we are handling a nonformal function call made from IL, the first parameter is the 'default' or 'current' + * il value. However, a pointer to a copy of the prev_il_instruction is pre-pended into the operand list, so + * the call + * call_param_value->accept(*this); + * may actually be calling an object of the base symbol_c . + */ + set_datatype(desired_datatype, call_param_value); + call_param_value->accept(*this); + + if (NULL != param_name) + if (extensible_parameter_highest_index < fp_iterator.extensible_param_index()) + extensible_parameter_highest_index = fp_iterator.extensible_param_index(); + } + /* In the case of a call to an extensible function, we store the highest index + * of the extensible parameters this particular call uses, in the symbol_c object + * of the function call itself! + * In calls to non-extensible functions, this value will be set to -1. + * This information is later used in stage4 to correctly generate the + * output code. + */ + if ((NULL != ext_parm_count) && (extensible_parameter_highest_index >=0) /* if call to extensible function */) + *ext_parm_count = 1 + extensible_parameter_highest_index - fp_iterator.first_extensible_param_index(); +} + + + +void narrow_candidate_datatypes_c::narrow_formal_call(symbol_c *f_call, symbol_c *f_decl, int *ext_parm_count) { + symbol_c *call_param_value, *call_param_name, *param_type; + symbol_c *verify_duplicate_param; + identifier_c *param_name; + function_param_iterator_c fp_iterator(f_decl); + function_call_param_iterator_c fcp_iterator(f_call); + int extensible_parameter_highest_index = -1; + identifier_c *extensible_parameter_name; + unsigned int i; + + if (NULL != ext_parm_count) *ext_parm_count = -1; + /* Iterating through the formal parameters of the function call */ + while((call_param_name = fcp_iterator.next_f()) != NULL) { + + /* Obtaining the value being passed in the function call */ + call_param_value = fcp_iterator.get_current_value(); + /* the following should never occur. If it does, then we have a bug in our code... */ + if (NULL == call_param_value) ERROR; + + /* Find the corresponding parameter in function declaration */ + param_name = fp_iterator.search(call_param_name); + + /* Set the desired datatype for this parameter, and call it recursively. */ + /* NOTE: When handling a FB call, this narrow_formal_call() may be called to analyse + * an invalid FB call (call with parameters that do not exist on the FB declaration). + * For this reason, the param_name may come out as NULL! + */ + symbol_c *desired_datatype = base_type(fp_iterator.param_type()); + if ((NULL != param_name) && (NULL == desired_datatype)) ERROR; + if ((NULL == param_name) && (NULL != desired_datatype)) ERROR; + + /* set the desired data type for this parameter */ + set_datatype(desired_datatype, call_param_value); + /* And recursively call that parameter/expression, so it can propagate that info */ + call_param_value->accept(*this); + + /* set the extensible_parameter_highest_index, which will be needed in stage 4 */ + /* This value says how many extensible parameters are being passed to the standard function */ + if (NULL != param_name) + if (extensible_parameter_highest_index < fp_iterator.extensible_param_index()) + extensible_parameter_highest_index = fp_iterator.extensible_param_index(); + } + /* call is compatible! */ + + /* In the case of a call to an extensible function, we store the highest index + * of the extensible parameters this particular call uses, in the symbol_c object + * of the function call itself! + * In calls to non-extensible functions, this value will be set to -1. + * This information is later used in stage4 to correctly generate the + * output code. + */ + if ((NULL != ext_parm_count) && (extensible_parameter_highest_index >=0) /* if call to extensible function */) + *ext_parm_count = 1 + extensible_parameter_highest_index - fp_iterator.first_extensible_param_index(); +} + + +/* +typedef struct { + symbol_c *function_name, + symbol_c *nonformal_operand_list, + symbol_c * formal_operand_list, + + std::vector &candidate_functions, + symbol_c &*called_function_declaration, + int &extensible_param_count +} generic_function_call_t; +*/ +void narrow_candidate_datatypes_c::narrow_function_invocation(symbol_c *fcall, generic_function_call_t fcall_data) { + /* set the called_function_declaration. */ + fcall_data.called_function_declaration = NULL; + + /* set the called_function_declaration taking into account the datatype that we need to return */ + for(unsigned int i = 0; i < fcall->candidate_datatypes.size(); i++) { + if (is_type_equal(fcall->candidate_datatypes[i], fcall->datatype)) { + fcall_data.called_function_declaration = fcall_data.candidate_functions[i]; + break; + } + } + + /* NOTE: If we can't figure out the declaration of the function being called, this is not + * necessarily an internal compiler error. It could be because the symbol->datatype is NULL + * (because the ST code being analysed has an error _before_ this function invocation). + * However, we don't just give, up, we carry on recursivly analysing the code, so as to be + * able to print out any error messages related to the parameters being passed in this function + * invocation. + */ + /* if (NULL == symbol->called_function_declaration) ERROR; */ + if (fcall->candidate_datatypes.size() == 1) { + /* If only one function declaration, then we use that (even if symbol->datatypes == NULL) + * so we can check for errors in the expressions used to pass parameters in this + * function invocation. + */ + fcall_data.called_function_declaration = fcall_data.candidate_functions[0]; + } + + /* If an overloaded function is being invoked, and we cannot determine which version to use, + * then we can not meaningfully verify the expressions used inside that function invocation. + * We simply give up! + */ + if (NULL == fcall_data.called_function_declaration) + return; + + if (NULL != fcall_data.nonformal_operand_list) narrow_nonformal_call(fcall, fcall_data.called_function_declaration, &(fcall_data.extensible_param_count)); + if (NULL != fcall_data. formal_operand_list) narrow_formal_call(fcall, fcall_data.called_function_declaration, &(fcall_data.extensible_param_count)); + + return; +} + + + + +/* narrow implicit FB call in IL. + * e.g. CLK ton_var + * CU counter_var + * + * The algorithm will be to build a fake il_fb_call_c equivalent to the implicit IL FB call, and let + * the visit(il_fb_call_c *) method handle it! + */ +void *narrow_candidate_datatypes_c::narrow_implicit_il_fb_call(symbol_c *il_instruction, const char *param_name, symbol_c *&called_fb_declaration) { + + /* set the datatype of the il_operand, this is, the FB being called! */ + if (NULL != il_operand) { + /* only set it if it is in the candidate datatypes list! */ + set_datatype(called_fb_declaration, il_operand); + il_operand->accept(*this); + } + symbol_c *fb_decl = il_operand->datatype; + + if (0 == fake_prev_il_instruction->prev_il_instruction.size()) { + /* This IL implicit FB call (e.g. CLK ton_var) is not preceded by another IL instruction + * (or list of instructions) that will set the IL current/default value. + * We cannot proceed verifying type compatibility of something that does not exist. + */ + return NULL; + } + + if (NULL == fb_decl) { + /* the il_operand is a not FB instance */ + /* so we simply pass on the required datatype to the prev_il_instructions */ + /* The invalid FB invocation will be caught in the print_datatypes_error_c by analysing NULL value in il_operand->datatype! */ + set_datatype_in_prev_il_instructions(il_instruction->datatype, fake_prev_il_instruction); + return NULL; + } + + + /* The value being passed to the 'param_name' parameter is actually the prev_il_instruction. + * However, we do not place that object directly in the fake il_param_list_c that we will be + * creating, since the visit(il_fb_call_c *) method will recursively call every object in that list. + * The il_prev_intruction object will be visited once we have handled this implici IL FB call + * (called from the instruction_list_c for() loop that works backwards). We DO NOT want to visit it twice. + * (Anyway, if we let the visit(il_fb_call_c *) recursively visit the current prev_il_instruction, this pointer + * would be changed to the IL instruction coming before the current prev_il_instruction! => things would get all messed up!) + * The easiest way to work around this is to simply use a new object, and copy the relevant details to that object! + */ + symbol_c param_value = *fake_prev_il_instruction; /* copy the candidate_datatypes list ! */ + + identifier_c variable_name(param_name); + // SYM_REF1(il_assign_operator_c, variable_name) + il_assign_operator_c il_assign_operator(&variable_name); + // SYM_REF3(il_param_assignment_c, il_assign_operator, il_operand, simple_instr_list) + il_param_assignment_c il_param_assignment(&il_assign_operator, ¶m_value/*il_operand*/, NULL); + il_param_list_c il_param_list; + il_param_list.add_element(&il_param_assignment); + // SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list, symbol_c *called_fb_declaration) + CAL_operator_c CAL_operator; + il_fb_call_c il_fb_call(&CAL_operator, il_operand, NULL, &il_param_list); + + /* A FB call does not return any datatype, but the IL instructions that come after this + * FB call may require a specific datatype in the il current/default variable, + * so we must pass this information up to the IL instruction before the FB call, since it will + * be that IL instruction that will be required to produce the desired dtataype. + * + * The above will be done by the visit(il_fb_call_c *) method, so we must make sure to + * correctly set up the il_fb_call.datatype variable! + */ + il_fb_call.called_fb_declaration = called_fb_declaration; + il_fb_call.accept(*this); + + /* set the required datatype of the previous IL instruction! */ + /* NOTE: + * When handling these implicit IL calls, the parameter_value being passed to the FB parameter + * is actually the prev_il_instruction. + * + * However, since the FB call does not change the value in the current/default IL variable, this value + * must also be used ny the IL instruction coming after this FB call. + * + * This means that we have two consumers/users for the same value. + * We must therefore check whether the datatype required by the IL instructions following this FB call + * is the same as that required for the first parameter. If not, then we have a semantic error, + * and we set it to invalid_type_name. + * + * However, we only do that if: + * - The IL instruction that comes after this IL FB call actually asked this FB call for a specific + * datatype in the current/default vairable, once this IL FB call returns. + * However, sometimes, (for e.g., this FB call is the last in the IL list) the subsequent FB to not aks this + * FB call for any datatype. In that case, then the datatype required to pass to the first parameter of the + * FB call must be left unchanged! + */ + if ((NULL == il_instruction->datatype) || (is_type_equal(param_value.datatype, il_instruction->datatype))) { + set_datatype_in_prev_il_instructions(param_value.datatype, fake_prev_il_instruction); + } else { + set_datatype_in_prev_il_instructions(&search_constant_type_c::invalid_type_name, fake_prev_il_instruction); + } + return NULL; +} + + +/* a helper function... */ +symbol_c *narrow_candidate_datatypes_c::base_type(symbol_c *symbol) { + /* NOTE: symbol == NULL is valid. It will occur when, for e.g., an undefined/undeclared symbolic_variable is used + * in the code. + */ + if (symbol == NULL) return NULL; + return (symbol_c *)symbol->accept(search_base_type); +} + +/*********************/ +/* B 1.2 - Constants */ +/*********************/ + +/**********************/ +/* B 1.3 - Data types */ +/**********************/ +/********************************/ +/* B 1.3.3 - Derived data types */ +/********************************/ +/* signed_integer DOTDOT signed_integer */ +// SYM_REF2(subrange_c, lower_limit, upper_limit) +void *narrow_candidate_datatypes_c::visit(subrange_c *symbol) { + symbol->lower_limit->datatype = symbol->datatype; + symbol->lower_limit->accept(*this); + symbol->upper_limit->datatype = symbol->datatype; + symbol->upper_limit->accept(*this); + return NULL; +} + +/* simple_specification ASSIGN constant */ +// SYM_REF2(simple_spec_init_c, simple_specification, constant) +void *narrow_candidate_datatypes_c::visit(simple_spec_init_c *symbol) { + symbol_c *datatype = base_type(symbol->simple_specification); + if (NULL != symbol->constant) { + int typeoffset = search_in_candidate_datatype_list(datatype, symbol->constant->candidate_datatypes); + if (typeoffset >= 0) + symbol->constant->datatype = symbol->constant->candidate_datatypes[typeoffset]; + } + return NULL; +} + +/*********************/ +/* B 1.4 - Variables */ +/*********************/ + +/********************************************/ +/* B 1.4.1 - Directly Represented Variables */ +/********************************************/ + +/*************************************/ +/* B 1.4.2 - Multi-element variables */ +/*************************************/ +/* subscripted_variable '[' subscript_list ']' */ +// SYM_REF2(array_variable_c, subscripted_variable, subscript_list) +void *narrow_candidate_datatypes_c::visit(array_variable_c *symbol) { + /* we need to check the data types of the expressions used for the subscripts... */ + symbol->subscript_list->accept(*this); + return NULL; +} + + +/* subscript_list ',' subscript */ +// SYM_LIST(subscript_list_c) +void *narrow_candidate_datatypes_c::visit(subscript_list_c *symbol) { + for (int i = 0; i < symbol->n; i++) { + for (unsigned int k = 0; k < symbol->elements[i]->candidate_datatypes.size(); k++) { + if (is_ANY_INT_type(symbol->elements[i]->candidate_datatypes[k])) + symbol->elements[i]->datatype = symbol->elements[i]->candidate_datatypes[k]; + } + symbol->elements[i]->accept(*this); + } + return NULL; +} + + + +/************************************/ +/* B 1.5 Program organization units */ +/************************************/ +/*********************/ +/* B 1.5.1 Functions */ +/*********************/ +void *narrow_candidate_datatypes_c::visit(function_declaration_c *symbol) { + search_varfb_instance_type = new search_varfb_instance_type_c(symbol); + symbol->var_declarations_list->accept(*this); + if (debug) printf("Narrowing candidate data types list in body of function %s\n", ((token_c *)(symbol->derived_function_name))->value); + symbol->function_body->accept(*this); + delete search_varfb_instance_type; + search_varfb_instance_type = NULL; + return NULL; +} + +/***************************/ +/* B 1.5.2 Function blocks */ +/***************************/ +void *narrow_candidate_datatypes_c::visit(function_block_declaration_c *symbol) { + search_varfb_instance_type = new search_varfb_instance_type_c(symbol); + symbol->var_declarations->accept(*this); + if (debug) printf("Narrowing candidate data types list in body of FB %s\n", ((token_c *)(symbol->fblock_name))->value); + symbol->fblock_body->accept(*this); + delete search_varfb_instance_type; + search_varfb_instance_type = NULL; + return NULL; +} + +/********************/ +/* B 1.5.3 Programs */ +/********************/ +void *narrow_candidate_datatypes_c::visit(program_declaration_c *symbol) { + search_varfb_instance_type = new search_varfb_instance_type_c(symbol); + symbol->var_declarations->accept(*this); + if (debug) printf("Narrowing candidate data types list in body of program %s\n", ((token_c *)(symbol->program_type_name))->value); + symbol->function_block_body->accept(*this); + delete search_varfb_instance_type; + search_varfb_instance_type = NULL; + return NULL; +} + + +/********************************/ +/* B 1.7 Configuration elements */ +/********************************/ +void *narrow_candidate_datatypes_c::visit(configuration_declaration_c *symbol) { + // TODO !!! + /* for the moment we must return NULL so semantic analysis of remaining code is not interrupted! */ + return NULL; +} + + +/****************************************/ +/* B.2 - Language IL (Instruction List) */ +/****************************************/ +/***********************************/ +/* B 2.1 Instructions and Operands */ +/***********************************/ + +/*| instruction_list il_instruction */ +// SYM_LIST(instruction_list_c) +void *narrow_candidate_datatypes_c::visit(instruction_list_c *symbol) { + /* In order to execute the narrow algoritm correctly, we need to go through the instructions backwards, + * so we can not use the base class' visitor + */ + /* In order to execute the narrow algoritm correctly + * in IL instruction lists containing JMPs to labels that come before the JMP instruction + * itself, we need to run the narrow algorithm twice on the Instruction List. + * e.g.: ... + * ld 23 + * label1:st byte_var + * ld 34 + * JMP label1 + * + * Note that the second time we run the narrow, most of the datatypes are already filled + * in, so it will be able to produce tha correct datatypes for the IL instruction referenced + * by the label, as in the 2nd pass we already know the datatypes of the JMP instruction! + */ + for(int j = 0; j < 2; j++) { + for(int i = symbol->n-1; i >= 0; i--) { + symbol->elements[i]->accept(*this); + } + } + return NULL; +} + +/* | label ':' [il_incomplete_instruction] eol_list */ +// SYM_REF2(il_instruction_c, label, il_instruction) +// void *visit(instruction_list_c *symbol); +void *narrow_candidate_datatypes_c::visit(il_instruction_c *symbol) { + if (NULL == symbol->il_instruction) { + /* this empty/null il_instruction cannot generate the desired datatype. We pass on the request to the previous il instruction. */ + set_datatype_in_prev_il_instructions(symbol->datatype, symbol); + } else { + il_instruction_c tmp_prev_il_instruction(NULL, NULL); + /* the narrow algorithm will need access to the intersected candidate_datatype lists of all prev_il_instructions, as well as the + * list of the prev_il_instructions. + * Instead of creating two 'global' (within the class) variables, we create a single il_instruction_c variable (fake_prev_il_instruction), + * and shove that data into this single variable. + */ + tmp_prev_il_instruction.prev_il_instruction = symbol->prev_il_instruction; + intersect_prev_candidate_datatype_lists(&tmp_prev_il_instruction); + /* Tell the il_instruction the datatype that it must generate - this was chosen by the next il_instruction (remember: we are iterating backwards!) */ + fake_prev_il_instruction = &tmp_prev_il_instruction; + symbol->il_instruction->datatype = symbol->datatype; + symbol->il_instruction->accept(*this); + fake_prev_il_instruction = NULL; + } + return NULL; +} + + + + +// void *visit(instruction_list_c *symbol); +void *narrow_candidate_datatypes_c::visit(il_simple_operation_c *symbol) { + /* Tell the il_simple_operator the datatype that it must generate - this was chosen by the next il_instruction (we iterate backwards!) */ + symbol->il_simple_operator->datatype = symbol->datatype; + /* recursive call to see whether data types are compatible */ + il_operand = symbol->il_operand; + symbol->il_simple_operator->accept(*this); + il_operand = NULL; + return NULL; +} + +/* | function_name [il_operand_list] */ +/* NOTE: The parameters 'called_function_declaration' and 'extensible_param_count' are used to pass data between the stage 3 and stage 4. */ +// SYM_REF2(il_function_call_c, function_name, il_operand_list, symbol_c *called_function_declaration; int extensible_param_count;) +void *narrow_candidate_datatypes_c::visit(il_function_call_c *symbol) { + /* The first parameter of a non formal function call in IL will be the 'current value' (i.e. the prev_il_instruction) + * In order to be able to handle this without coding special cases, we will simply prepend that symbol + * to the il_operand_list, and remove it after calling handle_function_call(). + * However, since handle_function_call() will be recursively calling all parameter, and we don't want + * to do that for the prev_il_instruction (since it has already been visited by the fill_candidate_datatypes_c) + * we create a new ____ symbol_c ____ object, and copy the relevant info to/from that object before/after + * the call to handle_function_call(). + * + * However, if no further paramters are given, then il_operand_list will be NULL, and we will + * need to create a new object to hold the pointer to prev_il_instruction. + * This change will also be undone later in print_datatypes_error_c. + */ + symbol_c param_value = *fake_prev_il_instruction; /* copy the candidate_datatypes list */ + if (NULL == symbol->il_operand_list) symbol->il_operand_list = new il_operand_list_c; + if (NULL == symbol->il_operand_list) ERROR; + + ((list_c *)symbol->il_operand_list)->insert_element(¶m_value, 0); + + generic_function_call_t fcall_param = { + /* fcall_param.function_name = */ symbol->function_name, + /* fcall_param.nonformal_operand_list = */ symbol->il_operand_list, + /* fcall_param.formal_operand_list = */ NULL, + /* enum {POU_FB, POU_function} POU_type = */ generic_function_call_t::POU_function, + /* fcall_param.candidate_functions = */ symbol->candidate_functions, + /* fcall_param.called_function_declaration = */ symbol->called_function_declaration, + /* fcall_param.extensible_param_count = */ symbol->extensible_param_count + }; + + narrow_function_invocation(symbol, fcall_param); + set_datatype_in_prev_il_instructions(param_value.datatype, fake_prev_il_instruction); + + /* Undo the changes to the abstract syntax tree we made above... */ + ((list_c *)symbol->il_operand_list)->remove_element(0); + if (((list_c *)symbol->il_operand_list)->n == 0) { + /* if the list becomes empty, then that means that it did not exist before we made these changes, so we delete it! */ + delete symbol->il_operand_list; + symbol->il_operand_list = NULL; + } + + return NULL; +} + + +/* | il_expr_operator '(' [il_operand] eol_list [simple_instr_list] ')' */ +// SYM_REF3(il_expression_c, il_expr_operator, il_operand, simple_instr_list); +void *narrow_candidate_datatypes_c::visit(il_expression_c *symbol) { + /* first handle the operation (il_expr_operator) that will use the result coming from the parenthesised IL list (i.e. simple_instr_list) */ + symbol->il_expr_operator->datatype = symbol->datatype; + il_operand = symbol->simple_instr_list; /* This is not a bug! The parenthesised expression will be used as the operator! */ + symbol->il_expr_operator->accept(*this); + + /* now give the parenthesised IL list a chance to narrow the datatypes */ + /* The datatype that is must return was set by the call symbol->il_expr_operator->accept(*this) */ + il_instruction_c *save_fake_prev_il_instruction = fake_prev_il_instruction; /*this is not really necessary, but lets play it safe */ + symbol->simple_instr_list->accept(*this); + fake_prev_il_instruction = save_fake_prev_il_instruction; + return NULL; +} + + + + +/* il_jump_operator label */ +void *narrow_candidate_datatypes_c::visit(il_jump_operation_c *symbol) { + /* recursive call to fill the datatype */ + symbol->il_jump_operator->datatype = symbol->datatype; + symbol->il_jump_operator->accept(*this); + return NULL; +} + + + + + + + +/* il_call_operator prev_declared_fb_name + * | il_call_operator prev_declared_fb_name '(' ')' + * | il_call_operator prev_declared_fb_name '(' eol_list ')' + * | il_call_operator prev_declared_fb_name '(' il_operand_list ')' + * | il_call_operator prev_declared_fb_name '(' eol_list il_param_list ')' + */ +/* NOTE: The parameter 'called_fb_declaration'is used to pass data between stage 3 and stage4 (although currently it is not used in stage 4 */ +// SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list, symbol_c *called_fb_declaration) +void *narrow_candidate_datatypes_c::visit(il_fb_call_c *symbol) { + symbol_c *fb_decl = symbol->called_fb_declaration; + + /* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */ + if (NULL == fb_decl) ERROR; + if (NULL != symbol->il_operand_list) narrow_nonformal_call(symbol, fb_decl); + if (NULL != symbol-> il_param_list) narrow_formal_call(symbol, fb_decl); + + /* Let the il_call_operator (CAL, CALC, or CALCN) set the datatype of prev_il_instruction... */ + symbol->il_call_operator->datatype = symbol->datatype; + symbol->il_call_operator->accept(*this); + return NULL; +} + + +/* | function_name '(' eol_list [il_param_list] ')' */ +/* NOTE: The parameter 'called_function_declaration' is used to pass data between the stage 3 and stage 4. */ +// SYM_REF2(il_formal_funct_call_c, function_name, il_param_list, symbol_c *called_function_declaration; int extensible_param_count;) +void *narrow_candidate_datatypes_c::visit(il_formal_funct_call_c *symbol) { + generic_function_call_t fcall_param = { + /* fcall_param.function_name = */ symbol->function_name, + /* fcall_param.nonformal_operand_list = */ NULL, + /* fcall_param.formal_operand_list = */ symbol->il_param_list, + /* enum {POU_FB, POU_function} POU_type = */ generic_function_call_t::POU_function, + /* fcall_param.candidate_functions = */ symbol->candidate_functions, + /* fcall_param.called_function_declaration = */ symbol->called_function_declaration, + /* fcall_param.extensible_param_count = */ symbol->extensible_param_count + }; + + narrow_function_invocation(symbol, fcall_param); + /* The desired datatype of the previous il instruction was already set by narrow_function_invocation() */ + return NULL; +} + + +// void *visit(il_operand_list_c *symbol); + + +/* | simple_instr_list il_simple_instruction */ +/* This object is referenced by il_expression_c objects */ +void *narrow_candidate_datatypes_c::visit(simple_instr_list_c *symbol) { + if (symbol->n > 0) + symbol->elements[symbol->n - 1]->datatype = symbol->datatype; + + for(int i = symbol->n-1; i >= 0; i--) { + symbol->elements[i]->accept(*this); + } + return NULL; +} + + +// SYM_REF1(il_simple_instruction_c, il_simple_instruction, symbol_c *prev_il_instruction;) +void *narrow_candidate_datatypes_c::visit(il_simple_instruction_c *symbol) { + if (symbol->prev_il_instruction.size() > 1) ERROR; /* There should be no labeled insructions inside an IL expression! */ + + il_instruction_c tmp_prev_il_instruction(NULL, NULL); + /* the narrow algorithm will need access to the intersected candidate_datatype lists of all prev_il_instructions, as well as the + * list of the prev_il_instructions. + * Instead of creating two 'global' (within the class) variables, we create a single il_instruction_c variable (fake_prev_il_instruction), + * and shove that data into this single variable. + */ + if (symbol->prev_il_instruction.size() > 0) + tmp_prev_il_instruction.candidate_datatypes = symbol->prev_il_instruction[0]->candidate_datatypes; + tmp_prev_il_instruction.prev_il_instruction = symbol->prev_il_instruction; + + /* copy the candidate_datatypes list */ + fake_prev_il_instruction = &tmp_prev_il_instruction; + symbol->il_simple_instruction->datatype = symbol->datatype; + symbol->il_simple_instruction->accept(*this); + fake_prev_il_instruction = NULL; + return NULL; +} + +// void *visit(il_param_list_c *symbol); +// void *visit(il_param_assignment_c *symbol); +// void *visit(il_param_out_assignment_c *symbol); + + +/*******************/ +/* B 2.2 Operators */ +/*******************/ +void *narrow_candidate_datatypes_c::narrow_binary_operator(const struct widen_entry widen_table[], symbol_c *symbol, bool *deprecated_operation) { + symbol_c *prev_instruction_type, *operand_type; + int count = 0; + + if (NULL == symbol->datatype) + /* next IL instructions were unable to determine the datatype this instruction should produce */ + return NULL; + + if (NULL != deprecated_operation) + *deprecated_operation = false; + + /* NOTE 1: the il_operand __may__ be pointing to a parenthesized list of IL instructions. + * e.g. LD 33 + * AND ( 45 + * OR 56 + * ) + * When we handle the first 'AND' IL_operator, the il_operand will point to an simple_instr_list_c. + * In this case, when we call il_operand->accept(*this);, the prev_il_instruction pointer will be overwritten! + * + * We must therefore set the prev_il_instruction->datatype = symbol->datatype; + * __before__ calling il_operand->accept(*this) !! + * + * NOTE 2: We do not need to call prev_il_instruction->accept(*this), as the object to which prev_il_instruction + * is pointing to will be later narrowed by the call from the for() loop of the instruction_list_c + * (or simple_instr_list_c), which iterates backwards. + */ + for(unsigned int i = 0; i < fake_prev_il_instruction->candidate_datatypes.size(); i++) { + for(unsigned int j = 0; j < il_operand->candidate_datatypes.size(); j++) { + prev_instruction_type = fake_prev_il_instruction->candidate_datatypes[i]; + operand_type = il_operand->candidate_datatypes[j]; + if (is_widening_compatible(widen_table, prev_instruction_type, operand_type, symbol->datatype, deprecated_operation)) { + /* set the desired datatype of the previous il instruction */ + set_datatype_in_prev_il_instructions(prev_instruction_type, fake_prev_il_instruction); + /* set the datatype for the operand */ + il_operand->datatype = operand_type; + + count ++; + } + } + } +// if (count > 1) ERROR; /* Since we also support SAFE data types, this assertion is not necessarily always tru! */ + if (is_type_valid(symbol->datatype) && (count <= 0)) ERROR; + + il_operand->accept(*this); + return NULL; +} + + + + + +void *narrow_candidate_datatypes_c::handle_il_instruction(symbol_c *symbol) { + if (NULL == symbol->datatype) + /* next IL instructions were unable to determine the datatype this instruction should produce */ + return NULL; + /* NOTE 1: the il_operand __may__ be pointing to a parenthesized list of IL instructions. + * e.g. LD 33 + * AND ( 45 + * OR 56 + * ) + * When we handle the first 'AND' IL_operator, the il_operand will point to an simple_instr_list_c. + * In this case, when we call il_operand->accept(*this);, the prev_il_instruction pointer will be overwritten! + * + * We must therefore set the prev_il_instruction->datatype = symbol->datatype; + * __before__ calling il_operand->accept(*this) !! + * + * NOTE 2: We do not need to call prev_il_instruction->accept(*this), as the object to which prev_il_instruction + * is pointing to will be later narrowed by the call from the for() loop of the instruction_list_c + * (or simple_instr_list_c), which iterates backwards. + */ + /* set the desired datatype of the previous il instruction */ + set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction); + + /* set the datatype for the operand */ + il_operand->datatype = symbol->datatype; + il_operand->accept(*this); + return NULL; +} + + + + +void *narrow_candidate_datatypes_c::visit(LD_operator_c *symbol) { + if (NULL == symbol->datatype) + /* next IL instructions were unable to determine the datatype this instruction should produce */ + return NULL; + /* set the datatype for the operand */ + il_operand->datatype = symbol->datatype; + il_operand->accept(*this); + return NULL; +} + + +void *narrow_candidate_datatypes_c::visit(LDN_operator_c *symbol) { + if (NULL == symbol->datatype) + /* next IL instructions were unable to determine the datatype this instruction should produce */ + return NULL; + /* set the datatype for the operand */ + il_operand->datatype = symbol->datatype; + il_operand->accept(*this); + return NULL; +} + +void *narrow_candidate_datatypes_c::visit(ST_operator_c *symbol) { + if (symbol->candidate_datatypes.size() != 1) + return NULL; + symbol->datatype = symbol->candidate_datatypes[0]; + /* set the datatype for the operand */ + il_operand->datatype = symbol->datatype; + il_operand->accept(*this); + /* set the desired datatype of the previous il instruction */ + set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction); + return NULL; +} + +void *narrow_candidate_datatypes_c::visit(STN_operator_c *symbol) { + if (symbol->candidate_datatypes.size() != 1) + return NULL; + symbol->datatype = symbol->candidate_datatypes[0]; + /* set the datatype for the operand */ + il_operand->datatype = symbol->datatype; + il_operand->accept(*this); + /* set the desired datatype of the previous il instruction */ + set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction); + return NULL; +} + +void *narrow_candidate_datatypes_c::visit(NOT_operator_c *symbol) { + /* NOTE: the standard allows syntax in which the NOT operator is followed by an optional + * NOT [] + * However, it does not define the semantic of the NOT operation when the is specified. + * We therefore consider it an error if an il_operand is specified! + */ + /* We do not change the data type, we simply invert the bits in bit types! */ + /* So, we set the desired datatype of the previous il instruction */ + set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction); + return NULL; +} + +void *narrow_candidate_datatypes_c::visit(S_operator_c *symbol) { + /* TODO: what if this is a FB call? */ + return handle_il_instruction(symbol); +} +void *narrow_candidate_datatypes_c::visit(R_operator_c *symbol) { + /* TODO: what if this is a FB call? */ + return handle_il_instruction(symbol); +} + + +void *narrow_candidate_datatypes_c::visit( S1_operator_c *symbol) {return narrow_implicit_il_fb_call(symbol, "S1", symbol->called_fb_declaration);} +void *narrow_candidate_datatypes_c::visit( R1_operator_c *symbol) {return narrow_implicit_il_fb_call(symbol, "R1", symbol->called_fb_declaration);} +void *narrow_candidate_datatypes_c::visit( CLK_operator_c *symbol) {return narrow_implicit_il_fb_call(symbol, "CLK", symbol->called_fb_declaration);} +void *narrow_candidate_datatypes_c::visit( CU_operator_c *symbol) {return narrow_implicit_il_fb_call(symbol, "CU", symbol->called_fb_declaration);} +void *narrow_candidate_datatypes_c::visit( CD_operator_c *symbol) {return narrow_implicit_il_fb_call(symbol, "CD", symbol->called_fb_declaration);} +void *narrow_candidate_datatypes_c::visit( PV_operator_c *symbol) {return narrow_implicit_il_fb_call(symbol, "PV", symbol->called_fb_declaration);} +void *narrow_candidate_datatypes_c::visit( IN_operator_c *symbol) {return narrow_implicit_il_fb_call(symbol, "IN", symbol->called_fb_declaration);} +void *narrow_candidate_datatypes_c::visit( PT_operator_c *symbol) {return narrow_implicit_il_fb_call(symbol, "PT", symbol->called_fb_declaration);} + +void *narrow_candidate_datatypes_c::visit( AND_operator_c *symbol) {return narrow_binary_operator(widen_AND_table, symbol);} +void *narrow_candidate_datatypes_c::visit( OR_operator_c *symbol) {return narrow_binary_operator( widen_OR_table, symbol);} +void *narrow_candidate_datatypes_c::visit( XOR_operator_c *symbol) {return narrow_binary_operator(widen_XOR_table, symbol);} +void *narrow_candidate_datatypes_c::visit(ANDN_operator_c *symbol) {return narrow_binary_operator(widen_AND_table, symbol);} +void *narrow_candidate_datatypes_c::visit( ORN_operator_c *symbol) {return narrow_binary_operator( widen_OR_table, symbol);} +void *narrow_candidate_datatypes_c::visit(XORN_operator_c *symbol) {return narrow_binary_operator(widen_XOR_table, symbol);} +void *narrow_candidate_datatypes_c::visit( ADD_operator_c *symbol) {return narrow_binary_operator(widen_ADD_table, symbol, &(symbol->deprecated_operation));} +void *narrow_candidate_datatypes_c::visit( SUB_operator_c *symbol) {return narrow_binary_operator(widen_SUB_table, symbol, &(symbol->deprecated_operation));} +void *narrow_candidate_datatypes_c::visit( MUL_operator_c *symbol) {return narrow_binary_operator(widen_MUL_table, symbol, &(symbol->deprecated_operation));} +void *narrow_candidate_datatypes_c::visit( DIV_operator_c *symbol) {return narrow_binary_operator(widen_DIV_table, symbol, &(symbol->deprecated_operation));} +void *narrow_candidate_datatypes_c::visit( MOD_operator_c *symbol) {return narrow_binary_operator(widen_MOD_table, symbol);} +void *narrow_candidate_datatypes_c::visit( GT_operator_c *symbol) {return narrow_binary_operator(widen_CMP_table, symbol);} +void *narrow_candidate_datatypes_c::visit( GE_operator_c *symbol) {return narrow_binary_operator(widen_CMP_table, symbol);} +void *narrow_candidate_datatypes_c::visit( EQ_operator_c *symbol) {return narrow_binary_operator(widen_CMP_table, symbol);} +void *narrow_candidate_datatypes_c::visit( LT_operator_c *symbol) {return narrow_binary_operator(widen_CMP_table, symbol);} +void *narrow_candidate_datatypes_c::visit( LE_operator_c *symbol) {return narrow_binary_operator(widen_CMP_table, symbol);} +void *narrow_candidate_datatypes_c::visit( NE_operator_c *symbol) {return narrow_binary_operator(widen_CMP_table, symbol);} + + + + +void *narrow_candidate_datatypes_c::narrow_conditional_flow_control_IL_instruction(symbol_c *symbol) { + /* if the next IL instructions needs us to provide a datatype other than a bool, + * then we have an internal compiler error - most likely in fill_candidate_datatypes_c + */ + if ((NULL != symbol->datatype) && (!is_ANY_BOOL_compatible(symbol->datatype))) ERROR; + if (symbol->candidate_datatypes.size() > 1) ERROR; + + /* NOTE: If there is no IL instruction following this CALC, CALCN, JMPC, JMPC, ..., instruction, + * we must still provide a bool_type_name_c datatype (if possible, i.e. if it exists in the candidate datatype list). + * If it is not possible, we set it to NULL + */ + if (symbol->candidate_datatypes.size() == 0) symbol->datatype = NULL; + else symbol->datatype = symbol->candidate_datatypes[0]; /* i.e. a bool_type_name_c! */ + if ((NULL != symbol->datatype) && (!is_ANY_BOOL_compatible(symbol->datatype))) ERROR; + + /* set the required datatype of the previous IL instruction, i.e. a bool_type_name_c! */ + set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction); + return NULL; +} + + +// SYM_REF0(CAL_operator_c) +// SYM_REF0(CALC_operator_c) +// SYM_REF0(CALCN_operator_c) +/* called from visit(il_fb_call_c *) {symbol->il_call_operator->accpet(*this)} */ +/* NOTE: The CAL, JMP and RET instructions simply set the desired datatype of the previous il instruction since they do not change the value in the current/default IL variable */ +/* called from il_fb_call_c (symbol->il_call_operator->accpet(*this) ) */ +void *narrow_candidate_datatypes_c::visit( CAL_operator_c *symbol) {set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction); return NULL;} +void *narrow_candidate_datatypes_c::visit( RET_operator_c *symbol) {set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction); return NULL;} +void *narrow_candidate_datatypes_c::visit( JMP_operator_c *symbol) {set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction); return NULL;} +void *narrow_candidate_datatypes_c::visit( CALC_operator_c *symbol) {return narrow_conditional_flow_control_IL_instruction(symbol);} +void *narrow_candidate_datatypes_c::visit(CALCN_operator_c *symbol) {return narrow_conditional_flow_control_IL_instruction(symbol);} +void *narrow_candidate_datatypes_c::visit( RETC_operator_c *symbol) {return narrow_conditional_flow_control_IL_instruction(symbol);} +void *narrow_candidate_datatypes_c::visit(RETCN_operator_c *symbol) {return narrow_conditional_flow_control_IL_instruction(symbol);} +void *narrow_candidate_datatypes_c::visit( JMPC_operator_c *symbol) {return narrow_conditional_flow_control_IL_instruction(symbol);} +void *narrow_candidate_datatypes_c::visit(JMPCN_operator_c *symbol) {return narrow_conditional_flow_control_IL_instruction(symbol);} + +/* Symbol class handled together with function call checks */ +// void *visit(il_assign_operator_c *symbol, variable_name); +/* Symbol class handled together with function call checks */ +// void *visit(il_assign_operator_c *symbol, option, variable_name); + + +/***************************************/ +/* B.3 - Language ST (Structured Text) */ +/***************************************/ +/***********************/ +/* B 3.1 - Expressions */ +/***********************/ +void *narrow_candidate_datatypes_c::narrow_binary_expression(const struct widen_entry widen_table[], symbol_c *symbol, symbol_c *l_expr, symbol_c *r_expr, bool *deprecated_operation) { + symbol_c *l_type, *r_type; + int count = 0; + + if (NULL != deprecated_operation) + *deprecated_operation = false; + + for(unsigned int i = 0; i < l_expr->candidate_datatypes.size(); i++) { + for(unsigned int j = 0; j < r_expr->candidate_datatypes.size(); j++) { + /* test widening compatibility */ + l_type = l_expr->candidate_datatypes[i]; + r_type = r_expr->candidate_datatypes[j]; + if (is_widening_compatible(widen_table, l_type, r_type, symbol->datatype, deprecated_operation)) { + l_expr->datatype = l_type; + r_expr->datatype = r_type; + count ++; + } + } + } +// if (count > 1) ERROR; /* Since we also support SAFE data types, this assertion is not necessarily always tru! */ + if (is_type_valid(symbol->datatype) && (count <= 0)) ERROR; + + l_expr->accept(*this); + r_expr->accept(*this); + return NULL; +} + + + +void *narrow_candidate_datatypes_c::visit( or_expression_c *symbol) {return narrow_binary_expression( widen_OR_table, symbol, symbol->l_exp, symbol->r_exp);} +void *narrow_candidate_datatypes_c::visit( xor_expression_c *symbol) {return narrow_binary_expression(widen_XOR_table, symbol, symbol->l_exp, symbol->r_exp);} +void *narrow_candidate_datatypes_c::visit( and_expression_c *symbol) {return narrow_binary_expression(widen_AND_table, symbol, symbol->l_exp, symbol->r_exp);} + +void *narrow_candidate_datatypes_c::visit( equ_expression_c *symbol) {return narrow_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);} +void *narrow_candidate_datatypes_c::visit(notequ_expression_c *symbol) {return narrow_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);} +void *narrow_candidate_datatypes_c::visit( lt_expression_c *symbol) {return narrow_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);} +void *narrow_candidate_datatypes_c::visit( gt_expression_c *symbol) {return narrow_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);} +void *narrow_candidate_datatypes_c::visit( le_expression_c *symbol) {return narrow_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);} +void *narrow_candidate_datatypes_c::visit( ge_expression_c *symbol) {return narrow_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);} + +void *narrow_candidate_datatypes_c::visit( add_expression_c *symbol) {return narrow_binary_expression(widen_ADD_table, symbol, symbol->l_exp, symbol->r_exp, &symbol->deprecated_operation);} +void *narrow_candidate_datatypes_c::visit( sub_expression_c *symbol) {return narrow_binary_expression(widen_SUB_table, symbol, symbol->l_exp, symbol->r_exp, &symbol->deprecated_operation);} +void *narrow_candidate_datatypes_c::visit( mul_expression_c *symbol) {return narrow_binary_expression(widen_MUL_table, symbol, symbol->l_exp, symbol->r_exp, &symbol->deprecated_operation);} +void *narrow_candidate_datatypes_c::visit( div_expression_c *symbol) {return narrow_binary_expression(widen_DIV_table, symbol, symbol->l_exp, symbol->r_exp, &symbol->deprecated_operation);} +void *narrow_candidate_datatypes_c::visit( mod_expression_c *symbol) {return narrow_binary_expression(widen_MOD_table, symbol, symbol->l_exp, symbol->r_exp);} +void *narrow_candidate_datatypes_c::visit( power_expression_c *symbol) {return narrow_binary_expression(widen_EXPT_table,symbol, symbol->l_exp, symbol->r_exp);} + + +void *narrow_candidate_datatypes_c::visit(neg_expression_c *symbol) { + symbol->exp->datatype = symbol->datatype; + symbol->exp->accept(*this); + return NULL; +} + + +void *narrow_candidate_datatypes_c::visit(not_expression_c *symbol) { + symbol->exp->datatype = symbol->datatype; + symbol->exp->accept(*this); + return NULL; +} + + + +/* NOTE: The parameter 'called_function_declaration', 'extensible_param_count' and 'candidate_functions' are used to pass data between the stage 3 and stage 4. */ +/* formal_param_list -> may be NULL ! */ +/* nonformal_param_list -> may be NULL ! */ +// SYM_REF3(function_invocation_c, function_name, formal_param_list, nonformal_param_list, symbol_c *called_function_declaration; int extensible_param_count; std::vector candidate_functions;) +void *narrow_candidate_datatypes_c::visit(function_invocation_c *symbol) { + generic_function_call_t fcall_param = { + /* fcall_param.function_name = */ symbol->function_name, + /* fcall_param.nonformal_operand_list = */ symbol->nonformal_param_list, + /* fcall_param.formal_operand_list = */ symbol->formal_param_list, + /* enum {POU_FB, POU_function} POU_type = */ generic_function_call_t::POU_function, + /* fcall_param.candidate_functions = */ symbol->candidate_functions, + /* fcall_param.called_function_declaration = */ symbol->called_function_declaration, + /* fcall_param.extensible_param_count = */ symbol->extensible_param_count + }; + + narrow_function_invocation(symbol, fcall_param); + return NULL; +} + +/********************/ +/* B 3.2 Statements */ +/********************/ + + +/*********************************/ +/* B 3.2.1 Assignment Statements */ +/*********************************/ + +void *narrow_candidate_datatypes_c::visit(assignment_statement_c *symbol) { + if (symbol->candidate_datatypes.size() != 1) + return NULL; + symbol->datatype = symbol->candidate_datatypes[0]; + symbol->l_exp->datatype = symbol->datatype; + symbol->l_exp->accept(*this); + symbol->r_exp->datatype = symbol->datatype; + symbol->r_exp->accept(*this); + return NULL; +} + + +/*****************************************/ +/* B 3.2.2 Subprogram Control Statements */ +/*****************************************/ + +void *narrow_candidate_datatypes_c::visit(fb_invocation_c *symbol) { + /* Note: We do not use the symbol->called_fb_declaration value (set in fill_candidate_datatypes_c) + * because we try to identify any other datatype errors in the expressions used in the + * parameters to the FB call (e.g. fb_var(var1 * 56 + func(var * 43)) ) + * even it the call to the FB is invalid. + * This makes sense because it may be errors in those expressions which are + * making this an invalid call, so it makes sense to point them out to the user! + */ + symbol_c *fb_decl = search_varfb_instance_type->get_basetype_decl(symbol->fb_name); + + /* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */ + if (NULL == fb_decl) ERROR; + if (NULL != symbol->nonformal_param_list) narrow_nonformal_call(symbol, fb_decl); + if (NULL != symbol-> formal_param_list) narrow_formal_call(symbol, fb_decl); + + return NULL; +} + + +/********************************/ +/* B 3.2.3 Selection Statements */ +/********************************/ + +void *narrow_candidate_datatypes_c::visit(if_statement_c *symbol) { + for(unsigned int i = 0; i < symbol->expression->candidate_datatypes.size(); i++) { + if (is_ANY_BOOL_compatible(symbol->expression->candidate_datatypes[i])) + symbol->expression->datatype = symbol->expression->candidate_datatypes[i]; + } + symbol->expression->accept(*this); + if (NULL != symbol->statement_list) + symbol->statement_list->accept(*this); + if (NULL != symbol->elseif_statement_list) + symbol->elseif_statement_list->accept(*this); + if (NULL != symbol->else_statement_list) + symbol->else_statement_list->accept(*this); + return NULL; +} + + +void *narrow_candidate_datatypes_c::visit(elseif_statement_c *symbol) { + for (unsigned int i = 0; i < symbol->expression->candidate_datatypes.size(); i++) { + if (is_ANY_BOOL_compatible(symbol->expression->candidate_datatypes[i])) + symbol->expression->datatype = symbol->expression->candidate_datatypes[i]; + } + symbol->expression->accept(*this); + if (NULL != symbol->statement_list) + symbol->statement_list->accept(*this); + return NULL; +} + +/* CASE expression OF case_element_list ELSE statement_list END_CASE */ +// SYM_REF3(case_statement_c, expression, case_element_list, statement_list) +void *narrow_candidate_datatypes_c::visit(case_statement_c *symbol) { + for (unsigned int i = 0; i < symbol->expression->candidate_datatypes.size(); i++) { + if ((is_ANY_INT_type(symbol->expression->candidate_datatypes[i])) + || (search_base_type.type_is_enumerated(symbol->expression->candidate_datatypes[i]))) + symbol->expression->datatype = symbol->expression->candidate_datatypes[i]; + } + symbol->expression->accept(*this); + if (NULL != symbol->statement_list) + symbol->statement_list->accept(*this); + if (NULL != symbol->case_element_list) { + symbol->case_element_list->datatype = symbol->expression->datatype; + symbol->case_element_list->accept(*this); + } + return NULL; +} + +/* helper symbol for case_statement */ +// SYM_LIST(case_element_list_c) +void *narrow_candidate_datatypes_c::visit(case_element_list_c *symbol) { + for (int i = 0; i < symbol->n; i++) { + symbol->elements[i]->datatype = symbol->datatype; + symbol->elements[i]->accept(*this); + } + return NULL; +} + +/* case_list ':' statement_list */ +// SYM_REF2(case_element_c, case_list, statement_list) +void *narrow_candidate_datatypes_c::visit(case_element_c *symbol) { + symbol->case_list->datatype = symbol->datatype; + symbol->case_list->accept(*this); + symbol->statement_list->accept(*this); + return NULL; +} + +// SYM_LIST(case_list_c) +void *narrow_candidate_datatypes_c::visit(case_list_c *symbol) { + for (int i = 0; i < symbol->n; i++) { + for (unsigned int k = 0; k < symbol->elements[i]->candidate_datatypes.size(); k++) { + if (is_type_equal(symbol->datatype, symbol->elements[i]->candidate_datatypes[k])) + symbol->elements[i]->datatype = symbol->elements[i]->candidate_datatypes[k]; + } + /* NOTE: this may be an integer, a subrange_c, or a enumerated value! */ + symbol->elements[i]->accept(*this); + } + return NULL; +} + + +/********************************/ +/* B 3.2.4 Iteration Statements */ +/********************************/ +void *narrow_candidate_datatypes_c::visit(for_statement_c *symbol) { + /* Control variable */ + for(unsigned int i = 0; i < symbol->control_variable->candidate_datatypes.size(); i++) { + if (is_ANY_INT_type(symbol->control_variable->candidate_datatypes[i])) { + symbol->control_variable->datatype = symbol->control_variable->candidate_datatypes[i]; + } + } + symbol->control_variable->accept(*this); + /* BEG expression */ + for(unsigned int i = 0; i < symbol->beg_expression->candidate_datatypes.size(); i++) { + if (is_type_equal(symbol->control_variable->datatype,symbol->beg_expression->candidate_datatypes[i]) && + is_ANY_INT_type(symbol->beg_expression->candidate_datatypes[i])) { + symbol->beg_expression->datatype = symbol->beg_expression->candidate_datatypes[i]; + } + } + symbol->beg_expression->accept(*this); + /* END expression */ + for(unsigned int i = 0; i < symbol->end_expression->candidate_datatypes.size(); i++) { + if (is_type_equal(symbol->control_variable->datatype,symbol->end_expression->candidate_datatypes[i]) && + is_ANY_INT_type(symbol->end_expression->candidate_datatypes[i])) { + symbol->end_expression->datatype = symbol->end_expression->candidate_datatypes[i]; + } + } + symbol->end_expression->accept(*this); + /* BY expression */ + if (NULL != symbol->by_expression) { + for(unsigned int i = 0; i < symbol->by_expression->candidate_datatypes.size(); i++) { + if (is_type_equal(symbol->control_variable->datatype,symbol->by_expression->candidate_datatypes[i]) && + is_ANY_INT_type(symbol->by_expression->candidate_datatypes[i])) { + symbol->by_expression->datatype = symbol->by_expression->candidate_datatypes[i]; + } + } + symbol->by_expression->accept(*this); + } + if (NULL != symbol->statement_list) + symbol->statement_list->accept(*this); + return NULL; +} + +void *narrow_candidate_datatypes_c::visit(while_statement_c *symbol) { + for (unsigned int i = 0; i < symbol->expression->candidate_datatypes.size(); i++) { + if(is_BOOL_type(symbol->expression->candidate_datatypes[i])) + symbol->expression->datatype = symbol->expression->candidate_datatypes[i]; + } + symbol->expression->accept(*this); + if (NULL != symbol->statement_list) + symbol->statement_list->accept(*this); + return NULL; +} + +void *narrow_candidate_datatypes_c::visit(repeat_statement_c *symbol) { + for (unsigned int i = 0; i < symbol->expression->candidate_datatypes.size(); i++) { + if(is_BOOL_type(symbol->expression->candidate_datatypes[i])) + symbol->expression->datatype = symbol->expression->candidate_datatypes[i]; + } + symbol->expression->accept(*this); + if (NULL != symbol->statement_list) + symbol->statement_list->accept(*this); + return NULL; +} + + + + + diff -r 34a5571c859c -r 0bb88139e471 stage3/narrow_candidate_datatypes.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stage3/narrow_candidate_datatypes.hh Sat Mar 31 21:46:37 2012 +0100 @@ -0,0 +1,242 @@ +/* + * matiec - a compiler for the programming languages defined in IEC 61131-3 + * + * Copyright (C) 2009-2012 Mario de Sousa (msousa@fe.up.pt) + * Copyright (C) 2012 Manuele Conti (manuele.conti@sirius-es.it) + * Copyright (C) 2012 Matteo Facchinetti (matteo.facchinetti@sirius-es.it) + * + * + * 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 3 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, see . + * + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + */ + +/* + * An IEC 61131-3 compiler. + * + * Based on the + * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) + * + */ + + +#include "../absyntax_utils/absyntax_utils.hh" +#include "datatype_functions.hh" + +class narrow_candidate_datatypes_c: public iterator_visitor_c { + + private: + search_varfb_instance_type_c *search_varfb_instance_type; + search_base_type_c search_base_type; + symbol_c *il_operand; + il_instruction_c *fake_prev_il_instruction; + std::vector *prev_il_instructions; + std::vector *prev_il_instructions_intersected_datatypes; + + bool is_widening_compatible(const struct widen_entry widen_table[], symbol_c *left_type, symbol_c *right_type, symbol_c *result_type, bool *deprecated_status = NULL); + + void narrow_function_invocation(symbol_c *f_call, generic_function_call_t fcall_data); + void narrow_nonformal_call(symbol_c *f_call, symbol_c *f_decl, int *ext_parm_count = NULL); + void narrow_formal_call(symbol_c *f_call, symbol_c *f_decl, int *ext_parm_count = NULL); + void *narrow_implicit_il_fb_call(symbol_c *il_instruction, const char *param_name, symbol_c *&called_fb_declaration); + + void *handle_il_instruction(symbol_c *symbol); + void *narrow_binary_operator (const struct widen_entry widen_table[], symbol_c *symbol, bool *deprecated_operation = NULL); + void *narrow_binary_expression(const struct widen_entry widen_table[], symbol_c *symbol, symbol_c *l_expr, symbol_c *r_expr, bool *deprecated_operation = NULL); + + void *narrow_conditional_flow_control_IL_instruction(symbol_c *symbol); + + + public: + narrow_candidate_datatypes_c(symbol_c *ignore); + virtual ~narrow_candidate_datatypes_c(void); + + symbol_c *base_type(symbol_c *symbol); + + /**********************/ + /* B 1.3 - Data types */ + /**********************/ + /********************************/ + /* B 1.3.3 - Derived data types */ + /********************************/ + void *visit(subrange_c *symbol); + void *visit(simple_spec_init_c *symbol); + + /*********************/ + /* B 1.4 - Variables */ + /*********************/ + /********************************************/ + /* B 1.4.1 - Directly Represented Variables */ + /********************************************/ + /*************************************/ + /* B 1.4.2 - Multi-element variables */ + /*************************************/ + void *visit(array_variable_c *symbol); + void *visit(subscript_list_c *symbol); + + /**************************************/ + /* B 1.5 - Program organization units */ + /**************************************/ + /***********************/ + /* B 1.5.1 - Functions */ + /***********************/ + void *visit(function_declaration_c *symbol); + + /*****************************/ + /* B 1.5.2 - Function blocks */ + /*****************************/ + void *visit(function_block_declaration_c *symbol); + + /**********************/ + /* B 1.5.3 - Programs */ + /**********************/ + void *visit(program_declaration_c *symbol); + + /********************************/ + /* B 1.7 Configuration elements */ + /********************************/ + void *visit(configuration_declaration_c *symbol); + /****************************************/ + /* B.2 - Language IL (Instruction List) */ + /****************************************/ + /***********************************/ + /* B 2.1 Instructions and Operands */ + /***********************************/ + void *visit(instruction_list_c *symbol); + void *visit(il_instruction_c *symbol); + void *visit(il_simple_operation_c *symbol); + void *visit(il_function_call_c *symbol); + void *visit(il_expression_c *symbol); + void *visit(il_jump_operation_c *symbol); + void *visit(il_fb_call_c *symbol); + void *visit(il_formal_funct_call_c *symbol); +// void *visit(il_operand_list_c *symbol); + void *visit(simple_instr_list_c *symbol); + void *visit(il_simple_instruction_c*symbol); +// void *visit(il_param_list_c *symbol); +// void *visit(il_param_assignment_c *symbol); +// void *visit(il_param_out_assignment_c *symbol); + + /*******************/ + /* B 2.2 Operators */ + /*******************/ + void *visit(LD_operator_c *symbol); + void *visit(LDN_operator_c *symbol); + void *visit(ST_operator_c *symbol); + void *visit(STN_operator_c *symbol); + void *visit(NOT_operator_c *symbol); + void *visit(S_operator_c *symbol); + void *visit(R_operator_c *symbol); + void *visit(S1_operator_c *symbol); + void *visit(R1_operator_c *symbol); + void *visit(CLK_operator_c *symbol); + void *visit(CU_operator_c *symbol); + void *visit(CD_operator_c *symbol); + void *visit(PV_operator_c *symbol); + void *visit(IN_operator_c *symbol); + void *visit(PT_operator_c *symbol); + void *visit(AND_operator_c *symbol); + void *visit(OR_operator_c *symbol); + void *visit(XOR_operator_c *symbol); + void *visit(ANDN_operator_c *symbol); + void *visit(ORN_operator_c *symbol); + void *visit(XORN_operator_c *symbol); + void *visit(ADD_operator_c *symbol); + void *visit(SUB_operator_c *symbol); + void *visit(MUL_operator_c *symbol); + void *visit(DIV_operator_c *symbol); + void *visit(MOD_operator_c *symbol); + void *visit(GT_operator_c *symbol); + void *visit(GE_operator_c *symbol); + void *visit(EQ_operator_c *symbol); + void *visit(LT_operator_c *symbol); + void *visit(LE_operator_c *symbol); + void *visit(NE_operator_c *symbol); + void *visit(CAL_operator_c *symbol); + void *visit(CALC_operator_c *symbol); + void *visit(CALCN_operator_c *symbol); + void *visit(RET_operator_c *symbol); + void *visit(RETC_operator_c *symbol); + void *visit(RETCN_operator_c *symbol); + void *visit(JMP_operator_c *symbol); + void *visit(JMPC_operator_c *symbol); + void *visit(JMPCN_operator_c *symbol); + /* Symbol class handled together with function call checks */ + // void *visit(il_assign_operator_c *symbol, variable_name); + /* Symbol class handled together with function call checks */ + // void *visit(il_assign_operator_c *symbol, option, variable_name); + /***************************************/ + /* B.3 - Language ST (Structured Text) */ + /***************************************/ + /***********************/ + /* B 3.1 - Expressions */ + /***********************/ + void *visit(or_expression_c *symbol); + void *visit(xor_expression_c *symbol); + void *visit(and_expression_c *symbol); + void *visit(equ_expression_c *symbol); + void *visit(notequ_expression_c *symbol); + void *visit(lt_expression_c *symbol); + void *visit(gt_expression_c *symbol); + void *visit(le_expression_c *symbol); + void *visit(ge_expression_c *symbol); + void *visit(add_expression_c *symbol); + void *visit(sub_expression_c *symbol); + void *visit(mul_expression_c *symbol); + void *visit(div_expression_c *symbol); + void *visit(mod_expression_c *symbol); + void *visit(power_expression_c *symbol); + void *visit(neg_expression_c *symbol); + void *visit(not_expression_c *symbol); + + void *visit(function_invocation_c *symbol); + + /*********************************/ + /* B 3.2.1 Assignment Statements */ + /*********************************/ + void *visit(assignment_statement_c *symbol); + + /*****************************************/ + /* B 3.2.2 Subprogram Control Statements */ + /*****************************************/ + void *visit(fb_invocation_c *symbol); + + /********************************/ + /* B 3.2.3 Selection Statements */ + /********************************/ + void *visit(if_statement_c *symbol); + void *visit(elseif_statement_c *symbol); + void *visit(case_statement_c *symbol); + void *visit(case_element_list_c *symbol); + void *visit(case_element_c *symbol); + void *visit(case_list_c *symbol); + + /********************************/ + /* B 3.2.4 Iteration Statements */ + /********************************/ + void *visit(for_statement_c *symbol); + void *visit(while_statement_c *symbol); + void *visit(repeat_statement_c *symbol); + +}; // narrow_candidate_datatypes_c + + + + + + + + diff -r 34a5571c859c -r 0bb88139e471 stage3/print_datatypes_error.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stage3/print_datatypes_error.cc Sat Mar 31 21:46:37 2012 +0100 @@ -0,0 +1,1233 @@ +/* + * matiec - a compiler for the programming languages defined in IEC 61131-3 + * + * Copyright (C) 2009-2011 Mario de Sousa (msousa@fe.up.pt) + * Copyright (C) 2011-2012 Manuele Conti (manuele.conti@sirius-es.it) + * Copyright (C) 2011-2012 Matteo Facchinetti (matteo.facchinetti@sirius-es.it) + * + * 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 3 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, see . + * + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + */ + +/* + * An IEC 61131-3 compiler. + * + * Based on the + * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) + * + */ + + +/* + * Fill candidate list of data types for all symbols + */ + +#include "print_datatypes_error.hh" +#include "datatype_functions.hh" + +#include +#include +#include +#include +#include + + + + + + +#define FIRST_(symbol1, symbol2) (((symbol1)->first_order < (symbol2)->first_order) ? (symbol1) : (symbol2)) +#define LAST_(symbol1, symbol2) (((symbol1)->last_order > (symbol2)->last_order) ? (symbol1) : (symbol2)) + +#define STAGE3_ERROR(error_level, symbol1, symbol2, ...) { \ + if (current_display_error_level >= error_level) { \ + fprintf(stderr, "%s:%d-%d..%d-%d: error: ", \ + FIRST_(symbol1,symbol2)->first_file, FIRST_(symbol1,symbol2)->first_line, FIRST_(symbol1,symbol2)->first_column,\ + LAST_(symbol1,symbol2) ->last_line, LAST_(symbol1,symbol2) ->last_column);\ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ + il_error = true; \ + error_found = true; \ + } \ +} + + +#define STAGE3_WARNING(symbol1, symbol2, ...) { \ + fprintf(stderr, "%s:%d-%d..%d-%d: warning: ", \ + FIRST_(symbol1,symbol2)->first_file, FIRST_(symbol1,symbol2)->first_line, FIRST_(symbol1,symbol2)->first_column,\ + LAST_(symbol1,symbol2) ->last_line, LAST_(symbol1,symbol2) ->last_column);\ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ + warning_found = true; \ +} + + +/* set to 1 to see debug info during execution */ +static int debug = 0; + +print_datatypes_error_c::print_datatypes_error_c(symbol_c *ignore) { + error_found = false; + warning_found = false; + current_display_error_level = error_level_default; +} + +print_datatypes_error_c::~print_datatypes_error_c(void) { +} + +int print_datatypes_error_c::get_error_found() { + return error_found; +} + + + + + +/* Verify if the datatypes of all prev_il_instructions are valid and equal! */ +static bool are_all_datatypes_of_prev_il_instructions_datatypes_equal(il_instruction_c *symbol) { + if (NULL == symbol) ERROR; + bool res; + + if (symbol->prev_il_instruction.size() > 0) + res = is_type_valid(symbol->prev_il_instruction[0]->datatype); + + for (unsigned int i = 1; i < symbol->prev_il_instruction.size(); i++) + res &= is_type_equal(symbol->prev_il_instruction[i-1]->datatype, symbol->prev_il_instruction[i]->datatype); + + return res; +} + + + + +/* a helper function... */ +symbol_c *print_datatypes_error_c::base_type(symbol_c *symbol) { + /* NOTE: symbol == NULL is valid. It will occur when, for e.g., an undefined/undeclared symbolic_variable is used + * in the code. + */ + if (symbol == NULL) return NULL; + return (symbol_c *)symbol->accept(search_base_type); +} + + + +/* +typedef struct { + symbol_c *function_name, + symbol_c *nonformal_operand_list, + symbol_c * formal_operand_list, + + std::vector &candidate_functions, + symbol_c &*called_function_declaration, + int &extensible_param_count +} generic_function_call_t; +*/ +void print_datatypes_error_c::handle_function_invocation(symbol_c *fcall, generic_function_call_t fcall_data) { + symbol_c *param_value, *param_name; + function_call_param_iterator_c fcp_iterator(fcall); + bool function_invocation_error = false; + const char *POU_str = NULL; + + if (generic_function_call_t::POU_FB == fcall_data.POU_type) POU_str = "FB"; + if (generic_function_call_t::POU_function == fcall_data.POU_type) POU_str = "function"; + if (NULL == POU_str) ERROR; + + if ((NULL != fcall_data.formal_operand_list) && (NULL != fcall_data.nonformal_operand_list)) + ERROR; + + symbol_c *f_decl = fcall_data.called_function_declaration; + if ((NULL == f_decl) && (generic_function_call_t::POU_FB ==fcall_data.POU_type)) { + /* Due to the way the syntax analysis is buit (i.e. stage 2), this should never occur. */ + /* I.e., a FB invocation using an undefined FB variable is not possible in the current implementation of stage 2. */ + ERROR; + } + if (NULL == f_decl) { + /* we now try to find any function declaration with the same name, just so we can provide some relevant error messages */ + function_symtable_t::iterator lower = function_symtable.lower_bound(fcall_data.function_name); + if (lower == function_symtable.end()) ERROR; + f_decl = function_symtable.get_value(lower); + } + + if (NULL != fcall_data.formal_operand_list) { + fcall_data.formal_operand_list->accept(*this); + if (NULL != f_decl) { + function_param_iterator_c fp_iterator(f_decl); + while ((param_name = fcp_iterator.next_f()) != NULL) { + param_value = fcp_iterator.get_current_value(); + + /* Check if there are duplicate parameter values */ + if(fcp_iterator.search_f(param_name) != param_value) { + function_invocation_error = true; + STAGE3_ERROR(0, param_name, param_name, "Duplicate parameter '%s' when invoking %s '%s'", ((identifier_c *)param_name)->value, POU_str, ((identifier_c *)fcall_data.function_name)->value); + continue; /* jump to next parameter */ + } + + /* Find the corresponding parameter in function declaration */ + if (NULL == fp_iterator.search(param_name)) { + function_invocation_error = true; + STAGE3_ERROR(0, param_name, param_name, "Invalid parameter '%s' when invoking %s '%s'", ((identifier_c *)param_name)->value, POU_str, ((identifier_c *)fcall_data.function_name)->value); + continue; /* jump to next parameter */ + } + + /* check whether direction (IN, OUT, IN_OUT) and assignment types (:= , =>) are compatible !!! */ + /* Obtaining the assignment direction: := (assign_in) or => (assign_out) */ + function_call_param_iterator_c::assign_direction_t call_param_dir = fcp_iterator.get_assign_direction(); + /* Get the parameter direction: IN, OUT, IN_OUT */ + function_param_iterator_c::param_direction_t param_dir = fp_iterator.param_direction(); + if (function_call_param_iterator_c::assign_in == call_param_dir) { + if ((function_param_iterator_c::direction_in != param_dir) && + (function_param_iterator_c::direction_inout != param_dir)) { + function_invocation_error = true; + STAGE3_ERROR(0, param_name, param_name, "Invalid assignment syntax ':=' used for parameter '%s', when invoking %s '%s'", ((identifier_c *)param_name)->value, POU_str, ((identifier_c *)fcall_data.function_name)->value); + continue; /* jump to next parameter */ + } + } else if (function_call_param_iterator_c::assign_out == call_param_dir) { + if ((function_param_iterator_c::direction_out != param_dir)) { + function_invocation_error = true; + STAGE3_ERROR(0, param_name, param_name, "Invalid assignment syntax '=>' used for parameter '%s', when invoking %s '%s'", ((identifier_c *)param_name)->value, POU_str, ((identifier_c *)fcall_data.function_name)->value); + continue; /* jump to next parameter */ + } + } else ERROR; + + if (NULL == param_value->datatype) { + function_invocation_error = true; + STAGE3_ERROR(0, param_value, param_value, "Data type incompatibility between parameter '%s' and value being passed, when invoking %s '%s'", ((identifier_c *)param_name)->value, POU_str, ((identifier_c *)fcall_data.function_name)->value); + continue; /* jump to next parameter */ + } + } + } + } + if (NULL != fcall_data.nonformal_operand_list) { + fcall_data.nonformal_operand_list->accept(*this); + if (f_decl) + for (int i = 1; (param_value = fcp_iterator.next_nf()) != NULL; i++) { + /* TODO: verify if it is lvalue when INOUT or OUTPUT parameters! */ + + /* This handle_function_invocation() will be called to handle IL function calls, where the first parameter comes from the previous IL instruction. + * In this case, the previous IL instruction will be artifically (and temporarily) added to the begining ot the parameter list + * so we (in this function) can handle this situation like all the other function calls. + * However, + * a) if NO previous IL function exists, then we get a fake previous IL function, with no location data (i.e. not found anywhere in the source code. + * b) the function call may actually have several prev IL instructions (if several JMP instructions jump directly to the il function call). + * In order to handle these situations gracefully, we first check whether the first parameter is really an IL istruction! + */ + il_instruction_c *il_instruction_symbol = dynamic_cast(param_value); + if ((NULL != il_instruction_symbol) && (i == 1)) { + /* We are in a situation where an IL function call is passed the first parameter, which is actually the previous IL instruction */ + /* However, this is really a fake previous il instruction (see visit(il_instruction_c *) ) + * We will iterate through all the real previous IL instructions, and analyse each of them one by one */ + if (il_instruction_symbol->prev_il_instruction.size() == 0) { + function_invocation_error = true; + STAGE3_ERROR(0, fcall, fcall, "No available data to pass to first parameter of IL function %s. Missing a previous LD instruction?", ((identifier_c *)fcall_data.function_name)->value); + } +#if 0 + /* NOTE: We currently comment out this code... + * This does not currently work, since the narrow operation is currently done on the intersection + * of all the previous IL instructions, so we currently either accept them all, or none at all. + * In order to be able to produce these user freindly error messages, we will need to update the + * narrow algorithm. We leave this untill somebody aks for it... + * So, for now, we simply comment out this code. + */ + for (unsigned int p = 0; p < il_instruction_symbol->prev_il_instruction.size(); p++) { + symbol_c *value = il_instruction_symbol->prev_il_instruction[p]; + if (!is_type_valid(value->datatype)) { + function_invocation_error = true; + STAGE3_ERROR(0, fcall, fcall, "Data type incompatibility for value passed to first parameter when invoking function '%s'", ((identifier_c *)fcall_data.function_name)->value); + STAGE3_ERROR(0, value, value, "This is the IL instruction producing the incompatible data type to first parameter of function '%s'", ((identifier_c *)fcall_data.function_name)->value); + } + } +#else + if (!is_type_valid(il_instruction_symbol->datatype)) { + function_invocation_error = true; + STAGE3_ERROR(0, fcall, fcall, "Data type incompatibility between value in IL 'accumulator' and first parameter of function '%s'", ((identifier_c *)fcall_data.function_name)->value); + } +#endif + if (function_invocation_error) + /* when handling a IL function call, and an error is found in the first parameter, then we bug out and do not print out any more error messages. */ + return; + } + else if (!is_type_valid(param_value->datatype)) { + function_invocation_error = true; + STAGE3_ERROR(0, param_value, param_value, "Data type incompatibility for value passed in position %d when invoking %s '%s'", i, POU_str, ((identifier_c *)fcall_data.function_name)->value); + } + } + } + + if (NULL == fcall_data.called_function_declaration) { + function_invocation_error = true; + STAGE3_ERROR(0, fcall, fcall, "Unable to resolve which overloaded %s '%s' is being invoked.", POU_str, ((identifier_c *)fcall_data.function_name)->value); + } + + if (function_invocation_error) { + /* No compatible function exists */ + STAGE3_ERROR(2, fcall, fcall, "Invalid parameters when invoking %s '%s'", POU_str, ((identifier_c *)fcall_data.function_name)->value); + } + + return; +} + + + +void *print_datatypes_error_c::handle_implicit_il_fb_invocation(const char *param_name, symbol_c *il_operator, symbol_c *called_fb_declaration) { + if (NULL == il_operand) { + STAGE3_ERROR(0, il_operator, il_operator, "Missing operand for FB call operator '%s'.", param_name); + return NULL; + } + il_operand->accept(*this); + + if (NULL == called_fb_declaration) { + STAGE3_ERROR(0, il_operator, il_operand, "Invalid FB call: operand is not a FB instance."); + return NULL; + } + + if (fake_prev_il_instruction->prev_il_instruction.empty()) { + STAGE3_ERROR(0, il_operator, il_operand, "FB invocation operator '%s' must be preceded by a 'LD' (or equivalent) operator.", param_name); + return NULL; + } + + /* Find the corresponding parameter in function declaration */ + function_param_iterator_c fp_iterator(called_fb_declaration); + if (NULL == fp_iterator.search(param_name)) { + /* TODO: must also check whther it is an IN parameter!! */ + /* NOTE: although all standard FBs have the implicit FB calls defined as input parameters + * (i.e., for all standard FBs, CLK, PT, IN, CU, CD, S1, R1, etc... is always an input parameter) + * if a non-standard (i.e. a FB not defined in the standard library) FB is being called, then + * this (CLK, PT, IN, CU, ...) parameter may just have been defined as OUT or INOUT, + * which will not work for an implicit FB call! + */ + STAGE3_ERROR(0, il_operator, il_operand, "FB called by '%s' operator does not have a parameter named '%s'", param_name, param_name); + return NULL; + } + if (!are_all_datatypes_of_prev_il_instructions_datatypes_equal(fake_prev_il_instruction)) { + STAGE3_ERROR(0, il_operator, il_operand, "Data type incompatibility between parameter '%s' and value being passed.", param_name); + return NULL; + } + + + /* NOTE: The error_level currently being used for errors in variables/constants etc... is rather high. + * However, in the case of an implicit FB call, if the datatype of the operand == NULL, this may be + * the __only__ indication of an error! So we test it here again, to make sure thtis error will really + * be printed out! + */ + if (NULL == il_operand->datatype) { + /* Note: the case of (NULL == fb_declaration) was already caught above! */ +// if (NULL != fb_declaration) { + STAGE3_ERROR(0, il_operator, il_operator, "Invalid FB call: Datatype incompatibility between the FB's '%s' parameter and value being passed, or paramater '%s' is not a 'VAR_INPUT' parameter.", param_name, param_name); + return NULL; +// } + } + + return NULL; +} + + +/*********************/ +/* B 1.2 - Constants */ +/*********************/ +/******************************/ +/* B 1.2.1 - Numeric Literals */ +/******************************/ +void *print_datatypes_error_c::visit(real_c *symbol) { + if (symbol->candidate_datatypes.size() == 0) { + STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for ANY_REAL data type."); + } else if (NULL == symbol->datatype) { + STAGE3_ERROR(4, symbol, symbol, "ANY_REAL data type not valid in this location."); + } + return NULL; +} + +void *print_datatypes_error_c::visit(integer_c *symbol) { + if (symbol->candidate_datatypes.size() == 0) { + STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for ANY_INT data type."); + } else if (NULL == symbol->datatype) { + STAGE3_ERROR(4, symbol, symbol, "ANY_INT data type not valid in this location."); + } + return NULL; +} + +void *print_datatypes_error_c::visit(neg_real_c *symbol) { + if (symbol->candidate_datatypes.size() == 0) { + STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for ANY_REAL data type."); + } else if (NULL == symbol->datatype) { + STAGE3_ERROR(4, symbol, symbol, "ANY_REAL data type not valid in this location."); + } + return NULL; +} + +void *print_datatypes_error_c::visit(neg_integer_c *symbol) { + if (symbol->candidate_datatypes.size() == 0) { + STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for ANY_INT data type."); + } else if (NULL == symbol->datatype) { + STAGE3_ERROR(4, symbol, symbol, "ANY_INT data type not valid in this location."); + } + return NULL; +} + +void *print_datatypes_error_c::visit(binary_integer_c *symbol) { + if (symbol->candidate_datatypes.size() == 0) { + STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for ANY_INT data type."); + } else if (NULL == symbol->datatype) { + STAGE3_ERROR(4, symbol, symbol, "ANY_INT data type not valid in this location."); + } + return NULL; +} + +void *print_datatypes_error_c::visit(octal_integer_c *symbol) { + if (symbol->candidate_datatypes.size() == 0) { + STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for ANY_INT data type."); + } else if (NULL == symbol->datatype) { + STAGE3_ERROR(4, symbol, symbol, "ANY_INT data type not valid in this location."); + } + return NULL; +} + +void *print_datatypes_error_c::visit(hex_integer_c *symbol) { + if (symbol->candidate_datatypes.size() == 0) { + STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for ANY_INT data type."); + } else if (NULL == symbol->datatype) { + STAGE3_ERROR(4, symbol, symbol, "ANY_INT data type not valid in this location."); + } + return NULL; +} + +void *print_datatypes_error_c::visit(integer_literal_c *symbol) { + if (symbol->candidate_datatypes.size() == 0) { + STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for %s data type.", elementary_type_c::to_string(symbol->type)); + } else if (NULL == symbol->datatype) { + STAGE3_ERROR(4, symbol, symbol, "ANY_INT data type not valid in this location."); + } + return NULL; +} + +void *print_datatypes_error_c::visit(real_literal_c *symbol) { + if (symbol->candidate_datatypes.size() == 0) { + STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for %s data type.", elementary_type_c::to_string(symbol->type)); + } else if (NULL == symbol->datatype) { + STAGE3_ERROR(4, symbol, symbol, "ANY_REAL data type not valid in this location."); + } + return NULL; +} + +void *print_datatypes_error_c::visit(bit_string_literal_c *symbol) { + if (symbol->candidate_datatypes.size() == 0) { + STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for %s data type.", elementary_type_c::to_string(symbol->type)); + } else if (NULL == symbol->datatype) { + STAGE3_ERROR(4, symbol, symbol, "ANY_BIT data type not valid in this location."); + } + return NULL; +} + +void *print_datatypes_error_c::visit(boolean_literal_c *symbol) { + if (symbol->candidate_datatypes.size() == 0) { + STAGE3_ERROR(0, symbol, symbol, "Value is not valid for %s data type.", elementary_type_c::to_string(symbol->type)); + } else if (NULL == symbol->datatype) { + STAGE3_ERROR(4, symbol, symbol, "ANY_BOOL data type not valid in this location."); + } + return NULL; +} + +void *print_datatypes_error_c::visit(boolean_true_c *symbol) { + if (symbol->candidate_datatypes.size() == 0) { + STAGE3_ERROR(0, symbol, symbol, "Value is not valid for ANY_BOOL data type."); + } else if (NULL == symbol->datatype) { + STAGE3_ERROR(4, symbol, symbol, "ANY_BOOL data type not valid in this location."); + } + return NULL; +} + +void *print_datatypes_error_c::visit(boolean_false_c *symbol) { + if (symbol->candidate_datatypes.size() == 0) { + STAGE3_ERROR(0, symbol, symbol, "Value is not valid for ANY_BOOL data type."); + } else if (NULL == symbol->datatype) { + STAGE3_ERROR(4, symbol, symbol, "ANY_BOOL data type not valid in this location."); + } + return NULL; +} + +/*******************************/ +/* B.1.2.2 Character Strings */ +/*******************************/ +void *print_datatypes_error_c::visit(double_byte_character_string_c *symbol) { + if (symbol->candidate_datatypes.size() == 0) { + STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for WSTRING data type."); + } else if (NULL == symbol->datatype) { + STAGE3_ERROR(4, symbol, symbol, "WSTRING data type not valid in this location."); + } + return NULL; +} + +void *print_datatypes_error_c::visit(single_byte_character_string_c *symbol) { + if (symbol->candidate_datatypes.size() == 0) { + STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for STRING data type."); + } else if (NULL == symbol->datatype) { + STAGE3_ERROR(4, symbol, symbol, "STRING data type not valid in this location."); + } + return NULL; +} + +/***************************/ +/* B 1.2.3 - Time Literals */ +/***************************/ +/************************/ +/* B 1.2.3.1 - Duration */ +/************************/ +void *print_datatypes_error_c::visit(duration_c *symbol) { + if (symbol->candidate_datatypes.size() == 0) { + STAGE3_ERROR(0, symbol, symbol, "Invalid syntax for TIME data type."); + } else if (NULL == symbol->datatype) { + STAGE3_ERROR(4, symbol, symbol, "TIME data type not valid in this location."); + } + return NULL; +} + +/************************************/ +/* B 1.2.3.2 - Time of day and Date */ +/************************************/ +void *print_datatypes_error_c::visit(time_of_day_c *symbol) { + if (symbol->candidate_datatypes.size() == 0) { + STAGE3_ERROR(0, symbol, symbol, "Invalid syntax for TOD data type."); + } else if (NULL == symbol->datatype) { + STAGE3_ERROR(4, symbol, symbol, "TOD data type not valid in this location."); + } + return NULL; +} + +void *print_datatypes_error_c::visit(date_c *symbol) { + if (symbol->candidate_datatypes.size() == 0) { + STAGE3_ERROR(0, symbol, symbol, "Invalid syntax for DATE data type."); + } else if (NULL == symbol->datatype) { + STAGE3_ERROR(4, symbol, symbol, "DATE data type not valid in this location."); + } + return NULL; +} + +void *print_datatypes_error_c::visit(date_and_time_c *symbol) { + if (symbol->candidate_datatypes.size() == 0) { + STAGE3_ERROR(0, symbol, symbol, "Invalid syntax for DT data type."); + } else if (NULL == symbol->datatype) { + STAGE3_ERROR(4, symbol, symbol, "DT data type not valid in this location."); + } + return NULL; +} + +/**********************/ +/* B 1.3 - Data types */ +/**********************/ +/********************************/ +/* B 1.3.3 - Derived data types */ +/********************************/ +void *print_datatypes_error_c::visit(data_type_declaration_c *symbol) { + // TODO !!! + /* for the moment we must return NULL so semantic analysis of remaining code is not interrupted! */ + return NULL; +} + +void *print_datatypes_error_c::visit(enumerated_value_c *symbol) { + if (symbol->candidate_datatypes.size() == 0) + STAGE3_ERROR(0, symbol, symbol, "Ambiguous enumerate value or Variable not declared in this scope."); + return NULL; +} + + +/*********************/ +/* B 1.4 - Variables */ +/*********************/ +void *print_datatypes_error_c::visit(symbolic_variable_c *symbol) { + if (symbol->candidate_datatypes.size() == 0) + STAGE3_ERROR(0, symbol, symbol, "Variable not declared in this scope."); + return NULL; +} + +/********************************************/ +/* B 1.4.1 - Directly Represented Variables */ +/********************************************/ +void *print_datatypes_error_c::visit(direct_variable_c *symbol) { + if (symbol->candidate_datatypes.size() == 0) + STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for located variable data type."); + return NULL; +} + +/*************************************/ +/* B 1.4.2 - Multi-element variables */ +/*************************************/ +/* subscripted_variable '[' subscript_list ']' */ +// SYM_REF2(array_variable_c, subscripted_variable, subscript_list) +void *print_datatypes_error_c::visit(array_variable_c *symbol) { + if (symbol->candidate_datatypes.size() == 0) + STAGE3_ERROR(0, symbol, symbol, "Array variable not declared in this scope."); + + /* recursively call the subscript list to print any errors in the expressions used in the subscript...*/ + symbol->subscript_list->accept(*this); + return NULL; +} + +/* subscript_list ',' subscript */ +// SYM_LIST(subscript_list_c) +/* NOTE: we inherit from iterator visitor, so we do not need to implement this method... */ +// void *print_datatypes_error_c::visit(subscript_list_c *symbol) + + +/* record_variable '.' field_selector */ +/* WARNING: input and/or output variables of function blocks + * may be accessed as fields of a structured variable! + * Code handling a structured_variable_c must take + * this into account! + */ +// SYM_REF2(structured_variable_c, record_variable, field_selector) +/* NOTE: We do not recursively determine the data types of each field_selector in fill_candidate_datatypes_c, + * so it does not make sense to recursively visit all the field_selectors to print out error messages. + * Maybe in the future, if we find the need to print out more detailed error messages, we might do it that way. For now, we don't! + */ +void *print_datatypes_error_c::visit(structured_variable_c *symbol) { + if (symbol->candidate_datatypes.size() == 0) + STAGE3_ERROR(0, symbol, symbol, "Undeclared structured/FB variable."); + return NULL; +} + +/************************************/ +/* B 1.5 Program organization units */ +/************************************/ +/*********************/ +/* B 1.5.1 Functions */ +/*********************/ +void *print_datatypes_error_c::visit(function_declaration_c *symbol) { + search_varfb_instance_type = new search_varfb_instance_type_c(symbol); + /* We do not check for data type errors in variable declarations, Skip this for now... */ +// symbol->var_declarations_list->accept(*this); + if (debug) printf("Print error data types list in body of function %s\n", ((token_c *)(symbol->derived_function_name))->value); + il_parenthesis_level = 0; + il_error = false; + symbol->function_body->accept(*this); + delete search_varfb_instance_type; + search_varfb_instance_type = NULL; + return NULL; +} + +/***************************/ +/* B 1.5.2 Function blocks */ +/***************************/ +void *print_datatypes_error_c::visit(function_block_declaration_c *symbol) { + search_varfb_instance_type = new search_varfb_instance_type_c(symbol); + /* We do not check for data type errors in variable declarations, Skip this for now... */ +// symbol->var_declarations->accept(*this); + if (debug) printf("Print error data types list in body of FB %s\n", ((token_c *)(symbol->fblock_name))->value); + il_parenthesis_level = 0; + il_error = false; + symbol->fblock_body->accept(*this); + delete search_varfb_instance_type; + search_varfb_instance_type = NULL; + return NULL; +} + +/**********************/ +/* B 1.5.3 - Programs */ +/**********************/ +void *print_datatypes_error_c::visit(program_declaration_c *symbol) { + search_varfb_instance_type = new search_varfb_instance_type_c(symbol); + /* We do not check for data type errors in variable declarations, Skip this for now... */ +// symbol->var_declarations->accept(*this); + if (debug) printf("Print error data types list in body of program %s\n", ((token_c *)(symbol->program_type_name))->value); + il_parenthesis_level = 0; + il_error = false; + symbol->function_block_body->accept(*this); + delete search_varfb_instance_type; + search_varfb_instance_type = NULL; + return NULL; +} + + + +/********************************/ +/* B 1.7 Configuration elements */ +/********************************/ +void *print_datatypes_error_c::visit(configuration_declaration_c *symbol) { + // TODO !!! + /* for the moment we must return NULL so semantic analysis of remaining code is not interrupted! */ + return NULL; +} + +/****************************************/ +/* B.2 - Language IL (Instruction List) */ +/****************************************/ +/***********************************/ +/* B 2.1 Instructions and Operands */ +/***********************************/ + +// void *visit(instruction_list_c *symbol); + +/* | label ':' [il_incomplete_instruction] eol_list */ +// SYM_REF2(il_instruction_c, label, il_instruction) +void *print_datatypes_error_c::visit(il_instruction_c *symbol) { + if (NULL != symbol->il_instruction) { + il_instruction_c tmp_prev_il_instruction(NULL, NULL); +#if 0 + /* NOTE: The following is currently no longer needed. Since the following code is actually cool, + * we don't delete it, but simply comment it out. It might just come in handy later on... + */ + /* When handling a il function call, this fake_prev_il_instruction may be used as a standard function call parameter, so it is important that + * it contain some valid location info so error messages make sense. + */ + if (symbol->prev_il_instruction.size() > 0) { + /* since we don't want to copy all that data one variable at a time, we copy it all at once */ + /* This has the advantage that, if we ever add some more data to the base symbol_c later on, we will not need to + * change the following line to guarantee that the data is copied correctly! + * However, it does have the drawback of copying more data than what we want! + * In order to only copy the data in the base class symbol_c, we use the tmp_symbol pointer! + * I (mario) have checked with a debugger, and it is working as intended! + */ + symbol_c *tmp_symbol1 = symbol->prev_il_instruction[0]; + symbol_c *tmp_symbol2 = &tmp_prev_il_instruction; + *tmp_symbol2 = *tmp_symbol1; + /* we do not want to copy the datatype variable, so we reset it to NULL */ + tmp_prev_il_instruction.datatype = NULL; + /* We don't need to worry about the candidate_datatype list (which we don't want to copy just yet), since that will + * be reset to the correct value when we call intersect_prev_candidate_datatype_lists() later on... + */ + } +#endif + /* the print error algorithm will need access to the intersected candidate_datatype lists of all prev_il_instructions, as well as the + * list of the prev_il_instructions. + * Instead of creating two 'global' (within the class) variables, we create a single il_instruction_c variable (fake_prev_il_instruction), + * and shove that data into this single variable. + */ + tmp_prev_il_instruction.prev_il_instruction = symbol->prev_il_instruction; + intersect_prev_candidate_datatype_lists(&tmp_prev_il_instruction); + if (are_all_datatypes_of_prev_il_instructions_datatypes_equal(symbol)) + if (symbol->prev_il_instruction.size() > 0) + tmp_prev_il_instruction.datatype = (symbol->prev_il_instruction[0])->datatype; + + /* Tell the il_instruction the datatype that it must generate - this was chosen by the next il_instruction (remember: we are iterating backwards!) */ + fake_prev_il_instruction = &tmp_prev_il_instruction; + symbol->il_instruction->accept(*this); + fake_prev_il_instruction = NULL; + } + + return NULL; +} + + + +void *print_datatypes_error_c::visit(il_simple_operation_c *symbol) { + il_operand = symbol->il_operand; + if (NULL != symbol->il_operand) { + symbol->il_operand->accept(*this); + } + /* recursive call to see whether data types are compatible */ + symbol->il_simple_operator->accept(*this); + il_operand = NULL; + return NULL; +} + +/* | function_name [il_operand_list] */ +/* NOTE: The parameters 'called_function_declaration' and 'extensible_param_count' are used to pass data between the stage 3 and stage 4. */ +// SYM_REF2(il_function_call_c, function_name, il_operand_list, symbol_c *called_function_declaration; int extensible_param_count;) +void *print_datatypes_error_c::visit(il_function_call_c *symbol) { + /* The first parameter of a non formal function call in IL will be the 'current value' (i.e. the prev_il_instruction) + * In order to be able to handle this without coding special cases, we will simply prepend that symbol + * to the il_operand_list, and remove it after calling handle_function_call(). + * + * However, if no further paramters are given, then il_operand_list will be NULL, and we will + * need to create a new object to hold the pointer to prev_il_instruction. + * This change will also be undone later in print_datatypes_error_c. + */ + if (NULL == symbol->il_operand_list) symbol->il_operand_list = new il_operand_list_c; + if (NULL == symbol->il_operand_list) ERROR; + + ((list_c *)symbol->il_operand_list)->insert_element(fake_prev_il_instruction, 0); + + generic_function_call_t fcall_param = { + /* fcall_param.function_name = */ symbol->function_name, + /* fcall_param.nonformal_operand_list = */ symbol->il_operand_list, + /* fcall_param.formal_operand_list = */ NULL, + /* enum {POU_FB, POU_function} POU_type = */ generic_function_call_t::POU_function, + /* fcall_param.candidate_functions = */ symbol->candidate_functions, + /* fcall_param.called_function_declaration = */ symbol->called_function_declaration, + /* fcall_param.extensible_param_count = */ symbol->extensible_param_count + }; + +/* TODO: check what error message (if any) the compiler will give out if this function invocation + * is not preceded by a LD operator (or another equivalent operator or list of operators). + */ + handle_function_invocation(symbol, fcall_param); + + /* We now undo those changes to the abstract syntax tree made above! */ + ((list_c *)symbol->il_operand_list)->remove_element(0); + if (((list_c *)symbol->il_operand_list)->n == 0) { + /* if the list becomes empty, then that means that it did not exist before we made these changes, so we delete it! */ + delete symbol->il_operand_list; + symbol->il_operand_list = NULL; + } + + return NULL; +} + + +/* | il_expr_operator '(' [il_operand] eol_list [simple_instr_list] ')' */ +// SYM_REF3(il_expression_c, il_expr_operator, il_operand, simple_instr_list); +void *print_datatypes_error_c::visit(il_expression_c *symbol) { + /* first give the parenthesised IL list a chance to print errors */ + il_instruction_c *save_fake_prev_il_instruction = fake_prev_il_instruction; + symbol->simple_instr_list->accept(*this); + fake_prev_il_instruction = save_fake_prev_il_instruction; + + /* Now handle the operation (il_expr_operator) that will use the result coming from the parenthesised IL list (i.e. simple_instr_list) */ + il_operand = symbol->simple_instr_list; /* This is not a bug! The parenthesised expression will be used as the operator! */ + symbol->il_expr_operator->accept(*this); + +return NULL; +} + + +/* il_call_operator prev_declared_fb_name + * | il_call_operator prev_declared_fb_name '(' ')' + * | il_call_operator prev_declared_fb_name '(' eol_list ')' + * | il_call_operator prev_declared_fb_name '(' il_operand_list ')' + * | il_call_operator prev_declared_fb_name '(' eol_list il_param_list ')' + */ +/* NOTE: The parameter 'called_fb_declaration'is used to pass data between stage 3 and stage4 (although currently it is not used in stage 4 */ +// SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list, symbol_c *called_fb_declaration) +void *print_datatypes_error_c::visit(il_fb_call_c *symbol) { + int extensible_param_count; /* unused vairable! Needed for compilation only! */ + std::vector candidate_functions; /* unused vairable! Needed for compilation only! */ + generic_function_call_t fcall_param = { + /* fcall_param.function_name = */ symbol->fb_name, + /* fcall_param.nonformal_operand_list = */ symbol->il_operand_list, + /* fcall_param.formal_operand_list = */ symbol->il_param_list, + /* enum {POU_FB, POU_function} POU_type = */ generic_function_call_t::POU_FB, + /* fcall_param.candidate_functions = */ candidate_functions, /* will not be used, but must provide a reference to be able to compile */ + /* fcall_param.called_function_declaration = */ symbol->called_fb_declaration, + /* fcall_param.extensible_param_count = */ extensible_param_count /* will not be used, but must provide a reference to be able to compile */ + }; + + handle_function_invocation(symbol, fcall_param); + /* check the semantics of the CALC, CALCN operators! */ + symbol->il_call_operator->accept(*this); + return NULL; +} + +/* | function_name '(' eol_list [il_param_list] ')' */ +/* NOTE: The parameter 'called_function_declaration' is used to pass data between the stage 3 and stage 4. */ +// SYM_REF2(il_formal_funct_call_c, function_name, il_param_list, symbol_c *called_function_declaration; int extensible_param_count;) +void *print_datatypes_error_c::visit(il_formal_funct_call_c *symbol) { + generic_function_call_t fcall_param = { + /* fcall_param.function_name = */ symbol->function_name, + /* fcall_param.nonformal_operand_list = */ NULL, + /* fcall_param.formal_operand_list = */ symbol->il_param_list, + /* enum {POU_FB, POU_function} POU_type = */ generic_function_call_t::POU_function, + /* fcall_param.candidate_functions = */ symbol->candidate_functions, + /* fcall_param.called_function_declaration = */ symbol->called_function_declaration, + /* fcall_param.extensible_param_count = */ symbol->extensible_param_count + }; + + handle_function_invocation(symbol, fcall_param); + return NULL; +} + + +// void *visit(il_operand_list_c *symbol); +// void *visit(simple_instr_list_c *symbol); + +// SYM_REF1(il_simple_instruction_c, il_simple_instruction, symbol_c *prev_il_instruction;) +void *print_datatypes_error_c::visit(il_simple_instruction_c *symbol) { + if (symbol->prev_il_instruction.size() > 1) ERROR; /* There should be no labeled insructions inside an IL expression! */ + + il_instruction_c tmp_prev_il_instruction(NULL, NULL); + /* the print error algorithm will need access to the intersected candidate_datatype lists of all prev_il_instructions, as well as the + * list of the prev_il_instructions. + * Instead of creating two 'global' (within the class) variables, we create a single il_instruction_c variable (fake_prev_il_instruction), + * and shove that data into this single variable. + */ + if (symbol->prev_il_instruction.size() > 0) + tmp_prev_il_instruction.candidate_datatypes = symbol->prev_il_instruction[0]->candidate_datatypes; + tmp_prev_il_instruction.prev_il_instruction = symbol->prev_il_instruction; + + /* copy the candidate_datatypes list */ + fake_prev_il_instruction = &tmp_prev_il_instruction; + symbol->il_simple_instruction->accept(*this); + fake_prev_il_instruction = NULL; + return NULL; + + +// if (symbol->prev_il_instruction.size() == 0) prev_il_instruction = NULL; +// else prev_il_instruction = symbol->prev_il_instruction[0]; + +// symbol->il_simple_instruction->accept(*this); +// prev_il_instruction = NULL; +// return NULL; +} + + +// void *visit(il_param_list_c *symbol); +// void *visit(il_param_assignment_c *symbol); +// void *visit(il_param_out_assignment_c *symbol); + +/*******************/ +/* B 2.2 Operators */ +/*******************/ +void *print_datatypes_error_c::print_binary_operator_errors(const char *il_operator, symbol_c *symbol, bool deprecated_operation) { + if ((symbol->candidate_datatypes.size() == 0) && (il_operand->candidate_datatypes.size() > 0)) { + STAGE3_ERROR(0, symbol, symbol, "Data type mismatch for '%s' operator.", il_operator); + } else if (NULL == symbol->datatype) { + STAGE3_WARNING(symbol, symbol, "Result of '%s' operation is never used.", il_operator); + } else if (deprecated_operation) + STAGE3_WARNING(symbol, symbol, "Deprecated operation for '%s' operator.", il_operator); + return NULL; +} + + +void *print_datatypes_error_c::visit(LD_operator_c *symbol) { + return NULL; +} + +void *print_datatypes_error_c::visit(LDN_operator_c *symbol) { + if ((symbol->candidate_datatypes.size() == 0) && + (il_operand->candidate_datatypes.size() > 0)) + STAGE3_ERROR(0, symbol, symbol, "Data type mismatch for 'LDN' operator."); + return NULL; +} + +void *print_datatypes_error_c::visit(ST_operator_c *symbol) { + /* MANU: + * if prev_instruction is NULL we can print a message error or warning error like: + * we can't use a ST like first instruction. + * What do you think? + */ + if ((symbol->candidate_datatypes.size() == 0) && + (il_operand->candidate_datatypes.size() > 0)) + STAGE3_ERROR(0, symbol, symbol, "Data type mismatch for 'ST' operator."); + return NULL; +} + +void *print_datatypes_error_c::visit(STN_operator_c *symbol) { + /* MANU: + * if prev_instruction is NULL we can print a message error or warning error like: + * we can't use a ST like first instruction. + * What do you think? + */ + if ((symbol->candidate_datatypes.size() == 0) && + (il_operand->candidate_datatypes.size() > 0)) + STAGE3_ERROR(0, symbol, symbol, "Data type mismatch for 'STN' operator."); + return NULL; +} + +void *print_datatypes_error_c::visit(NOT_operator_c *symbol) { + /* NOTE: the standard allows syntax in which the NOT operator is followed by an optional + * NOT [] + * However, it does not define the semantic of the NOT operation when the is specified. + * We therefore consider it an error if an il_operand is specified! + */ + if (il_operand != NULL) + STAGE3_ERROR(0, symbol, symbol, "'NOT' operator may not have an operand."); + if (symbol->candidate_datatypes.size() == 0) + STAGE3_ERROR(0, symbol, symbol, "Data type mismatch for 'NOT' operator."); + return NULL; +} + +void *print_datatypes_error_c::visit(S_operator_c *symbol) { + /* TODO: what if this is a FB call ?? */ + if ((symbol->candidate_datatypes.size() == 0) && + (il_operand->candidate_datatypes.size() > 0)) + STAGE3_ERROR(0, symbol, symbol, "Data type mismatch for 'S' operator."); + return NULL; +} + +void *print_datatypes_error_c::visit(R_operator_c *symbol) { + /* TODO: what if this is a FB call ?? */ + if ((symbol->candidate_datatypes.size() == 0) && + (il_operand->candidate_datatypes.size() > 0)) + STAGE3_ERROR(0, symbol, symbol, "Data type mismatch for 'R' operator."); + return NULL; +} + +void *print_datatypes_error_c::visit( S1_operator_c *symbol) {return handle_implicit_il_fb_invocation( "S1", symbol, symbol->called_fb_declaration);} +void *print_datatypes_error_c::visit( R1_operator_c *symbol) {return handle_implicit_il_fb_invocation( "R1", symbol, symbol->called_fb_declaration);} +void *print_datatypes_error_c::visit(CLK_operator_c *symbol) {return handle_implicit_il_fb_invocation("CLK", symbol, symbol->called_fb_declaration);} +void *print_datatypes_error_c::visit( CU_operator_c *symbol) {return handle_implicit_il_fb_invocation( "CU", symbol, symbol->called_fb_declaration);} +void *print_datatypes_error_c::visit( CD_operator_c *symbol) {return handle_implicit_il_fb_invocation( "CD", symbol, symbol->called_fb_declaration);} +void *print_datatypes_error_c::visit( PV_operator_c *symbol) {return handle_implicit_il_fb_invocation( "PV", symbol, symbol->called_fb_declaration);} +void *print_datatypes_error_c::visit( IN_operator_c *symbol) {return handle_implicit_il_fb_invocation( "IN", symbol, symbol->called_fb_declaration);} +void *print_datatypes_error_c::visit( PT_operator_c *symbol) {return handle_implicit_il_fb_invocation( "PT", symbol, symbol->called_fb_declaration);} + +void *print_datatypes_error_c::visit( AND_operator_c *symbol) {return print_binary_operator_errors("AND" , symbol);} +void *print_datatypes_error_c::visit( OR_operator_c *symbol) {return print_binary_operator_errors( "OR" , symbol);} +void *print_datatypes_error_c::visit( XOR_operator_c *symbol) {return print_binary_operator_errors("XOR" , symbol);} +void *print_datatypes_error_c::visit(ANDN_operator_c *symbol) {return print_binary_operator_errors("ANDN", symbol);} +void *print_datatypes_error_c::visit( ORN_operator_c *symbol) {return print_binary_operator_errors( "ORN", symbol);} +void *print_datatypes_error_c::visit(XORN_operator_c *symbol) {return print_binary_operator_errors("XORN", symbol);} +void *print_datatypes_error_c::visit( ADD_operator_c *symbol) {return print_binary_operator_errors("ADD" , symbol, symbol->deprecated_operation);} +void *print_datatypes_error_c::visit( SUB_operator_c *symbol) {return print_binary_operator_errors("SUB" , symbol, symbol->deprecated_operation);} +void *print_datatypes_error_c::visit( MUL_operator_c *symbol) {return print_binary_operator_errors("MUL" , symbol, symbol->deprecated_operation);} +void *print_datatypes_error_c::visit( DIV_operator_c *symbol) {return print_binary_operator_errors("DIV" , symbol, symbol->deprecated_operation);} +void *print_datatypes_error_c::visit( MOD_operator_c *symbol) {return print_binary_operator_errors("MOD" , symbol);} + +void *print_datatypes_error_c::visit( GT_operator_c *symbol) {return print_binary_operator_errors( "GT" , symbol);} +void *print_datatypes_error_c::visit( GE_operator_c *symbol) {return print_binary_operator_errors( "GE" , symbol);} +void *print_datatypes_error_c::visit( EQ_operator_c *symbol) {return print_binary_operator_errors( "EQ" , symbol);} +void *print_datatypes_error_c::visit( LT_operator_c *symbol) {return print_binary_operator_errors( "LT" , symbol);} +void *print_datatypes_error_c::visit( LE_operator_c *symbol) {return print_binary_operator_errors( "LE" , symbol);} +void *print_datatypes_error_c::visit( NE_operator_c *symbol) {return print_binary_operator_errors( "NE" , symbol);} + + + + +void *print_datatypes_error_c::handle_conditional_flow_control_IL_instruction(symbol_c *symbol, const char *oper) { + if (NULL == symbol->datatype) + STAGE3_ERROR(0, symbol, symbol, "%s operator must be preceded by an IL instruction producing a BOOL value.", oper); + return NULL; +} + +void *print_datatypes_error_c::visit( CAL_operator_c *symbol) {return NULL;} +void *print_datatypes_error_c::visit( CALC_operator_c *symbol) {return handle_conditional_flow_control_IL_instruction(symbol, "CALC" );} +void *print_datatypes_error_c::visit(CALCN_operator_c *symbol) {return handle_conditional_flow_control_IL_instruction(symbol, "CALCN");} +void *print_datatypes_error_c::visit( RET_operator_c *symbol) {return NULL;} +void *print_datatypes_error_c::visit( RETC_operator_c *symbol) {return handle_conditional_flow_control_IL_instruction(symbol, "RETC" );} +void *print_datatypes_error_c::visit(RETCN_operator_c *symbol) {return handle_conditional_flow_control_IL_instruction(symbol, "RETCN");} +void *print_datatypes_error_c::visit( JMP_operator_c *symbol) {return NULL;} +void *print_datatypes_error_c::visit( JMPC_operator_c *symbol) {return handle_conditional_flow_control_IL_instruction(symbol, "JMPC" );} +void *print_datatypes_error_c::visit(JMPCN_operator_c *symbol) {return handle_conditional_flow_control_IL_instruction(symbol, "JMPCN");} + + + +/* Symbol class handled together with function call checks */ +// void *visit(il_assign_operator_c *symbol, variable_name); +/* Symbol class handled together with function call checks */ +// void *visit(il_assign_operator_c *symbol, option, variable_name); + +/***************************************/ +/* B.3 - Language ST (Structured Text) */ +/***************************************/ +/***********************/ +/* B 3.1 - Expressions */ +/***********************/ + +void *print_datatypes_error_c::print_binary_expression_errors(const char *operation, symbol_c *symbol, symbol_c *l_expr, symbol_c *r_expr, bool deprecated_operation) { + l_expr->accept(*this); + r_expr->accept(*this); + if ((symbol->candidate_datatypes.size() == 0) && + (l_expr->candidate_datatypes.size() > 0) && + (r_expr->candidate_datatypes.size() > 0)) + STAGE3_ERROR(0, symbol, symbol, "Data type mismatch for '%s' expression.", operation); + if (deprecated_operation) + STAGE3_WARNING(symbol, symbol, "Deprecated operation for '%s' expression.", operation); + return NULL; +} + + +void *print_datatypes_error_c::visit( or_expression_c *symbol) {return print_binary_expression_errors( "OR", symbol, symbol->l_exp, symbol->r_exp);} +void *print_datatypes_error_c::visit( xor_expression_c *symbol) {return print_binary_expression_errors("XOR", symbol, symbol->l_exp, symbol->r_exp);} +void *print_datatypes_error_c::visit( and_expression_c *symbol) {return print_binary_expression_errors("AND", symbol, symbol->l_exp, symbol->r_exp);} +void *print_datatypes_error_c::visit( equ_expression_c *symbol) {return print_binary_expression_errors( "=" , symbol, symbol->l_exp, symbol->r_exp);} +void *print_datatypes_error_c::visit(notequ_expression_c *symbol) {return print_binary_expression_errors( "<>", symbol, symbol->l_exp, symbol->r_exp);} +void *print_datatypes_error_c::visit( lt_expression_c *symbol) {return print_binary_expression_errors( "<" , symbol, symbol->l_exp, symbol->r_exp);} +void *print_datatypes_error_c::visit( gt_expression_c *symbol) {return print_binary_expression_errors( ">" , symbol, symbol->l_exp, symbol->r_exp);} +void *print_datatypes_error_c::visit( le_expression_c *symbol) {return print_binary_expression_errors( "<=", symbol, symbol->l_exp, symbol->r_exp);} +void *print_datatypes_error_c::visit( ge_expression_c *symbol) {return print_binary_expression_errors( ">=", symbol, symbol->l_exp, symbol->r_exp);} +void *print_datatypes_error_c::visit( add_expression_c *symbol) {return print_binary_expression_errors( "+" , symbol, symbol->l_exp, symbol->r_exp, symbol->deprecated_operation);} +void *print_datatypes_error_c::visit( sub_expression_c *symbol) {return print_binary_expression_errors( "-" , symbol, symbol->l_exp, symbol->r_exp, symbol->deprecated_operation);} +void *print_datatypes_error_c::visit( mul_expression_c *symbol) {return print_binary_expression_errors( "*" , symbol, symbol->l_exp, symbol->r_exp, symbol->deprecated_operation);} +void *print_datatypes_error_c::visit( div_expression_c *symbol) {return print_binary_expression_errors( "/" , symbol, symbol->l_exp, symbol->r_exp, symbol->deprecated_operation);} +void *print_datatypes_error_c::visit( mod_expression_c *symbol) {return print_binary_expression_errors("MOD", symbol, symbol->l_exp, symbol->r_exp);} +void *print_datatypes_error_c::visit( power_expression_c *symbol) {return print_binary_expression_errors( "**", symbol, symbol->l_exp, symbol->r_exp);} + + +void *print_datatypes_error_c::visit(neg_expression_c *symbol) { + symbol->exp->accept(*this); + if ((symbol->candidate_datatypes.size() == 0) && + (symbol->exp->candidate_datatypes.size() > 0)) + STAGE3_ERROR(0, symbol, symbol, "Invalid data type for 'NEG' expression."); + return NULL; +} + + +void *print_datatypes_error_c::visit(not_expression_c *symbol) { + symbol->exp->accept(*this); + if ((symbol->candidate_datatypes.size() == 0) && + (symbol->exp->candidate_datatypes.size() > 0)) + STAGE3_ERROR(0, symbol, symbol, "Invalid data type for 'NOT' expression."); + return NULL; +} + +/* NOTE: The parameter 'called_function_declaration', 'extensible_param_count' and 'candidate_functions' are used to pass data between the stage 3 and stage 4. */ +/* formal_param_list -> may be NULL ! */ +/* nonformal_param_list -> may be NULL ! */ +// SYM_REF3(function_invocation_c, function_name, formal_param_list, nonformal_param_list, symbol_c *called_function_declaration; int extensible_param_count; std::vector candidate_functions;) +void *print_datatypes_error_c::visit(function_invocation_c *symbol) { + generic_function_call_t fcall_param = { + /* fcall_param.function_name = */ symbol->function_name, + /* fcall_param.nonformal_operand_list = */ symbol->nonformal_param_list, + /* fcall_param.formal_operand_list = */ symbol->formal_param_list, + /* enum {POU_FB, POU_function} POU_type = */ generic_function_call_t::POU_function, + /* fcall_param.candidate_functions = */ symbol->candidate_functions, + /* fcall_param.called_function_declaration = */ symbol->called_function_declaration, + /* fcall_param.extensible_param_count = */ symbol->extensible_param_count + }; + + handle_function_invocation(symbol, fcall_param); + return NULL; +} + + + +/********************/ +/* B 3.2 Statements */ +/********************/ + +/*********************************/ +/* B 3.2.1 Assignment Statements */ +/*********************************/ +void *print_datatypes_error_c::visit(assignment_statement_c *symbol) { + symbol->l_exp->accept(*this); + symbol->r_exp->accept(*this); + if ((NULL == symbol->l_exp->datatype) && + (NULL == symbol->r_exp->datatype) && + (symbol->l_exp->candidate_datatypes.size() > 0) && + (symbol->r_exp->candidate_datatypes.size() > 0)) + STAGE3_ERROR(0, symbol, symbol, "Incompatible data types for ':=' operation."); + return NULL; +} + + +/*****************************************/ +/* B 3.2.2 Subprogram Control Statements */ +/*****************************************/ +/* fb_name '(' [param_assignment_list] ')' */ +/* formal_param_list -> may be NULL ! */ +/* nonformal_param_list -> may be NULL ! */ +/* NOTE: The parameter 'called_fb_declaration'is used to pass data between stage 3 and stage4 (although currently it is not used in stage 4 */ +// SYM_REF3(fb_invocation_c, fb_name, formal_param_list, nonformal_param_list, symbol_c *called_fb_declaration;) +void *print_datatypes_error_c::visit(fb_invocation_c *symbol) { + int extensible_param_count; /* unused vairable! Needed for compilation only! */ + std::vector candidate_functions; /* unused vairable! Needed for compilation only! */ + generic_function_call_t fcall_param = { + /* fcall_param.function_name = */ symbol->fb_name, + /* fcall_param.nonformal_operand_list = */ symbol->nonformal_param_list, + /* fcall_param.formal_operand_list = */ symbol->formal_param_list, + /* enum {POU_FB, POU_function} POU_type = */ generic_function_call_t::POU_FB, + /* fcall_param.candidate_functions = */ candidate_functions, /* will not be used, but must provide a reference to be able to compile */ + /* fcall_param.called_function_declaration = */ symbol->called_fb_declaration, + /* fcall_param.extensible_param_count = */ extensible_param_count /* will not be used, but must provide a reference to be able to compile */ + }; + + handle_function_invocation(symbol, fcall_param); + return NULL; +} + + +/********************************/ +/* B 3.2.3 Selection Statements */ +/********************************/ + +void *print_datatypes_error_c::visit(if_statement_c *symbol) { + symbol->expression->accept(*this); + if ((NULL == symbol->expression->datatype) && + (symbol->expression->candidate_datatypes.size() > 0)) { + STAGE3_ERROR(0, symbol, symbol, "Invalid data type for 'IF' condition."); + } + if (NULL != symbol->statement_list) + symbol->statement_list->accept(*this); + if (NULL != symbol->elseif_statement_list) + symbol->elseif_statement_list->accept(*this); + if (NULL != symbol->else_statement_list) + symbol->else_statement_list->accept(*this); + return NULL; +} + +void *print_datatypes_error_c::visit(elseif_statement_c *symbol) { + symbol->expression->accept(*this); + if ((NULL == symbol->expression->datatype) && + (symbol->expression->candidate_datatypes.size() > 0)) { + STAGE3_ERROR(0, symbol, symbol, "Invalid data type for 'ELSIF' condition."); + } + if (NULL != symbol->statement_list) + symbol->statement_list->accept(*this); + return NULL; +} + + +void *print_datatypes_error_c::visit(case_statement_c *symbol) { + symbol->expression->accept(*this); + if ((NULL == symbol->expression->datatype) && + (symbol->expression->candidate_datatypes.size() > 0)) { + STAGE3_ERROR(0, symbol, symbol, "'CASE' quantity not an integer or enumerated."); + } + symbol->case_element_list->accept(*this); + if (NULL != symbol->statement_list) + symbol->statement_list->accept(*this); + return NULL; +} + +/********************************/ +/* B 3.2.4 Iteration Statements */ +/********************************/ + +void *print_datatypes_error_c::visit(for_statement_c *symbol) { + symbol->control_variable->accept(*this); + symbol->beg_expression->accept(*this); + symbol->end_expression->accept(*this); + /* Control variable */ + if ((NULL == symbol->control_variable->datatype) && + (symbol->control_variable->candidate_datatypes.size() > 0)) { + STAGE3_ERROR(0, symbol, symbol, "Invalid data type for 'FOR' control variable."); + } + /* BEG expression */ + if ((NULL == symbol->beg_expression->datatype) && + (symbol->beg_expression->candidate_datatypes.size() > 0)) { + STAGE3_ERROR(0, symbol, symbol, "Invalid data type for 'FOR' begin expression."); + } + /* END expression */ + if ((NULL == symbol->end_expression->datatype) && + (symbol->end_expression->candidate_datatypes.size() > 0)) { + STAGE3_ERROR(0, symbol, symbol, "Invalid data type for 'FOR' end expression."); + } + /* BY expression */ + if ((NULL != symbol->by_expression) && + (NULL == symbol->by_expression->datatype) && + (symbol->end_expression->candidate_datatypes.size() > 0)) { + STAGE3_ERROR(0, symbol, symbol, "Invalid data type for 'FOR' by expression."); + } + /* DO statement */ + if (NULL != symbol->statement_list) + symbol->statement_list->accept(*this); + + return NULL; +} + +void *print_datatypes_error_c::visit(while_statement_c *symbol) { + symbol->expression->accept(*this); + if (symbol->candidate_datatypes.size() != 1) { + STAGE3_ERROR(0, symbol, symbol, "Invalid data type for 'WHILE' condition."); + return NULL; + } + if (NULL != symbol->statement_list) + symbol->statement_list->accept(*this); + return NULL; +} + +void *print_datatypes_error_c::visit(repeat_statement_c *symbol) { + if (symbol->candidate_datatypes.size() != 1) { + STAGE3_ERROR(0, symbol, symbol, "Invalid data type for 'REPEAT' condition."); + return NULL; + } + if (NULL != symbol->statement_list) + symbol->statement_list->accept(*this); + symbol->expression->accept(*this); + return NULL; +} + + + + + diff -r 34a5571c859c -r 0bb88139e471 stage3/print_datatypes_error.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stage3/print_datatypes_error.hh Sat Mar 31 21:46:37 2012 +0100 @@ -0,0 +1,323 @@ +/* + * matiec - a compiler for the programming languages defined in IEC 61131-3 + * + * Copyright (C) 2009-2011 Mario de Sousa (msousa@fe.up.pt) + * Copyright (C) 2011-2012 Manuele Conti (manuele.conti@sirius-es.it) + * Copyright (C) 2011-2012 Matteo Facchinetti (matteo.facchinetti@sirius-es.it) + * + * + * 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 3 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, see . + * + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + */ + +/* + * An IEC 61131-3 compiler. + * + * Based on the + * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) + * + */ + + +#include "../absyntax_utils/absyntax_utils.hh" +#include "datatype_functions.hh" + + +class print_datatypes_error_c: public iterator_visitor_c { + + private: + /* The level of detail that the user wants us to display error messages. */ +// #define error_level_default (1) + #define error_level_default (1) + #define error_level_nagging (4) + unsigned int current_display_error_level; + + search_varfb_instance_type_c *search_varfb_instance_type; + search_base_type_c search_base_type; + /* When calling a function block, we must first find it's type, + * by searching through the declarations of the variables currently + * in scope. + * This class does just that... + * A new object instance is instantiated whenever we start checking semantics + * for a function block type declaration, or a program declaration. + * This object instance will then later be called while the + * function block's or the program's body is being handled. + * + * Note that functions cannot contain calls to function blocks, + * so we do not create an object instance when handling + * a function declaration. + */ + + /* In IL code, once we find a type mismatch error, it is best to + * ignore any further errors until the end of the logical operation, + * i.e. until the next LD. + * However, we cannot clear the il_error flag on all LD operations, + * as these may also be used within parenthesis. LD operations + * within parenthesis may not clear the error flag. + * We therefore need a counter to know how deep inside a parenthesis + * structure we are. + */ + int il_parenthesis_level; + bool il_error; + bool error_found; + bool warning_found; + + /* the current data type of the data stored in the IL stack, i.e. the default variable */ + il_instruction_c *fake_prev_il_instruction; + /* the narrow algorithm will need access to the intersected candidate_datatype lists of all prev_il_instructions, as well as the + * list of the prev_il_instructions. + * Instead of creating two 'global' (within the class) variables, we create a single il_instruction_c variable (fake_prev_il_instruction), + * and shove that data into this single variable. + */ + symbol_c *il_operand_type; + symbol_c *il_operand; + + /* some helper functions... */ + symbol_c *base_type(symbol_c *symbol); + void handle_function_invocation(symbol_c *fcall, generic_function_call_t fcall_data); + void *handle_implicit_il_fb_invocation(const char *param_name, symbol_c *il_operator, symbol_c *called_fb_declaration); + void *handle_conditional_flow_control_IL_instruction(symbol_c *symbol, const char *oper); + + void *print_binary_operator_errors (const char *il_operator, symbol_c *symbol, bool deprecated_operation = false); + void *print_binary_expression_errors(const char *operation , symbol_c *symbol, symbol_c *l_expr, symbol_c *r_expr, bool deprecated_operation = false); + + + public: + print_datatypes_error_c(symbol_c *ignore); + virtual ~print_datatypes_error_c(void); + int get_error_found(); + + + /*********************/ + /* B 1.2 - Constants */ + /*********************/ + /******************************/ + /* B 1.2.1 - Numeric Literals */ + /******************************/ + void *visit(real_c *symbol); + void *visit(integer_c *symbol); + void *visit(neg_real_c *symbol); + void *visit(neg_integer_c *symbol); + void *visit(binary_integer_c *symbol); + void *visit(octal_integer_c *symbol); + void *visit(hex_integer_c *symbol); + void *visit(integer_literal_c *symbol); + void *visit(real_literal_c *symbol); + void *visit(bit_string_literal_c *symbol); + void *visit(boolean_literal_c *symbol); + void *visit(boolean_true_c *symbol); + void *visit(boolean_false_c *symbol); + + /*******************************/ + /* B.1.2.2 Character Strings */ + /*******************************/ + void *visit(double_byte_character_string_c *symbol); + void *visit(single_byte_character_string_c *symbol); + + /***************************/ + /* B 1.2.3 - Time Literals */ + /***************************/ + /************************/ + /* B 1.2.3.1 - Duration */ + /************************/ + void *visit(duration_c *symbol); + + /************************************/ + /* B 1.2.3.2 - Time of day and Date */ + /************************************/ + void *visit(time_of_day_c *symbol); + void *visit(date_c *symbol); + void *visit(date_and_time_c *symbol); + + /**********************/ + /* B 1.3 - Data types */ + /**********************/ + /********************************/ + /* B 1.3.3 - Derived data types */ + /********************************/ + void *visit(data_type_declaration_c *symbol); + void *visit(enumerated_value_c *symbol); + + /*********************/ + /* B 1.4 - Variables */ + /*********************/ + void *visit(symbolic_variable_c *symbol); + + /********************************************/ + /* B 1.4.1 - Directly Represented Variables */ + /********************************************/ + void *visit(direct_variable_c *symbol); + + /*************************************/ + /* B 1.4.2 - Multi-element variables */ + /*************************************/ + void *visit(array_variable_c *symbol); + void *visit(structured_variable_c *symbol); + + /**************************************/ + /* B 1.5 - Program organization units */ + /**************************************/ + /***********************/ + /* B 1.5.1 - Functions */ + /***********************/ + void *visit(function_declaration_c *symbol); + + /*****************************/ + /* B 1.5.2 - Function blocks */ + /*****************************/ + void *visit(function_block_declaration_c *symbol); + + /**********************/ + /* B 1.5.3 - Programs */ + /**********************/ + void *visit(program_declaration_c *symbol); + + /********************************/ + /* B 1.7 Configuration elements */ + /********************************/ + void *visit(configuration_declaration_c *symbol); + + /****************************************/ + /* B.2 - Language IL (Instruction List) */ + /****************************************/ + /***********************************/ + /* B 2.1 Instructions and Operands */ + /***********************************/ +// void *visit(instruction_list_c *symbol); + void *visit(il_instruction_c *symbol); + void *visit(il_simple_operation_c *symbol); + void *visit(il_function_call_c *symbol); + void *visit(il_expression_c *symbol); + void *visit(il_fb_call_c *symbol); + void *visit(il_formal_funct_call_c *symbol); +// void *visit(il_operand_list_c *symbol); +// void *visit(simple_instr_list_c *symbol); + void *visit(il_simple_instruction_c*symbol); +// void *visit(il_param_list_c *symbol); +// void *visit(il_param_assignment_c *symbol); +// void *visit(il_param_out_assignment_c *symbol); + + /*******************/ + /* B 2.2 Operators */ + /*******************/ + void *visit(LD_operator_c *symbol); + void *visit(LDN_operator_c *symbol); + void *visit(ST_operator_c *symbol); + void *visit(STN_operator_c *symbol); + void *visit(NOT_operator_c *symbol); + void *visit(S_operator_c *symbol); + void *visit(R_operator_c *symbol); + void *visit(S1_operator_c *symbol); + void *visit(R1_operator_c *symbol); + void *visit(CLK_operator_c *symbol); + void *visit(CU_operator_c *symbol); + void *visit(CD_operator_c *symbol); + void *visit(PV_operator_c *symbol); + void *visit(IN_operator_c *symbol); + void *visit(PT_operator_c *symbol); + void *visit(AND_operator_c *symbol); + void *visit(OR_operator_c *symbol); + void *visit(XOR_operator_c *symbol); + void *visit(ANDN_operator_c *symbol); + void *visit(ORN_operator_c *symbol); + void *visit(XORN_operator_c *symbol); + void *visit(ADD_operator_c *symbol); + void *visit(SUB_operator_c *symbol); + void *visit(MUL_operator_c *symbol); + void *visit(DIV_operator_c *symbol); + void *visit(MOD_operator_c *symbol); + void *visit(GT_operator_c *symbol); + void *visit(GE_operator_c *symbol); + void *visit(EQ_operator_c *symbol); + void *visit(LT_operator_c *symbol); + void *visit(LE_operator_c *symbol); + void *visit(NE_operator_c *symbol); + void *visit(CAL_operator_c *symbol); + void *visit(CALC_operator_c *symbol); + void *visit(CALCN_operator_c *symbol); + void *visit(RET_operator_c *symbol); + void *visit(RETC_operator_c *symbol); + void *visit(RETCN_operator_c *symbol); + void *visit(JMP_operator_c *symbol); + void *visit(JMPC_operator_c *symbol); + void *visit(JMPCN_operator_c *symbol); + /* Symbol class handled together with function call checks */ + // void *visit(il_assign_operator_c *symbol, variable_name); + /* Symbol class handled together with function call checks */ + // void *visit(il_assign_operator_c *symbol, option, variable_name); + + /***************************************/ + /* B.3 - Language ST (Structured Text) */ + /***************************************/ + /***********************/ + /* B 3.1 - Expressions */ + /***********************/ + void *visit(or_expression_c *symbol); + void *visit(xor_expression_c *symbol); + void *visit(and_expression_c *symbol); + void *visit(equ_expression_c *symbol); + void *visit(notequ_expression_c *symbol); + void *visit(lt_expression_c *symbol); + void *visit(gt_expression_c *symbol); + void *visit(le_expression_c *symbol); + void *visit(ge_expression_c *symbol); + void *visit(add_expression_c *symbol); + void *visit(sub_expression_c *symbol); + void *visit(mul_expression_c *symbol); + void *visit(div_expression_c *symbol); + void *visit(mod_expression_c *symbol); + void *visit(power_expression_c *symbol); + void *visit(neg_expression_c *symbol); + void *visit(not_expression_c *symbol); + void *visit(function_invocation_c *symbol); + + /*********************************/ + /* B 3.2.1 Assignment Statements */ + /*********************************/ + void *visit(assignment_statement_c *symbol); + + /*****************************************/ + /* B 3.2.2 Subprogram Control Statements */ + /*****************************************/ + void *visit(fb_invocation_c *symbol); + + /********************************/ + /* B 3.2.3 Selection Statements */ + /********************************/ + void *visit(if_statement_c *symbol); + // void *visit(elseif_statement_list_c *symbol); + void *visit(elseif_statement_c *symbol); + void *visit(case_statement_c *symbol); + // void *visit(case_element_list_c *symbol); + // void *visit(case_element_c *symbol); + // void *visit(case_list_c *symbol); + + /********************************/ + /* B 3.2.4 Iteration Statements */ + /********************************/ + void *visit(for_statement_c *symbol); + void *visit(while_statement_c *symbol); + void *visit(repeat_statement_c *symbol); + +}; // print_datatypes_error_c + + + + + + + diff -r 34a5571c859c -r 0bb88139e471 stage3/stage3.cc --- a/stage3/stage3.cc Thu Mar 22 00:22:48 2012 +0100 +++ b/stage3/stage3.cc Sat Mar 31 21:46:37 2012 +0100 @@ -1,8 +1,10 @@ /* * matiec - a compiler for the programming languages defined in IEC 61131-3 * - * Copyright (C) 2009-2011 Mario de Sousa (msousa@fe.up.pt) + * Copyright (C) 2009-2012 Mario de Sousa (msousa@fe.up.pt) * Copyright (C) 2007-2011 Laurent Bessard and Edouard Tisserant + * Copyright (C) 2012 Manuele Conti (manuele.conti@sirius-es.it) + * Copyright (C) 2012 Matteo Facchinetti (matteo.facchinetti@sirius-es.it) * * 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 @@ -32,17 +34,36 @@ #include "stage3.hh" -int type_safety(symbol_c *tree_root){ - visit_expression_type_c visit_expression_type(tree_root); +#include "flow_control_analysis.hh" +#include "fill_candidate_datatypes.hh" +#include "narrow_candidate_datatypes.hh" +#include "print_datatypes_error.hh" - (*tree_root).accept(visit_expression_type); - if (visit_expression_type.get_error_found()) - return -1; - +static int flow_control_analysis(symbol_c *tree_root){ + flow_control_analysis_c flow_control_analysis(tree_root); + tree_root->accept(flow_control_analysis); + return 0; +} + +/* Type safety analysis assumes that flow control analysis has already been completed, + * so be sure to call flow_control_analysis() before calling this function + */ +static int type_safety(symbol_c *tree_root){ + fill_candidate_datatypes_c fill_candidate_datatypes(tree_root); + tree_root->accept(fill_candidate_datatypes); + narrow_candidate_datatypes_c narrow_candidate_datatypes(tree_root); + tree_root->accept(narrow_candidate_datatypes); + print_datatypes_error_c print_datatypes_error(tree_root); + tree_root->accept(print_datatypes_error); + if (print_datatypes_error.get_error_found()) + return -1; return 0; } + + int stage3(symbol_c *tree_root){ + flow_control_analysis(tree_root); return type_safety(tree_root); } diff -r 34a5571c859c -r 0bb88139e471 stage3/stage3.hh --- a/stage3/stage3.hh Thu Mar 22 00:22:48 2012 +0100 +++ b/stage3/stage3.hh Sat Mar 31 21:46:37 2012 +0100 @@ -31,20 +31,8 @@ */ -// #include /* required for NULL */ -#include -#include -#include -#include -#include -#include - #include "../util/symtable.hh" -#include "../util/dsymtable.hh" -#include "../absyntax/visitor.hh" - -#include "visit_expression_type.hh" int stage3(symbol_c *tree_root); -int type_safety(symbol_c *tree_root); + diff -r 34a5571c859c -r 0bb88139e471 stage3/visit_expression_type.cc --- a/stage3/visit_expression_type.cc Thu Mar 22 00:22:48 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2456 +0,0 @@ -/* - * matiec - a compiler for the programming languages defined in IEC 61131-3 - * - * Copyright (C) 2009-2011 Mario de Sousa (msousa@fe.up.pt) - * Copyright (C) 2007-2011 Laurent Bessard and Edouard Tisserant - * - * 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 3 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, see . - * - * - * This code is made available on the understanding that it will not be - * used in safety-critical situations without a full and competent review. - */ - -/* - * An IEC 61131-3 compiler. - * - * Based on the - * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) - * - */ - - -/* Verify whether the semantic rules of data type compatibility are being followed. - * - * For example: - */ - -#include "visit_expression_type.hh" -#include -#include -#include -#include -#include - - -#define FIRST_(symbol1, symbol2) (((symbol1)->first_order < (symbol2)->first_order) ? (symbol1) : (symbol2)) -#define LAST_(symbol1, symbol2) (((symbol1)->last_order > (symbol2)->last_order) ? (symbol1) : (symbol2)) - -#define STAGE3_ERROR(symbol1, symbol2, ...) { \ - fprintf(stderr, "%s:%d-%d..%d-%d: error : ", \ - FIRST_(symbol1,symbol2)->first_file, FIRST_(symbol1,symbol2)->first_line, FIRST_(symbol1,symbol2)->first_column, \ - LAST_(symbol1,symbol2) ->last_line, LAST_(symbol1,symbol2) ->last_column); \ - fprintf(stderr, __VA_ARGS__); \ - fprintf(stderr, "\n"); \ - il_error = true; \ - error_found = true; \ - } - - -/* set to 1 to see debug info during execution */ -static int debug = 0; - - -void *visit_expression_type_c::visit(program_declaration_c *symbol) { - search_varfb_instance_type = new search_varfb_instance_type_c(symbol); - symbol->var_declarations->accept(*this); - if (debug) printf("checking semantics in body of program %s\n", ((token_c *)(symbol->program_type_name))->value); - il_parenthesis_level = 0; - il_error = false; - il_default_variable_type = NULL; - symbol->function_block_body->accept(*this); - il_default_variable_type = NULL; - delete search_varfb_instance_type; - search_varfb_instance_type = NULL; - return NULL; -} - -void *visit_expression_type_c::visit(function_declaration_c *symbol) { - search_varfb_instance_type = new search_varfb_instance_type_c(symbol); - symbol->var_declarations_list->accept(*this); - if (debug) printf("checking semantics in body of function %s\n", ((token_c *)(symbol->derived_function_name))->value); - il_parenthesis_level = 0; - il_error = false; - il_default_variable_type = NULL; - symbol->function_body->accept(*this); - il_default_variable_type = NULL; - delete search_varfb_instance_type; - search_varfb_instance_type = NULL; - return NULL; -} - -void *visit_expression_type_c::visit(function_block_declaration_c *symbol) { - search_varfb_instance_type = new search_varfb_instance_type_c(symbol); - symbol->var_declarations->accept(*this); - if (debug) printf("checking semantics in body of FB %s\n", ((token_c *)(symbol->fblock_name))->value); - il_parenthesis_level = 0; - il_error = false; - il_default_variable_type = NULL; - symbol->fblock_body->accept(*this); - il_default_variable_type = NULL; - delete search_varfb_instance_type; - search_varfb_instance_type = NULL; - return NULL; -} - - - - - - - - - -visit_expression_type_c::visit_expression_type_c(symbol_c *ignore) { - error_found = false; -} - -visit_expression_type_c::~visit_expression_type_c(void) { -} - -bool visit_expression_type_c::get_error_found(void) { - return error_found; -} - - - -/* NOTE on data type handling and literals... - * ========================================== - * - * Literals that are explicitly type cast - * e.g.: BYTE#42 - * INT#65 - * TIME#45h23m - * etc... - * are NOT considered literals in the following code. - * Since they are type cast, and their data type is fixed and well known, - * they are treated as a variable of that data type (except when determining lvalues) - * In other words, when calling search_constant_type_c on these constants, it returns - * a xxxxx_type_name_c, and not one of the xxxx_literal_c ! - * - * When the following code handles a literal, it is really a literal of unknown data type. - * e.g. 42, may be considered an int, a byte, a word, etc... - * - * NOTE: type_symbol == NULL is valid! - * This will occur, for example, when and undefined/undeclared symbolic_variable is used in the program. - * This will not be of any type, so we always return false. - */ - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_ELEMENTARY_type(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - return is_ANY_MAGNITUDE_type(type_symbol) - || is_ANY_BIT_type (type_symbol) - || is_ANY_STRING_type (type_symbol) - || is_ANY_DATE_type (type_symbol); -} - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_SAFEELEMENTARY_type(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - return is_ANY_SAFEMAGNITUDE_type(type_symbol) - || is_ANY_SAFEBIT_type (type_symbol) - || is_ANY_SAFESTRING_type (type_symbol) - || is_ANY_SAFEDATE_type (type_symbol); -} - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_ELEMENTARY_compatible(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - /* NOTE: doing - * return is_ANY_SAFEELEMENTARY_type() || is_ANY_ELEMENTARY_type() - * is incorrect, as the literals would never be considered compatible... - */ - return is_ANY_MAGNITUDE_compatible(type_symbol) - || is_ANY_BIT_compatible (type_symbol) - || is_ANY_STRING_compatible (type_symbol) - || is_ANY_DATE_compatible (type_symbol); -} - - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_MAGNITUDE_type(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (typeid(*type_symbol) == typeid(time_type_name_c)) {return true;} - return is_ANY_NUM_type(type_symbol); -} - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_SAFEMAGNITUDE_type(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (typeid(*type_symbol) == typeid(safetime_type_name_c)) {return true;} - return is_ANY_SAFENUM_type(type_symbol); -} - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_MAGNITUDE_compatible(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (is_ANY_MAGNITUDE_type (type_symbol)) {return true;} - if (is_ANY_SAFEMAGNITUDE_type(type_symbol)) {return true;} - - return is_ANY_NUM_compatible(type_symbol); -} - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_NUM_type(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (is_ANY_REAL_type(type_symbol)) {return true;} - if (is_ANY_INT_type(type_symbol)) {return true;} - return false; -} - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_SAFENUM_type(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - return is_ANY_SAFEREAL_type(type_symbol) - || is_ANY_SAFEINT_type (type_symbol); -} - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_NUM_compatible(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (is_ANY_REAL_compatible(type_symbol)) {return true;} - if (is_ANY_INT_compatible(type_symbol)) {return true;} - return false; -} - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_DATE_type(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (typeid(*type_symbol) == typeid(date_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(tod_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(dt_type_name_c)) {return true;} - return false; -} - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_SAFEDATE_type(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (typeid(*type_symbol) == typeid(safedate_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(safetod_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(safedt_type_name_c)) {return true;} - return false; -} - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_DATE_compatible(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (is_ANY_DATE_type (type_symbol)) {return true;} - if (is_ANY_SAFEDATE_type(type_symbol)) {return true;} - return false; -} - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_STRING_type(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (typeid(*type_symbol) == typeid(string_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(wstring_type_name_c)) {return true;} -// TODO literal_string ??? - return false; -} - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_SAFESTRING_type(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (typeid(*type_symbol) == typeid(safestring_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(safewstring_type_name_c)) {return true;} - return false; -} - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_STRING_compatible(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (is_ANY_STRING_type (type_symbol)) {return true;} - if (is_ANY_SAFESTRING_type(type_symbol)) {return true;} - return false; -} - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_INT_type(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (typeid(*type_symbol) == typeid(sint_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(int_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(dint_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(lint_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(usint_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(uint_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(udint_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(ulint_type_name_c)) {return true;} - return false; -} - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_SAFEINT_type(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (typeid(*type_symbol) == typeid(safesint_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(safeint_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(safedint_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(safelint_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(safeusint_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(safeuint_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(safeudint_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(safeulint_type_name_c)) {return true;} - return false; -} - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_INT_compatible(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (is_ANY_INT_type (type_symbol)) {return true;} - if (is_ANY_SAFEINT_type(type_symbol)) {return true;} - if (is_literal_integer_type(type_symbol)) {return true;} - return false; -} - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_REAL_type(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (typeid(*type_symbol) == typeid(real_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(lreal_type_name_c)) {return true;} - return false; -} - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_SAFEREAL_type(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (typeid(*type_symbol) == typeid(safereal_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(safelreal_type_name_c)) {return true;} - return false; -} - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_REAL_compatible(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (is_ANY_REAL_type (type_symbol)) {return true;} - if (is_ANY_SAFEREAL_type(type_symbol)) {return true;} - if (is_literal_real_type(type_symbol)) {return true;} - return false; -} - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_BIT_type(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (typeid(*type_symbol) == typeid(bool_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(byte_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(word_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(dword_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(lword_type_name_c)) {return true;} - return false; -} - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_SAFEBIT_type(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (typeid(*type_symbol) == typeid(safebool_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(safebyte_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(safeword_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(safedword_type_name_c)) {return true;} - if (typeid(*type_symbol) == typeid(safelword_type_name_c)) {return true;} - return false; -} - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_BIT_compatible(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (is_ANY_BIT_type (type_symbol)) {return true;} - if (is_ANY_SAFEBIT_type(type_symbol)) {return true;} - if (is_nonneg_literal_integer_type(type_symbol)) {return true;} - if (is_literal_bool_type(type_symbol)) {return true;} - return false; -} - -/* A helper function... */ -bool visit_expression_type_c::is_BOOL_type(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (typeid(*type_symbol) == typeid(bool_type_name_c)) {return true;} - return false; -} - -/* A helper function... */ -bool visit_expression_type_c::is_SAFEBOOL_type(symbol_c *type_symbol){ - if (type_symbol == NULL) {return false;} - if (typeid(*type_symbol) == typeid(safebool_type_name_c)) {return true;} - return false; -} - -/* A helper function... */ -bool visit_expression_type_c::is_ANY_BOOL_compatible(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (is_BOOL_type (type_symbol)) {return true;} - if (is_SAFEBOOL_type(type_symbol)) {return true;} - if (is_literal_bool_type(type_symbol)) {return true;} - return false; -} - - -#define is_type(type_name_symbol, type_name_class) ((type_name_symbol == NULL) ? false : (typeid(*type_name_symbol) == typeid(type_name_class))) - - -#define sizeoftype(symbol) get_sizeof_datatype_c::getsize(symbol) - - -/* A helper function... */ -bool visit_expression_type_c::is_literal_integer_type(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (typeid(*type_symbol) == typeid(neg_integer_c)) {return true;} - return is_nonneg_literal_integer_type(type_symbol); -} - - -/* A helper function... */ -bool visit_expression_type_c::is_nonneg_literal_integer_type(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (typeid(*type_symbol) == typeid(integer_c)) {return true;} - if (typeid(*type_symbol) == typeid(binary_integer_c)) {return true;} - if (typeid(*type_symbol) == typeid(octal_integer_c)) {return true;} - if (typeid(*type_symbol) == typeid(hex_integer_c)) {return true;} - return false; -} - - -/* A helper function... */ -bool visit_expression_type_c::is_literal_real_type(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (typeid(*type_symbol) == typeid(real_c)) {return true;} - if (typeid(*type_symbol) == typeid(neg_real_c)) {return true;} - return false; -} - - -/* A helper function... */ -bool visit_expression_type_c::is_literal_bool_type(symbol_c *type_symbol) { - bool_type_name_c bool_t; - - if (type_symbol == NULL) {return false;} - if (typeid(*type_symbol) == typeid(boolean_true_c)) {return true;} - if (typeid(*type_symbol) == typeid(boolean_false_c)) {return true;} - if (is_nonneg_literal_integer_type(type_symbol)) - if (sizeoftype(&bool_t) >= sizeoftype(type_symbol)) {return true;} - return false; -} - -bool visit_expression_type_c::is_ANY_ELEMENTARY_OR_ENUMERATED_compatible(symbol_c *type_symbol) { - if (type_symbol == NULL) {return false;} - if (search_base_type.type_is_enumerated(type_symbol)) {return true;} - return is_ANY_ELEMENTARY_compatible(type_symbol); -} - - -/* Determine the common data type between two data types. - * If no common data type found, return NULL. - * - * If data types are identical, return the first (actually any would do...). - * If any of the data types is a literal, we confirm that - * the literal uses less bits than the fixed size data type. - * e.g. BYTE and 1024 returns NULL - * BYTE and 255 returns BYTE - * - * If two literals, then return the literal that requires more bits... - */ - -symbol_c *visit_expression_type_c::common_type__(symbol_c *first_type, symbol_c *second_type) { - if (first_type == NULL && second_type == NULL) {return NULL;} - if (first_type == NULL) {return second_type;} - if (second_type == NULL) {return first_type;} - - if (is_literal_integer_type(first_type) && is_literal_integer_type(second_type)) - {return ((sizeoftype(first_type) > sizeoftype(second_type))? first_type:second_type);} - - if (is_literal_real_type(first_type) && is_literal_real_type(second_type)) - {return ((sizeoftype(first_type) > sizeoftype(second_type))? first_type:second_type);} - - if (is_literal_bool_type(first_type) && is_literal_bool_type(second_type)) - {return first_type;} - - /* The following check can only be made after the is_literal_XXXX checks */ - /* When two literals of the same type, with identical typeid's are checked, - * we must return the one that occupies more bits... This is done above. - */ - if (typeid(*first_type) == typeid(*second_type)) {return first_type;} - - /* NOTE Although a BOOL is also an ANY_BIT, we must check it explicitly since some - * literal bool values are not literal integers... - */ - if (is_BOOL_type(first_type) && is_literal_bool_type(second_type)) {return first_type;} - if (is_BOOL_type(second_type) && is_literal_bool_type(first_type)) {return second_type;} - - if (is_SAFEBOOL_type(first_type) && is_literal_bool_type(second_type)) {return first_type;} - if (is_SAFEBOOL_type(second_type) && is_literal_bool_type(first_type)) {return second_type;} - - if (is_SAFEBOOL_type(first_type) && is_BOOL_type(second_type)) {return second_type;} - if (is_SAFEBOOL_type(second_type) && is_BOOL_type(first_type)) {return first_type;} - - if (is_ANY_BIT_type(first_type) && is_nonneg_literal_integer_type(second_type)) - {return ((sizeoftype(first_type) >= sizeoftype(second_type))? first_type :NULL);} - if (is_ANY_BIT_type(second_type) && is_nonneg_literal_integer_type(first_type)) - {return ((sizeoftype(second_type) >= sizeoftype(first_type)) ? second_type:NULL);} - - if (is_ANY_SAFEBIT_type(first_type) && is_nonneg_literal_integer_type(second_type)) - {return ((sizeoftype(first_type) >= sizeoftype(second_type))? first_type :NULL);} - if (is_ANY_SAFEBIT_type(second_type) && is_nonneg_literal_integer_type(first_type)) - {return ((sizeoftype(second_type) >= sizeoftype(first_type)) ? second_type:NULL);} - - if (is_ANY_SAFEBIT_type(first_type) && is_ANY_BIT_type(second_type)) - {return ((sizeoftype(first_type) == sizeoftype(second_type))? second_type:NULL);} - if (is_ANY_SAFEBIT_type(second_type) && is_ANY_BIT_type(first_type)) - {return ((sizeoftype(first_type) == sizeoftype(second_type))? first_type :NULL);} - - if (is_ANY_INT_type(first_type) && is_literal_integer_type(second_type)) - {return ((sizeoftype(first_type) >= sizeoftype(second_type))? first_type :NULL);} - if (is_ANY_INT_type(second_type) && is_literal_integer_type(first_type)) - {return ((sizeoftype(second_type) >= sizeoftype(first_type)) ? second_type:NULL);} - - if (is_ANY_SAFEINT_type(first_type) && is_literal_integer_type(second_type)) - {return ((sizeoftype(first_type) >= sizeoftype(second_type))? first_type :NULL);} - if (is_ANY_SAFEINT_type(second_type) && is_literal_integer_type(first_type)) - {return ((sizeoftype(second_type) >= sizeoftype(first_type)) ? second_type:NULL);} - - if (is_ANY_SAFEINT_type(first_type) && is_ANY_INT_type(second_type)) - {return ((sizeoftype(first_type) == sizeoftype(second_type))? second_type:NULL);} - if (is_ANY_SAFEINT_type(second_type) && is_ANY_INT_type(first_type)) - {return ((sizeoftype(first_type) == sizeoftype(second_type))? first_type :NULL);} - - if (is_ANY_REAL_type(first_type) && is_literal_real_type(second_type)) - {return ((sizeoftype(first_type) >= sizeoftype(second_type))? first_type :NULL);} - if (is_ANY_REAL_type(second_type) && is_literal_real_type(first_type)) - {return ((sizeoftype(second_type) >= sizeoftype(first_type)) ? second_type:NULL);} - - if (is_ANY_SAFEREAL_type(first_type) && is_literal_real_type(second_type)) - {return ((sizeoftype(first_type) >= sizeoftype(second_type))? first_type :NULL);} - if (is_ANY_SAFEREAL_type(second_type) && is_literal_real_type(first_type)) - {return ((sizeoftype(second_type) >= sizeoftype(first_type)) ? second_type:NULL);} - - if (is_ANY_SAFEREAL_type(first_type) && is_ANY_REAL_type(second_type)) - {return ((sizeoftype(first_type) == sizeoftype(second_type))? second_type:NULL);} - if (is_ANY_SAFEREAL_type(second_type) && is_ANY_REAL_type(first_type)) - {return ((sizeoftype(first_type) == sizeoftype(second_type))? first_type :NULL);} - - /* the Time and Date types... */ - if (is_type(first_type, safetime_type_name_c) && is_type(second_type, time_type_name_c)) {return second_type;} - if (is_type(second_type, safetime_type_name_c) && is_type( first_type, time_type_name_c)) {return first_type;} - - if (is_type(first_type, safedate_type_name_c) && is_type(second_type, date_type_name_c)) {return second_type;} - if (is_type(second_type, safedate_type_name_c) && is_type( first_type, date_type_name_c)) {return first_type;} - - if (is_type(first_type, safedt_type_name_c) && is_type(second_type, dt_type_name_c)) {return second_type;} - if (is_type(second_type, safedt_type_name_c) && is_type( first_type, dt_type_name_c)) {return first_type;} - - if (is_type(first_type, safetod_type_name_c) && is_type(second_type, tod_type_name_c)) {return second_type;} - if (is_type(second_type, safetod_type_name_c) && is_type( first_type, tod_type_name_c)) {return first_type;} - - /* no common type */ - return NULL; -} - -/* Determine the common data type between two data types. - * Unlike the common_type__() function, we stop the compiler with an ERROR - * if no common data type is found. - */ -symbol_c *visit_expression_type_c::common_type(symbol_c *first_type, symbol_c *second_type) { -/* - symbol_c *res = common_type__(first_type, second_type); - if (NULL == res) ERROR; - return res; -*/ - return common_type__(first_type, second_type); -} - -symbol_c *visit_expression_type_c::common_literal(symbol_c *first_type, symbol_c *second_type) { - printf("common_literal: %d == %d, %d == %d, %d == %d\n", - (int)is_ANY_INT_compatible(first_type), - (int)is_ANY_INT_compatible(second_type), - (int)is_ANY_REAL_compatible(first_type), - (int)is_ANY_REAL_compatible(second_type), - (int)is_ANY_BIT_compatible(first_type), - (int)is_ANY_BIT_compatible(second_type)); - if ((is_ANY_INT_compatible(first_type) && is_ANY_INT_compatible(second_type)) || - (is_ANY_BIT_compatible(first_type) && is_ANY_BIT_compatible(second_type))) - return &search_constant_type_c::integer; - else if (is_ANY_REAL_compatible(first_type) && is_ANY_REAL_compatible(second_type)) - return &search_constant_type_c::real; - return NULL; -} - -symbol_c *visit_expression_type_c::overloaded_return_type(symbol_c *type) { - if (is_ANY_INT_compatible(type)) - return &search_constant_type_c::ulint_type_name; - else if (is_ANY_REAL_compatible(type)) - return &search_constant_type_c::lreal_type_name; - else if (is_ANY_BIT_compatible(type)) - return &search_constant_type_c::lword_type_name; - return NULL; -} - -/* Return TRUE if the second (value) data type may be assigned to a variable of the first (variable) data type - * such as: - * var_type value_type - * BOOL BYTE#7 -> returns false - * INT INT#7 -> returns true - * INT 7 -> returns true - * REAL 7.89 -> returns true - * REAL 7 -> returns true - * INT 7.89 -> returns false - * SAFEBOOL BOOL#1 -> returns false !!! - * etc... - * - * NOTE: It is assumed that the var_type is the data type of an lvalue - */ -bool visit_expression_type_c::is_valid_assignment(symbol_c *var_type, symbol_c *value_type) { - if (var_type == NULL) {/* STAGE3_ERROR(value_type, value_type, "Var_type == NULL"); */ return false;} - if (value_type == NULL) {/* STAGE3_ERROR(var_type, var_type, "Value_type == NULL"); */ return false;} - - symbol_c *common_type = common_type__(var_type, value_type); - if (NULL == common_type) - return false; - return (typeid(*var_type) == typeid(*common_type)); -} - - -/* Return TRUE if there is a common data type, otherwise return FALSE - * i.e., return TRUE if both data types may be used simultaneously in an expression - * such as: - * BOOL#0 AND BYTE#7 -> returns false - * 0 AND BYTE#7 -> returns true - * INT#10 AND INT#7 -> returns true - * INT#10 AND 7 -> returns true - * REAL#34.3 AND 7.89 -> returns true - * REAL#34.3 AND 7 -> returns true - * INT#10 AND 7.89 -> returns false - * SAFEBOOL#0 AND BOOL#1 -> returns true !!! - * etc... - */ -bool visit_expression_type_c::is_compatible_type(symbol_c *first_type, symbol_c *second_type) { - if (first_type == NULL || second_type == NULL) {return false;} - return (NULL != common_type__(first_type, second_type)); -} - - - - -/* A helper function... */ -/* -symbol_c *visit_expression_type_c::compute_boolean_expression(symbol_c *left_type, symbol_c *right_type, - is_data_type_t is_data_type) { -*/ -symbol_c *visit_expression_type_c::compute_expression(symbol_c *left_type, symbol_c *right_type, is_data_type_t is_data_type, - symbol_c *left_expr, symbol_c *right_expr) { - bool error = false; - - if (!(this->*is_data_type)(left_type)) { - if (debug) printf("visit_expression_type_c::compute_expression(): invalid left_type\n"); - if (left_expr != NULL) - STAGE3_ERROR(left_expr, left_expr, "Invalid data type of operand, or of data resulting from previous IL instructions."); - error = true; - } - if (!(this->*is_data_type)(right_type)) { - if (debug) printf("visit_expression_type_c::compute_expression(): invalid right_type\n"); - if (right_expr != NULL) - STAGE3_ERROR(right_expr, right_expr, "Invalid data type of operand."); - error = true; - } - if (!is_compatible_type(left_type, right_type)) { - if (debug) printf("visit_expression_type_c::compute_expression(): left_type & right_type are incompatible\n"); - if ((left_expr != NULL) && (right_expr != NULL)) - STAGE3_ERROR(left_expr, right_expr, "Type mismatch between operands."); - error = true; - } - - if (error) - return NULL; - else - return common_type(left_type, right_type); -} - - - - -/* A helper function... */ -/* check the semantics of a FB or Function non-formal call */ -/* e.g. foo(1, 2, 3, 4); */ -/* If error_count pointer is != NULL, we do not really print out the errors, - * but rather only count how many errors were found. - * This is used to support overloaded functions, where we have to check each possible - * function, one at a time, untill we find a function call without any errors. - */ -void visit_expression_type_c::check_nonformal_call(symbol_c *f_call, symbol_c *f_decl, bool use_il_defvar, int *error_count) { - symbol_c *call_param_value, *call_param_type, *param_type; - identifier_c *param_name; - function_param_iterator_c fp_iterator(f_decl); - function_call_param_iterator_c fcp_iterator(f_call); - int extensible_parameter_highest_index = -1; - - /* reset error counter */ - if (error_count != NULL) *error_count = 0; - /* if use_il_defvar, then the first parameter for the call comes from the il_default_variable */ - if (use_il_defvar) { - /* The first parameter of the function corresponds to the il_default_variable_type of the function call */ - do { - param_name = fp_iterator.next(); - if(param_name == NULL) break; - /* The EN and ENO parameters are default parameters. - * In the non-formal invocation of a function there can be no assignment of - * values to these parameters. Therefore, we ignore the parameters declared - * in the function. - */ - } while ((strcmp(param_name->value, "EN") == 0) || (strcmp(param_name->value, "ENO") == 0)); - /* If the function does not have any parameters (param_name == NULL) - * then we cannot compare its type with the il_default_variable_type. - * - * However, I (Mario) think this is invalid syntax, as it seems to me all functions must - * have at least one parameter. - * However, we will make this semantic verification consider it possible, as later - * versions of the standard may change that syntax. - * So, instead of generating a syntax error message, we simply check whether the call - * is passing any more parameters besides the default variable (the il default variable may be ignored - * in this case, and not consider it as being a parameter being passed to the function). - * If it does, then we have found a semantic error, otherwise the function call is - * correct, and we simply return. - */ - if(param_name == NULL) { - if (fcp_iterator.next_nf() != NULL) - STAGE3_ERROR(f_call, f_call, "Too many parameters in function/FB call."); - return; - } else { - /* param_name != NULL */ - param_type = fp_iterator.param_type(); - if(!is_valid_assignment(param_type, il_default_variable_type)) { - if (error_count != NULL) (*error_count)++; - else STAGE3_ERROR(f_call, f_call, "In function/FB call, first parameter has invalid data type."); - } - } - - /* the fisrt parameter (il_def_variable) is correct */ - if (extensible_parameter_highest_index < fp_iterator.extensible_param_index()) { - extensible_parameter_highest_index = fp_iterator.extensible_param_index(); - } - } // if (use_il_defvar) - - - - /* Iterating through the non-formal parameters of the function call */ - while((call_param_value = fcp_iterator.next_nf()) != NULL) { - /* Obtaining the type of the value being passed in the function call */ - call_param_type = base_type((symbol_c*)call_param_value->accept(*this)); - if (call_param_type == NULL) { - if (error_count != NULL) (*error_count)++; - /* the following error will usually occur when ST code uses an identifier, that could refer to an enumerated constant, - * but was not actually used as a constant in any definitions of an enumerated data type - */ - else STAGE3_ERROR(call_param_value, call_param_value, "Could not determine data type of value being passed in function/FB call."); - continue; - } - - /* Iterate to the next parameter of the function being called. - * Get the name of that parameter, and ignore if EN or ENO. - */ - do { - param_name = fp_iterator.next(); - /* If there is no other parameter declared, then we are passing too many parameters... */ - if(param_name == NULL) { - if (error_count != NULL) (*error_count)++; - /* Note: We don't want to print out the follwoing error message multiple times, so we return instead of continuing with 'break' */ - else STAGE3_ERROR(f_call, f_call, "Too many parameters in function/FB call."); return; - } - } while ((strcmp(param_name->value, "EN") == 0) || (strcmp(param_name->value, "ENO") == 0)); - - /* Get the parameter type */ - param_type = base_type(fp_iterator.param_type()); - /* If the declared parameter and the parameter from the function call do not have the same type */ - if(!is_valid_assignment(param_type, call_param_type)) { - if (error_count != NULL) (*error_count)++; - else STAGE3_ERROR(call_param_value, call_param_value, "Type mismatch in function/FB call parameter."); - } - - if (extensible_parameter_highest_index < fp_iterator.extensible_param_index()) { - extensible_parameter_highest_index = fp_iterator.extensible_param_index(); - } - } - - /* The function call may not have any errors! */ - /* In the case of a call to an extensible function, we store the highest index - * of the extensible parameters this particular call uses, in the symbol_c object - * of the function call itself! - * In calls to non-extensible functions, this value will be set to -1. - * This information is later used in stage4 to correctly generate the - * output code. - */ - int extensible_param_count = -1; - if (extensible_parameter_highest_index >=0) /* if call to extensible function */ - extensible_param_count = 1 + extensible_parameter_highest_index - fp_iterator.first_extensible_param_index(); - il_function_call_c *il_function_call = dynamic_cast(f_call); - function_invocation_c *function_invocation = dynamic_cast(f_call); - if (il_function_call != NULL) il_function_call ->extensible_param_count = extensible_param_count; - else if (function_invocation != NULL) function_invocation->extensible_param_count = extensible_param_count; - // else ERROR; /* this function is also called by Function Blocks, so this is not an error! */ -} - - -/* check semantics of FB call in the IL language using input operators */ -/* e.g. CU, CLK, IN, PT, SR, ... */ -void visit_expression_type_c::check_il_fbcall(symbol_c *il_operator, const char *il_operator_str) { - symbol_c *call_param_type = il_default_variable_type; - symbol_c *fb_decl = il_operand_type; - /* The following should never occur. The function block must be defined, - * and the FB type being called MUST be in the symtable... - * This was all already checked at stage 2! - */ - if (NULL == fb_decl) ERROR; - if (call_param_type == NULL) ERROR; - - /* We also create an identifier_c object, so we can later use it to find the equivalent FB parameter */ - /* Note however that this symbol does not have the correct location (file name and line numbers) - * so any error messages must use the il_operator symbol to generate the error location - */ - identifier_c call_param_name(il_operator_str); - - /* Obtaining the type of the value being passed in the function call */ - call_param_type = base_type(call_param_type); - if (call_param_type == NULL) STAGE3_ERROR(il_operator, il_operator, "Could not determine data type of value being passed in FB call."); - - /* Find the corresponding parameter of the function being called */ - function_param_iterator_c fp_iterator(fb_decl); - if(fp_iterator.search(&call_param_name) == NULL) { - STAGE3_ERROR(il_operand, il_operand, "Called FB does not have an input parameter named %s.", il_operator_str); - } else { - /* Get the parameter type */ - symbol_c *param_type = base_type(fp_iterator.param_type()); - /* If the declared parameter and the parameter from the function call have the same type */ - if(!is_valid_assignment(param_type, call_param_type)) STAGE3_ERROR(il_operator, il_operator, "Type mismatch in FB call parameter."); - } -} - - -/* A helper function... */ -/* check the semantics of a FB or Function formal call */ -/* e.g. foo(IN1 := 1, OUT1 =>x, EN := true); */ -/* If error_count pointer is != NULL, we do not really print out the errors, - * but rather only count how many errors were found. - * This is used to support overloaded functions, where we have to check each possible - * function, one at a time, untill we find a function call without any errors. - */ -void visit_expression_type_c::check_formal_call(symbol_c *f_call, symbol_c *f_decl, int *error_count) { - symbol_c *call_param_value, *call_param_type, *call_param_name, *param_type; - symbol_c *verify_duplicate_param; - identifier_c *param_name; - function_param_iterator_c fp_iterator(f_decl); - function_call_param_iterator_c fcp_iterator(f_call); - int extensible_parameter_highest_index = -1; - identifier_c *extensible_parameter_name; - - /* reset error counter */ - if (error_count != NULL) *error_count = 0; - - /* Iterating through the formal parameters of the function call */ - while((call_param_name = fcp_iterator.next_f()) != NULL) { - - /* Obtaining the value being passed in the function call */ - call_param_value = fcp_iterator.get_current_value(); - /* the following should never occur. If it does, then we have a bug in our code... */ - if (NULL == call_param_value) ERROR; - - /* Checking if there are duplicated parameter values */ - verify_duplicate_param = fcp_iterator.search_f(call_param_name); - if(verify_duplicate_param != call_param_value){ - if (error_count != NULL) (*error_count)++; - else STAGE3_ERROR(call_param_name, verify_duplicate_param, "Duplicated parameter values."); - } - - /* Obtaining the type of the value being passed in the function call */ - call_param_type = (symbol_c*)call_param_value->accept(*this); - if (call_param_type == NULL) { - if (error_count != NULL) (*error_count)++; - else STAGE3_ERROR(call_param_name, call_param_value, "Could not determine data type of value being passed in function/FB call."); - /* The data value being passed is possibly any enumerated type value. - * We do not yet handle semantic verification of enumerated types. - */ - ERROR; - } - call_param_type = base_type(call_param_type); - if (call_param_type == NULL) STAGE3_ERROR(call_param_name, call_param_value, "Could not determine data type of value being passed in function/FB call."); - - /* Find the corresponding parameter of the function being called */ - param_name = fp_iterator.search(call_param_name); - if(param_name == NULL) { - if (error_count != NULL) (*error_count)++; - else STAGE3_ERROR(call_param_name, call_param_name, "Invalid parameter in function/FB call."); - } else { - /* Get the parameter type */ - param_type = base_type(fp_iterator.param_type()); - /* If the declared parameter and the parameter from the function call have the same type */ - if(!is_valid_assignment(param_type, call_param_type)) { - if (error_count != NULL) (*error_count)++; - else STAGE3_ERROR(call_param_name, call_param_value, "Type mismatch function/FB call parameter."); - } - if (extensible_parameter_highest_index < fp_iterator.extensible_param_index()) { - extensible_parameter_highest_index = fp_iterator.extensible_param_index(); - extensible_parameter_name = param_name; - } - } - } - - /* In the case of a call to an extensible function, we store the highest index - * of the extensible parameters this particular call uses, in the symbol_c object - * of the function call itself! - * In calls to non-extensible functions, this value will be set to -1. - * This information is later used in stage4 to correctly generate the - * output code. - */ - int extensible_param_count = -1; - if (extensible_parameter_highest_index >=0) /* if call to extensible function */ - extensible_param_count = 1 + extensible_parameter_highest_index - fp_iterator.first_extensible_param_index(); - il_formal_funct_call_c *il_formal_funct_call = dynamic_cast(f_call); - function_invocation_c *function_invocation = dynamic_cast(f_call); - if (il_formal_funct_call != NULL) il_formal_funct_call->extensible_param_count = extensible_param_count; - else if (function_invocation != NULL) function_invocation->extensible_param_count = extensible_param_count; -// else ERROR; /* this function is also called by Function Blocks, so this is not an error! */ - - /* We have iterated through all the formal parameters of the function call, - * and everything seems fine. - * If the function being called in an extensible function, we now check - * whether the extensible paramters in the formal invocation do not skip - * any indexes... - * - * f(in1:=0, in2:=0, in4:=0) --> ERROR!! - */ - if (extensible_parameter_highest_index >=0) { /* if call to extensible function */ - for (int i=fp_iterator.first_extensible_param_index(); i < extensible_parameter_highest_index; i++) { - char tmp[256]; - if (snprintf(tmp, 256, "%s%d", extensible_parameter_name->value, i) >= 256) ERROR; - if (fcp_iterator.search_f(tmp) == NULL) { - /* error in invocation of extensible function */ - if (error_count != NULL) (*error_count)++; - else STAGE3_ERROR(f_call, f_call, "Missing extensible parameters in call to extensible function."); - } - } - } -} - - - - -/* a helper function... */ -symbol_c *visit_expression_type_c::base_type(symbol_c *symbol) { - /* NOTE: symbol == NULL is valid. It will occur when, for e.g., an undefined/undeclared symbolic_variable is used - * in the code. - */ - if (symbol == NULL) return NULL; - return (symbol_c *)symbol->accept(search_base_type); -} - - -/* a helper function... */ -void *visit_expression_type_c::verify_null(symbol_c *symbol){ - if(il_default_variable_type == NULL){ - STAGE3_ERROR(symbol, symbol, "Missing LD instruction (or equivalent) before this instruction."); - } - if(il_operand_type == NULL){ - STAGE3_ERROR(symbol, symbol, "This instruction requires an operand."); - } - return NULL; -} - - -/********************************/ -/* B 1.3.3 - Derived data types */ -/********************************/ -void *visit_expression_type_c::visit(data_type_declaration_c *symbol) { - // TODO !!! - /* for the moment we must return NULL so semantic analysis of remaining code is not interrupted! */ - return NULL; -} - - -/*********************/ -/* B 1.4 - Variables */ -/*********************/ - -void *visit_expression_type_c::visit(symbolic_variable_c *symbol) { - return search_varfb_instance_type->get_basetype_decl(symbol); -} - -/********************************************/ -/* B 1.4.1 - Directly Represented Variables */ -/********************************************/ -void *visit_expression_type_c::visit(direct_variable_c *symbol) { - switch (symbol->value[2]) { - case 'X': // bit - 1 bit - return (void *)&bool_type_name; - case 'B': // byte - 8 bits - return (void *)&byte_type_name; - case 'W': // word - 16 bits - return (void *)&word_type_name; - case 'D': // double word - 32 bits - return (void *)&dword_type_name; - case 'L': // long word - 64 bits - return (void *)&lword_type_name; - default: // if none of the above, then the empty string was used <=> boolean - return (void *)&bool_type_name; - } -} - -/*************************************/ -/* B 1.4.2 - Multi-element variables */ -/*************************************/ -void *visit_expression_type_c::visit(array_variable_c *symbol) { - return search_varfb_instance_type->get_basetype_decl(symbol); -} - -void *visit_expression_type_c::visit(structured_variable_c *symbol) { - return search_varfb_instance_type->get_basetype_decl(symbol); -} - - - -/********************************/ -/* B 1.7 Configuration elements */ -/********************************/ -void *visit_expression_type_c::visit(configuration_declaration_c *symbol) { - // TODO !!! - /* for the moment we must return NULL so semantic analysis of remaining code is not interrupted! */ - return NULL; -} - - -/****************************************/ -/* B.2 - Language IL (Instruction List) */ -/****************************************/ -/***********************************/ -/* B 2.1 Instructions and Operands */ -/***********************************/ -/*| instruction_list il_instruction */ -/* The visitor of the base class search_visitor_c will handle calling each instruction in the list. - * We do not need to do anything here... - */ -// void *visit_expression_type_c::visit(instruction_list_c *symbol) - -/* | label ':' [il_incomplete_instruction] eol_list */ -//SYM_REF2(il_instruction_c, label, il_instruction) -// void *visit_expression_type_c::visit(il_instruction_c *symbol); - - -/* | il_simple_operator [il_operand] */ -// SYM_REF2(il_simple_operation_c, il_simple_operator, il_operand) -void *visit_expression_type_c::visit(il_simple_operation_c *symbol) { - if (il_error) - return NULL; - - /* determine the data type of the operand */ - il_operand = symbol->il_operand; - if (symbol->il_operand != NULL){ - il_operand_type = base_type((symbol_c *)symbol->il_operand->accept(*this)); - } else { - il_operand_type = NULL; - } - /* recursive call to see whether data types are compatible */ - symbol->il_simple_operator->accept(*this); - - il_operand_type = NULL; - il_operand = NULL; - return NULL; -} - -// | function_name [il_operand_list] */ -//SYM_REF2(il_function_call_c, function_name, il_operand_list) -void *visit_expression_type_c::visit(il_function_call_c *symbol) { - if (il_error) - return NULL; - - symbol_c *return_data_type = NULL; - symbol_c* fdecl_return_type; - symbol_c* overloaded_data_type = NULL; - int extensible_param_count = -1; - symbol->called_function_declaration = NULL; - - /* First find the declaration of the function being called! */ - function_symtable_t::iterator lower = function_symtable.lower_bound(symbol->function_name); - function_symtable_t::iterator upper = function_symtable.upper_bound(symbol->function_name); - function_symtable_t::iterator current; - if (lower == function_symtable.end()) ERROR; - - int error_count = 0; - int *error_count_ptr = NULL; - - function_symtable_t::iterator second = lower; - second++; - if (second != upper) - /* This is a call to an overloaded function... */ - error_count_ptr = &error_count; - - for(current = lower; current != upper; current++) { - function_declaration_c *f_decl = function_symtable.get_value(current); - - check_nonformal_call(symbol, f_decl, true, error_count_ptr); - - if (0 == error_count) { - /* Either: - * (i) we have a call to a non-overloaded function (error_cnt_ptr is NULL!, so error_count won't change!) - * (ii) we have a call to an overloaded function, with no errors! - */ - - fdecl_return_type = base_type(f_decl->type_name); - - if (symbol->called_function_declaration == NULL) { - /* Store the pointer to the declaration of the function being called. - * This data will be used by stage 4 to call the correct function. - * Mostly needed to disambiguate overloaded functions... - * See comments in absyntax.def for more details - */ - symbol->called_function_declaration = f_decl; - extensible_param_count = symbol->extensible_param_count; - - /* determine the base data type returned by the function being called... */ - return_data_type = fdecl_return_type; - } - else if (typeid(*return_data_type) != typeid(*fdecl_return_type)){ - return_data_type = common_literal(return_data_type, fdecl_return_type); - overloaded_data_type = overloaded_return_type(return_data_type); - } - - if (NULL == return_data_type) ERROR; - } - } - - if (overloaded_data_type != NULL) { - for(current = lower; current != upper; current++) { - function_declaration_c *f_decl = function_symtable.get_value(current); - - /* check semantics of data passed in the function call... */ - check_nonformal_call(symbol, f_decl, true, error_count_ptr); - - if (0 == error_count) { - - fdecl_return_type = base_type(f_decl->type_name); - - if (typeid(*overloaded_data_type) == typeid(*fdecl_return_type)){ - /* Store the pointer to the declaration of the function being called. - * This data will be used by stage 4 to call the correct function. - * Mostly needed to disambiguate overloaded functions... - * See comments in absyntax.def for more details - */ - symbol->called_function_declaration = f_decl; - extensible_param_count = symbol->extensible_param_count; - } - } - } - } - - if (NULL == return_data_type) { - /* No compatible function was found for this function call */ - STAGE3_ERROR(symbol, symbol, "Call to an overloaded function with invalid parameter type."); - } - else { - symbol->extensible_param_count = extensible_param_count; - /* set the new data type of the default variable for the following verifications... */ - il_default_variable_type = return_data_type; - } - - return NULL; -} - - -/* | il_expr_operator '(' [il_operand] eol_list [simple_instr_list] ')' */ -// SYM_REF3(il_expression_c, il_expr_operator, il_operand, simple_instr_list); -void *visit_expression_type_c::visit(il_expression_c *symbol) { - if (il_error) - return NULL; - - symbol_c *il_default_variable_type_back = il_default_variable_type; - - il_parenthesis_level++; - - if(symbol->il_operand != NULL) { - il_default_variable_type = base_type((symbol_c *)symbol->il_operand->accept(*this)); - } else { - il_default_variable_type = NULL; - } - - if(symbol->simple_instr_list != NULL) { - symbol->simple_instr_list->accept(*this); - } - - il_parenthesis_level--; - if (il_parenthesis_level < 0) ERROR; - - il_operand = symbol->simple_instr_list; - il_operand_type = il_default_variable_type; - il_default_variable_type = il_default_variable_type_back; - - /* Now check the if the data type semantics of operation are correct, - * but only if no previous error has been found... - */ - if (!il_error) - symbol->il_expr_operator->accept(*this); - - il_operand_type = NULL; - il_operand = NULL; - return NULL; -} - - -#if 0 -/* il_jump_operator label */ -SYM_REF2(il_jump_operation_c, il_jump_operator, label) -void *visit_expression_type_c::visit(il_jump_operation_c *symbol); -#endif - - -/* il_call_operator prev_declared_fb_name - * | il_call_operator prev_declared_fb_name '(' ')' - * | il_call_operator prev_declared_fb_name '(' eol_list ')' - * | il_call_operator prev_declared_fb_name '(' il_operand_list ')' - * | il_call_operator prev_declared_fb_name '(' eol_list il_param_list ')' - */ -/* SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list) */ -void *visit_expression_type_c::visit(il_fb_call_c *symbol) { - if (il_error) - return NULL; - - /* first check whether the il_default_variable is of the correct type - * for the CAL / CALC / CALCN operator being used... - */ - symbol->il_call_operator->accept(*this); - - /* Now check the FB call itself... */ - - /* First we find the declaration of the FB type of the FB instance being called... */ - /* e.g. Function_block foo_fb_type - * ... - * End_Function_Block - * - * Program test - * var fb1 : foo_fb_type; end_var - * fb1(...) - * End_Program - * - * search_varfb_instance_type->get_basetype_decl( identifier_c("fb1") ) - * in the scope of Program 'test' - * will return the fb declaration of foo_fb_type !! - */ -#if 0 - symbol_c *fb_decl_symbol = search_varfb_instance_type->get_basetype_decl(symbol->fb_name); - /* The following should never occur. The function block must be defined, - * and the FB type being called MUST be in the symtable... - * This was all already checked at stage 2! - */ - if (NULL == fb_decl_symbol) ERROR; - - function_block_declaration_c *fb_decl = dynamic_cast(fb_decl_symbol); - /* should never occur. ... */ - if (NULL == fb_decl) ERROR; -#endif - symbol_c *fb_decl = search_varfb_instance_type->get_basetype_decl(symbol->fb_name); - /* The following should never occur. The function block must be defined, - * and the FB type being called MUST be in the symtable... - * This was all already checked at stage 2! - */ - if (NULL == fb_decl) ERROR; - - /* now check the semantics of the fb call... */ - /* If the syntax parser is working correctly, exactly one of the - * following two symbols will be NULL, while the other is != NULL. - */ - if (NULL != symbol->il_operand_list) check_nonformal_call(symbol, fb_decl); - if (NULL != symbol->il_param_list) check_formal_call (symbol, fb_decl); - - return NULL; -} - - - -/* | function_name '(' eol_list [il_param_list] ')' */ -/* SYM_REF2(il_formal_funct_call_c, function_name, il_param_list) */ -void *visit_expression_type_c::visit(il_formal_funct_call_c *symbol) { - if (il_error) - return NULL; - - symbol_c *return_data_type = NULL; - symbol_c* fdecl_return_type; - symbol_c *overloaded_data_type = NULL; - int extensible_param_count = -1; - symbol->called_function_declaration = NULL; - - function_symtable_t::iterator lower = function_symtable.lower_bound(symbol->function_name); - function_symtable_t::iterator upper = function_symtable.upper_bound(symbol->function_name); - function_symtable_t::iterator current; - - if (lower == function_symtable.end()) { - function_type_t current_function_type = get_function_type((identifier_c *)symbol->function_name); - if (current_function_type == function_none) ERROR; - return NULL; - } - - int error_count = 0; - int *error_count_ptr = NULL; - - function_symtable_t::iterator second = lower; - second++; - if (second != upper) - /* This is a call to an overloaded function... */ - error_count_ptr = &error_count; - - for(current = lower; current != upper; current++) { - function_declaration_c *f_decl = function_symtable.get_value(current); - - /* check semantics of data passed in the function call... */ - check_formal_call(symbol, f_decl, error_count_ptr); - - if (0 == error_count) { - /* Either: - * (i) we have a call to a non-overloaded function (error_cnt_ptr is NULL!, so error_count won't change!) - * (ii) we have a call to an overloaded function, with no errors! - */ - - fdecl_return_type = base_type(f_decl->type_name); - - if (symbol->called_function_declaration == NULL) { - /* Store the pointer to the declaration of the function being called. - * This data will be used by stage 4 to call the correct function. - * Mostly needed to disambiguate overloaded functions... - * See comments in absyntax.def for more details - */ - symbol->called_function_declaration = f_decl; - extensible_param_count = symbol->extensible_param_count; - - /* determine the base data type returned by the function being called... */ - return_data_type = fdecl_return_type; - } - else if (typeid(*return_data_type) != typeid(*fdecl_return_type)){ - return_data_type = common_literal(return_data_type, fdecl_return_type); - overloaded_data_type = overloaded_return_type(return_data_type); - } - - /* the following should never occur. If it does, then we have a bug in the syntax parser (stage 2)... */ - if (NULL == return_data_type) ERROR; - - } - } - - if (overloaded_data_type != NULL) { - for(current = lower; current != upper; current++) { - function_declaration_c *f_decl = function_symtable.get_value(current); - - /* check semantics of data passed in the function call... */ - check_formal_call(symbol, f_decl, error_count_ptr); - - if (0 == error_count) { - - fdecl_return_type = base_type(f_decl->type_name); - - if (typeid(*overloaded_data_type) == typeid(*fdecl_return_type)){ - /* Store the pointer to the declaration of the function being called. - * This data will be used by stage 4 to call the correct function. - * Mostly needed to disambiguate overloaded functions... - * See comments in absyntax.def for more details - */ - symbol->called_function_declaration = f_decl; - extensible_param_count = symbol->extensible_param_count; - } - } - } - } - - if (NULL == return_data_type) { - /* No compatible function was found for this function call */ - STAGE3_ERROR(symbol, symbol, "Call to an overloaded function with invalid parameter type."); - } - else { - symbol->extensible_param_count = extensible_param_count; - /* the data type of the data returned by the function, and stored in the il default variable... */ - il_default_variable_type = return_data_type; - } - - return NULL; -} - - -#if 0 -/* | il_operand_list ',' il_operand */ -SYM_LIST(il_operand_list_c) -void *visit_expression_type_c::visit(il_operand_list_c *symbol); - -/* | simple_instr_list il_simple_instruction */ -SYM_LIST(simple_instr_list_c) -void *visit_expression_type_c::visit(simple_instr_list_c *symbol); - -/* | il_initial_param_list il_param_instruction */ -SYM_LIST(il_param_list_c) -void *visit_expression_type_c::visit(il_param_list_c *symbol); - -/* il_assign_operator il_operand - * | il_assign_operator '(' eol_list simple_instr_list ')' - */ -SYM_REF3(il_param_assignment_c, il_assign_operator, il_operand, simple_instr_list) -void *visit_expression_type_c::visit(il_param_assignment_c *symbol); -/* il_assign_out_operator variable */ -SYM_REF2(il_param_out_assignment_c, il_assign_out_operator, variable) -void *visit_expression_type_c::visit(il_param_out_assignment_c *symbol); - -#endif - - -/*******************/ -/* B 2.2 Operators */ -/*******************/ - -//SYM_REF0(LD_operator_c) -void *visit_expression_type_c::visit(LD_operator_c *symbol) { - if (0 == il_parenthesis_level) - il_error = false; - - if(il_operand_type == NULL) - STAGE3_ERROR(symbol, symbol, "LD operator requires an operand."); - il_default_variable_type = il_operand_type; - return NULL; -} - -// SYM_REF0(LDN_operator_c) -void *visit_expression_type_c::visit(LDN_operator_c *symbol) { - if(il_operand_type == NULL) - STAGE3_ERROR(symbol, symbol, "LDN operator requires an operand."); - if(!is_ANY_BIT_compatible(il_operand_type)) - STAGE3_ERROR(symbol, il_operand, "invalid data type of LDN operand, should be of type ANY_BIT."); - il_default_variable_type = il_operand_type; - return NULL; -} - -// SYM_REF0(ST_operator_c) -void *visit_expression_type_c::visit(ST_operator_c *symbol) { - verify_null(symbol); - - if(!is_valid_assignment(il_operand_type, il_default_variable_type)) - STAGE3_ERROR(symbol, symbol, "Type mismatch in ST operation."); - /* TODO: check whether il_operand_type is an LVALUE !! */ - /* data type of il_default_variable_type is unchanged... */ - // il_default_variable_type = il_default_variable_type; - return NULL; -} - -// SYM_REF0(STN_operator_c) - void *visit_expression_type_c::visit(STN_operator_c *symbol) { - verify_null(symbol); - if(!is_valid_assignment(il_operand_type, il_default_variable_type)) - STAGE3_ERROR(symbol, symbol, "Type mismatch in ST operation."); - /* TODO: check whether il_operand_type is an LVALUE !! */ - if(!is_ANY_BIT_compatible(il_default_variable_type)) - STAGE3_ERROR(symbol, symbol, "invalid data type of il_default_variable for STN operand, should be of type ANY_BIT."); - if(!is_ANY_BIT_compatible(il_operand_type)) - STAGE3_ERROR(symbol, il_operand, "invalid data type of STN operand, should be of type ANY_BIT."); - /* data type of il_default_variable_type is unchanged... */ - // il_default_variable_type = il_default_variable_type; - return NULL; -} - -//SYM_REF0(NOT_operator_c) -void *visit_expression_type_c::visit(NOT_operator_c *symbol) { - if(il_operand_type != NULL){ - STAGE3_ERROR(symbol, il_operand, "NOT operator may not have an operand."); - return NULL; - } - if(il_default_variable_type == NULL) { - STAGE3_ERROR(symbol, symbol, "Il default variable should not be NULL."); - return NULL; - } - if(!is_ANY_BIT_compatible(il_default_variable_type)) { - STAGE3_ERROR(symbol, symbol, "Il default variable should be of type ANY_BIT."); - return NULL; - } - /* data type of il_default_variable_type is unchanged... */ - // il_default_variable_type = il_default_variable_type; - return NULL; -} - -// SYM_REF0(S_operator_c) -void *visit_expression_type_c::visit(S_operator_c *symbol) { - verify_null(symbol); - if (!is_BOOL_type(il_default_variable_type)) {STAGE3_ERROR(symbol, symbol, "IL default variable should be BOOL type.");} - if (!is_BOOL_type(il_operand_type)) {STAGE3_ERROR(symbol, il_operand, "operator S requires operand of type BOOL.");} - /* TODO: check whether il_operand_type is an LVALUE !! */ - /* data type of il_default_variable_type is unchanged... */ - // il_default_variable_type = il_default_variable_type; - return NULL; -} - -// SYM_REF0(R_operator_c) -void *visit_expression_type_c::visit(R_operator_c *symbol) { - verify_null(symbol); - if (!is_BOOL_type(il_default_variable_type)) {STAGE3_ERROR(symbol, symbol, "IL default variable should be BOOL type.");} - if (!is_BOOL_type(il_operand_type)) {STAGE3_ERROR(symbol, il_operand, "operator R requires operand of type BOOL.");} - /* TODO: check whether il_operand_type is an LVALUE !! */ - /* data type of il_default_variable_type is unchanged... */ - // il_default_variable_type = il_default_variable_type; - return NULL; -} - - -// SYM_REF0(S1_operator_c) -void *visit_expression_type_c::visit(S1_operator_c *symbol){ - check_il_fbcall(symbol, "S1"); - return NULL; -} - -// SYM_REF0(R1_operator_c) -void *visit_expression_type_c::visit(R1_operator_c *symbol) { - check_il_fbcall(symbol, "R1"); - return NULL; -} - -// SYM_REF0(CLK_operator_c) -void *visit_expression_type_c::visit(CLK_operator_c *symbol) { - check_il_fbcall(symbol, "CLK"); - return NULL; -} - -// SYM_REF0(CU_operator_c) -void *visit_expression_type_c::visit(CU_operator_c *symbol) { - check_il_fbcall(symbol, "CU"); - return NULL; -} - -// SYM_REF0(CD_operator_c) -void *visit_expression_type_c::visit(CD_operator_c *symbol) { - check_il_fbcall(symbol, "CD"); - return NULL; -} - -// SYM_REF0(PV_operator_c) -void *visit_expression_type_c::visit(PV_operator_c *symbol) { - check_il_fbcall(symbol, "PV"); - return NULL; -} - -// SYM_REF0(IN_operator_c) -void *visit_expression_type_c::visit(IN_operator_c *symbol) { - check_il_fbcall(symbol, "IN"); - return NULL; -} - -// SYM_REF0(PT_operator_c) -void *visit_expression_type_c::visit(PT_operator_c *symbol) { - check_il_fbcall(symbol, "PT"); - return NULL; -} - -//SYM_REF0(AND_operator_c) -void *visit_expression_type_c::visit(AND_operator_c *symbol) { - verify_null(symbol); - il_default_variable_type = compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_BIT_compatible, - symbol , il_operand); - return NULL; -} - -//SYM_REF0(OR_operator_c) -void *visit_expression_type_c::visit(OR_operator_c *symbol) { - verify_null(symbol); - il_default_variable_type = compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_BIT_compatible, - symbol , il_operand); - return NULL; -} - -//SYM_REF0(XOR_operator_c) -void *visit_expression_type_c::visit(XOR_operator_c *symbol) { - verify_null(symbol); - il_default_variable_type = compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_BIT_compatible, - symbol , il_operand); - return NULL; -} - -// SYM_REF0(ANDN_operator_c) -void *visit_expression_type_c::visit(ANDN_operator_c *symbol) { - verify_null(symbol); - il_default_variable_type = compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_BIT_compatible, - symbol , il_operand); - return NULL; -} - -// SYM_REF0(ORN_operator_c) -void *visit_expression_type_c::visit(ORN_operator_c *symbol) { - verify_null(symbol); - il_default_variable_type = compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_BIT_compatible, - symbol , il_operand); - return NULL; -} - -// SYM_REF0(XORN_operator_c) -void *visit_expression_type_c::visit(XORN_operator_c *symbol) { - verify_null(symbol); - il_default_variable_type = compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_BIT_compatible, - symbol , il_operand); - return NULL; -} - -// SYM_REF0(ADD_operator_c) -void *visit_expression_type_c::visit(ADD_operator_c *symbol) { - verify_null(symbol); - symbol_c *left_type = il_default_variable_type; - symbol_c *right_type = il_operand_type; - -/* The following is not required, it is already handled by compute_expression() ... */ -/* - if (is_type(left_type, time_type_name_c) && is_type(right_type, time_type_name_c)) - il_default_variable_type = &time_type_name; -*/ - - if (is_type(left_type, tod_type_name_c) && is_type(right_type, time_type_name_c)) - il_default_variable_type = &tod_type_name; - else if (is_type(left_type, safetod_type_name_c) && is_type(right_type, time_type_name_c)) - il_default_variable_type = &tod_type_name; - else if (is_type(left_type, tod_type_name_c) && is_type(right_type, safetime_type_name_c)) - il_default_variable_type = &tod_type_name; - else if (is_type(left_type, safetod_type_name_c) && is_type(right_type, safetime_type_name_c)) - il_default_variable_type = &safetod_type_name; - - else if (is_type(left_type, dt_type_name_c) && is_type(right_type, time_type_name_c)) - il_default_variable_type = &dt_type_name; - else if (is_type(left_type, safedt_type_name_c) && is_type(right_type, time_type_name_c)) - il_default_variable_type = &dt_type_name; - else if (is_type(left_type, dt_type_name_c) && is_type(right_type, safetime_type_name_c)) - il_default_variable_type = &dt_type_name; - else if (is_type(left_type, safedt_type_name_c) && is_type(right_type, safetime_type_name_c)) - il_default_variable_type = &safedt_type_name; - - else il_default_variable_type = compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_MAGNITUDE_compatible, - symbol , il_operand); - return NULL; -} - -// SYM_REF0(SUB_operator_c) -void *visit_expression_type_c::visit(SUB_operator_c *symbol) { - verify_null(symbol); - symbol_c *left_type = il_default_variable_type; - symbol_c *right_type = il_operand_type;; - -/* The following is not required, it is already handled by compute_expression() ... */ -/* - if (typeid(*left_type) == typeid(time_type_name_c) && typeid(*right_type) == typeid(time_type_name_c)) - il_default_variable_type = &time_type_name; -*/ - - if (is_type(left_type, tod_type_name_c) && is_type(right_type, time_type_name_c)) - il_default_variable_type = &tod_type_name; - else if (is_type(left_type, safetod_type_name_c) && is_type(right_type, time_type_name_c)) - il_default_variable_type = &tod_type_name; - else if (is_type(left_type, tod_type_name_c) && is_type(right_type, safetime_type_name_c)) - il_default_variable_type = &tod_type_name; - else if (is_type(left_type, safetod_type_name_c) && is_type(right_type, safetime_type_name_c)) - il_default_variable_type = &safetod_type_name; - - else if (is_type(left_type, dt_type_name_c) && is_type(right_type, time_type_name_c)) - il_default_variable_type = &dt_type_name; - else if (is_type(left_type, safedt_type_name_c) && is_type(right_type, time_type_name_c)) - il_default_variable_type = &dt_type_name; - else if (is_type(left_type, dt_type_name_c) && is_type(right_type, safetime_type_name_c)) - il_default_variable_type = &dt_type_name; - else if (is_type(left_type, safedt_type_name_c) && is_type(right_type, safetime_type_name_c)) - il_default_variable_type = &safedt_type_name; - - else if (is_type(left_type, date_type_name_c) && is_type(right_type, date_type_name_c)) - il_default_variable_type = &time_type_name; - else if (is_type(left_type, safedate_type_name_c) && is_type(right_type, date_type_name_c)) - il_default_variable_type = &time_type_name; - else if (is_type(left_type, date_type_name_c) && is_type(right_type, safedate_type_name_c)) - il_default_variable_type = &time_type_name; - else if (is_type(left_type, safedate_type_name_c) && is_type(right_type, safedate_type_name_c)) - il_default_variable_type = &safetime_type_name; - - else if (is_type(left_type, tod_type_name_c) && is_type(right_type, tod_type_name_c)) - il_default_variable_type = &time_type_name; - else if (is_type(left_type, safetod_type_name_c) && is_type(right_type, tod_type_name_c)) - il_default_variable_type = &time_type_name; - else if (is_type(left_type, tod_type_name_c) && is_type(right_type, safetod_type_name_c)) - il_default_variable_type = &time_type_name; - else if (is_type(left_type, safetod_type_name_c) && is_type(right_type, safetod_type_name_c)) - il_default_variable_type = &safetime_type_name; - - else if (is_type(left_type, dt_type_name_c) && is_type(right_type, dt_type_name_c)) - il_default_variable_type = &time_type_name; - else if (is_type(left_type, safedt_type_name_c) && is_type(right_type, dt_type_name_c)) - il_default_variable_type = &time_type_name; - else if (is_type(left_type, dt_type_name_c) && is_type(right_type, safedt_type_name_c)) - il_default_variable_type = &time_type_name; - else if (is_type(left_type, safedt_type_name_c) && is_type(right_type, safedt_type_name_c)) - il_default_variable_type = &safetime_type_name; - - else il_default_variable_type = compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_MAGNITUDE_compatible, - symbol , il_operand); - return NULL; -} - -// SYM_REF0(MUL_operator_c) -void *visit_expression_type_c::visit(MUL_operator_c *symbol) { - verify_null(symbol); - symbol_c *left_type = il_default_variable_type; - symbol_c *right_type = il_operand_type; - - if (is_type(left_type, time_type_name_c) && is_ANY_NUM_compatible(right_type)) - il_default_variable_type = &time_type_name; - else if (is_type(left_type, safetime_type_name_c) && is_ANY_NUM_type(right_type)) - il_default_variable_type = &time_type_name; - else if (is_type(left_type, safetime_type_name_c) && is_ANY_SAFENUM_type(right_type)) - il_default_variable_type = &safetime_type_name; - /* Since we have already checked for ANY_NUM_type and ANY_SAFENUM_type in the previous lines, - * this next line is really only to check for integers/reals of undefined type on 'right_type'... - */ - else if (is_type(left_type, safetime_type_name_c) && is_ANY_NUM_compatible(right_type)) - il_default_variable_type = &safetime_type_name; - - else il_default_variable_type = compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_NUM_compatible, - symbol , il_operand); - return NULL; -} - -// SYM_REF0(DIV_operator_c) -void *visit_expression_type_c::visit(DIV_operator_c *symbol) { - verify_null(symbol); - symbol_c *left_type = il_default_variable_type; - symbol_c *right_type = il_operand_type; - - if (is_type(left_type, time_type_name_c) && is_ANY_NUM_compatible(right_type)) - il_default_variable_type = &time_type_name; - else if (is_type(left_type, safetime_type_name_c) && is_ANY_NUM_type(right_type)) - il_default_variable_type = &time_type_name; - else if (is_type(left_type, safetime_type_name_c) && is_ANY_SAFENUM_type(right_type)) - il_default_variable_type = &safetime_type_name; - /* Since we have already checked for ANY_NUM_type and ANY_SAFENUM_type in the previous lines, - * this next line is really only to check for integers/reals of undefined type on 'right_type'... - */ - else if (is_type(left_type, safetime_type_name_c) && is_ANY_NUM_compatible(right_type)) - il_default_variable_type = &safetime_type_name; - - else il_default_variable_type = compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_NUM_compatible, - symbol , il_operand); - return NULL; -} - -// SYM_REF0(MOD_operator_c) -void *visit_expression_type_c::visit(MOD_operator_c *symbol) { - verify_null(symbol); - il_default_variable_type = compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_INT_compatible, - symbol , il_operand); - return NULL; -} - -// SYM_REF0(GT_operator_c) -void *visit_expression_type_c::visit(GT_operator_c *symbol) { - verify_null(symbol); - compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_ELEMENTARY_compatible, - symbol , il_operand); - il_default_variable_type = &search_expression_type_c::bool_type_name; - return NULL; -} - -//SYM_REF0(GE_operator_c) -void *visit_expression_type_c::visit(GE_operator_c *symbol) { - verify_null(symbol); - compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_ELEMENTARY_compatible, - symbol , il_operand); - il_default_variable_type = &search_expression_type_c::bool_type_name; - return NULL; -} - -//SYM_REF0(EQ_operator_c) -void *visit_expression_type_c::visit(EQ_operator_c *symbol) { - verify_null(symbol); - compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_ELEMENTARY_compatible, - symbol , il_operand); - il_default_variable_type = &search_expression_type_c::bool_type_name; - return NULL; -} - -//SYM_REF0(LT_operator_c) -void *visit_expression_type_c::visit(LT_operator_c *symbol) { - verify_null(symbol); - compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_ELEMENTARY_compatible, - symbol , il_operand); - il_default_variable_type = &search_expression_type_c::bool_type_name; - return NULL; -} - -//SYM_REF0(LE_operator_c) -void *visit_expression_type_c::visit(LE_operator_c *symbol) { - verify_null(symbol); - compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_ELEMENTARY_compatible, - symbol , il_operand); - il_default_variable_type = &search_expression_type_c::bool_type_name; - return NULL; -} - -//SYM_REF0(NE_operator_c) -void *visit_expression_type_c::visit(NE_operator_c *symbol) { - verify_null(symbol); - compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_ELEMENTARY_compatible, - symbol , il_operand); - il_default_variable_type = &search_expression_type_c::bool_type_name; - return NULL; -} - -// SYM_REF0(CAL_operator_c) -void *visit_expression_type_c::visit(CAL_operator_c *symbol) { - return NULL; -} - -// SYM_REF0(CALC_operator_c) -void *visit_expression_type_c::visit(CALC_operator_c *symbol) { - if(il_default_variable_type == NULL) - STAGE3_ERROR(symbol, symbol, "CALC: il default variable should not be NULL."); - if (!is_BOOL_type(il_default_variable_type)) - STAGE3_ERROR(symbol, symbol, "CALC operator requires il_default_variable to be of type BOOL."); - return NULL; -} - -// SYM_REF0(CALCN_operator_c) -void *visit_expression_type_c::visit(CALCN_operator_c *symbol) { - if(il_default_variable_type == NULL) - STAGE3_ERROR(symbol, symbol, "CALCN: il_default_variable should not be NULL."); - if (!is_BOOL_type(il_default_variable_type)) - STAGE3_ERROR(symbol, symbol, "CALCN operator requires il_default_variable to be of type BOOL."); - return NULL; -} - -// SYM_REF0(RET_operator_c) -void *visit_expression_type_c::visit(RET_operator_c *symbol) { - return NULL; -} - -// SYM_REF0(RETC_operator_c) -void *visit_expression_type_c::visit(RETC_operator_c *symbol) { - if(il_default_variable_type == NULL) - STAGE3_ERROR(symbol, symbol, "RETC: il default variable should not be NULL."); - if (!is_BOOL_type(il_default_variable_type)) - STAGE3_ERROR(symbol, symbol, "RETC operator requires il_default_variable to be of type BOOL."); - return NULL; -} - -// SYM_REF0(RETCN_operator_c) -void *visit_expression_type_c::visit(RETCN_operator_c *symbol) { - if(il_default_variable_type == NULL) - STAGE3_ERROR(symbol, symbol, "RETCN: il_default_variable should not be NULL."); - if (!is_BOOL_type(il_default_variable_type)) - STAGE3_ERROR(symbol, symbol, "RETCN operator requires il_default_variable to be of type BOOL."); - return NULL; -} - -// SYM_REF0(JMP_operator_c) -void *visit_expression_type_c::visit(JMP_operator_c *symbol){ - return NULL; -} - -// SYM_REF0(JMPC_operator_c) -void *visit_expression_type_c::visit(JMPC_operator_c *symbol) { - if(il_default_variable_type == NULL) - STAGE3_ERROR(symbol, symbol, "JMPC: il default variable should not be NULL."); - if (!is_BOOL_type(il_default_variable_type)) - STAGE3_ERROR(symbol, symbol, "JMPC operator requires il_default_variable to be of type BOOL."); - return NULL; -} - -// SYM_REF0(JMPCN_operator_c) -void *visit_expression_type_c::visit(JMPCN_operator_c *symbol) { - if(il_default_variable_type == NULL) - STAGE3_ERROR(symbol, symbol, "JMPCN: il_default_variable should not be NULL."); - if (!is_BOOL_type(il_default_variable_type)) - STAGE3_ERROR(symbol, symbol, "JMPCN operator requires il_default_variable to be of type BOOL."); - return NULL; -} - -/* Symbol class handled together with function call checks */ -/* any_identifier ASSIGN */ -// SYM_REF1(il_assign_operator_c, variable_name) -// void *visit_expression_type_c::visit(il_assign_operator_c *symbol, variable_name); - -/* Symbol class handled together with function call checks */ -/*| [NOT] any_identifier SENDTO */ -// SYM_REF2(il_assign_out_operator_c, option, variable_name) -// void *visit_expression_type_c::visit(il_assign_operator_c *symbol, option, variable_name); - - - - - -/***************************************/ -/* B.3 - Language ST (Structured Text) */ -/***************************************/ -/***********************/ -/* B 3.1 - Expressions */ -/***********************/ - -void *visit_expression_type_c::visit(or_expression_c *symbol) { - symbol_c *left_type = base_type((symbol_c *)symbol->l_exp->accept(*this)); - symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this)); - return compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_BIT_compatible, symbol->l_exp, symbol->r_exp); -} - - -void *visit_expression_type_c::visit(xor_expression_c *symbol) { - symbol_c *left_type = base_type((symbol_c *)symbol->l_exp->accept(*this)); - symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this)); - return compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_BIT_compatible, symbol->l_exp, symbol->r_exp); -} - - -void *visit_expression_type_c::visit(and_expression_c *symbol) { - symbol_c *left_type = base_type((symbol_c *)symbol->l_exp->accept(*this)); - symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this)); - return compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_BIT_compatible, symbol->l_exp, symbol->r_exp); -} - - -void *visit_expression_type_c::visit(equ_expression_c *symbol) { - symbol_c *left_type = base_type((symbol_c *)symbol->l_exp->accept(*this)); - symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this)); - compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_ELEMENTARY_OR_ENUMERATED_compatible, symbol->l_exp, symbol->r_exp); - return &search_expression_type_c::bool_type_name; -} - - -void *visit_expression_type_c::visit(notequ_expression_c *symbol) { - symbol_c *left_type = base_type((symbol_c *)symbol->l_exp->accept(*this)); - symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this)); - compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_ELEMENTARY_OR_ENUMERATED_compatible, symbol->l_exp, symbol->r_exp); - return &search_expression_type_c::bool_type_name; -} - - -void *visit_expression_type_c::visit(lt_expression_c *symbol) { - symbol_c *left_type = base_type((symbol_c *)symbol->l_exp->accept(*this)); - symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this)); - compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_ELEMENTARY_compatible, symbol->l_exp, symbol->r_exp); - return &search_expression_type_c::bool_type_name; -} - - -void *visit_expression_type_c::visit(gt_expression_c *symbol) { - symbol_c *left_type = base_type((symbol_c *)symbol->l_exp->accept(*this)); - symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this)); - compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_ELEMENTARY_compatible, symbol->l_exp, symbol->r_exp); - return &search_expression_type_c::bool_type_name; -} - - -void *visit_expression_type_c::visit(le_expression_c *symbol) { - symbol_c *left_type = base_type((symbol_c *)symbol->l_exp->accept(*this)); - symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this)); - compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_ELEMENTARY_compatible, symbol->l_exp, symbol->r_exp); - return &search_expression_type_c::bool_type_name; -} - - -void *visit_expression_type_c::visit(ge_expression_c *symbol) { - symbol_c *left_type = base_type((symbol_c *)symbol->l_exp->accept(*this)); - symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this)); - compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_ELEMENTARY_compatible, symbol->l_exp, symbol->r_exp); - return &search_expression_type_c::bool_type_name; -} - - -void *visit_expression_type_c::visit(add_expression_c *symbol) { - symbol_c *left_type = base_type((symbol_c *)symbol->l_exp->accept(*this)); - symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this)); - -/* The following is already checked in compute_expression */ -/* - if (is_type(left_type, time_type_name_c) && is_type(right_type, time_type_name_c)) - return (void *)&time_type_name; -*/ - - if (is_type(left_type, tod_type_name_c) && is_type(right_type, time_type_name_c)) - return (void *)&tod_type_name; - if (is_type(left_type, safetod_type_name_c) && is_type(right_type, time_type_name_c)) - return (void *)&tod_type_name; - if (is_type(left_type, tod_type_name_c) && is_type(right_type, safetime_type_name_c)) - return (void *)&tod_type_name; - if (is_type(left_type, safetod_type_name_c) && is_type(right_type, safetime_type_name_c)) - return (void *)&safetod_type_name; - - if (is_type(left_type, dt_type_name_c) && is_type(right_type, time_type_name_c)) - return (void *)&dt_type_name; - if (is_type(left_type, safedt_type_name_c) && is_type(right_type, time_type_name_c)) - return (void *)&dt_type_name; - if (is_type(left_type, dt_type_name_c) && is_type(right_type, safetime_type_name_c)) - return (void *)&dt_type_name; - if (is_type(left_type, safedt_type_name_c) && is_type(right_type, safetime_type_name_c)) - return (void *)&safedt_type_name; - - return compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_MAGNITUDE_compatible, symbol->l_exp, symbol->r_exp); -} - - -void *visit_expression_type_c::visit(sub_expression_c *symbol) { - symbol_c *left_type = base_type((symbol_c *)symbol->l_exp->accept(*this)); - symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this)); - -/* The following is already checked in compute_expression */ -/* - if (is_type(left_type, time_type_name_c) && is_type(right_type, time_type_name_c)) - return (void *)&time_type_name; -*/ - - if (is_type(left_type, tod_type_name_c) && is_type(right_type, time_type_name_c)) - return (void *)&tod_type_name; - if (is_type(left_type, safetod_type_name_c) && is_type(right_type, time_type_name_c)) - return (void *)&tod_type_name; - if (is_type(left_type, tod_type_name_c) && is_type(right_type, safetime_type_name_c)) - return (void *)&tod_type_name; - if (is_type(left_type, safetod_type_name_c) && is_type(right_type, safetime_type_name_c)) - return (void *)&safetod_type_name; - - if (is_type(left_type, dt_type_name_c) && is_type(right_type, time_type_name_c)) - return (void *)&dt_type_name; - if (is_type(left_type, safedt_type_name_c) && is_type(right_type, time_type_name_c)) - return (void *)&dt_type_name; - if (is_type(left_type, dt_type_name_c) && is_type(right_type, safetime_type_name_c)) - return (void *)&dt_type_name; - if (is_type(left_type, safedt_type_name_c) && is_type(right_type, safetime_type_name_c)) - return (void *)&safedt_type_name; - - if (is_type(left_type, tod_type_name_c) && is_type(right_type, tod_type_name_c)) - return (void *)&time_type_name; - if (is_type(left_type, safetod_type_name_c) && is_type(right_type, tod_type_name_c)) - return (void *)&time_type_name; - if (is_type(left_type, tod_type_name_c) && is_type(right_type, safetod_type_name_c)) - return (void *)&time_type_name; - if (is_type(left_type, safetod_type_name_c) && is_type(right_type, safetod_type_name_c)) - return (void *)&safetime_type_name; - - if (is_type(left_type, date_type_name_c) && is_type(right_type, date_type_name_c)) - return (void *)&time_type_name; - if (is_type(left_type, safedate_type_name_c) && is_type(right_type, date_type_name_c)) - return (void *)&time_type_name; - if (is_type(left_type, date_type_name_c) && is_type(right_type, safedate_type_name_c)) - return (void *)&time_type_name; - if (is_type(left_type, safedate_type_name_c) && is_type(right_type, safedate_type_name_c)) - return (void *)&safetime_type_name; - - if (is_type(left_type, dt_type_name_c) && is_type(right_type, dt_type_name_c)) - return (void *)&time_type_name; - if (is_type(left_type, safedt_type_name_c) && is_type(right_type, dt_type_name_c)) - return (void *)&time_type_name; - if (is_type(left_type, dt_type_name_c) && is_type(right_type, safedt_type_name_c)) - return (void *)&time_type_name; - if (is_type(left_type, safedt_type_name_c) && is_type(right_type, safedt_type_name_c)) - return (void *)&safetime_type_name; - - return compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_MAGNITUDE_compatible, symbol->l_exp, symbol->r_exp); -} - - -void *visit_expression_type_c::visit(mul_expression_c *symbol) { - symbol_c *left_type = base_type((symbol_c *)symbol->l_exp->accept(*this)); - symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this)); - - if (is_type(left_type, time_type_name_c) && is_ANY_NUM_compatible(right_type)) - return (void *)&time_type_name; - if (is_type(left_type, safetime_type_name_c) && is_ANY_NUM_type(right_type)) - return (void *)&time_type_name; - if (is_type(left_type, safetime_type_name_c) && is_ANY_SAFENUM_type(right_type)) - return (void *)&safetime_type_name; - /* Since we have already checked for ANY_NUM_type and ANY_SAFENUM_type in the previous lines, - * this next line is really only to check for integers/reals of undefined type on 'right_type'... - */ - if (is_type(left_type, safetime_type_name_c) && is_ANY_NUM_compatible(right_type)) - return (void *)&safetime_type_name; - - return compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_NUM_compatible, symbol->l_exp, symbol->r_exp); -} - - -void *visit_expression_type_c::visit(div_expression_c *symbol) { - symbol_c *left_type = base_type((symbol_c *)symbol->l_exp->accept(*this)); - symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this)); - - if (is_type(left_type, time_type_name_c) && is_ANY_NUM_compatible(right_type)) - return (void *)&time_type_name; - if (is_type(left_type, safetime_type_name_c) && is_ANY_NUM_type(right_type)) - return (void *)&time_type_name; - if (is_type(left_type, safetime_type_name_c) && is_ANY_SAFENUM_type(right_type)) - return (void *)&safetime_type_name; - /* Since we have already checked for ANY_NUM_type and ANY_SAFENUM_type in the previous lines, - * this next line is really only to check for integers/reals of undefined type on 'right_type'... - */ - if (is_type(left_type, safetime_type_name_c) && is_ANY_NUM_compatible(right_type)) - return (void *)&safetime_type_name; - - return compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_NUM_compatible, symbol->l_exp, symbol->r_exp); -} - - -void *visit_expression_type_c::visit(mod_expression_c *symbol) { - symbol_c *left_type = base_type((symbol_c *)symbol->l_exp->accept(*this)); - symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this)); - return compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_INT_compatible, symbol->l_exp, symbol->r_exp); -} - - -void *visit_expression_type_c::visit(power_expression_c *symbol) { - symbol_c *left_type = base_type((symbol_c *)symbol->l_exp->accept(*this)); - symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this)); - if (!is_ANY_REAL_compatible(left_type)) - STAGE3_ERROR(symbol->l_exp, symbol->l_exp, "first operand of ** operator has invalid data type, should be of type ANY_REAL."); - if (!is_ANY_NUM_compatible(right_type)) - STAGE3_ERROR(symbol->r_exp, symbol->r_exp, "second operand of ** operator has invalid data type, should be of type ANY_NUM."); - - return (void *)left_type; -} - - -void *visit_expression_type_c::visit(neg_expression_c *symbol) { - symbol_c *exp_type = base_type((symbol_c *)symbol->exp->accept(*this)); - if (!is_ANY_MAGNITUDE_compatible(exp_type)) - STAGE3_ERROR(symbol, symbol, "operand of negate expression '-' has invalid data type, should be of type ANY_MAGNITUDE."); - - return exp_type; -} - - -void *visit_expression_type_c::visit(not_expression_c *symbol) { - symbol_c *type = base_type((symbol_c *)symbol->exp->accept(*this)); - return compute_expression(type, type, &visit_expression_type_c::is_ANY_BIT_compatible, NULL, symbol->exp); -} - - -void *visit_expression_type_c::visit(function_invocation_c *symbol) { - function_symtable_t::iterator lower = function_symtable.lower_bound(symbol->function_name); - function_symtable_t::iterator upper = function_symtable.upper_bound(symbol->function_name); - function_symtable_t::iterator current; - if (lower == function_symtable.end()) ERROR; - - symbol_c* return_data_type; - symbol_c* fdecl_return_type; - symbol_c* overloaded_data_type = NULL; - int extensible_param_count = -1; - symbol->called_function_declaration = NULL; - - function_symtable_t::iterator second = lower; - second++; - if (second == upper) { - /* call to a function that is not overloaded. */ - /* now check the semantics of the function call... */ - /* If the syntax parser is working correctly, exactly one of the - * following two symbols will be NULL, while the other is != NULL. - */ - function_declaration_c *f_decl = function_symtable.get_value(lower); - if (symbol-> formal_param_list != NULL) check_formal_call (symbol, f_decl); - if (symbol->nonformal_param_list != NULL) check_nonformal_call(symbol, f_decl); - /* Store the pointer to the declaration of the function being called. - * This data will be used by stage 4 to call the correct function. - * Mostly needed to disambiguate overloaded functions... - * See comments in absyntax.def for more details - */ - symbol->called_function_declaration = f_decl; - return base_type(f_decl->type_name); - } - - /* This is a call to an overloaded function... */ - if (debug) printf("visit_expression_type_c::visit(function_invocation_c *symbol): FOUND CALL TO OVERLOADED FUNCTION!!\n"); - for(current = lower; current != upper; current++) { - if (debug) printf("visit_expression_type_c::visit(function_invocation_c *symbol): FOUND CALL TO OVERLOADED FUNCTION!! iterating...\n"); - int error_count = 0; - function_declaration_c *f_decl = function_symtable.get_value(current); - if (symbol-> formal_param_list != NULL) check_formal_call (symbol, f_decl, &error_count); - if (symbol->nonformal_param_list != NULL) check_nonformal_call(symbol, f_decl, false, &error_count); - if (0 == error_count) { - - fdecl_return_type = base_type(f_decl->type_name); - - if (symbol->called_function_declaration == NULL) { - /* Store the pointer to the declaration of the function being called. - * This data will be used by stage 4 to call the correct function. - * Mostly needed to disambiguate overloaded functions... - * See comments in absyntax.def for more details - */ - symbol->called_function_declaration = f_decl; - extensible_param_count = symbol->extensible_param_count; - - /* determine the base data type returned by the function being called... */ - return_data_type = fdecl_return_type; - } - else if (typeid(*return_data_type) != typeid(*fdecl_return_type)){ - return_data_type = common_literal(return_data_type, fdecl_return_type); - overloaded_data_type = overloaded_return_type(return_data_type); - } - - if (NULL == return_data_type) ERROR; - } - } - - if (overloaded_data_type != NULL) { - for(current = lower; current != upper; current++) { - function_declaration_c *f_decl = function_symtable.get_value(current); - int error_count = 0; - if (symbol-> formal_param_list != NULL) check_formal_call (symbol, f_decl, &error_count); - if (symbol->nonformal_param_list != NULL) check_nonformal_call(symbol, f_decl, false, &error_count); - if (0 == error_count) { - - fdecl_return_type = base_type(f_decl->type_name); - - if (typeid(*overloaded_data_type) == typeid(*fdecl_return_type)){ - /* Store the pointer to the declaration of the function being called. - * This data will be used by stage 4 to call the correct function. - * Mostly needed to disambiguate overloaded functions... - * See comments in absyntax.def for more details - */ - symbol->called_function_declaration = f_decl; - extensible_param_count = symbol->extensible_param_count; - } - } - } - } - - if (return_data_type != NULL) { - symbol->extensible_param_count = extensible_param_count; - return return_data_type; - } - - /* No compatible function was found for this function call */ - STAGE3_ERROR(symbol, symbol, "Call to an overloaded function with invalid parameter type."); - return NULL; -} - -/********************/ -/* B 3.2 Statements */ -/********************/ -// SYM_LIST(statement_list_c) -/* The visitor of the base class search_visitor_c will handle calling each instruction in the list. - * We do not need to do anything here... - */ -// void *visit_expression_type_c::visit(statement_list_c *symbol) - - -/*********************************/ -/* B 3.2.1 Assignment Statements */ -/*********************************/ - -void *visit_expression_type_c::visit(assignment_statement_c *symbol) { - symbol_c *left_type = base_type((symbol_c *)symbol->l_exp->accept(*this)); - symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this)); - - if (debug) { - printf("visit_expression_type_c::visit(assignment_statement_c) called. Checking --->"); - symbolic_variable_c *hi = dynamic_cast(symbol->l_exp); - if (hi != NULL) { - identifier_c *hi1 = dynamic_cast(hi->var_name); - if (hi1 != NULL) printf("%s", hi1->value); - } - printf(" := "); - hex_integer_c *hi2 = dynamic_cast(symbol->r_exp); - if (hi2 != NULL) printf("%s", hi2->value); - printf("\n"); - } // if (debug) - - if (NULL == left_type) { - STAGE3_ERROR(symbol->l_exp, symbol->l_exp, "Could not determine data type of expression (undefined variable, constant, or structure element?).\n"); - } else if (NULL == right_type) { - STAGE3_ERROR(symbol->r_exp, symbol->r_exp, "Could not determine data type of expression (undefined variable, constant, or structure element?).\n"); - } else if (!is_valid_assignment(left_type, right_type)) - STAGE3_ERROR(symbol, symbol, "data type mismatch in assignment statement!\n"); - - return NULL; -} - - - -/*****************************************/ -/* B 3.2.2 Subprogram Control Statements */ -/*****************************************/ - -/* RETURN */ -// SYM_REF0(return_statement_c) - - -/* fb_name '(' [param_assignment_list] ')' */ -/* param_assignment_list -> may be NULL ! */ -// SYM_REF3(fb_invocation_c, fb_name, formal_param_list, nonformal_param_list) -void *visit_expression_type_c::visit(fb_invocation_c *symbol) { - symbol_c *fb_decl = search_varfb_instance_type->get_basetype_decl(symbol->fb_name); - /* The following should never occur. The function block must be defined, - * and the FB type being called MUST be in the symtable... - * This was all already checked at stage 2! - */ - if (NULL == fb_decl) ERROR; - - /* now check the semantics of the fb call... */ - /* If the syntax parser is working correctly, exactly one of the - * following two symbols will be NULL, while the other is != NULL. - */ - if (symbol-> formal_param_list != NULL) check_formal_call (symbol, fb_decl); - if (symbol->nonformal_param_list != NULL) check_nonformal_call(symbol, fb_decl); - - return NULL; -} - - -#if 0 -/* helper symbol for fb_invocation */ -/* param_assignment_list ',' param_assignment */ -SYM_LIST(param_assignment_list_c) - -/* variable_name ASSIGN expression */ -SYM_REF2(input_variable_param_assignment_c, variable_name, expression) - -/* [NOT] variable_name '=>' variable */ -SYM_REF3(output_variable_param_assignment_c, not_param, variable_name, variable) - -/* helper CLASS for output_variable_param_assignment */ -SYM_REF0(not_paramassign_c) -#endif - -/********************************/ -/* B 3.2.3 Selection Statements */ -/********************************/ - -/* IF expression THEN statement_list elseif_statement_list ELSE statement_list END_IF */ -// SYM_REF4(if_statement_c, expression, statement_list, elseif_statement_list, else_statement_list) -void *visit_expression_type_c::visit(if_statement_c *symbol) { - symbol_c *expr_type = base_type((symbol_c*)symbol->expression->accept(*this)); - if (!is_BOOL_type(expr_type)) STAGE3_ERROR(symbol->expression,symbol->expression,"IF conditional expression is not of boolean type."); - if (NULL != symbol->statement_list) - symbol->statement_list->accept(*this); - if (NULL != symbol->elseif_statement_list) - symbol->elseif_statement_list->accept(*this); - if (NULL != symbol->else_statement_list) - symbol->else_statement_list->accept(*this); - return NULL; -} - -/* helper symbol for if_statement */ -// SYM_LIST(elseif_statement_list_c) -// void *visit_expression_type_c::visit(elseif_statement_list_c *symbol) { } - -/* helper symbol for elseif_statement_list */ -/* ELSIF expression THEN statement_list */ -// SYM_REF2(elseif_statement_c, expression, statement_list) -void *visit_expression_type_c::visit(elseif_statement_c *symbol) { - symbol_c *elseif_expr_type = base_type((symbol_c*)symbol->expression->accept(*this)); - if(!is_BOOL_type(elseif_expr_type)) STAGE3_ERROR(symbol->expression,symbol->expression,"ELSIF conditional expression is not of boolean type."); - if (NULL != symbol->statement_list) - symbol->statement_list->accept(*this); - return NULL; -} - - -/* CASE expression OF case_element_list ELSE statement_list END_CASE */ -// SYM_REF3(case_statement_c, expression, case_element_list, statement_list) -void *visit_expression_type_c::visit(case_statement_c *symbol) { - case_expression_type = base_type((symbol_c*)symbol->expression->accept(*this)); - if (NULL != case_expression_type) { - if (NULL != symbol->case_element_list) - symbol->case_element_list->accept(*this); - } - if (NULL != symbol->statement_list) - symbol->statement_list->accept(*this); - return NULL; -} - -#if 0 -/* helper symbol for case_statement */ -// SYM_LIST(case_element_list_c) -// void *visit_expression_type_c::visit(case_element_list_c *symbol); - -/* case_list ':' statement_list */ -// SYM_REF2(case_element_c, case_list, statement_list) -void *visit_expression_type_c::visit(case_element_c *symbol); -#endif - -// SYM_LIST(case_list_c) -void *visit_expression_type_c::visit(case_list_c *symbol) { - symbol_c *element_type; - for(int i = 0; i < symbol->n; i++) { - element_type = (symbol_c *)symbol->elements[i]->accept(*this); - if (NULL == element_type) { - STAGE3_ERROR(symbol->elements[i], symbol->elements[i], "Case list element has undefined data type."); - } else { - element_type = base_type(element_type); - if (NULL != element_type){ - /* The CASE value is only used for comparison (and not assingment), so we only check for compatibility! */ - if (!is_compatible_type(case_expression_type, element_type)) - STAGE3_ERROR(symbol->elements[i], symbol->elements[i], "Invalid data type of case list element."); - } - } - } - return NULL; -} - -/********************************/ -/* B 3.2.4 Iteration Statements */ -/********************************/ - -/* FOR control_variable ASSIGN expression TO expression [BY expression] DO statement_list END_FOR */ -// SYM_REF5(for_statement_c, control_variable, beg_expression, end_expression, by_expression, statement_list) -void *visit_expression_type_c::visit(for_statement_c *symbol) { - symbol_c *var_type = (symbol_c*)symbol->control_variable->accept(*this); - if (NULL == var_type) ERROR; - var_type = base_type(var_type); - if (NULL == var_type) ERROR; - // ASSIGN - symbol_c *beg_expr_type = base_type((symbol_c*)symbol->beg_expression->accept(*this)); - if (NULL != beg_expr_type) { - /* The BEG value is assigned to the variable, so we check for assignment validity! */ - if(!is_valid_assignment(var_type, beg_expr_type)) - STAGE3_ERROR(symbol->beg_expression, symbol->beg_expression, "Data type mismatch between control variable and initial value."); - } - // TO - symbol_c *end_expr_type = base_type((symbol_c*)symbol->end_expression->accept(*this)); - if (NULL != end_expr_type) { - /* The TO value is only used for comparison, so we only check for compatibility! */ - if(!is_compatible_type(var_type, end_expr_type)) - STAGE3_ERROR(symbol->end_expression, symbol->end_expression, "Data type mismatch between control variable and final value."); - } - // BY - if(symbol->by_expression != NULL) { - symbol_c *by_expr_type = base_type((symbol_c*)symbol->by_expression->accept(*this)); - if (NULL != end_expr_type) { - /* The BY value is used in an expression (add, sub, ...), so we only check for compatibility! */ - if(!is_compatible_type(var_type, by_expr_type)) - STAGE3_ERROR(symbol->by_expression, symbol->by_expression, "Data type mismatch between control variable and BY value."); - } - } - // DO - if (NULL != symbol->statement_list) - symbol->statement_list->accept(*this); - return NULL; -} - - -/* WHILE expression DO statement_list END_WHILE */ -// SYM_REF2(while_statement_c, expression, statement_list) -void *visit_expression_type_c::visit(while_statement_c *symbol) { - symbol_c *expr_type = base_type((symbol_c*)symbol->expression->accept(*this)); - if (NULL != expr_type) { - if(!is_BOOL_type(expr_type)) - STAGE3_ERROR(symbol->expression,symbol->expression,"WHILE conditional expression is not of boolean type."); - } - - if (NULL != symbol->statement_list) - symbol->statement_list->accept(*this); - return NULL; -} - -/* REPEAT statement_list UNTIL expression END_REPEAT */ -// SYM_REF2(repeat_statement_c, statement_list, expression) -void *visit_expression_type_c::visit(repeat_statement_c *symbol) { - if (NULL != symbol->statement_list) - symbol->statement_list->accept(*this); - - symbol_c *expr_type = base_type((symbol_c*)symbol->expression->accept(*this)); - if (NULL != expr_type) { - if(!is_BOOL_type(expr_type)) - STAGE3_ERROR(symbol->expression,symbol->expression,"REPEAT conditional expression is not of boolean type."); - } - return NULL; -} - -/* EXIT */ -// SYM_REF0(exit_statement_c) - - - diff -r 34a5571c859c -r 0bb88139e471 stage3/visit_expression_type.hh --- a/stage3/visit_expression_type.hh Thu Mar 22 00:22:48 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,393 +0,0 @@ -/* - * matiec - a compiler for the programming languages defined in IEC 61131-3 - * - * Copyright (C) 2009-2011 Mario de Sousa (msousa@fe.up.pt) - * Copyright (C) 2007-2011 Laurent Bessard and Edouard Tisserant - * - * 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 3 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, see . - * - * - * This code is made available on the understanding that it will not be - * used in safety-critical situations without a full and competent review. - */ - -/* - * An IEC 61131-3 compiler. - * - * Based on the - * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) - * - */ - -/* Verify whether the semantic rules of data type compatibility are being followed. - * - * For example: - */ - -#include "../absyntax_utils/absyntax_utils.hh" - -class visit_expression_type_c: public search_constant_type_c { - - private: - search_varfb_instance_type_c *search_varfb_instance_type; - search_base_type_c search_base_type; - - /* When calling a function block, we must first find it's type, - * by searching through the declarations of the variables currently - * in scope. - * This class does just that... - * A new bject instance is instantiated whenever we start checking semantics - * for a function block type declaration, or a program declaration. - * This object instance will then later be called while the - * function block's or the program's body is being handled. - * - * Note that functions cannot contain calls to function blocks, - * so we do not create an object instance when handling - * a function declaration. - */ -// search_var_instance_decl_c *search_var_instance_decl; - - /* This variable was created to pass information from - * visit_expression_type_c::visit(case_statement_c *symbol) function to - * visit_expression_type_c::visit(case_list_c *symbol) function. - */ - symbol_c *case_expression_type; - - /* In IL code, once we find a type mismatch error, it is best to - * ignore any further errors until the end of the logicl operation, - * i.e. until the next LD. - * However, we cannot clear the il_error flag on all LD operations, - * as these may also be used within parenthesis. LD operations - * within parenthesis may not clear the error flag. - * We therefore need a counter to know how deep inside a parenthesis - * structure we are. - */ - int il_parenthesis_level; - bool il_error; - bool error_found; - - /* the current data type of the data stored in the IL stack, i.e. the default variable */ - symbol_c *il_default_variable_type; - /* the current IL operand being analysed - its symbol and its data type */ - symbol_c *il_operand_type; - symbol_c *il_operand; - - - public: - visit_expression_type_c(symbol_c *ignore); - virtual ~visit_expression_type_c(void); - - bool get_error_found(void); - - typedef struct { - symbol_c *value; - symbol_c *type; - } value_and_type_t; - - /* A helper function... */ - bool is_ANY_ELEMENTARY_type (symbol_c *type_symbol); - bool is_ANY_SAFEELEMENTARY_type (symbol_c *type_symbol); - bool is_ANY_ELEMENTARY_compatible (symbol_c *type_symbol); - - bool is_ANY_MAGNITUDE_type (symbol_c *type_symbol); - bool is_ANY_SAFEMAGNITUDE_type (symbol_c *type_symbol); - bool is_ANY_MAGNITUDE_compatible (symbol_c *type_symbol); - - bool is_ANY_DATE_type (symbol_c *type_symbol); - bool is_ANY_SAFEDATE_type (symbol_c *type_symbol); - bool is_ANY_DATE_compatible (symbol_c *type_symbol); - - bool is_ANY_STRING_type (symbol_c *type_symbol); - bool is_ANY_SAFESTRING_type (symbol_c *type_symbol); - bool is_ANY_STRING_compatible (symbol_c *type_symbol); - - bool is_ANY_INT_type (symbol_c *type_symbol); - bool is_ANY_SAFEINT_type (symbol_c *type_symbol); - bool is_ANY_INT_compatible (symbol_c *type_symbol); - - bool is_ANY_REAL_type (symbol_c *type_symbol); - bool is_ANY_SAFEREAL_type (symbol_c *type_symbol); - bool is_ANY_REAL_compatible (symbol_c *type_symbol); - - bool is_ANY_NUM_type (symbol_c *type_symbol); - bool is_ANY_SAFENUM_type (symbol_c *type_symbol); - bool is_ANY_NUM_compatible (symbol_c *type_symbol); - - bool is_ANY_BIT_type (symbol_c *type_symbol); - bool is_ANY_SAFEBIT_type (symbol_c *type_symbol); - bool is_ANY_BIT_compatible (symbol_c *type_symbol); - - bool is_BOOL_type (symbol_c *type_symbol); - bool is_SAFEBOOL_type (symbol_c *type_symbol); - bool is_ANY_BOOL_compatible (symbol_c *type_symbol); - - bool is_nonneg_literal_integer_type (symbol_c *type_symbol); - bool is_literal_integer_type (symbol_c *type_symbol); - bool is_literal_real_type (symbol_c *type_symbol); - bool is_literal_bool_type (symbol_c *type_symbol); - - bool is_ANY_ELEMENTARY_OR_ENUMERATED_compatible (symbol_c *type_symbol); - - /* Determine the common data type between two data types. - * If no common data type found, return NULL. - * - * If data types are identical, return the first (any would do...). - * If any of the datat types is a literal, we confirm that - * the literal uses less bits than the fixed size data type. - * e.g. BYTE and 1024 returns NULL - * BYTE and 255 returns BYTE - * - * If two literals, then return the literal that requires more bits... - */ - symbol_c *common_type__(symbol_c *first_type, symbol_c *second_type); - /* Determine the common data type between two data types. - * Unlike the common_type__() function, we stop the compiler with an ERROR - * if no common data type is found. - */ - symbol_c *common_type(symbol_c *first_type, symbol_c *second_type); - - symbol_c *common_literal(symbol_c *first_type, symbol_c *second_type); - symbol_c *overloaded_return_type(symbol_c *type); - -/* Return TRUE if the second (value) data type may be assigned to a variable of the first (variable) data type - * such as: - * var_type value_type - * BOOL BYTE#7 -> returns false - * INT INT#7 -> returns true - * INT 7 -> returns true - * REAL 7.89 -> returns true - * REAL 7 -> returns true - * INT 7.89 -> returns false - * SAFEBOOL BOOL#1 -> returns false !!! - * etc... - * - * NOTE: It is assumed that the var_type is the data type of an lvalue - */ - bool is_valid_assignment(symbol_c *var_type, symbol_c *value_type); - -/* Return TRUE if there is a common data type, otherwise return FALSE - * i.e., return TRUE if both data types may be used simultaneously in an expression - * such as: - * BOOL#0 AND BYTE#7 -> returns false - * 0 AND BYTE#7 -> returns true - * INT#10 AND INT#7 -> returns true - * INT#10 AND 7 -> returns true - * REAL#34.3 AND 7.89 -> returns true - * REAL#34.3 AND 7 -> returns true - * INT#10 AND 7.89 -> returns false - * SAFEBOOL#0 AND BOOL#1 -> returns true !!! - * etc... - */ - bool is_compatible_type(symbol_c *first_type, symbol_c *second_type); - - /* check semantics of FB call in the IL language using input operators */ - /* e.g. CU, CLK, IN, PT, SR, ... */ - void check_il_fbcall(symbol_c *symbol, const char *input_operator); - /* check the semantics of a FB or Function non-formal call */ - /* e.g. foo(1, 2, 3, 4); */ - /* If error_count pointer is NULL, print out error messages. - * If error_count pointer is != NULL, do not print out error messages, but tally up - * how many errors were found. - */ - void check_nonformal_call(symbol_c *f_call, symbol_c *f_decl, bool use_il_defvar = false, int *error_count = NULL); - /* check the semantics of a FB or Function formal call */ - /* e.g. foo(IN1 := 1, OUT1 =>x, EN := true); */ - /* If error_count pointer is NULL, print out error messages. - * If error_count pointer is != NULL, do not print out error messages, but tally up - * how many errors were found. - */ - void check_formal_call(symbol_c *f_call, symbol_c *f_decl, int *error_count = NULL); - - - void *compute_standard_function_default(function_invocation_c *st_symbol, il_formal_funct_call_c *il_symbol); - void *compute_standard_function_il(il_function_call_c *symbol, symbol_c *param_data_type); - - - /* A helper function... */ - typedef bool (visit_expression_type_c::*is_data_type_t)(symbol_c *type_symbol); /* a pointer to a function! */ -// symbol_c *compute_boolean_expression(symbol_c *left_exp, symbol_c *right_exp, is_data_type_t is_data_type); -// symbol_c *compute_numeric_expression(symbol_c *left_exp, symbol_c *right_exp, is_data_type_t is_data_type); -// symbol_c *compute_expression(symbol_c *left_exp, symbol_c *right_exp, is_data_type_t is_data_type); - symbol_c *compute_expression(symbol_c *left_type, symbol_c *right_type, is_data_type_t is_data_type, - symbol_c *left_expr, symbol_c *right_expr); - - - /* a helper function... */ - symbol_c *base_type(symbol_c *symbol); - - /* a helper function... */ - void *verify_null(symbol_c *symbol); - - /********************************/ - /* B 1.3.3 - Derived data types */ - /********************************/ - void *visit(data_type_declaration_c *symbol); - - /*********************/ - /* B 1.4 - Variables */ - /*********************/ - void *visit(symbolic_variable_c *symbol); - - /********************************************/ - /* B 1.4.1 - Directly Represented Variables */ - /********************************************/ - void *visit(direct_variable_c *symbol); - - /*************************************/ - /* B 1.4.2 - Multi-element variables */ - /*************************************/ - - void *visit(array_variable_c *symbol); - void *visit(structured_variable_c *symbol); - - /********************************/ - /* B 1.7 Configuration elements */ - /********************************/ - void *visit(configuration_declaration_c *symbol); - -/****************************************/ - /* B.2 - Language IL (Instruction List) */ - /****************************************/ - /***********************************/ - /* B 2.1 Instructions and Operands */ - /***********************************/ - // void *visit(instruction_list_c *symbol); - void *visit(il_simple_operation_c *symbol); - void *visit(il_function_call_c *symbol); - void *visit(il_expression_c *symbol); -// void *visit(il_jump_operation_c *symbol); - void *visit(il_fb_call_c *symbol); - void *visit(il_formal_funct_call_c *symbol); - /* - void *visit(il_operand_list_c *symbol); - void *visit(simple_instr_list_c *symbol); - void *visit(il_param_list_c *symbol); - void *visit(il_param_assignment_c *symbol); - void *visit(il_param_out_assignment_c *symbol); - */ - - /*******************/ - /* B 2.2 Operators */ - /*******************/ - void *visit(LD_operator_c *symbol); - void *visit(LDN_operator_c *symbol); - void *visit(ST_operator_c *symbol); - void *visit(STN_operator_c *symbol); - void *visit(NOT_operator_c *symbol); - void *visit(S_operator_c *symbol); - void *visit(R_operator_c *symbol); - void *visit(S1_operator_c *symbol); - void *visit(R1_operator_c *symbol); - void *visit(CLK_operator_c *symbol); - void *visit(CU_operator_c *symbol); - void *visit(CD_operator_c *symbol); - void *visit(PV_operator_c *symbol); - void *visit(IN_operator_c *symbol); - void *visit(PT_operator_c *symbol); - void *visit(AND_operator_c *symbol); - void *visit(OR_operator_c *symbol); - void *visit(XOR_operator_c *symbol); - void *visit(ANDN_operator_c *symbol); - void *visit(ORN_operator_c *symbol); - void *visit(XORN_operator_c *symbol); - void *visit(ADD_operator_c *symbol); - void *visit(SUB_operator_c *symbol); - void *visit(MUL_operator_c *symbol); - void *visit(DIV_operator_c *symbol); - void *visit(MOD_operator_c *symbol); - void *visit(GT_operator_c *symbol); - void *visit(GE_operator_c *symbol); - void *visit(EQ_operator_c *symbol); - void *visit(LT_operator_c *symbol); - void *visit(LE_operator_c *symbol); - void *visit(NE_operator_c *symbol); - void *visit(CAL_operator_c *symbol); - void *visit(CALC_operator_c *symbol); - void *visit(CALCN_operator_c *symbol); - void *visit(RET_operator_c *symbol); - void *visit(RETC_operator_c *symbol); - void *visit(RETCN_operator_c *symbol); - void *visit(JMP_operator_c *symbol); - void *visit(JMPC_operator_c *symbol); - void *visit(JMPCN_operator_c *symbol); - /* Symbol class handled together with function call checks */ - // void *visit(il_assign_operator_c *symbol, variable_name); - /* Symbol class handled together with function call checks */ - // void *visit(il_assign_operator_c *symbol, option, variable_name); - - - - /***************************************/ - /* B.3 - Language ST (Structured Text) */ - /***************************************/ - /***********************/ - /* B 3.1 - Expressions */ - /***********************/ - void *visit(or_expression_c *symbol); - void *visit(xor_expression_c *symbol); - void *visit(and_expression_c *symbol); - void *visit(equ_expression_c *symbol); - void *visit(notequ_expression_c *symbol); - void *visit(lt_expression_c *symbol); - void *visit(gt_expression_c *symbol); - void *visit(le_expression_c *symbol); - void *visit(ge_expression_c *symbol); - void *visit(add_expression_c *symbol); - void *visit(sub_expression_c *symbol); - void *visit(mul_expression_c *symbol); - void *visit(div_expression_c *symbol); - void *visit(mod_expression_c *symbol); - void *visit(power_expression_c *symbol); - void *visit(neg_expression_c *symbol); - void *visit(not_expression_c *symbol); - void *visit(function_invocation_c *symbol); - - /*********************************/ - /* B 3.2.1 Assignment Statements */ - /*********************************/ - void *visit(assignment_statement_c *symbol); - - /*****************************************/ - /* B 3.2.2 Subprogram Control Statements */ - /*****************************************/ - void *visit(fb_invocation_c *symbol); - - /********************************/ - /* B 3.2.3 Selection Statements */ - /********************************/ - - void *visit(if_statement_c *symbol); -// void *visit(elseif_statement_list_c *symbol); - void *visit(elseif_statement_c *symbol); - void *visit(case_statement_c *symbol); -// void *visit(case_element_list_c *symbol); -// void *visit(case_element_c *symbol); - void *visit(case_list_c *symbol); - - /********************************/ - /* B 3.2.4 Iteration Statements */ - /********************************/ - - void *visit(for_statement_c *symbol); - void *visit(while_statement_c *symbol); - void *visit(repeat_statement_c *symbol); - - -//TODO: delete this functions. Why are they needed? -void *visit(program_declaration_c *symbol); -void *visit(function_declaration_c *symbol); -void *visit(function_block_declaration_c *symbol); - -}; // visit_expression_type_c - diff -r 34a5571c859c -r 0bb88139e471 stage4/generate_c/generate_c.cc --- a/stage4/generate_c/generate_c.cc Thu Mar 22 00:22:48 2012 +0100 +++ b/stage4/generate_c/generate_c.cc Sat Mar 31 21:46:37 2012 +0100 @@ -197,10 +197,9 @@ } public: - print_function_parameter_data_types_c(stage4out_c *s4o_ptr): - generate_c_base_c(s4o_ptr) { - current_type = NULL; - } + print_function_parameter_data_types_c(stage4out_c *s4o_ptr): + generate_c_base_c(s4o_ptr) + {current_type = NULL;} /**************************************/ /* B.1.5 - Program organization units */ @@ -211,8 +210,7 @@ /* FUNCTION derived_function_name ':' elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION */ /* | FUNCTION derived_function_name ':' derived_type_name io_OR_function_var_declarations_list function_body END_FUNCTION */ void *visit(function_declaration_c *symbol) { - /* return type */ - symbol->type_name->accept(*this); + symbol->type_name->accept(*this); /* return type */ symbol->var_declarations_list->accept(*this); return NULL; } @@ -2226,10 +2224,10 @@ if (var_decl == NULL) ERROR; else - vartype = search_config_instance->get_vartype(); + vartype = search_config_instance->get_vartype(current_var_reference); } else - vartype = search_resource_instance->get_vartype(); + vartype = search_resource_instance->get_vartype(current_var_reference); s4o.print(s4o.indent_spaces + "{extern "); var_decl->accept(*this); @@ -2261,10 +2259,10 @@ if (var_decl == NULL) ERROR; else - vartype = search_config_instance->get_vartype(); + vartype = search_config_instance->get_vartype(current_var_reference); } else - vartype = search_resource_instance->get_vartype(); + vartype = search_resource_instance->get_vartype(current_var_reference); s4o.print(s4o.indent_spaces + "{extern "); var_decl->accept(*this); diff -r 34a5571c859c -r 0bb88139e471 stage4/generate_c/generate_c_il.cc --- a/stage4/generate_c/generate_c_il.cc Thu Mar 22 00:22:48 2012 +0100 +++ b/stage4/generate_c/generate_c_il.cc Sat Mar 31 21:46:37 2012 +0100 @@ -1562,6 +1562,12 @@ return NULL; } +// SYM_REF1(il_simple_instruction_c, il_simple_instruction, symbol_c *prev_il_instruction;) +void *visit(il_simple_instruction_c *symbol) { + return symbol->il_simple_instruction->accept(*this); +} + + /* | il_initial_param_list il_param_instruction */ // SYM_LIST(il_param_list_c) void *visit(il_param_list_c *symbol) {ERROR; return NULL;} // should never get called! @@ -1640,6 +1646,12 @@ } void *visit(NOT_operator_c *symbol) { + /* NOTE: the standard allows syntax in which the NOT operator is followed by an optional + * NOT [] + * However, it does not define the semantic of the NOT operation when the is specified. + * We therefore consider it an error if an il_operand is specified! + * The error is caught in stage 3! + */ if ((NULL != this->current_operand) || (NULL != this->current_operand_type)) ERROR; XXX_operator(&(this->default_variable_name), search_expression_type->is_bool_type(this->default_variable_name.current_type)?" = !":" = ~", diff -r 34a5571c859c -r 0bb88139e471 stage4/generate_c/generate_c_inlinefcall.cc --- a/stage4/generate_c/generate_c_inlinefcall.cc Thu Mar 22 00:22:48 2012 +0100 +++ b/stage4/generate_c/generate_c_inlinefcall.cc Sat Mar 31 21:46:37 2012 +0100 @@ -826,6 +826,11 @@ this->default_variable_back_name.current_type = this->default_variable_name.current_type; return NULL; } + + // SYM_REF1(il_simple_instruction_c, il_simple_instruction, symbol_c *prev_il_instruction;) + void *visit(il_simple_instruction_c *symbol) { + return symbol->il_simple_instruction->accept(*this); + } void *visit(LD_operator_c *symbol) { /* the data type resulting from this operation... */ diff -r 34a5571c859c -r 0bb88139e471 stage4/generate_c/generate_c_sfc.cc --- a/stage4/generate_c/generate_c_sfc.cc Thu Mar 22 00:22:48 2012 +0100 +++ b/stage4/generate_c/generate_c_sfc.cc Sat Mar 31 21:46:37 2012 +0100 @@ -844,7 +844,7 @@ for(pt = variable_list.begin(); pt != variable_list.end(); pt++) { symbol_c *var_decl = search_var_instance_decl->get_decl(pt->symbol); if (var_decl != NULL) { - unsigned int vartype = search_var_instance_decl->get_vartype(); + unsigned int vartype = search_var_instance_decl->get_vartype(pt->symbol); s4o.print(s4o.indent_spaces); if (vartype == search_var_instance_decl_c::external_vt) diff -r 34a5571c859c -r 0bb88139e471 stage4/generate_c/generate_c_st.cc --- a/stage4/generate_c/generate_c_st.cc Thu Mar 22 00:22:48 2012 +0100 +++ b/stage4/generate_c/generate_c_st.cc Sat Mar 31 21:46:37 2012 +0100 @@ -347,7 +347,7 @@ case complextype_suffix_vg: symbol->subscripted_variable->accept(*this); - current_array_type = search_varfb_instance_type->get_type_id(symbol->subscripted_variable); + current_array_type = search_varfb_instance_type->get_basetype_decl(symbol->subscripted_variable); if (current_array_type == NULL) ERROR; s4o.print(".table"); @@ -361,7 +361,7 @@ if (this->is_variable_prefix_null()) { symbol->subscripted_variable->accept(*this); - current_array_type = search_varfb_instance_type->get_type_id(symbol->subscripted_variable); + current_array_type = search_varfb_instance_type->get_basetype_decl(symbol->subscripted_variable); if (current_array_type == NULL) ERROR; s4o.print(".table"); diff -r 34a5571c859c -r 0bb88139e471 stage4/generate_iec/generate_iec.cc --- a/stage4/generate_iec/generate_iec.cc Thu Mar 22 00:22:48 2012 +0100 +++ b/stage4/generate_iec/generate_iec.cc Sat Mar 31 21:46:37 2012 +0100 @@ -58,6 +58,10 @@ +#define ERROR error_exit(__FILE__,__LINE__) +/* function defined in main.cc */ +extern void error_exit(const char *file_name, int line_no); + @@ -153,6 +157,13 @@ #endif +/* A class used to identify an entry (literal, variable, etc...) in the abstract syntax tree with an invalid data type */ +/* This is only used from stage3 onwards. Stages 1 and 2 will never create any instances of invalid_type_name_c */ +// SYM_REF0(invalid_type_name_c) +void *visit(invalid_type_name_c *symbol) { + ERROR; + return NULL; +} /******************/ @@ -1670,6 +1681,17 @@ return print_list(symbol, s4o.indent_spaces, "\n" + s4o.indent_spaces, "\n"); } + +/* il_simple_instruction: + * il_simple_operation eol_list + * | il_expression eol_list + * | il_formal_funct_call eol_list + */ +void *visit(il_simple_instruction_c *symbol) { + return symbol->il_simple_instruction->accept(*this); +} + + /* | il_initial_param_list il_param_instruction */ void *visit(il_param_list_c *symbol) { // return print_list(symbol);