merging with Lauren't changeset.
--- 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( \
--- 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(<value>) - 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 <symbol_c *> 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 <symbol_c *> 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 <symbol_c *> 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 <symbol_c *> 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 <symbol_c *> 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 */
--- 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 <stdio.h> // required for NULL
+#include <vector>
/* 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 <symbol_c *> 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);
};
--- 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; \
--- 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 \
--- 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@
--- 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 */
/*********************/
--- 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"
/***********************************************************************/
/***********************************************************************/
--- 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 <param_name>... */
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<identifier_c *>(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);
}
--- 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 <param_name>... */
+ 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 <param_name>... */
- 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 */
--- 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<function_block_declaration_c *>(pou_decl);
program_declaration_c * p_decl = dynamic_cast<program_declaration_c *>(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<identifier_c *>((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;
}
--- 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.
--- 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 <stdint.h> // get definition of uint64_t and UINT64_MAX
+#include <errno.h>
#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 ! */
--- 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 */
--- 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
--- 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");
--- 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 */
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * 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;
+}
+
+
+
+
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * 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
+
+
+
+
+
+
+
+
--- 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 */
/***************************/
--- 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:
--- 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;
+}
--- 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 */
/**************************************/
--- 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;
--- 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
--- 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 */
--- 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)\
--- 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)
--- 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;}
--- 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...
--- 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
--- 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 $@ $<
--- /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."
+
+
+
+
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * 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 <vector>
+// #include <algorithm>
+
+
+
+
+
+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 <symbol_c *> 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<symbol_c *>::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;
+}
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * 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 <typeinfo>
+
+
+
+
+
+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 <symbol_c *> &candidate_datatypes;
+ std::vector <symbol_c *> &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 <symbol_c *> 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_ */
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * 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 <typeinfo>
+#include <list>
+#include <string>
+#include <string.h>
+#include <strings.h>
+
+/* 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 <symbol_c *>&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 <symbol_c *> &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 <symbol_c *> *candidate_datatypes,
+ std::vector <symbol_c *> *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 <il_operand>
+ * NOT [<il_operand>]
+ * However, it does not define the semantic of the NOT operation when the <il_operand> 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;
+}
+
+
+
+
+
+
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * 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
+
+
+
+
+
+
+
+
+
+
+
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * 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);
+
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * 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
+
+
+
+
+
+
+
+
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * 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 <typeinfo>
+#include <list>
+#include <string>
+#include <string.h>
+#include <strings.h>
+
+
+/* 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 <symbol_c *> 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 <symbol_c *> &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 <il_operand>
+ * NOT [<il_operand>]
+ * However, it does not define the semantic of the NOT operation when the <il_operand> 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 <symbol_c *> 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;
+}
+
+
+
+
+
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * 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 <symbol_c *> *prev_il_instructions;
+ std::vector <symbol_c *> *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
+
+
+
+
+
+
+
+
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * 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 <typeinfo>
+#include <list>
+#include <string>
+#include <string.h>
+#include <strings.h>
+
+
+
+
+
+
+#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 <symbol_c *> &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<il_instruction_c *>(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 <symbol_c *> 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 <il_operand>
+ * NOT [<il_operand>]
+ * However, it does not define the semantic of the NOT operation when the <il_operand> 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 <symbol_c *> 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 <symbol_c *> 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;
+}
+
+
+
+
+
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * 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
+
+
+
+
+
+
+
--- 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);
}
--- 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 <stdio.h> /* required for NULL */
-#include <string>
-#include <iostream>
-#include <sstream>
-#include <typeinfo>
-#include <list>
-#include <strings.h>
-
#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);
+
--- 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 <http://www.gnu.org/licenses/>.
- *
- *
- * 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 <typeinfo>
-#include <list>
-#include <string>
-#include <string.h>
-#include <strings.h>
-
-
-#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<il_function_call_c *>(f_call);
- function_invocation_c *function_invocation = dynamic_cast<function_invocation_c *>(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<il_formal_funct_call_c *>(f_call);
- function_invocation_c *function_invocation = dynamic_cast<function_invocation_c *>(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<function_block_declaration_c *>(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<symbolic_variable_c *>(symbol->l_exp);
- if (hi != NULL) {
- identifier_c *hi1 = dynamic_cast<identifier_c *>(hi->var_name);
- if (hi1 != NULL) printf("%s", hi1->value);
- }
- printf(" := ");
- hex_integer_c *hi2 = dynamic_cast<hex_integer_c *>(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)
-
-
-
--- 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 <http://www.gnu.org/licenses/>.
- *
- *
- * 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
-
--- 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);
--- 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 <il_operand>
+ * NOT [<il_operand>]
+ * However, it does not define the semantic of the NOT operation when the <il_operand> 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)?" = !":" = ~",
--- 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... */
--- 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)
--- 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");
--- 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);