--- a/Makefile Wed Sep 02 13:39:05 2009 +0200
+++ b/Makefile Wed Sep 02 14:05:27 2009 +0200
@@ -30,7 +30,8 @@
LIBS = absyntax/absyntax.o absyntax/visitor.o
LIBS += stage1_2/stage1_2.o stage1_2/iec.y.o stage1_2/iec.flex.o
-
+LIBS += stage3/stage3.o
+LIBS += stage3/visit_expression_type.o
LIBS += absyntax_utils/absyntax_utils.o
LIBS += absyntax_utils/search_expression_type.o
LIBS += absyntax_utils/decompose_var_instance_name.o
@@ -45,6 +46,8 @@
LIBS += absyntax_utils/search_var_instance_decl.o
LIBS += absyntax_utils/spec_init_separator.o
LIBS += absyntax_utils/type_initial_value.o
+LIBS += absyntax_utils/add_en_eno_param_decl.o
+LIBS += absyntax_utils/get_sizeof_datatype.o
LIBS += absyntax_utils/get_function_type.o
@@ -69,4 +72,3 @@
-
--- a/absyntax/absyntax.def Wed Sep 02 13:39:05 2009 +0200
+++ b/absyntax/absyntax.def Wed Sep 02 14:05:27 2009 +0200
@@ -84,8 +84,14 @@
/* EN/ENO */
+/* NOTE we store 'EN' and 'ENO' tokens in an identifier_c
+ * as they may be used as variables, and it is much easier
+ * to handle them (fewer special cases) if we do it that way...
+ */
+/*
SYM_REF0(en_param_c)
SYM_REF0(eno_param_c)
+*/
/***************************/
/* 2.1.6 - Pragmas */
@@ -132,7 +138,9 @@
SYM_REF1(neg_literal_c, exp)
+/* Not required:
SYM_REF2(numeric_literal_c, type, value)
+*/
SYM_REF2(integer_literal_c, type, value)
SYM_REF2(real_literal_c, type, value)
SYM_REF2(bit_string_literal_c, type, value)
@@ -206,8 +214,11 @@
SYM_REF0(lword_type_name_c)
SYM_REF0(string_type_name_c)
SYM_REF0(wstring_type_name_c)
+
+/*
SYM_REF0(constant_int_type_name_c)
SYM_REF0(constant_real_type_name_c)
+*/
/********************************/
@@ -403,16 +414,42 @@
SYM_REF0(non_retain_option_c)
/* option -> the RETAIN/NON_RETAIN/<NULL> directive... */
-SYM_REF2(input_declarations_c, option, input_declaration_list)
+/* NOTE: We need to implicitly define the EN and ENO function and FB parameters when the user
+ * does not do it explicitly in the IEC 61131-3 source code.
+ * To be able to distinguish later on between implictly and explicitly defined
+ * variables, we use the 'method' flag that allows us to remember
+ * whether this declaration was in the original source code (method -> implicit_definition_c)
+ * or not (method -> explicit_definition_c).
+ */
+SYM_REF3(input_declarations_c, option, input_declaration_list, method)
/* helper symbol for input_declarations */
SYM_LIST(input_declaration_list_c)
+/* NOTE: The formal definition of the standard is erroneous, as it simply does not
+ * consider the EN and ENO keywords!
+ * The semantic description of the languages clearly states that these may be
+ * used in several ways. One of them is to declare an EN input parameter, or
+ * an ENO output parameter.
+ * We have added the 'en_param_declaration_c' and 'eno_param_declaration_c'
+ * to cover for this.
+ *
+ * We could have re-used the standard class used for all other input variables (with
+ * an identifier set to 'EN' or 'ENO') however we may sometimes need to add this
+ * declaration implicitly (if the user does not include it in the source
+ * code himself), and it is good to know whether it was added implicitly or not.
+ * So we create a new class that has a 'method' flag that allows us to remember
+ * whether this declaration was in the original source code (method -> implicit_definition_c)
+ * or not (method -> explicit_definition_c).
+ */
+SYM_REF0(implicit_definition_c)
+SYM_REF0(explicit_definition_c)
+SYM_REF4(en_param_declaration_c, name, type, value, method)
+SYM_REF3(eno_param_declaration_c, name, type, method)
+
/* edge -> The F_EDGE or R_EDGE directive */
SYM_REF2(edge_declaration_c, edge, var1_list)
-SYM_REF0(en_param_declaration_c)
-
SYM_REF0(raising_edge_option_c)
SYM_REF0(falling_edge_option_c)
@@ -441,9 +478,14 @@
/* VAR_OUTPUT [RETAIN | NON_RETAIN] var_init_decl_list END_VAR */
/* option -> may be NULL ! */
-SYM_REF2(output_declarations_c, option, var_init_decl_list)
-
-SYM_REF0(eno_param_declaration_c)
+/* NOTE: We need to implicitly define the EN and ENO function and FB parameters when the user
+ * does not do it explicitly in the IEC 61131-3 source code.
+ * To be able to distinguish later on between implictly and explicitly defined
+ * variables, we use the 'method' flag that allows us to remember
+ * whether this declaration was in the original source code (method -> implicit_definition_c)
+ * or not (method -> explicit_definition_c).
+ */
+SYM_REF3(output_declarations_c, option, var_init_decl_list, method)
/* VAR_IN_OUT var_declaration_list END_VAR */
SYM_REF1(input_output_declarations_c, var_declaration_list)
@@ -885,7 +927,9 @@
SYM_REF1(neg_expression_c, exp)
SYM_REF1(not_expression_c, exp)
-SYM_REF2(function_invocation_c, function_name, parameter_assignment_list)
+/* 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)
/********************/
@@ -908,8 +952,9 @@
SYM_REF0(return_statement_c)
/* fb_name '(' [param_assignment_list] ')' */
-/* param_assignment_list -> may be NULL ! */
-SYM_REF2(fb_invocation_c, 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)
/* helper symbol for fb_invocation */
/* param_assignment_list ',' param_assignment */
--- a/absyntax_utils/Makefile Wed Sep 02 13:39:05 2009 +0200
+++ b/absyntax_utils/Makefile Wed Sep 02 14:05:27 2009 +0200
@@ -14,10 +14,13 @@
SEARCH_UTIL_FILES += search_constant_type.o
SEARCH_UTIL_FILES += search_fb_instance_decl.o
SEARCH_UTIL_FILES += search_fb_typedecl.o
+SEARCH_UTIL_FILES += search_il_operand_type.o
SEARCH_UTIL_FILES += search_varfb_instance_type.o
SEARCH_UTIL_FILES += search_var_instance_decl.o
SEARCH_UTIL_FILES += spec_init_separator.o
SEARCH_UTIL_FILES += type_initial_value.o
+SEARCH_UTIL_FILES += add_en_eno_param_decl.o
+SEARCH_UTIL_FILES += get_sizeof_datatype.o
SEARCH_UTIL_FILES += get_function_type.o
--- a/absyntax_utils/absyntax_utils.hh Wed Sep 02 13:39:05 2009 +0200
+++ b/absyntax_utils/absyntax_utils.hh Wed Sep 02 14:05:27 2009 +0200
@@ -85,7 +85,10 @@
#include "decompose_var_instance_name.hh"
#include "search_varfb_instance_type.hh"
#include "search_constant_type.hh"
+#include "search_il_operand_type.hh"
#include "search_expression_type.hh"
+#include "add_en_eno_param_decl.hh"
+#include "get_sizeof_datatype.hh"
#include "get_function_type.h"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/absyntax_utils/add_en_eno_param_decl.cc Wed Sep 02 14:05:27 2009 +0200
@@ -0,0 +1,196 @@
+/*
+ * (c) 2009 Mario de Sousa
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * 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 IL and ST compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ */
+
+
+/*
+ * Iterate through all declared functions and Function Blocks,
+ * and, for each function/FB, add a declaration of the EN and ENO
+ * parameters, if they have not already been explicitly declared.
+ *
+ * EN and ENO parameters declared explicitly (by the user in the source code)
+ * and implicitly (by the comnpiler, i.e. by this visitor class) may be
+ * distinguished later on by the 'method' flag in the en_param_declaration_c
+ * and eno_param_declaration_c objects.
+ */
+
+#include "add_en_eno_param_decl.hh"
+#include <strings.h>
+
+
+// #define DEBUG
+#ifdef DEBUG
+#define TRACE(classname) printf("\n____%s____\n",classname);
+#else
+#define TRACE(classname)
+#endif
+
+
+#define ERROR error_exit(__FILE__,__LINE__)
+/* function defined in main.cc */
+extern void error_exit(const char *file_name, int line_no);
+
+
+
+/* This class is a singleton.
+ * So we need a pointer to the singe instance...
+ */
+add_en_eno_param_decl_c *add_en_eno_param_decl_c::singleton = NULL;
+
+/* Constructor for the singleton class */
+symbol_c *add_en_eno_param_decl_c::add_to(symbol_c *tree_root) {
+ if (NULL == singleton) {
+ singleton = new add_en_eno_param_decl_c;
+ if (NULL == singleton)
+ return NULL;
+ }
+ tree_root->accept(*singleton);
+ return tree_root;
+ }
+
+/* Destructor for the singleton class */
+add_en_eno_param_decl_c::~add_en_eno_param_decl_c(void) {
+ if (NULL != singleton) delete singleton;
+ singleton = NULL;
+ }
+
+
+
+void* add_en_eno_param_decl_c::iterate_list(list_c *list) {
+ for (int i = 0; i < list->n; i++) {
+ list->elements[i]->accept(*this);
+ }
+ return NULL;
+}
+
+
+input_declarations_c *add_en_eno_param_decl_c::build_en_param(void) {
+ boolean_literal_c *boolean_literal =
+ new boolean_literal_c(new bool_type_name_c(), new boolean_true_c());
+ identifier_c *identifier =
+ new identifier_c("EN");
+ en_param_declaration_c *en_param_declaration =
+ new en_param_declaration_c(identifier, new bool_type_name_c(), boolean_literal, new implicit_definition_c());
+ /* the last paramater is to flag that this
+ * declaration was inserted automatically, i.e. an implicit declaration
+ */
+ input_declaration_list_c *input_declaration_list = new input_declaration_list_c();
+ input_declaration_list->add_element(en_param_declaration);
+
+ input_declarations_c *input_declarations = new input_declarations_c(NULL, input_declaration_list, new implicit_definition_c());
+ return input_declarations;
+}
+
+
+output_declarations_c *add_en_eno_param_decl_c::build_eno_param(void) {
+ identifier_c *identifier =
+ new identifier_c("ENO");
+ eno_param_declaration_c *eno_param_declaration =
+ new eno_param_declaration_c(identifier, new bool_type_name_c(), new implicit_definition_c());
+ /* the last paramater is to flag that this
+ * declaration was inserted automatically, i.e. an implicit declaration
+ */
+ var_init_decl_list_c *var_init_decl_list = new var_init_decl_list_c();
+ var_init_decl_list->add_element(eno_param_declaration);
+
+ output_declarations_c *output_declarations = new output_declarations_c(NULL, var_init_decl_list, new implicit_definition_c());
+ return output_declarations;
+}
+
+
+
+
+/***************************/
+/* B 0 - Programming Model */
+/***************************/
+void *add_en_eno_param_decl_c::visit(library_c *symbol) {
+ TRACE("library_c");
+ return iterate_list(symbol);
+}
+
+
+/***********************/
+/* B 1.5.1 - Functions */
+/***********************/
+void *add_en_eno_param_decl_c::visit(function_declaration_c *symbol) {
+ TRACE("function_declaration_c");
+ return symbol->var_declarations_list->accept(*this);
+}
+
+void *add_en_eno_param_decl_c::visit(var_declarations_list_c *symbol) {
+ TRACE("var_declarations_list_c");
+ en_declared = false;
+ eno_declared = false;
+ iterate_list(symbol);
+ if(en_declared == false) symbol->add_element(build_en_param());
+ if(eno_declared == false) symbol->add_element(build_eno_param());
+ return NULL;
+}
+
+
+
+/****************************************/
+/* 1.4.3 - Declaration & Initialisation */
+/****************************************/
+void *add_en_eno_param_decl_c::visit(input_declarations_c *symbol) {
+ TRACE("input_declarations_c");
+// current_param_direction = direction_in;
+ return symbol->input_declaration_list->accept(*this);
+}
+
+void *add_en_eno_param_decl_c::visit(input_declaration_list_c *symbol) {TRACE("input_declaration_list_c"); return iterate_list(symbol);}
+
+void *add_en_eno_param_decl_c::visit(en_param_declaration_c *symbol) {
+ TRACE("en_param_declaration_c");
+ en_declared = true;
+ return NULL;
+}
+
+void *add_en_eno_param_decl_c::visit(eno_param_declaration_c *symbol) {
+ TRACE("eno_param_declaration_c");
+ eno_declared = true;
+ return NULL;
+}
+
+void *add_en_eno_param_decl_c::visit(output_declarations_c *symbol) {
+ TRACE("output_declarations_c");
+// current_param_direction = direction_out;
+ return symbol->var_init_decl_list->accept(*this);
+}
+
+void *add_en_eno_param_decl_c::visit(var_init_decl_list_c *symbol)
+{TRACE("var_init_decl_list_c"); return iterate_list(symbol);}
+
+
+/*****************************/
+/* B 1.5.2 - Function Blocks */
+/*****************************/
+/* FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */
+void *add_en_eno_param_decl_c::visit(function_block_declaration_c *symbol) {
+ TRACE("function_block_declaration_c");
+ return symbol->var_declarations->accept(*this);
+}
+
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/absyntax_utils/add_en_eno_param_decl.hh Wed Sep 02 14:05:27 2009 +0200
@@ -0,0 +1,96 @@
+/*
+ * (c) 2009 Mario de Sousa
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * 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 IL and ST compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ */
+
+
+/*
+ * Iterate through all declared functions and Function Blocks,
+ * and, for each function/FB, add a declaration of the EN and ENO
+ * parameters, if they have not already been explicitly declared.
+ *
+ * EN and ENO parameters declared explicitly (by the user in the source code)
+ * and implicitly (by the comnpiler, i.e. by this visitor class) may be
+ * distinguished later on by the 'method' flag in the en_param_declaration_c
+ * and eno_param_declaration_c objects.
+ */
+
+#include "../absyntax/visitor.hh"
+
+
+class add_en_eno_param_decl_c : public null_visitor_c {
+ public:
+ static symbol_c *add_to(symbol_c *tree_root);
+ ~add_en_eno_param_decl_c(void);
+
+ private:
+ /* this class is a singleton. So we need a pointer to the single instance... */
+ static add_en_eno_param_decl_c *singleton;
+
+ /* flags to remember whether the EN and/or ENO parameters have already
+ * been explicitly declared by the user in the IEC 61131-3 source code we are parsing...
+ */
+ bool en_declared;
+ bool eno_declared;
+
+ private:
+ void* iterate_list(list_c *list);
+ input_declarations_c *build_en_param (void);
+ output_declarations_c *build_eno_param(void);
+
+ private:
+ /***************************/
+ /* B 0 - Programming Model */
+ /***************************/
+ void *visit(library_c *symbol);
+
+ /***********************/
+ /* B 1.5.1 - Functions */
+ /***********************/
+ void *visit(function_declaration_c *symbol);
+ /* intermediate helper symbol for function_declaration */
+ void *visit(var_declarations_list_c *symbol);
+
+ /******************************************/
+ /* B 1.4.3 - Declaration & Initialisation */
+ /******************************************/
+ void *visit(input_declarations_c *symbol);
+ void *visit(input_declaration_list_c *symbol);
+ void *visit(en_param_declaration_c *symbol);
+ void *visit(eno_param_declaration_c *symbol);
+ void *visit(output_declarations_c *symbol);
+ void *visit(var_init_decl_list_c *symbol);
+
+ /*****************************/
+ /* B 1.5.2 - Function Blocks */
+ /*****************************/
+ /* FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */
+ void *visit(function_block_declaration_c *symbol);
+
+}; // function_param_iterator_c
+
+
+
+
+
+
+
--- a/absyntax_utils/decompose_var_instance_name.cc Wed Sep 02 13:39:05 2009 +0200
+++ b/absyntax_utils/decompose_var_instance_name.cc Wed Sep 02 14:05:27 2009 +0200
@@ -60,6 +60,16 @@
return res;
}
+
+/*************************/
+/* B.1 - Common elements */
+/*************************/
+/*******************************************/
+/* B 1.1 - Letters, digits and identifiers */
+/*******************************************/
+/* sometimes (e.g. FB calls) the name of the variable is stored directly in an identifier_c object */
+void *decompose_var_instance_name_c::visit(identifier_c *symbol) {return (void *)symbol;}
+
/*********************/
/* B 1.4 - Variables */
/*********************/
--- a/absyntax_utils/decompose_var_instance_name.hh Wed Sep 02 13:39:05 2009 +0200
+++ b/absyntax_utils/decompose_var_instance_name.hh Wed Sep 02 14:05:27 2009 +0200
@@ -56,11 +56,19 @@
symbol_c *next_part(void);
private:
+ /*************************/
+ /* B.1 - Common elements */
+ /*************************/
+ /*******************************************/
+ /* B 1.1 - Letters, digits and identifiers */
+ /*******************************************/
+ void *visit(identifier_c *symbol);
+
/*********************/
/* B 1.4 - Variables */
/*********************/
void *visit(symbolic_variable_c *symbol);
-
+
/********************************************/
/* B.1.4.1 Directly Represented Variables */
/********************************************/
--- a/absyntax_utils/function_call_iterator.cc Wed Sep 02 13:39:05 2009 +0200
+++ b/absyntax_utils/function_call_iterator.cc Wed Sep 02 14:05:27 2009 +0200
@@ -32,8 +32,7 @@
*/
/* given a function_body_c, iterate through each
- * function in/out/inout parameter, returning the name
- * of each parameter...
+ * function/FB call in that code.
*/
--- a/absyntax_utils/function_call_iterator.hh Wed Sep 02 13:39:05 2009 +0200
+++ b/absyntax_utils/function_call_iterator.hh Wed Sep 02 14:05:27 2009 +0200
@@ -37,9 +37,9 @@
/* given a function_body_c, iterate through each
- * function in/out/inout parameter, returning the name
- * of each parameter...
+ * function/FB call in that code.
*/
+
class function_call_iterator_c : public iterator_visitor_c {
private:
--- a/absyntax_utils/function_call_param_iterator.cc Wed Sep 02 13:39:05 2009 +0200
+++ b/absyntax_utils/function_call_param_iterator.cc Wed Sep 02 14:05:27 2009 +0200
@@ -24,15 +24,16 @@
/*
* Function call parameter iterator.
- * It will iterate through the formal parameters of a function call
+ * It will iterate through the non-formal parameters of a function call
* (i.e. function calls using the foo(<param1>, <param2>, ...) syntax).
- * and/or search through the non-formal parameters of a function call
+ * and/or search through the formal parameters of a function call
* (i.e. function calls using the foo(<name1> = <param1>, <name2> = <param2>, ...) syntax).
*
* Calls to function blocks and programs are also supported.
*
- * Note that calls to next() will only iterate through formal parameters,
- * and calls to search() will only serach through non-formal parameters.
+ * Note that calls to next_nf() will only iterate through non-formal parameters,
+ * calls to next_f() will only iterate through formal parameters,
+ * and calls to search_f() will only serach through formal parameters.
*/
@@ -58,7 +59,7 @@
void *function_call_param_iterator_c::search_list(list_c *list) {
switch (current_operation) {
- case iterate_op:
+ case iterate_nf_op:
for(int i = 0; i < list->n; i++) {
void *res = list->elements[i]->accept(*this);
if (NULL != res) {
@@ -69,7 +70,7 @@
/* we do nothing... */
} else {
param_count++;
- if (param_count == next_param) {
+ if (param_count == iterate_nf_next_param) {
return list->elements[i];
}
}
@@ -77,7 +78,26 @@
return NULL;
break;
- case search_op:
+ case iterate_f_op:
+ for(int i = 0; i < list->n; i++) {
+ void *res = list->elements[i]->accept(*this);
+ if (NULL != res) {
+ /* It went through the handle_parameter_assignment() function,
+ * and is therefore a parameter assignment (<param> = <value>),
+ * and not a simple expression (<value>).
+ */
+ param_count++;
+ if (param_count == iterate_f_next_param) {
+ return res;
+ }
+ } else {
+ /* we do nothing... */
+ }
+ }
+ return NULL;
+ break;
+
+ case search_f_op:
for(int i = 0; i < list->n; i++) {
void *res = list->elements[i]->accept(*this);
if (res != NULL)
@@ -93,28 +113,21 @@
void *function_call_param_iterator_c::handle_parameter_assignment(symbol_c *variable_name, symbol_c *expression) {
switch (current_operation) {
- case iterate_op:
+ case iterate_nf_op:
/* UGLY HACK -> this will be detected in the search_list() function */
- return (void *)this; /* anything, as long as it is not NULL!! */
+ return (void *)variable_name; /* anything, as long as it is not NULL!! */
break;
- case search_op:
+ case iterate_f_op:
+ current_value = expression;
+ return (void *)variable_name;
+ break;
+
+ case search_f_op:
identifier_c *variable_name2 = dynamic_cast<identifier_c *>(variable_name);
-
- if (variable_name2 == NULL) {
- en_param_c *en_param = dynamic_cast<en_param_c *>(variable_name);
- if (en_param != NULL)
- variable_name2 = new identifier_c("EN");
- }
-
- if (variable_name2 == NULL) {
- eno_param_c *eno_param = dynamic_cast<eno_param_c *>(variable_name);
- if (eno_param != NULL)
- variable_name2 = new identifier_c("ENO");
- }
-
+
if (variable_name2 == NULL) ERROR;
-
+
if (strcasecmp(search_param_name->value, variable_name2->value) == 0)
/* FOUND! This is the same parameter!! */
return (void *)expression;
@@ -129,7 +142,9 @@
/* start off at the first parameter once again... */
void function_call_param_iterator_c::reset(void) {
- next_param = param_count = 0;
+ iterate_nf_next_param = 0;
+ iterate_f_next_param = 0;
+ param_count = 0;
}
/* initialise the iterator object.
@@ -150,32 +165,58 @@
reset();
}
-/* Skip to the next parameter. After object creation,
+/* 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 whatever is being passed to the parameter!
- */
-symbol_c *function_call_param_iterator_c::next(void) {
+ * 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 *function_call_param_iterator_c::next_f(void) {
+ current_value = NULL;
param_count = 0;
- next_param++;
- current_operation = function_call_param_iterator_c::iterate_op;
+ iterate_f_next_param++;
+ current_operation = function_call_param_iterator_c::iterate_f_op;
void *res = f_call->accept(*this);
return (symbol_c *)res;
}
+
+/* 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 *function_call_param_iterator_c::next_nf(void) {
+ current_value = NULL;
+ param_count = 0;
+ iterate_nf_next_param++;
+ current_operation = function_call_param_iterator_c::iterate_nf_op;
+ void *res = f_call->accept(*this);
+ current_value = (symbol_c *)res;
+ return (symbol_c *)res;
+}
+
/* Search for the value passed to the parameter named <param_name>... */
-symbol_c *function_call_param_iterator_c::search(symbol_c *param_name) {
+symbol_c *function_call_param_iterator_c::search_f(symbol_c *param_name) {
+ current_value = NULL;
if (NULL == param_name) ERROR;
search_param_name = dynamic_cast<identifier_c *>(param_name);
if (NULL == search_param_name) ERROR;
- current_operation = function_call_param_iterator_c::search_op;
+ current_operation = function_call_param_iterator_c::search_f_op;
void *res = f_call->accept(*this);
+ current_value = (symbol_c *)res;
return (symbol_c *)res;
}
-
+/* Returns the value being passed to the current parameter. */
+symbol_c *function_call_param_iterator_c::get_current_value(void) {
+ return current_value;
+}
/********************************/
/* B 1.7 Configuration elements */
@@ -403,7 +444,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;
- return handle_parameter_assignment(symbol->il_assign_operator, symbol->il_operand);
+ return handle_parameter_assignment((symbol_c *)symbol->il_assign_operator->accept(*this), symbol->il_operand);
}
/* il_assign_out_operator variable */
@@ -417,6 +458,13 @@
/*******************/
/* B 2.2 Operators */
/*******************/
+/* any_identifier ASSIGN */
+// SYM_REF1(il_assign_operator_c, variable_name)
+void *function_call_param_iterator_c::visit(il_assign_operator_c *symbol) {
+ TRACE("il_assign_operator_c");
+ return (void *)symbol->variable_name;
+}
+
/*| [NOT] any_identifier SENDTO */
// SYM_REF2(il_assign_out_operator_c, option, variable_name)
void *function_call_param_iterator_c::visit(il_assign_out_operator_c *symbol) {
@@ -424,7 +472,7 @@
// TODO : Handle not_param !!!
// we do not yet support it, so it is best to simply stop than to fail silently...
- if (NULL != symbol->option) ERROR;
+ // if (NULL != symbol->option) ERROR;
return (void *)symbol->variable_name;
}
@@ -444,10 +492,13 @@
*/
void *function_call_param_iterator_c::visit(function_invocation_c *symbol) {
TRACE("function_invocation_c");
- if ((symbol_c *)symbol == f_call && symbol->parameter_assignment_list != NULL)
- return symbol->parameter_assignment_list->accept(*this);
- else
- return NULL;
+ /* 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) return symbol-> formal_param_list->accept(*this);
+ if (symbol->nonformal_param_list != NULL) return symbol->nonformal_param_list->accept(*this);
+
+ return NULL;
}
@@ -474,10 +525,14 @@
// SYM_REF2(fb_invocation_c, fb_name, param_assignment_list)
void *function_call_param_iterator_c::visit(fb_invocation_c *symbol) {
TRACE("fb_invocation_c");
- if (symbol->param_assignment_list != NULL)
- return symbol->param_assignment_list->accept(*this);
- else
- return NULL;
+ /* If the syntax parser is working correctly, only one of the
+ * following two symbols will be != NULL.
+ * However, both may be NULL simultaneously!
+ */
+ if (symbol-> formal_param_list != NULL) return symbol-> formal_param_list->accept(*this);
+ if (symbol->nonformal_param_list != NULL) return symbol->nonformal_param_list->accept(*this);
+
+ return NULL;
}
/* helper symbol for fb_invocation */
--- a/absyntax_utils/function_call_param_iterator.hh Wed Sep 02 13:39:05 2009 +0200
+++ b/absyntax_utils/function_call_param_iterator.hh Wed Sep 02 14:05:27 2009 +0200
@@ -24,15 +24,16 @@
/*
* Function call parameter iterator.
- * It will iterate through the formal parameters of a function call
+ * It will iterate through the non-formal parameters of a function call
* (i.e. function calls using the foo(<param1>, <param2>, ...) syntax).
- * and/or search through the non-formal parameters of a function call
+ * and/or search through the formal parameters of a function call
* (i.e. function calls using the foo(<name1> = <param1>, <name2> = <param2>, ...) syntax).
*
* Calls to function blocks and programs are also supported.
*
- * Note that calls to next() will only iterate through formal parameters,
- * and calls to search() will only serach through non-formal parameters.
+ * Note that calls to next_nf() will only iterate through non-formal parameters,
+ * calls to next_f() will only iterate through formal parameters,
+ * and calls to search_f() will only serach through formal parameters.
*/
@@ -46,13 +47,16 @@
* (or function block or program call!)
*/
symbol_c *f_call;
- int next_param, param_count;
+ int iterate_f_next_param, iterate_nf_next_param, param_count;
identifier_c *search_param_name;
-
- /* Which operation of the class was called...
- * Search a parameter, or iterate to the next parameter.
+ symbol_c *current_value;
+
+ /* Which operation of the class was called:
+ * - iterate to the next non-formal parameter.
+ * - iterate to the next formal parameter.
+ * - search a formal parameter,
*/
- typedef enum {iterate_op, search_op} operation_t;
+ typedef enum {iterate_nf_op, iterate_f_op, search_f_op} operation_t;
operation_t current_operation;
private:
@@ -70,17 +74,31 @@
*/
function_call_param_iterator_c(symbol_c *f_call);
- /* Skip to the next parameter. After object creation,
+ /* 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(void);
+ symbol_c *next_nf(void);
/* Search for the value passed to the parameter named <param_name>... */
- symbol_c *search(symbol_c *param_name);
+ symbol_c *search_f(symbol_c *param_name);
+
+ /* Returns the value being passed to the current parameter. */
+ symbol_c *get_current_value(void);
private:
@@ -254,6 +272,10 @@
/*******************/
/* B 2.2 Operators */
/*******************/
+ /* any_identifier ASSIGN */
+ // SYM_REF1(il_assign_operator_c, variable_name)
+ void *visit(il_assign_operator_c *symbol);
+
/*| [NOT] any_identifier SENDTO */
// SYM_REF2(il_assign_out_operator_c, option, variable_name)
void *visit(il_assign_out_operator_c *symbol);
--- a/absyntax_utils/function_param_iterator.cc Wed Sep 02 13:39:05 2009 +0200
+++ b/absyntax_utils/function_param_iterator.cc Wed Sep 02 14:05:27 2009 +0200
@@ -60,21 +60,51 @@
void* function_param_iterator_c::handle_param_list(list_c *list) {
- if (next_param <= param_count + list->n)
- return list->elements[next_param - param_count - 1];
-
- /* the desired param is not on this list... */
- param_count += list->n;
- return NULL;
+ switch (current_operation) {
+ case iterate_op:
+ if (next_param <= param_count + list->n)
+ return list->elements[next_param - param_count - 1];
+
+ /* the desired param is not on this list... */
+ param_count += list->n;
+ break;
+
+ case search_op:
+ for(int i = 0; i < list->n; i++) {
+ identifier_c *variable_name = dynamic_cast<identifier_c *>(list->elements[i]);
+ if (variable_name == NULL) ERROR;
+
+ if (strcasecmp(search_param_name->value, variable_name->value) == 0)
+ /* FOUND! This is the same parameter!! */
+ return (void *)variable_name;
+ }
+ break;
+ } /* switch */
+
+ /* Not found! */
+ return NULL;
}
void* function_param_iterator_c::handle_single_param(symbol_c *var_name) {
- param_count++;
- if (next_param == param_count)
- return var_name;
-
- /* not yet the desired param... */
- return NULL;
+ switch (current_operation) {
+ case iterate_op:
+ param_count++;
+ if (next_param == param_count)
+ return var_name;
+ break;
+
+ case search_op:
+ identifier_c *variable_name = dynamic_cast<identifier_c *>(var_name);
+ if (variable_name == NULL) ERROR;
+
+ if (strcasecmp(search_param_name->value, variable_name->value) == 0)
+ /* FOUND! This is the same parameter!! */
+ return (void *)variable_name;
+ break;
+ } /* switch */
+
+ /* Not found! */
+ return NULL;
}
void* function_param_iterator_c::iterate_list(list_c *list) {
@@ -92,36 +122,30 @@
next_param = param_count = 0;
current_param_name = NULL;
current_param_type = current_param_default_value = NULL;
- en_declared = false;
- eno_declared = false;
-}
+}
+
/* initialise the iterator object.
- * We must be given a reference to the function declaration
+ * We must be given a reference to one of the following
+ * - function_declaration_c
+ * - function_block_declaration_c
+ * - program_declaration_c
* that will be analysed...
*/
-function_param_iterator_c::function_param_iterator_c(function_declaration_c *f_decl) {
- this->f_decl = f_decl;
+function_param_iterator_c::function_param_iterator_c(symbol_c *pou_decl) {
+ /* do some consistency checks... */
+ function_declaration_c * f_decl = dynamic_cast<function_declaration_c *>(pou_decl);
+ 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;
+
+ /* OK. Now initialise this object... */
+ this->f_decl = pou_decl;
reset();
}
-/* initialise the iterator object.
- * We must be given a reference to the function block declaration
- * that will be analysed...
- */
-function_param_iterator_c::function_param_iterator_c(function_block_declaration_c *fb_decl) {
- this->f_decl = fb_decl;
- reset();
-}
-
-/* initialise the iterator object.
- * We must be given a reference to the program declaration
- * that will be analysed...
- */
-function_param_iterator_c::function_param_iterator_c(program_declaration_c *p_decl) {
- this->f_decl = p_decl;
- reset();
-}
+
/* Skip to the next parameter. After object creation,
* the object references on parameter _before_ the first, so
@@ -133,44 +157,31 @@
identifier_c *function_param_iterator_c::next(void) {
void *res;
identifier_c *identifier;
+
param_count = 0;
next_param++;
+ current_operation = function_param_iterator_c::iterate_op;
res = f_decl->accept(*this);
- if (res != NULL) {
- symbol_c *sym = (symbol_c *)res;
- identifier = dynamic_cast<identifier_c *>(sym);
- if (identifier == NULL)
- ERROR;
- }
- else if (!en_declared) {
- current_param_direction = direction_in;
- identifier = declare_en_param();
- }
- else if (!eno_declared) {
- current_param_direction = direction_out;
- identifier = declare_eno_param();
- }
- else
+ if (res == NULL)
return NULL;
-
+
+ symbol_c *sym = (symbol_c *)res;
+ identifier = dynamic_cast<identifier_c *>(sym);
+ if (identifier == NULL)
+ ERROR;
current_param_name = identifier;
return current_param_name;
}
-identifier_c *function_param_iterator_c::declare_en_param(void) {
- en_declared = true;
- identifier_c *identifier = new identifier_c("EN");
- current_param_type = (symbol_c*)(new bool_type_name_c());
- current_param_default_value = (symbol_c*)(new boolean_literal_c(current_param_type, new boolean_true_c()));
- return identifier;
-}
-
-identifier_c *function_param_iterator_c::declare_eno_param(void) {
- eno_declared = true;
- identifier_c *identifier = new identifier_c("ENO");
- current_param_type = (symbol_c*)(new bool_type_name_c());
- current_param_default_value = NULL;
- return identifier;
+/* Search for the value passed to the parameter named <param_name>... */
+identifier_c *function_param_iterator_c::search(symbol_c *param_name) {
+ if (NULL == param_name) ERROR;
+ search_param_name = dynamic_cast<identifier_c *>(param_name);
+ if (NULL == search_param_name) ERROR;
+ 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);
+ return res_param_name;
}
/* Returns the currently referenced parameter's default value,
@@ -207,8 +218,16 @@
void *function_param_iterator_c::visit(en_param_declaration_c *symbol) {
TRACE("en_param_declaration_c");
- if (en_declared) ERROR;
- return (void *)declare_en_param();
+ /* It is OK to store these values in the current_param_XXX
+ * variables, because if the desired parameter is not in the
+ * variable list we will be analysing, the current_param_XXXX
+ * variables will get overwritten when we visit the next
+ * var1_init_decl_c list!
+ */
+ current_param_default_value = symbol->value;
+ current_param_type = symbol->type;
+
+ return handle_single_param(symbol->name);
}
/* var1_list ':' array_spec_init */
@@ -226,8 +245,20 @@
}
void *function_param_iterator_c::visit(eno_param_declaration_c *symbol) {
TRACE("eno_param_declaration_c");
+ /* It is OK to store these values in the current_param_XXX
+ * variables, because if the desired parameter is not in the
+ * variable list we will be analysing, the current_param_XXXX
+ * variables will get overwritten when we visit the next
+ * var1_init_decl_c list!
+ */
+ current_param_default_value = NULL;
+ current_param_type = symbol->type;
+
+ return handle_single_param(symbol->name);
+#if 0
if (eno_declared) ERROR;
return (void *)declare_eno_param();
+#endif
}
void *function_param_iterator_c::visit(input_output_declarations_c *symbol) {
TRACE("input_output_declarations_c");
--- a/absyntax_utils/function_param_iterator.hh Wed Sep 02 13:39:05 2009 +0200
+++ b/absyntax_utils/function_param_iterator.hh Wed Sep 02 14:05:27 2009 +0200
@@ -69,17 +69,23 @@
private:
- /* a pointer to the function_block_declaration_c
- * or function_declaration_c currently being analysed.
- */
+ /* a pointer to the function_block_declaration_c
+ * or function_declaration_c currently being analysed.
+ */
symbol_c *f_decl;
int next_param, param_count;
+ /* used when called to search() for a parameter by name */
+ identifier_c *search_param_name;
+ /* used when called to iterate() for a parameter */
identifier_c *current_param_name;
symbol_c *current_param_type;
symbol_c *current_param_default_value;
param_direction_t current_param_direction;
- bool en_declared;
- bool eno_declared;
+ /* Which operation of the class was called...
+ * Search a parameter, or iterate to the next parameter.
+ */
+ typedef enum {iterate_op, search_op} operation_t;
+ operation_t current_operation;
private:
void* handle_param_list(list_c *list);
@@ -92,22 +98,13 @@
void reset(void);
/* initialise the iterator object.
- * We must be given a reference to the function declaration
+ * We must be given a reference to one of the following
+ * - function_declaration_c
+ * - function_block_declaration_c
+ * - program_declaration_c
* that will be analysed...
*/
- function_param_iterator_c(function_declaration_c *f_decl);
-
- /* initialise the iterator object.
- * We must be given a reference to the function block declaration
- * that will be analysed...
- */
- function_param_iterator_c(function_block_declaration_c *fb_decl);
-
- /* initialise the iterator object.
- * We must be given a reference to the program declaration
- * that will be analysed...
- */
- function_param_iterator_c(program_declaration_c *p_decl);
+ function_param_iterator_c(symbol_c *pou_decl);
/* Skip to the next parameter. After object creation,
* the object references on parameter _before_ the first, so
@@ -118,9 +115,13 @@
*/
identifier_c *next(void);
- identifier_c *declare_en_param(void);
-
- identifier_c *declare_eno_param(void);
+ /* Search for the parameter named <param_name>... */
+ /* The seach() function does not in any way affect the internal state related
+ * to the iterate() function.
+ * It will, however, affect the internal state necessary to correctly
+ * return the param_type() and default_value() of the found parameter.
+ */
+ identifier_c *search(symbol_c *param_name);
/* Returns the currently referenced parameter's default value,
* or NULL if none is specified in the function declrataion itself.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/absyntax_utils/get_sizeof_datatype.cc Wed Sep 02 14:05:27 2009 +0200
@@ -0,0 +1,363 @@
+/*
+ * (c) 2003 Mario de Sousa
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * 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 IL and ST compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ */
+
+/* Determine the size, in bits, of the data type.
+ *
+ * NOTE: Currently, only elementary data types with well defined sizes (in the standard) are supported.
+ * - derived data types are not supported, and these will return 0
+ * - TIME, DATE, TIME_OF_DAY, and DATE_AND_TIME are not supported, and will return 0
+ * - STRING and WSTRING are not supported, and the standard merely defines bit per character,
+ * and not the maximum number of characters, so these will return 0
+ *
+ * We also support the 'Numeric Literals' Data types.
+ * i.e., numeric literals are considerd basic data types
+ * as their data type is undefined (e.g. the datat type of '30'
+ * could be 'INT' or 'SINT' or 'LINT' or 'USINT' or ...
+ * NOTE: for base 10 numeric literals, any number taking up more than 64 bits
+ * will only return a bitsize of 1024!
+ *
+ * For numeric literals, we return the minimum number of bits
+ * required to store the value.
+ *
+ * E.g. TYPE new_int_t : INT; END_TYPE;
+ * TYPE new_int2_t : INT = 2; END_TYPE;
+ * TYPE new_subr_t : INT (4..5); END_TYPE;
+ *
+ * sizeof(SINT) -> 8
+ * sizeof(INT) -> 16
+ * sizeof(DINT) -> 32
+ * sizeof(LINT) -> 64
+ *
+ * sizeof('1') -> 1
+ * sizeof('015') -> 4 # Leading zeros are ignored!
+ * sizeof('0') -> 1 # This is a special case! Even the value 0 needs at least 1 bit to store!
+ * sizeof('16') -> 5
+ * sizeof('2#00101') -> 3
+ * sizeof('8#334') -> 9
+ * sizeof('16#2A') -> 8
+ *
+ * sizeof('7.4') -> 32 # all real literals return 32 bits, the size of a 'REAL'
+ * # TODO: study IEC 60559 for the range of values that may be
+ * # stored in a REAL (basic single width floating point format)
+ * # and in a LREAL (basic double width floating point format)
+ * # and see if some real literals need to return 64 instead!
+ */
+
+#include "get_sizeof_datatype.hh"
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h> // get definition of ULLONG_MAX
+/* 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
+
+
+#define ERROR error_exit(__FILE__,__LINE__)
+/* function defined in main.cc */
+extern void error_exit(const char *file_name, int line_no);
+
+
+/* This class is a singleton.
+ * So we need a pointer to the singe instance...
+ */
+get_sizeof_datatype_c *get_sizeof_datatype_c::singleton = NULL;
+
+
+#define _encode_int(value) ((void *)(((char *)NULL) + value))
+#define _decode_int(ptr) (((char *)ptr) - ((char *)NULL))
+
+
+
+
+/* divide a base 10 literal in a string by 2 */
+/* returns remainder of division (0 or 1) */
+static int strdivby2(char **strptr) {
+ char *str = *strptr;
+ int carry = 0;
+
+ while (*str != '\0') {
+ /* Assumes ASCII */
+ int newcarry;
+// newcarry = ((*str-'0') mod 2);
+ newcarry = ((*str-'0') - ((*str-'0')/2)*2);
+ *str = (((*str-'0') + 10*carry)/2) + '0';
+ carry = newcarry;
+ str++;
+ }
+
+ /* ignore leading zeros in result... */
+ while (**strptr == '0')
+ (*strptr)++;
+
+ return carry;
+}
+
+
+/* Constructor for the singleton class */
+int get_sizeof_datatype_c::getsize(symbol_c *data_type_symbol) {
+ if (NULL == singleton) {
+ singleton = new get_sizeof_datatype_c;
+ if (NULL == singleton)
+ ERROR;
+ }
+ return _decode_int(data_type_symbol->accept(*singleton));
+ }
+
+/* Destructor for the singleton class */
+get_sizeof_datatype_c::~get_sizeof_datatype_c(void) {
+ if (NULL != singleton) delete singleton;
+ singleton = NULL;
+ }
+
+
+/*********************/
+/* 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
+ * numeric literal '30' must then be considered a LINT so the ADD function may be called
+ * with all inputs of the same data type.
+ * If 'x' were a SINT, then the '30' would have to be a SINT too!
+ */
+
+/* NOTE: all integer and real literal tokens will always be positive (i.e. no leading '-')
+ * due to the way the source code is parsed by iec.flex.
+ */
+void *get_sizeof_datatype_c::visit(real_c *symbol) {
+ return _encode_int(32);
+}
+
+/* NOTE: all integer and real literal tokens will always be positive (i.e. no leading '-')
+ * due to the way the source code is parsed by iec.flex.
+ */
+void *get_sizeof_datatype_c::visit(integer_c *symbol) {
+ int bitsize = 0;
+
+ if (NULL == symbol->value ) ERROR;
+ if ('\0' == *(symbol->value)) ERROR;
+
+#if 0
+ char *endptr;
+ /* Convert the string to an unsigned 64 bit integer */
+ /* We can use strtoull(), but we are not guaranteed that an unsigned long long int
+ * is 64 bits wide. First make sure that it is...
+ *
+ * We could also use the strtouq() instead, which converts
+ * to a quad word (64 bits). However, this requires either GCC or BSD extensions.
+ */
+ #ifdef strtoull // this ifdef does not work!!
+ /* we have long long int, use it... */
+ #define ival_MAX ULLONG_MAX
+ unsigned long long int ival = 0;
+ ival = strtoull (symbol->value, &endptr, 10 /* base */);
+ #else
+ /* use long int ... */
+ #define ival_MAX ULONG_MAX
+ unsigned long int ival = 0;
+ ival = strtoul (symbol->value, &endptr, 10 /* base */);
+ #endif
+
+ #if (ival_MAX < UINT64_MAX)
+ #error Largest strtoint() conversion function converts to an int less than 64 bits wide!
+ #endif
+
+ if (NULL == endptr) ERROR;
+ if ('\0' != *endptr) ERROR;
+ // TODO: return _encode_int(1024) if value takes up more than 64 bits!
+
+ /* determine the number of bits used... */
+ for (bitsize = 0; ival > 0; ival /= 2, bitsize++);
+
+ /* special case... if (value == 0) <=> (bitsize == 0), return bit size of 1 ! */
+ if (0 == bitsize) bitsize = 1;
+
+ return _encode_int(bitsize);
+#endif
+ /* We could first convert from string to some kind of integer, and then
+ * determine the the bitsize using integer aritmetic.
+ * However, we are then limited to the bit size of the widest available integer
+ * (usually 64 bits), which is not good at all!
+ */
+ /* Let's try to determine bitsize by converting directly from the string!! */
+ char *sval = strdup(symbol->value);
+ char *oval = sval;
+ if (NULL == sval) ERROR;
+ if ('\0' == *sval) ERROR;
+
+ for (bitsize = 0; *sval != '\0'; strdivby2(&sval), bitsize ++);
+
+ /* Even for (value == 0), the above loop will return bitsize == 1!,
+ * so we don't need to handle the special case...
+ */
+ /* special case... if (value == 0) <=> (bitsize == 0), return bit size of 1 ! */
+ // if (0 == bitsize) bitsize = 1;
+
+ free(oval);
+ return _encode_int(bitsize);
+}
+
+
+/* NOTE: all integer and real literal tokens will always be positive (i.e. no leading '-')
+ * due to the way the source code is parsed by iec.flex.
+ */
+void *get_sizeof_datatype_c::visit(binary_integer_c *symbol) {
+ const char *sval = symbol->value;
+ int bitsize = 0;
+
+ /* first 2 characters had better be "2#" ! */
+ if (NULL == sval) ERROR;
+ if ('\0' == *sval) ERROR;
+ if ( '2' != *sval) ERROR;
+ sval++;
+ if ('\0' == *sval) ERROR;
+ if ( '#' != *sval) ERROR;
+ sval++;
+ if ('\0' == *sval) ERROR;
+
+ /* determine the number of bits used... */
+ for (bitsize = 0; '\0' != *sval; sval++, bitsize++) {
+ /* consistency check: make sure we only have binary digits! */
+ if (('0' != *sval) && ('1' != *sval))
+ ERROR;
+ }
+
+ /* special case... if (value == 0) <=> (bitsize == 0), return bit size of 1 ! */
+ if (0 == bitsize) bitsize = 1;
+
+ return _encode_int(bitsize);
+}
+
+
+/* NOTE: all integer and real literal tokens will always be positive (i.e. no leading '-')
+ * due to the way the source code is parsed by iec.flex.
+ */
+void *get_sizeof_datatype_c::visit(octal_integer_c *symbol) {
+ const char *sval = symbol->value;
+ int bitsize = 0;
+
+ /* first 2 characters had better be "8#" ! */
+ if (NULL == sval) ERROR;
+ if ('\0' == *sval) ERROR;
+ if ( '8' != *sval) ERROR;
+ sval++;
+ if ('\0' == *sval) ERROR;
+ if ( '#' != *sval) ERROR;
+ sval++;
+ if ('\0' == *sval) ERROR;
+
+ /* determine the number of bits used... */
+ for (bitsize = 0; '\0' != *sval; sval++, bitsize += 3 /* 3 bits per octal digit */) {
+ /* consistency check: make sure we only have octal digits! */
+ /* Assumes ASCII */
+ if (('0' > *sval) || ('7' < *sval))
+ ERROR;
+ }
+
+ /* special case... if (value == 0) <=> (bitsize == 0), return bit size of 1 ! */
+ if (0 == bitsize) bitsize = 1;
+
+ return _encode_int(bitsize);
+}
+
+
+/* NOTE: all integer and real literal tokens will always be positive (i.e. no leading '-')
+ * due to the way the source code is parsed by iec.flex.
+ */
+void *get_sizeof_datatype_c::visit(hex_integer_c *symbol) {
+ const char *sval = symbol->value;
+ int bitsize = 0;
+
+ /* first 3 characters had better be "16#" ! */
+ if (NULL == sval) ERROR;
+ if ('\0' == *sval) ERROR;
+ if ( '1' != *sval) ERROR;
+ sval++;
+ if ('\0' == *sval) ERROR;
+ if ( '6' != *sval) ERROR;
+ sval++;
+ if ('\0' == *sval) ERROR;
+ if ( '#' != *sval) ERROR;
+ sval++;
+ if ('\0' == *sval) ERROR;
+
+ /* determine the number of bits used... */
+ for (bitsize = 0; '\0' != *sval; sval++, bitsize += 4 /* 4 bits per hex digit */) {
+ /* consistency check: make sure we only have hex digits! */
+ /* Assumes ASCII */
+ if (!(('0' <= *sval) && ('9' >= *sval)) &&
+ !(('A' <= *sval) && ('F' >= *sval)) &&
+ !(('a' <= *sval) && ('b' >= *sval)))
+ ERROR;
+ }
+
+ /* special case... if (value == 0) <=> (bitsize == 0), return bit size of 1 ! */
+ if (0 == bitsize) bitsize = 1;
+
+ return _encode_int(bitsize);
+}
+
+
+/***********************************/
+/* B 1.3.1 - Elementary Data Types */
+/***********************************/
+// void *get_sizeof_datatype_c::visit(time_type_name_c *symbol) {return _encode_int(0); }
+void *get_sizeof_datatype_c::visit(bool_type_name_c *symbol) {return _encode_int(1); }
+void *get_sizeof_datatype_c::visit(sint_type_name_c *symbol) {return _encode_int(8); }
+void *get_sizeof_datatype_c::visit(int_type_name_c *symbol) {return _encode_int(16);}
+void *get_sizeof_datatype_c::visit(dint_type_name_c *symbol) {return _encode_int(32);}
+void *get_sizeof_datatype_c::visit(lint_type_name_c *symbol) {return _encode_int(64);}
+void *get_sizeof_datatype_c::visit(usint_type_name_c *symbol) {return _encode_int(8); }
+void *get_sizeof_datatype_c::visit(uint_type_name_c *symbol) {return _encode_int(16);}
+void *get_sizeof_datatype_c::visit(udint_type_name_c *symbol) {return _encode_int(32);}
+void *get_sizeof_datatype_c::visit(ulint_type_name_c *symbol) {return _encode_int(64);}
+void *get_sizeof_datatype_c::visit(real_type_name_c *symbol) {return _encode_int(32);}
+void *get_sizeof_datatype_c::visit(lreal_type_name_c *symbol) {return _encode_int(64);}
+// void *get_sizeof_datatype_c::visit(date_type_name_c *symbol) {return _encode_int(0); }
+// void *get_sizeof_datatype_c::visit(tod_type_name_c *symbol) {return _encode_int(0); }
+// void *get_sizeof_datatype_c::visit(dt_type_name_c *symbol) {return _encode_int(0); }
+void *get_sizeof_datatype_c::visit(byte_type_name_c *symbol) {return _encode_int(8); }
+void *get_sizeof_datatype_c::visit(word_type_name_c *symbol) {return _encode_int(16);}
+void *get_sizeof_datatype_c::visit(dword_type_name_c *symbol) {return _encode_int(32);}
+void *get_sizeof_datatype_c::visit(lword_type_name_c *symbol) {return _encode_int(64);}
+// void *get_sizeof_datatype_c::visit(string_type_name_c *symbol) {return _encode_int(0); }
+// void *get_sizeof_datatype_c::visit(wstring_type_name_c *symbol) {return _encode_int(0); }
+/******************************************************/
+/* Extensions to the base standard as defined in */
+/* "Safety Software Technical Specification, */
+/* Part 1: Concepts and Function Blocks, */
+/* Version 1.0 – Official Release" */
+/* by PLCopen - Technical Committee 5 - 2006-01-31 */
+/******************************************************/
+void *get_sizeof_datatype_c::visit(safebool_type_name_c *symbol) {return _encode_int(1);}
+
+/********************************/
+/* B 1.3.3 - Derived data types */
+/********************************/
+// Not yet supported...
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/absyntax_utils/get_sizeof_datatype.hh Wed Sep 02 14:05:27 2009 +0200
@@ -0,0 +1,212 @@
+/*
+ * (c) 2009 Mario de Sousa
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * 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 IL and ST compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ */
+
+
+/* Determine the size, in bits, of the data type.
+ *
+ * NOTE: Currently, only elementary data types with well defined sizes (in the standard) are supported.
+ * - derived data types are not supported, and these will return 0
+ * - TIME, DATE, TIME_OF_DAY, and DATE_AND_TIME are not supported, and will return 0
+ * - STRING and WSTRING are not supported, and the standard merely defines bit per character,
+ * and not the maximum number of characters, so these will return 0
+ *
+ * We also support the 'Numeric Literals' Data types.
+ * i.e., numeric literals are considerd basic data types
+ * as their data type is undefined (e.g. the datat type of '30'
+ * could be 'INT' or 'SINT' or 'LINT' or 'USINT' or ...
+ *
+ * For numeric literals, we return the minimum number of bits
+ * required to store the value.
+ *
+ * E.g. TYPE new_int_t : INT; END_TYPE;
+ * TYPE new_int2_t : INT = 2; END_TYPE;
+ * TYPE new_subr_t : INT (4..5); END_TYPE;
+ *
+ * sizeof(SINT) -> 8
+ * sizeof(INT) -> 16
+ * sizeof(DINT) -> 32
+ * sizeof(LINT) -> 64
+ *
+ * sizeof('1') -> 1
+ * sizeof('015') -> 4 # Leading zeros are ignored!
+ * sizeof('0') -> 1 # This is a special case! Even the value 0 needs at least 1 bit to store!
+ * sizeof('16') -> 5
+ * sizeof('2#00101') -> 3
+ * sizeof('8#334') -> 9
+ * sizeof('16#2A') -> 8
+ *
+ * sizeof('7.4') -> 32 # all real literals return 32 bits, the size of a 'REAL'
+ * # TODO: study IEC 60559 for the range of values that may be
+ * # stored in a REAL (basic single width floating point format)
+ * # and in a LREAL (basic double width floating point format)
+ * # and see if some real literals need to return 64 instead!
+ */
+
+#include "../absyntax/visitor.hh"
+
+class get_sizeof_datatype_c: public null_visitor_c {
+
+ public:
+ static int getsize(symbol_c *data_type_symbol);
+ ~get_sizeof_datatype_c(void);
+
+ private:
+ /* this class is a singleton. So we need a pointer to the single instance... */
+ static get_sizeof_datatype_c *singleton;
+
+ private:
+ /*********************/
+ /* 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
+ * numeric literal '30' must then be considered a LINT so the ADD function may be called
+ * with all inputs of the same data type.
+ * If 'x' were a SINT, then the '30' would have to be a SINT too!
+ */
+ void *visit(real_c *symbol);
+ void *visit(integer_c *symbol);
+ void *visit(binary_integer_c *symbol);
+ void *visit(octal_integer_c *symbol);
+ void *visit(hex_integer_c *symbol);
+
+ /***********************************/
+ /* B 1.3.1 - Elementary Data Types */
+ /***********************************/
+// void *visit(time_type_name_c *symbol);
+ void *visit(bool_type_name_c *symbol);
+ void *visit(sint_type_name_c *symbol);
+ void *visit(int_type_name_c *symbol);
+ void *visit(dint_type_name_c *symbol);
+ void *visit(lint_type_name_c *symbol);
+ void *visit(usint_type_name_c *symbol);
+ void *visit(uint_type_name_c *symbol);
+ void *visit(udint_type_name_c *symbol);
+ void *visit(ulint_type_name_c *symbol);
+ void *visit(real_type_name_c *symbol);
+ void *visit(lreal_type_name_c *symbol);
+// void *visit(date_type_name_c *symbol);
+// void *visit(tod_type_name_c *symbol);
+// void *visit(dt_type_name_c *symbol) ;
+ void *visit(byte_type_name_c *symbol);
+ void *visit(word_type_name_c *symbol);
+ void *visit(dword_type_name_c *symbol);
+ void *visit(lword_type_name_c *symbol);
+// void *visit(string_type_name_c *symbol);
+// void *visit(wstring_type_name_c *symbol);
+
+ /******************************************************/
+ /* Extensions to the base standard as defined in */
+ /* "Safety Software Technical Specification, */
+ /* Part 1: Concepts and Function Blocks, */
+ /* Version 1.0 – Official Release" */
+ /* by PLCopen - Technical Committee 5 - 2006-01-31 */
+ /******************************************************/
+ void *visit(safebool_type_name_c *symbol);
+
+ /********************************/
+ /* B 1.3.3 - Derived data types */
+ /********************************/
+#if 0
+ /* simple_type_name ':' simple_spec_init */
+ void *visit(simple_type_declaration_c *symbol);
+ /* simple_specification ASSIGN constant */
+ void *visit(simple_spec_init_c *symbol);
+ /* subrange_type_name ':' subrange_spec_init */
+ void *visit(subrange_type_declaration_c *symbol);
+ /* subrange_specification ASSIGN signed_integer */
+ void *visit(subrange_spec_init_c *symbol);
+ /* integer_type_name '(' subrange')' */
+ void *visit(subrange_specification_c *symbol);
+ /* signed_integer DOTDOT signed_integer */
+ void *visit(subrange_c *symbol);
+
+ /* enumerated_type_name ':' enumerated_spec_init */
+ void *visit(enumerated_type_declaration_c *symbol);
+ /* enumerated_specification ASSIGN enumerated_value */
+ void *visit(enumerated_spec_init_c *symbol);
+ /* helper symbol for enumerated_specification->enumerated_spec_init */
+ /* enumerated_value_list ',' enumerated_value */
+ void *visit(enumerated_value_list_c *symbol);
+ /* enumerated_type_name '#' identifier */
+ // SYM_REF2(enumerated_value_c, type, value)
+ void *visit(enumerated_value_c *symbol);
+ /* identifier ':' array_spec_init */
+ void *visit(array_type_declaration_c *symbol);
+ /* array_specification [ASSIGN array_initialization} */
+ /* array_initialization may be NULL ! */
+ void *visit(array_spec_init_c *symbol);
+ /* ARRAY '[' array_subrange_list ']' OF non_generic_type_name */
+ void *visit(array_specification_c *symbol);
+ /* helper symbol for array_specification */
+ /* array_subrange_list ',' subrange */
+ void *visit(array_subrange_list_c *symbol);
+ /* array_initialization: '[' array_initial_elements_list ']' */
+ /* helper symbol for array_initialization */
+ /* array_initial_elements_list ',' array_initial_elements */
+ void *visit(array_initial_elements_list_c *symbol);
+ /* integer '(' [array_initial_element] ')' */
+ /* array_initial_element may be NULL ! */
+ void *visit(array_initial_elements_c *symbol);
+ /* structure_type_name ':' structure_specification */
+ /* NOTE: structure_specification will point to either a
+ * initialized_structure_c
+ * OR A
+ * structure_element_declaration_list_c
+ */
+ void *visit(structure_type_declaration_c *symbol);
+ /* structure_type_name ASSIGN structure_initialization */
+ /* structure_initialization may be NULL ! */
+ void *visit(initialized_structure_c *symbol);
+ /* helper symbol for structure_declaration */
+ /* structure_declaration: STRUCT structure_element_declaration_list END_STRUCT */
+ /* structure_element_declaration_list structure_element_declaration ';' */
+ void *visit(structure_element_declaration_list_c *symbol);
+ /* structure_element_name ':' *_spec_init */
+ void *visit(structure_element_declaration_c *symbol);
+ /* helper symbol for structure_initialization */
+ /* structure_initialization: '(' structure_element_initialization_list ')' */
+ /* structure_element_initialization_list ',' structure_element_initialization */
+ void *visit(structure_element_initialization_list_c *symbol);
+ /* structure_element_name ASSIGN value */
+ void *visit(structure_element_initialization_c *symbol);
+ /* 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);
+#endif
+}; // get_sizeof_datatype_c
+
+
+
+
--- a/absyntax_utils/search_base_type.cc Wed Sep 02 13:39:05 2009 +0200
+++ b/absyntax_utils/search_base_type.cc Wed Sep 02 14:05:27 2009 +0200
@@ -33,6 +33,9 @@
* new_int_t is really an INT!!
* new_int2_t is also really an INT!!
* new_subr_t is also really an INT!!
+ *
+ * Note that a FB declaration is also considered a base type, as
+ * we may have FB instances declared of a specific FB type.
*/
#include "absyntax_utils.hh"
@@ -67,6 +70,27 @@
return this->is_enumerated;
}
+/*********************/
+/* 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
+ * numeric literal '30' must then be considered a LINT so the ADD function may be called
+ * with all inputs of the same data type.
+ * If 'x' were a SINT, then the '30' would have to be a SINT too!
+ */
+void *search_base_type_c::visit(real_c *symbol) {return (void *)symbol;}
+void *search_base_type_c::visit(integer_c *symbol) {return (void *)symbol;}
+void *search_base_type_c::visit(binary_integer_c *symbol) {return (void *)symbol;}
+void *search_base_type_c::visit(octal_integer_c *symbol) {return (void *)symbol;}
+void *search_base_type_c::visit(hex_integer_c *symbol) {return (void *)symbol;}
+
+
/***********************************/
/* B 1.3.1 - Elementary Data Types */
/***********************************/
@@ -91,8 +115,10 @@
void *search_base_type_c::visit(lword_type_name_c *symbol) {return (void *)symbol;}
void *search_base_type_c::visit(string_type_name_c *symbol) {return (void *)symbol;}
void *search_base_type_c::visit(wstring_type_name_c *symbol) {return (void *)symbol;}
-void *search_base_type_c::visit(constant_int_type_name_c *symbol) {return (void *)symbol;}
-void *search_base_type_c::visit(constant_real_type_name_c *symbol) {return (void *)symbol;}
+/*
+void *search_base_type_c::visit(constant_int_type_name_c *symbol) {return (void *)symbol;}
+void *search_base_type_c::visit(constant_real_type_name_c *symbol) {return (void *)symbol;}
+*/
/******************************************************/
/* Extensions to the base standard as defined in */
/* "Safety Software Technical Specification, */
@@ -232,3 +258,14 @@
*/
void *search_base_type_c::visit(string_type_declaration_c *symbol) {return symbol;}
+
+
+/*****************************/
+/* B 1.5.2 - Function Blocks */
+/*****************************/
+/* FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */
+// SYM_REF3(function_block_declaration_c, fblock_name, var_declarations, fblock_body)
+void *search_base_type_c::visit(function_block_declaration_c *symbol) {
+ return symbol;
+}
+
--- a/absyntax_utils/search_base_type.hh Wed Sep 02 13:39:05 2009 +0200
+++ b/absyntax_utils/search_base_type.hh Wed Sep 02 14:05:27 2009 +0200
@@ -34,6 +34,9 @@
* new_int_t is really an INT!!
* new_int2_t is also really an INT!!
* new_subr_t is also really an INT!!
+ *
+ * Note that a FB declaration is also considered a base type, as
+ * we may have FB instances declared of a specific FB type.
*/
@@ -53,6 +56,27 @@
bool type_is_enumerated(symbol_c* type_decl);
public:
+ /*********************/
+ /* 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
+ * numeric literal '30' must then be considered a LINT so the ADD function may be called
+ * with all inputs of the same data type.
+ * If 'x' were a SINT, then the '30' would have to be a SINT too!
+ */
+ void *visit(real_c *symbol);
+ void *visit(integer_c *symbol);
+ void *visit(binary_integer_c *symbol);
+ void *visit(octal_integer_c *symbol);
+ void *visit(hex_integer_c *symbol);
+
+
/***********************************/
/* B 1.3.1 - Elementary Data Types */
/***********************************/
@@ -77,8 +101,11 @@
void *visit(lword_type_name_c *symbol);
void *visit(string_type_name_c *symbol);
void *visit(wstring_type_name_c *symbol);
+
+/*
void *visit(constant_int_type_name_c *symbol);
void *visit(constant_real_type_name_c *symbol);
+*/
/******************************************************/
/* Extensions to the base standard as defined in */
@@ -162,6 +189,14 @@
string_type_declaration_init) // may be == NULL!
*/
void *visit(string_type_declaration_c *symbol);
+
+ /*****************************/
+ /* B 1.5.2 - Function Blocks */
+ /*****************************/
+ /* FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */
+ // SYM_REF3(function_block_declaration_c, fblock_name, var_declarations, fblock_body)
+ void *visit(function_block_declaration_c *symbol);
+
}; // search_base_type_c
--- a/absyntax_utils/search_constant_type.cc Wed Sep 02 13:39:05 2009 +0200
+++ b/absyntax_utils/search_constant_type.cc Wed Sep 02 14:05:27 2009 +0200
@@ -51,14 +51,19 @@
/******************************/
/* B 1.2.1 - Numeric Literals */
/******************************/
-void *search_constant_type_c::visit(real_c *symbol) {return (void *)&constant_real_type_name;}
-void *search_constant_type_c::visit(integer_c *symbol) {return (void *)&constant_int_type_name;}
-void *search_constant_type_c::visit(binary_integer_c *symbol) {return (void *)&constant_int_type_name;}
-void *search_constant_type_c::visit(octal_integer_c *symbol) {return (void *)&constant_int_type_name;}
-void *search_constant_type_c::visit(hex_integer_c *symbol) {return (void *)&constant_int_type_name;}
+/* 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
+ * numeric literal '30' must then be considered a LINT so the ADD function may be called
+ * with all inputs of the same data type.
+ * If 'x' were a SINT, then the '30' would have to be a SINT too!
+ */
+void *search_constant_type_c::visit(real_c *symbol) {return (void *)symbol;}
+void *search_constant_type_c::visit(integer_c *symbol) {return (void *)symbol;}
+void *search_constant_type_c::visit(binary_integer_c *symbol) {return (void *)symbol;}
+void *search_constant_type_c::visit(octal_integer_c *symbol) {return (void *)symbol;}
+void *search_constant_type_c::visit(hex_integer_c *symbol) {return (void *)symbol;}
-void *search_constant_type_c::visit(numeric_literal_c *symbol)
- {return (void *)((symbol->type!=NULL)?symbol->type:symbol->value->accept(*this));}
void *search_constant_type_c::visit(integer_literal_c *symbol)
{return (void *)((symbol->type!=NULL)?symbol->type:symbol->value->accept(*this));}
void *search_constant_type_c::visit(real_literal_c *symbol)
@@ -68,6 +73,10 @@
void *search_constant_type_c::visit(boolean_literal_c *symbol)
{return (void *)((symbol->type!=NULL)?symbol->type:symbol->value->accept(*this));}
+void *search_constant_type_c::visit(boolean_true_c *symbol) {return (void *)symbol;}
+void *search_constant_type_c::visit(boolean_false_c *symbol) {return (void *)symbol;}
+
+
/*******************************/
/* B.1.2.2 Character Strings */
/*******************************/
@@ -103,22 +112,27 @@
lint_type_name_c search_constant_type_c::lint_type_name;
dint_type_name_c search_constant_type_c::dint_type_name;
date_type_name_c search_constant_type_c::date_type_name;
-dword_type_name_c search_constant_type_c::dword_type_name;
-dt_type_name_c search_constant_type_c::dt_type_name;
-tod_type_name_c search_constant_type_c::tod_type_name;
-udint_type_name_c search_constant_type_c::udint_type_name;
+dword_type_name_c search_constant_type_c::dword_type_name;
+dt_type_name_c search_constant_type_c::dt_type_name;
+tod_type_name_c search_constant_type_c::tod_type_name;
+udint_type_name_c search_constant_type_c::udint_type_name;
word_type_name_c search_constant_type_c::word_type_name;
-wstring_type_name_c search_constant_type_c::wstring_type_name;
-string_type_name_c search_constant_type_c::string_type_name;
-lword_type_name_c search_constant_type_c::lword_type_name;
+wstring_type_name_c search_constant_type_c::wstring_type_name;
+string_type_name_c search_constant_type_c::string_type_name;
+lword_type_name_c search_constant_type_c::lword_type_name;
uint_type_name_c search_constant_type_c::uint_type_name;
-lreal_type_name_c search_constant_type_c::lreal_type_name;
+lreal_type_name_c search_constant_type_c::lreal_type_name;
byte_type_name_c search_constant_type_c::byte_type_name;
-usint_type_name_c search_constant_type_c::usint_type_name;
-ulint_type_name_c search_constant_type_c::ulint_type_name;
+usint_type_name_c search_constant_type_c::usint_type_name;
+ulint_type_name_c search_constant_type_c::ulint_type_name;
bool_type_name_c search_constant_type_c::bool_type_name;
time_type_name_c search_constant_type_c::time_type_name;
-int_type_name_c search_constant_type_c::int_type_name;
+int_type_name_c search_constant_type_c::int_type_name;
+/*
constant_real_type_name_c search_constant_type_c::constant_real_type_name;
constant_int_type_name_c search_constant_type_c::constant_int_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");
--- a/absyntax_utils/search_constant_type.hh Wed Sep 02 13:39:05 2009 +0200
+++ b/absyntax_utils/search_constant_type.hh Wed Sep 02 14:05:27 2009 +0200
@@ -67,8 +67,12 @@
static time_type_name_c time_type_name;
static int_type_name_c int_type_name;
+/*
static constant_real_type_name_c constant_real_type_name;
static constant_int_type_name_c constant_int_type_name;
+*/
+/* temporarily here until we remove the st_code_gen.c and il_code_gen.c files... */
+ static integer_c integer;
/******************************************************/
/* Extensions to the base standard as defined in */
@@ -98,12 +102,14 @@
void *visit(octal_integer_c *symbol);
void *visit(hex_integer_c *symbol);
- void *visit(numeric_literal_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 */
/*******************************/
--- a/absyntax_utils/search_expression_type.cc Wed Sep 02 13:39:05 2009 +0200
+++ b/absyntax_utils/search_expression_type.cc Wed Sep 02 14:05:27 2009 +0200
@@ -65,32 +65,48 @@
/* A helper function... */
bool search_expression_type_c::is_string_type(symbol_c *type_symbol) {
if (type_symbol == NULL) {return true;}
- if (typeid(*type_symbol) == typeid(string_type_name_c)) {return true;}
+ 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 search_expression_type_c::is_literal_integer_type(symbol_c *type_symbol) {
+ if (type_symbol == NULL) {return true;}
+ 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 search_expression_type_c::is_integer_type(symbol_c *type_symbol) {
if (type_symbol == NULL) {return true;}
- 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(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(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;}
- if (typeid(*type_symbol) == typeid(constant_int_type_name_c)) {return true;}
- return false;
-}
-
+ return is_literal_integer_type(type_symbol);
+}
+
+/* A helper function... */
+bool search_expression_type_c::is_literal_real_type(symbol_c *type_symbol) {
+ if (type_symbol == NULL) {return true;}
+ if (typeid(*type_symbol) == typeid(real_c)) {return true;}
+ return false;
+}
+
+/* A helper function... */
bool search_expression_type_c::is_real_type(symbol_c *type_symbol) {
if (type_symbol == NULL) {return true;}
if (typeid(*type_symbol) == typeid(real_type_name_c)) {return true;}
if (typeid(*type_symbol) == typeid(lreal_type_name_c)) {return true;}
- if (typeid(*type_symbol) == typeid(constant_real_type_name_c)) {return true;}
- return false;
+ return is_literal_real_type(type_symbol);
}
bool search_expression_type_c::is_num_type(symbol_c *type_symbol) {
@@ -104,8 +120,7 @@
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;}
- if (typeid(*type_symbol) == typeid(constant_int_type_name_c)) {return true;}
- return false;
+ return is_literal_integer_type(type_symbol);
}
bool search_expression_type_c::is_binary_type(symbol_c *type_symbol) {
@@ -117,12 +132,12 @@
bool search_expression_type_c::is_same_type(symbol_c *first_type, symbol_c *second_type) {
if (first_type == NULL || second_type == NULL) {return true;}
if (typeid(*first_type) == typeid(*second_type)) {return true;}
- if (is_integer_type(first_type) && (typeid(*second_type) == typeid(constant_int_type_name_c))) {return true;}
- if ((typeid(*first_type) == typeid(constant_int_type_name_c) && is_integer_type(second_type))) {return true;}
- if (is_binary_type(first_type) && (typeid(*second_type) == typeid(constant_int_type_name_c))) {return true;}
- if ((typeid(*first_type) == typeid(constant_int_type_name_c) && is_binary_type(second_type))) {return true;}
- if (is_real_type(first_type) && (typeid(*second_type) == typeid(constant_real_type_name_c))) {return true;}
- if ((typeid(*first_type) == typeid(constant_real_type_name_c) && is_real_type(second_type))) {return true;}
+ if (is_integer_type(first_type) && is_literal_integer_type(second_type)) {return true;}
+ if (is_literal_integer_type(first_type) && is_integer_type(second_type)) {return true;}
+ if (is_binary_type(first_type) && is_literal_integer_type(second_type)) {return true;}
+ if (is_literal_integer_type(first_type) && is_binary_type(second_type)) {return true;}
+ if (is_real_type(first_type) && is_literal_real_type(second_type)) {return true;}
+ if (is_literal_real_type(first_type) && is_real_type(second_type)) {return true;}
return false;
}
@@ -131,18 +146,28 @@
if (first_type == NULL) {return second_type;}
if (second_type == NULL) {return first_type;}
if (typeid(*first_type) == typeid(*second_type)) {return first_type;}
- if (is_integer_type(first_type) && (typeid(*second_type) == typeid(constant_int_type_name_c))) {return first_type;}
- if ((typeid(*first_type) == typeid(constant_int_type_name_c)) && is_integer_type(second_type)) {return second_type;}
- if (is_binary_type(first_type) && (typeid(*second_type) == typeid(constant_int_type_name_c))) {return first_type;}
- if ((typeid(*first_type) == typeid(constant_int_type_name_c)) && is_binary_type(second_type)) {return second_type;}
- if (is_real_type(first_type) && (typeid(*second_type) == typeid(constant_real_type_name_c))) {return first_type;}
- if ((typeid(*first_type) == typeid(constant_real_type_name_c)) && is_real_type(second_type)) {return second_type;}
- return NULL;
-}
-
+ if (is_integer_type(first_type) && is_literal_integer_type(second_type)) {return first_type;}
+ if (is_literal_integer_type(first_type) && is_integer_type(second_type)) {return second_type;}
+ if (is_binary_type(first_type) && is_literal_integer_type(second_type)) {return first_type;}
+ if (is_literal_integer_type(first_type) && is_binary_type(second_type)) {return second_type;}
+ if (is_real_type(first_type) && is_literal_real_type(second_type)) {return first_type;}
+ if (is_literal_real_type(first_type) && is_real_type(second_type)) {return second_type;}
+ return NULL;
+}
+
+
+integer_c search_expression_type_c::integer("1"); // what default value should we use here ???
#define compute_standard_function_default search_expression_type_c::compute_standard_function_default
#define compute_standard_function_il search_expression_type_c::compute_standard_function_il
+#define search(x) search_f(x)
+#define next() next_nf()
+// #define search_constant_type_c::constant_int_type_name search_expression_type_c::integer
+#define constant_int_type_name integer
#include "search_type_code.c"
+#undef constant_int_type_name
+// #undef search_constant_type_c::constant_int_type_name
+#undef next
+#undef search
#undef compute_standard_function_default
#undef compute_standard_function_il
@@ -154,7 +179,7 @@
ERROR;
if (!is_bool_type(left_type) && !is_binary_type(left_type))
ERROR;
- if (typeid(*left_type) == typeid(constant_int_type_name_c)) {return (void *)right_type;}
+ if (is_literal_integer_type(left_type)) {return (void *)right_type;}
else {return (void *)left_type;}
}
@@ -164,7 +189,7 @@
ERROR;
if (!is_integer_type(left_type) && !is_real_type(left_type))
ERROR;
- if ((typeid(*left_type) == typeid(constant_int_type_name_c)) || (typeid(*left_type) == typeid(constant_real_type_name_c))) {return (void *)right_type;}
+ if (is_literal_integer_type(left_type) || is_literal_real_type(left_type)) {return (void *)right_type;}
else {return (void *)left_type;}
return NULL;
}
--- a/absyntax_utils/search_expression_type.hh Wed Sep 02 13:39:05 2009 +0200
+++ b/absyntax_utils/search_expression_type.hh Wed Sep 02 14:05:27 2009 +0200
@@ -46,7 +46,9 @@
bool is_bool_type(symbol_c *type_symbol);
bool is_time_type(symbol_c *type_symbol);
bool is_string_type(symbol_c *type_symbol);
+ bool is_literal_integer_type(symbol_c *type_symbol);
bool is_integer_type(symbol_c *type_symbol);
+ bool is_literal_real_type(symbol_c *type_symbol);
bool is_real_type(symbol_c *type_symbol);
bool is_num_type(symbol_c *type_symbol);
bool is_nbinary_type(symbol_c *type_symbol);
@@ -59,9 +61,6 @@
#include "search_type_code.c"
*/
void *compute_standard_function_default(function_invocation_c *st_symbol, il_formal_funct_call_c *il_symbol);
- /*
- void *compute_standard_function_default(function_invocation_c *st_symbol = NULL, il_formal_funct_call_c *il_symbol = NULL);
- */
void *compute_standard_function_il(il_function_call_c *symbol, symbol_c *param_data_type);
@@ -120,7 +119,11 @@
void *visit(neg_expression_c *symbol);
void *visit(not_expression_c *symbol);
void *visit(function_invocation_c *symbol);
+
+
+ static integer_c integer;
+
}; // search_expression_type_c
-/*bool_type_name_c search_expression_type_c::bool_type_name;*/
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/absyntax_utils/search_il_operand_type.cc Wed Sep 02 14:05:27 2009 +0200
@@ -0,0 +1,58 @@
+/*
+ * (c) 2003 Mario de Sousa
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * 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 IL and ST compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ */
+
+
+
+
+/* Returns the data type of an il_operand.
+ *
+ * Note that the il_operand may be a variable, in which case
+ * we return the type of the variable instance.
+ * The il_operand may also be a constant, in which case
+ * we return the data type of that constant.
+ *
+ * The variable instance may be a member of a structured variable,
+ * or an element in an array, or any combination of the two.
+ *
+ * The class constructor must be given the search scope
+ * (function, function block or program within which
+ * the possible il_operand variable instance was declared).
+ */
+
+#include "absyntax_utils.hh"
+
+symbol_c *search_il_operand_type_c::get_type(symbol_c *il_operand) {
+ symbol_c *res;
+
+ /* We first assume that it is a constant... */
+ res = search_constant_type.get_type(il_operand);
+ if (res != NULL) return res;
+
+ /* Nope, now we assume it is a variable, and determine its type... */
+ res = search_varfb_instance_type.get_type(il_operand);
+ if (NULL != res) return res;
+
+ /* not found */
+ return NULL;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/absyntax_utils/search_il_operand_type.hh Wed Sep 02 14:05:27 2009 +0200
@@ -0,0 +1,51 @@
+/*
+ * (c) 2003 Mario de Sousa
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * 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 IL and ST compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ */
+
+/* Returns the data type of an il_operand.
+ *
+ * Note that the il_operand may be a variable, in which case
+ * we return the type of the variable instance.
+ * The il_operand may also be a constant, in which case
+ * we return the data type of that constant.
+ *
+ * The variable instance may be a member of a structured variable,
+ * or an element in an array, or any combination of the two.
+ *
+ * The class constructor must be given the search scope
+ * (function, function block or program within which
+ * the possible il_operand variable instance was declared).
+ */
+
+class search_il_operand_type_c {
+
+ private:
+ search_varfb_instance_type_c::search_varfb_instance_type_c search_varfb_instance_type;
+ search_constant_type_c search_constant_type;
+
+ public:
+ search_il_operand_type_c(symbol_c *search_scope): search_varfb_instance_type(search_scope) {}
+
+ public:
+ symbol_c *get_type(symbol_c *il_operand);
+};
--- a/absyntax_utils/search_var_instance_decl.cc Wed Sep 02 13:39:05 2009 +0200
+++ b/absyntax_utils/search_var_instance_decl.cc Wed Sep 02 14:05:27 2009 +0200
@@ -121,6 +121,14 @@
return res;
}
+/* ENO : BOOL */
+void *search_var_instance_decl_c::visit(eno_param_declaration_c *symbol) {
+ if (compare_identifiers(symbol->name, search_name) == 0)
+ return symbol->type;
+ return NULL;
+}
+
+
/* VAR [CONSTANT] var_init_decl_list END_VAR */
/* option -> may be NULL ! */
/* helper symbol for input_declarations */
--- a/absyntax_utils/search_var_instance_decl.hh Wed Sep 02 13:39:05 2009 +0200
+++ b/absyntax_utils/search_var_instance_decl.hh Wed Sep 02 14:05:27 2009 +0200
@@ -102,6 +102,8 @@
void *visit(output_declarations_c *symbol);
/* VAR_IN_OUT var_declaration_list END_VAR */
void *visit(input_output_declarations_c *symbol);
+ /* ENO : BOOL */
+ void *visit(eno_param_declaration_c *symbol);
/* VAR [CONSTANT] var_init_decl_list END_VAR */
/* option -> may be NULL ! */
/* helper symbol for input_declarations */
--- a/absyntax_utils/search_varfb_instance_type.cc Wed Sep 02 13:39:05 2009 +0200
+++ b/absyntax_utils/search_varfb_instance_type.cc Wed Sep 02 14:05:27 2009 +0200
@@ -46,6 +46,10 @@
*/
+/*
+ * 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"
@@ -67,7 +71,7 @@
*/
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) {
--- a/main.cc Wed Sep 02 13:39:05 2009 +0200
+++ b/main.cc Wed Sep 02 14:05:27 2009 +0200
@@ -81,7 +81,7 @@
#include "stage1_2/stage1_2.hh"
#include "absyntax_utils/absyntax_utils.hh"
-//int stage3(symbol_c *tree_root);
+int stage3(symbol_c *tree_root);
int stage4(symbol_c *tree_root, const char *builddir);
@@ -172,11 +172,12 @@
/* 2nd Pass */
absyntax_utils_init(tree_root);
+ add_en_eno_param_decl_c::add_to(tree_root);
+
/* not yet implemented... */
- /*
if (stage3(tree_root) < 0)
return EXIT_FAILURE;
- */
+
/* 3rd Pass */
if (stage4(tree_root, builddir) < 0)
--- a/stage1_2/iec.y Wed Sep 02 13:39:05 2009 +0200
+++ b/stage1_2/iec.y Wed Sep 02 14:05:27 2009 +0200
@@ -167,7 +167,9 @@
symbol_c *il_operator_c_2_identifier_c(symbol_c *il_operator);
/* return if current token is a syntax element */
+/* ERROR_CHECK_BEGIN */
bool is_current_syntax_token();
+/* ERROR_CHECK_END */
/* print an error message */
void print_err_msg(int first_line,
@@ -211,9 +213,9 @@
-/*****************************/
-/* Prelimenary constructs... */
-/*****************************/
+/*************************************/
+/* Prelimenary helpful constructs... */
+/*************************************/
/* A token used to identify the very end of the input file
* after all includes have already been processed.
*
@@ -277,17 +279,27 @@
+/**********************************************************************************/
+/* B XXX - Things that are missing from the standard, but should have been there! */
+/**********************************************************************************/
+
+
/* The pragmas... */
%token <ID> pragma_token
%type <leaf> pragma
-/* Where do these tokens belong ?? */
-/* TODO: get the syntax parser to handle these tokens... */
+/* Where do these tokens belong?? They are missing from the standard! */
+/* NOTE: There are other tokens related to these 'EN' ENO', that are also
+ * missing from the standard. However, their location in the annex B is
+ * relatively obvious, so they have been inserted in what seems to us their
+ * correct place in order to ease understanding of the parser...
+ */
%token EN
%token ENO
-%type <leaf> en_param
-%type <leaf> eno_param
+%type <leaf> en_identifier
+%type <leaf> eno_identifier
+
@@ -669,6 +681,7 @@
%type <list> input_declaration_list
%type <leaf> input_declaration
%type <leaf> edge_declaration
+/* en_param_declaration is not in the standard, but should be! */
%type <leaf> en_param_declaration
%type <leaf> var_init_decl
%type <leaf> var1_init_decl
@@ -685,6 +698,7 @@
%type <leaf> output_declarations
%type <leaf> var_output_init_decl
%type <list> var_output_init_decl_list
+/* eno_param_declaration is not in the standard, but should be! */
%type <leaf> eno_param_declaration
%type <leaf> input_output_declarations
/* helper symbol for input_output_declarations */
@@ -1321,30 +1335,38 @@
/********************************************************/
-
-
-
-/*****************************/
-/* Prelimenary constructs... */
-/*****************************/
start:
library {$$ = $1;}
;
+
+/**********************************************************************************/
+/* B XXX - Things that are missing from the standard, but should have been there! */
+/**********************************************************************************/
+
+
/* the pragmas... */
pragma:
pragma_token {$$ = new pragma_c($1, locloc(@$));}
+
/* EN/ENO */
-en_param:
- EN {$$ = new en_param_c(locloc(@$));}
-;
-
-eno_param:
- ENO {$$ = new eno_param_c(locloc(@$));}
-;
-
-
+/* Tese tokens are essentially used as variable names, so we handle them
+ * similarly to these...
+ */
+en_identifier:
+ EN {$$ = new identifier_c("EN", locloc(@$));}
+;
+
+eno_identifier:
+ ENO {$$ = new identifier_c("ENO", locloc(@$));}
+;
+
+
+
+/*************************************/
+/* Prelimenary helpful constructs... */
+/*************************************/
/* NOTE:
* short version:
@@ -2997,10 +3019,26 @@
/*********************/
/* B 1.4 - Variables */
/*********************/
+/* NOTE: The standard is erroneous in it's definition of 'variable' because:
+ * - The standard considers 'ENO' as a keyword...
+ * - ...which means that it may never be parsed as an 'identifier'...
+ * - ...and therefore may never be used as the name of a variable inside an expression.
+ * - However, a function/FB must be able to assign the ENO parameter
+ * it's value, doing it in an assignment statement, and therefore using the 'ENO'
+ * character sequence as an identifier!
+ * The solution we found was to also allow the ENO keyword to be
+ * used as the name of a variable. Note that this variable may be used
+ * even though it is not explicitly declared as a function/FB variable,
+ * as the standard requires us to define it implicitly in this case!
+ * We could not therefore handle the ENO as a normal variable that would
+ * go into the previously_declared_variable symbol table, as we may need to
+ * allow it to be used as a variable even though it is not declared as such!
+ */
variable:
symbolic_variable
| prev_declared_direct_variable
-| eno_param
+| eno_identifier
+ {$$ = new symbolic_variable_c($1, locloc(@$));}
;
@@ -3140,11 +3178,11 @@
/******************************************/
input_declarations:
VAR_INPUT input_declaration_list END_VAR
- {$$ = new input_declarations_c(NULL, $2, locloc(@$));}
+ {$$ = new input_declarations_c(NULL, $2, new explicit_definition_c(), locloc(@$));}
| VAR_INPUT RETAIN input_declaration_list END_VAR
- {$$ = new input_declarations_c(new retain_option_c(locloc(@2)), $3, locloc(@$));}
+ {$$ = new input_declarations_c(new retain_option_c(locloc(@2)), $3, new explicit_definition_c(), locloc(@$));}
| VAR_INPUT NON_RETAIN input_declaration_list END_VAR
- {$$ = new input_declarations_c(new non_retain_option_c(locloc(@2)), $3, locloc(@$));}
+ {$$ = new input_declarations_c(new non_retain_option_c(locloc(@2)), $3, new explicit_definition_c(), locloc(@$));}
/* ERROR_CHECK_BEGIN */
| VAR_INPUT END_VAR
{$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in input variable(s) declaration."); yynerrs++;}
@@ -3194,6 +3232,11 @@
;
+/* NOTE: The formal definition of 'input_declaration' as defined in the standard is erroneous,
+ * as it does not allow a user defined 'EN' input parameter. However,
+ * The semantic description of the languages clearly states that this is allowed.
+ * We have added the 'en_param_declaration' clause to cover for this.
+ */
input_declaration:
var_init_decl
| edge_declaration
@@ -3212,7 +3255,9 @@
| var1_list BOOL F_EDGE
{$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in edge declaration."); yynerrs++;}
| var1_list ':' BOOL R_EDGE F_EDGE
- {$$ = NULL; print_err_msg(locf(@5), locl(@5), "'R_EDGE' and 'F_EDGE' can't be present at the same time in edge declaration."); yynerrs++;}
+ {$$ = NULL; print_err_msg(locl(@5), locf(@5), "'R_EDGE' and 'F_EDGE' can't be present at the same time in edge declaration."); yynerrs++;}
+| var1_list ':' BOOL F_EDGE R_EDGE
+ {$$ = NULL; print_err_msg(locl(@5), locf(@5), "'R_EDGE' and 'F_EDGE' can't be present at the same time in edge declaration."); yynerrs++;}
| var1_list ':' R_EDGE
{$$ = NULL; print_err_msg(locl(@2), locf(@3), "'BOOL' missing in edge declaration."); yynerrs++;}
| var1_list ':' F_EDGE
@@ -3220,21 +3265,28 @@
/* ERROR_CHECK_END */
;
+
+/* NOTE: The formal definition of the standard is erroneous, as it simply does not
+ * consider the EN and ENO keywords!
+ * The semantic description of the languages clearly states that these may be
+ * used in several ways. One of them is to declare an EN input parameter.
+ * We have added the 'en_param_declaration' clause to cover for this.
+ */
en_param_declaration:
- en_param ':' BOOL ASSIGN boolean_literal
- {$$ = new en_param_declaration_c(locloc(@$));}
-| en_param ':' BOOL ASSIGN integer
- {$$ = new en_param_declaration_c(locloc(@$));}
-/* ERROR_CHECK_BEGIN */
-| en_param BOOL ASSIGN boolean_literal
+ en_identifier ':' BOOL ASSIGN boolean_literal
+ {$$ = new en_param_declaration_c($1, new bool_type_name_c(locloc(@$)), $5, new explicit_definition_c(), locloc(@$));}
+| en_identifier ':' BOOL ASSIGN integer
+ {$$ = new en_param_declaration_c($1, new bool_type_name_c(locloc(@$)), $5, new explicit_definition_c(), locloc(@$));}
+/* ERROR_CHECK_BEGIN */
+| en_identifier BOOL ASSIGN boolean_literal
{$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in EN declaration."); yynerrs++;}
-| en_param BOOL ASSIGN integer
+| en_identifier BOOL ASSIGN integer
{$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in EN declaration."); yynerrs++;}
-| en_param ':' ASSIGN boolean_literal
+| en_identifier ':' ASSIGN boolean_literal
{$$ = NULL; print_err_msg(locl(@2), locf(@3), "'BOOL' missing in EN declaration."); yynerrs++;}
-| en_param ':' ASSIGN integer
+| en_identifier ':' ASSIGN integer
{$$ = NULL; print_err_msg(locl(@2), locf(@3), "'BOOL' missing in EN declaration."); yynerrs++;}
-| en_param ':' BOOL ASSIGN error
+| en_identifier ':' BOOL ASSIGN error
{$$ = NULL;
if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in EN declaration.");}
else {print_err_msg(locf(@3), locl(@3), "invalid specification in EN declaration."); yyclearin;}
@@ -3402,11 +3454,11 @@
output_declarations:
VAR_OUTPUT var_output_init_decl_list END_VAR
- {$$ = new output_declarations_c(NULL, $2, locloc(@$));}
+ {$$ = new output_declarations_c(NULL, $2, new explicit_definition_c(), locloc(@$));}
| VAR_OUTPUT RETAIN var_output_init_decl_list END_VAR
- {$$ = new output_declarations_c(new retain_option_c(locloc(@2)), $3, locloc(@$));}
+ {$$ = new output_declarations_c(new retain_option_c(locloc(@2)), $3, new explicit_definition_c(), locloc(@$));}
| VAR_OUTPUT NON_RETAIN var_output_init_decl_list END_VAR
- {$$ = new output_declarations_c(new non_retain_option_c(locloc(@2)), $3, locloc(@$));}
+ {$$ = new output_declarations_c(new non_retain_option_c(locloc(@2)), $3, new explicit_definition_c(), locloc(@$));}
/* ERROR_CHECK_BEGIN */
| VAR_OUTPUT END_VAR
{$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in output variable(s) declaration."); yynerrs++;}
@@ -3435,6 +3487,12 @@
/* ERROR_CHECK_END */
;
+
+/* NOTE: The formal definition of 'var_output_init_decl' as defined in the standard is erroneous,
+ * as it does not allow a user defined 'ENO' output parameter. However,
+ * The semantic description of the languages clearly states that this is allowed.
+ * We have added the 'eno_param_declaration' clause to cover for this.
+ */
var_output_init_decl:
var_init_decl
| eno_param_declaration
@@ -3453,13 +3511,23 @@
/* ERROR_CHECK_END */
;
+
+/* NOTE: The formal definition of the standard is erroneous, as it simply does not
+ * consider the EN and ENO keywords!
+ * The semantic description of the languages clearly states that these may be
+ * used in several ways. One of them is to declare an ENO output parameter.
+ * We have added the 'eno_param_declaration' clause to cover for this.
+ */
eno_param_declaration:
- eno_param ':' BOOL
- {$$ = new eno_param_declaration_c(locloc(@$));}
-/* ERROR_CHECK_BEGIN */
-| en_param BOOL
- {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in EN0 declaration."); yynerrs++;}
-| en_param ':' error
+ eno_identifier ':' BOOL
+ /* NOTE We do _NOT_ include this variable in the previously_declared_variable symbol table!
+ * Please read the comment above the definition of 'variable' for the reason for this.
+ */
+ {$$ = new eno_param_declaration_c($1, new bool_type_name_c(locloc(@$)), new explicit_definition_c(), locloc(@$));}
+/* ERROR_CHECK_BEGIN */
+| en_identifier BOOL
+ {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in ENO declaration."); yynerrs++;}
+| en_identifier ':' error
{$$ = NULL;
if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in ENO declaration.");}
else {print_err_msg(locf(@3), locl(@3), "invalid specification in ENO declaration."); yyclearin;}
@@ -6509,7 +6577,7 @@
/* variable_name ASSIGN */
any_identifier ASSIGN
{$$ = new il_assign_operator_c($1, locloc(@$));}
-| en_param ASSIGN
+| en_identifier ASSIGN
{$$ = new il_assign_operator_c($1, locloc(@$));}
/* ERROR_CHECK_BEGIN */
| error ASSIGN
@@ -6523,12 +6591,12 @@
/* any_identifier SENDTO */
sendto_identifier SENDTO
{$$ = new il_assign_out_operator_c(NULL, $1, locloc(@$));}
-| eno_param SENDTO
+| eno_identifier SENDTO
{$$ = new il_assign_out_operator_c(NULL, $1, locloc(@$));}
/*| NOT variable_name SENDTO */
| NOT sendto_identifier SENDTO
{$$ = new il_assign_out_operator_c(new not_paramassign_c(locloc(@1)), $2, locloc(@$));}
-| NOT eno_param SENDTO
+| NOT eno_identifier SENDTO
{$$ = new il_assign_out_operator_c(new not_paramassign_c(locloc(@1)), $2, locloc(@$));}
/* ERROR_CHECK_BEGIN */
| error SENDTO
@@ -6864,9 +6932,9 @@
function_invocation:
/* function_name '(' [param_assignment_list] ')' */
function_name_no_NOT_clashes '(' param_assignment_formal_list ')'
- {$$ = new function_invocation_c($1, $3, locloc(@$));}
+ {$$ = new function_invocation_c($1, $3, NULL, locloc(@$));}
| function_name_no_NOT_clashes '(' param_assignment_nonformal_list ')'
- {$$ = new function_invocation_c($1, $3, locloc(@$));}
+ {$$ = new function_invocation_c($1, NULL, $3, locloc(@$));}
/* ERROR_CHECK_BEGIN */
| function_name_no_NOT_clashes param_assignment_formal_list ')'
{$$ = NULL; print_err_msg(locl(@1), locf(@2), "'(' missing after function name in ST expression."); yynerrs++;}
@@ -6952,11 +7020,11 @@
fb_invocation:
prev_declared_fb_name '(' ')'
- {$$ = new fb_invocation_c($1, NULL, locloc(@$)); }
+ {$$ = new fb_invocation_c($1, NULL, NULL, locloc(@$)); }
| prev_declared_fb_name '(' param_assignment_formal_list ')'
- {$$ = new fb_invocation_c($1, $3, locloc(@$));}
+ {$$ = new fb_invocation_c($1, $3, NULL, locloc(@$));}
| prev_declared_fb_name '(' param_assignment_nonformal_list ')'
- {$$ = new fb_invocation_c($1, $3, locloc(@$));}
+ {$$ = new fb_invocation_c($1, NULL, $3, locloc(@$));}
/* ERROR_CHECK_BEGIN */
| prev_declared_fb_name ')'
{$$ = NULL; print_err_msg(locl(@1), locf(@2), "'(' missing after function block name in ST statement."); yynerrs++;}
@@ -7048,19 +7116,19 @@
param_assignment_formal:
any_identifier ASSIGN expression
{$$ = new input_variable_param_assignment_c($1, $3, locloc(@$));}
-| en_param ASSIGN expression
+| en_identifier ASSIGN expression
{$$ = new input_variable_param_assignment_c($1, $3, locloc(@$));}
/*| variable_name SENDTO variable */
/*| any_identifier SENDTO variable */
| sendto_identifier SENDTO variable
{$$ = new output_variable_param_assignment_c(NULL, $1, $3, locloc(@$));}
-| eno_param SENDTO variable
+| eno_identifier SENDTO variable
{$$ = new output_variable_param_assignment_c(NULL, $1, $3, locloc(@$));}
/*| NOT variable_name SENDTO variable */
/*| NOT any_identifier SENDTO variable*/
| NOT sendto_identifier SENDTO variable
{$$ = new output_variable_param_assignment_c(new not_paramassign_c(locloc(@$)), $2, $4, locloc(@$));}
-| NOT eno_param SENDTO variable
+| NOT eno_identifier SENDTO variable
{$$ = new output_variable_param_assignment_c(new not_paramassign_c(locloc(@$)), $2, $4, locloc(@$));}
/* ERROR_CHECK_BEGIN */
| any_identifier ASSIGN error
@@ -7069,7 +7137,7 @@
else {print_err_msg(locf(@3), locl(@3), "invalid expression in ST formal parameter assignment."); yyclearin;}
yyerrok;
}
-| en_param ASSIGN error
+| en_identifier ASSIGN error
{$$ = NULL;
if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined in ST formal parameter assignment.");}
else {print_err_msg(locf(@3), locl(@3), "invalid expression in ST formal parameter assignment."); yyclearin;}
@@ -7081,7 +7149,7 @@
else {print_err_msg(locf(@3), locl(@3), "invalid expression in ST formal parameter out assignment."); yyclearin;}
yyerrok;
}
-| eno_param SENDTO error
+| eno_identifier SENDTO error
{$$ = NULL;
if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined in ST formal parameter out assignment.");}
else {print_err_msg(locf(@3), locl(@3), "invalid expression in ST formal parameter out assignment."); yyclearin;}
@@ -7097,7 +7165,7 @@
else {print_err_msg(locf(@4), locl(@4), "invalid expression in ST formal parameter out negated assignment."); yyclearin;}
yyerrok;
}
-| NOT eno_param SENDTO error
+| NOT eno_identifier SENDTO error
{$$ = NULL;
if (is_current_syntax_token()) {print_err_msg(locl(@3), locf(@4), "no expression defined in ST formal parameter out negated assignment.");}
else {print_err_msg(locf(@4), locl(@4), "invalid expression in ST formal parameter out negated assignment."); yyclearin;}
@@ -7358,7 +7426,9 @@
* If we don't, then the correct use of any previosuly declared
* variable would result in an incorrect syntax error
*/
-control_variable: prev_declared_variable_name {$$ = $1;};
+control_variable:
+ prev_declared_variable_name
+ {$$ = new symbolic_variable_c($1,locloc(@$));};
// control_variable: identifier {$$ = $1;};
/* Integrated directly into for_statement */
@@ -7481,35 +7551,38 @@
}
+/* ERROR_CHECK_BEGIN */
bool is_current_syntax_token() {
- switch (yychar) {
- case ';':
- case ',':
- case ')':
- case ']':
- case '+':
- case '*':
- case '-':
- case '/':
- case '<':
- case '>':
- case '=':
- case '&':
- case OR:
- case XOR:
- case AND:
- case AND2:
- case OPER_NE:
- case OPER_LE:
- case OPER_GE:
- case MOD:
- case OPER_EXP:
- case NOT:
- return true;
- default:
- return false;
- }
+ switch (yychar) {
+ case ';':
+ case ',':
+ case ')':
+ case ']':
+ case '+':
+ case '*':
+ case '-':
+ case '/':
+ case '<':
+ case '>':
+ case '=':
+ case '&':
+ case OR:
+ case XOR:
+ case AND:
+ case AND2:
+ case OPER_NE:
+ case OPER_LE:
+ case OPER_GE:
+ case MOD:
+ case OPER_EXP:
+ case NOT:
+ return true;
+ default:
+ return false;
+ }
}
+/* ERROR_CHECK_END */
+
void print_err_msg(int first_line,
int first_column,
@@ -7544,64 +7617,64 @@
const char *name = NULL;
identifier_c *res;
- op_2_str(NOT, "NOT");
-
- op_2_str(AND, "AND");
- op_2_str(OR, "OR");
- op_2_str(XOR, "XOR");
- op_2_str(ADD, "ADD");
- op_2_str(SUB, "SUB");
- op_2_str(MUL, "MUL");
- op_2_str(DIV, "DIV");
- op_2_str(MOD, "MOD");
- op_2_str(GT, "GT");
- op_2_str(GE, "GE");
- op_2_str(EQ, "EQ");
- op_2_str(LT, "LT");
- op_2_str(LE, "LE");
- op_2_str(NE, "NE");
-
- op_2_str(LD, "LD");
- op_2_str(LDN, "LDN");
- op_2_str(ST, "ST");
- op_2_str(STN, "STN");
-
- op_2_str(S, "S");
- op_2_str(R, "R");
- op_2_str(S1, "S1");
- op_2_str(R1, "R1");
-
- op_2_str(CLK, "CLK");
- op_2_str(CU, "CU");
- op_2_str(CD, "CD");
- op_2_str(PV, "PV");
- op_2_str(IN, "IN");
- op_2_str(PT, "PT");
-
- op_2_str(ANDN, "ANDN");
- op_2_str(ORN, "ORN");
- op_2_str(XORN, "XORN");
-
- op_2_str(ADD, "ADD");
- op_2_str(SUB, "SUB");
- op_2_str(MUL, "MUL");
- op_2_str(DIV, "DIV");
-
- op_2_str(GT, "GT");
- op_2_str(GE, "GE");
- op_2_str(EQ, "EQ");
- op_2_str(LT, "LT");
- op_2_str(LE, "LE");
- op_2_str(NE, "NE");
-
- op_2_str(CAL, "CAL");
- op_2_str(CALC, "CALC");
+ op_2_str(NOT, "NOT");
+
+ op_2_str(AND, "AND");
+ op_2_str(OR, "OR");
+ op_2_str(XOR, "XOR");
+ op_2_str(ADD, "ADD");
+ op_2_str(SUB, "SUB");
+ op_2_str(MUL, "MUL");
+ op_2_str(DIV, "DIV");
+ op_2_str(MOD, "MOD");
+ op_2_str(GT, "GT");
+ op_2_str(GE, "GE");
+ op_2_str(EQ, "EQ");
+ op_2_str(LT, "LT");
+ op_2_str(LE, "LE");
+ op_2_str(NE, "NE");
+
+ op_2_str(LD, "LD");
+ op_2_str(LDN, "LDN");
+ op_2_str(ST, "ST");
+ op_2_str(STN, "STN");
+
+ op_2_str(S, "S");
+ op_2_str(R, "R");
+ op_2_str(S1, "S1");
+ op_2_str(R1, "R1");
+
+ op_2_str(CLK, "CLK");
+ op_2_str(CU, "CU");
+ op_2_str(CD, "CD");
+ op_2_str(PV, "PV");
+ op_2_str(IN, "IN");
+ op_2_str(PT, "PT");
+
+ op_2_str(ANDN, "ANDN");
+ op_2_str(ORN, "ORN");
+ op_2_str(XORN, "XORN");
+
+ op_2_str(ADD, "ADD");
+ op_2_str(SUB, "SUB");
+ op_2_str(MUL, "MUL");
+ op_2_str(DIV, "DIV");
+
+ op_2_str(GT, "GT");
+ op_2_str(GE, "GE");
+ op_2_str(EQ, "EQ");
+ op_2_str(LT, "LT");
+ op_2_str(LE, "LE");
+ op_2_str(NE, "NE");
+
+ op_2_str(CAL, "CAL");
+ op_2_str(CALC, "CALC");
op_2_str(CALCN, "CALCN");
- op_2_str(RET, "RET");
- op_2_str(RETC, "RETC");
+ op_2_str(RET, "RET");
+ op_2_str(RETC, "RETC");
op_2_str(RETCN, "RETCN");
- op_2_str(JMP, "JMP");
- op_2_str(JMPC, "JMPC");
+ op_2_str(JMP, "JMP");
+ op_2_str(JMPC, "JMPC");
op_2_str(JMPCN, "JMPCN");
if (name == NULL)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/stage3/Makefile Wed Sep 02 14:05:27 2009 +0200
@@ -0,0 +1,28 @@
+# include the system specific Makefile
+include ../Makefile.$(shell uname)
+
+
+
+
+STAGE3_FILES = stage3.o
+STAGE3_FILES += visit_expression_type.o
+
+default: all
+
+all: $(STAGE3_FILES)
+
+
+
+clean:
+ rm -f *.o Makefile.depend
+
+
+CXXFLAGS += -I. -I../*
+
+
+
+Makefile.depend depend:
+ $(CXX) -MM -MG -I. *.cc > Makefile.depend
+ #| perl -pe 's/:/ Makefile.depend:/' > Makefile.depend
+
+include Makefile.depend
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/stage3/stage3.cc Wed Sep 02 14:05:27 2009 +0200
@@ -0,0 +1,37 @@
+/*
+ * (c) 20099 Catarina da Costa Boucinha
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * 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 IL and ST compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2009-04-24)
+ *
+ */
+
+#include "stage3.hh"
+
+int type_safety(symbol_c *tree_root){
+ visit_expression_type_c visit_expression_type(tree_root);
+
+ (*tree_root).accept(visit_expression_type);
+
+ return 0;
+}
+
+int stage3(symbol_c *tree_root){
+ return type_safety(tree_root);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/stage3/stage3.hh Wed Sep 02 14:05:27 2009 +0200
@@ -0,0 +1,42 @@
+/*
+ * (c) 2009 Catarina da Costa Boucinha
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * 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 IL and ST compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2009-04-24)
+ *
+ */
+
+
+// #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);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/stage3/visit_expression_type.cc Wed Sep 02 14:05:27 2009 +0200
@@ -0,0 +1,1676 @@
+/*
+ * (c) 2009 Mario de Sousa
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * 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 IL and ST 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_line < (symbol2)->first_line) ? (symbol1) : \
+ ((symbol1)->first_line > (symbol2)->first_line) ? (symbol2) : \
+ ((symbol1)->first_column < (symbol2)->first_column) ? (symbol1) : \
+ ((symbol1)->first_column > (symbol2)->first_column) ? (symbol2) : \
+ (symbol1))
+
+#define LAST_(symbol1, symbol2) (((symbol1)->last_line < (symbol2)->last_line) ? (symbol2) : \
+ ((symbol1)->last_line > (symbol2)->last_line) ? (symbol1) : \
+ ((symbol1)->last_column < (symbol2)->last_column) ? (symbol2) : \
+ ((symbol1)->last_column > (symbol2)->last_column) ? (symbol1) : \
+ (symbol1))
+
+#define STAGE3_ERROR(symbol1, symbol2, msg) { \
+ printf("semantic error between (%d:%d) and (%d:%d): %s\n", \
+ FIRST_(symbol1,symbol2)->first_line, FIRST_(symbol1,symbol2)->first_column, \
+ LAST_(symbol1,symbol2) ->last_line, LAST_(symbol1,symbol2) ->last_column, \
+ msg); \
+ il_error = true; \
+ }
+
+
+
+
+
+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);
+ 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;
+ 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);
+ 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;
+ 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);
+ 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;
+ return NULL;
+}
+
+
+
+
+
+
+
+
+
+visit_expression_type_c::visit_expression_type_c(symbol_c *search_scope) {
+}
+
+visit_expression_type_c::~visit_expression_type_c(void) {
+}
+
+
+/* A helper function... */
+bool visit_expression_type_c::is_ANY_ELEMENTARY_type(symbol_c *type_symbol) {
+ if (type_symbol == NULL) {ERROR;}
+ 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_MAGNITUDE_type(symbol_c *type_symbol) {
+ if (type_symbol == NULL) {ERROR;}
+ 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_NUM_type(symbol_c *type_symbol) {
+ if (type_symbol == NULL) {ERROR;}
+ return is_ANY_REAL_type(type_symbol) || is_ANY_INT_type(type_symbol);
+}
+
+
+/* A helper function... */
+bool visit_expression_type_c::is_ANY_DATE_type(symbol_c *type_symbol) {
+ if (type_symbol == NULL) {ERROR;}
+ 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_STRING_type(symbol_c *type_symbol) {
+ if (type_symbol == NULL) {ERROR;}
+ 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 visit_expression_type_c::is_ANY_INT_type(symbol_c *type_symbol) {
+ if (type_symbol == NULL) {ERROR;}
+ 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;}
+ 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) {ERROR;}
+ if (typeid(*type_symbol) == typeid(real_type_name_c)) {return true;}
+ if (typeid(*type_symbol) == typeid(lreal_type_name_c)) {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) {ERROR;}
+ 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;}
+ if (is_literal_integer_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) {ERROR;}
+ if (typeid(*type_symbol) == typeid(bool_type_name_c)) {return true;}
+ if (is_literal_bool_type(type_symbol)) {return true;}
+ return false;
+}
+
+
+#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 true;}
+ 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 true;}
+ if (typeid(*type_symbol) == typeid(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 true;}
+ if (typeid(*type_symbol) == typeid(boolean_true_c)) {return true;}
+ if (typeid(*type_symbol) == typeid(boolean_false_c)) {return true;}
+ if (is_literal_integer_type(type_symbol))
+ if (sizeoftype(&bool_t) >= sizeoftype(type_symbol)) {return true;}
+ return false;
+}
+
+
+/* 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) {ERROR;}
+ 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;}
+
+ /* This 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...
+ */
+ if (typeid(*first_type) == typeid(*second_type)) {return first_type;}
+
+ 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_ANY_BIT_type(first_type) && is_literal_integer_type(second_type))
+ {return ((sizeoftype(first_type) >= sizeoftype(second_type))? first_type :NULL);}
+ if (is_ANY_BIT_type(second_type) && is_literal_integer_type(first_type))
+ {return ((sizeoftype(second_type) >= sizeoftype(first_type)) ? second_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_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);}
+
+ /* 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 TRUE if there is a common data type, otherwise return FALSE
+ */
+bool visit_expression_type_c::is_compatible_type(symbol_c *first_type, symbol_c *second_type) {
+ if (first_type == NULL || second_type == NULL) {ERROR;}
+ return (NULL != common_type__(first_type, second_type));
+}
+
+
+
+#define is_num_type is_ANY_NUM_type
+#define is_integer_type is_ANY_INT_type
+#define is_real_type is_ANY_REAL_type
+#define is_binary_type is_ANY_BIT_type
+ /* actually the ROR, ROL, SHL, and SHR function also accept boolean type! */
+#define is_nbinary_type is_ANY_BIT_type
+#define compute_standard_function_default visit_expression_type_c::compute_standard_function_default
+#define compute_standard_function_il visit_expression_type_c::compute_standard_function_il
+#define search_expression_type_c visit_expression_type_c
+#define search(x) search_f(x)
+#define next() next_nf()
+// #define search_constant_type_c::constant_int_type_name search_expression_type_c::integer
+#define constant_int_type_name integer
+#define is_same_type is_compatible_type
+#include "../absyntax_utils/search_type_code.c"
+#undef is_same_type
+#undef constant_int_type_name
+// #undef search_constant_type_c::constant_int_type_name
+#undef next
+#undef search
+#undef compute_standard_function_default
+#undef compute_standard_function_il
+#undef search_expression_type_c
+#undef is_real_type
+#undef is_binary_type
+#undef is_nbinary_type
+#undef is_integer_type
+#undef is_num_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) {
+ bool error = false;
+
+ if (!(this->*is_data_type)(left_type)) {
+ STAGE3_ERROR(left_type, left_type, "invalid data type of first operand.");
+ error = true;
+ }
+ if (!(this->*is_data_type)(right_type)) {
+ STAGE3_ERROR(right_type, right_type, "invalid data type of second operand.");
+ error = true;
+ }
+ if (!is_compatible_type(left_type, right_type)) {
+ STAGE3_ERROR(left_type, right_type, "type mismatch between operands.");
+ error = true;
+ }
+
+ if (error)
+ return NULL;
+ else
+ return common_type(left_type, right_type);
+}
+
+
+/* A helper function... */
+symbol_c *visit_expression_type_c::compute_numeric_expression(symbol_c *left_type, symbol_c *right_type,
+ is_data_type_t is_data_type) {
+ if (!(this->*is_data_type)(left_type))
+ STAGE3_ERROR(left_type, right_type, "Both parts of the equation must be the same type.");
+ if (!(this->*is_data_type)(right_type))
+ STAGE3_ERROR(left_type, right_type, "Both parts of the equation must be the same type.");
+ if (!is_compatible_type(left_type, right_type))
+ STAGE3_ERROR(left_type, right_type, "Both parts of the equation must be the same type.");
+
+ if (is_literal_integer_type(left_type) || is_literal_real_type(left_type)) {
+ return right_type;
+ } else {
+ return left_type;
+ }
+
+ /* humour the compiler... */
+ return NULL;
+}
+
+
+
+
+
+
+/* A helper function... */
+/* check the semantics of a FB or Function non-formal call */
+/* e.g. foo(1, 2, 3, 4); */
+void visit_expression_type_c::check_nonformal_call(symbol_c *f_call, symbol_c *f_decl, bool use_il_defvar) {
+ 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);
+
+ /* 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.
+ */
+ if(param_name != NULL) {
+ param_type = fp_iterator.param_type();
+ if(!is_compatible_type(il_default_variable_type,param_type))
+ STAGE3_ERROR(f_call, f_call, "In function/FB call, first parameter has invalid data type.");
+ }
+ } // 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 current parameter in the function call */
+ call_param_type = base_type((symbol_c*)call_param_value->accept(*this));
+ if (call_param_type == NULL) STAGE3_ERROR(call_param_value, call_param_value, "Could not determine data type of value being passed in function/FB 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 parameter declared with that name */
+ if(param_name == NULL) {STAGE3_ERROR(f_call, f_call, "Too many parameters in function/FB call."); break;}
+ } while ((strcmp(param_name->value, "EN") == 0) || (strcmp(param_name->value, "ENO") == 0));
+
+ if(param_name != NULL) {
+ /* Get the parameter type */
+ param_type = fp_iterator.param_type();
+ /* If the declared parameter and the parameter from the function call do no have the same type */
+ if(!is_compatible_type(call_param_type,param_type)) STAGE3_ERROR(call_param_value, call_param_value, "Type mismatch in function/FB call parameter.");
+ }
+ }
+}
+
+void visit_expression_type_c::compute_input_operatores(symbol_c *symbol, const char *input_operator){
+ symbol_c *call_param_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){
+ STAGE3_ERROR(symbol, symbol, "Parameter operator needs an instance of a function block operand.");
+ ERROR;
+ }
+
+ /* Iterating through the formal parameters of the function call */
+ identifier_c call_param_name(input_operator);
+
+ /* Obtaining the type of the value being passed in the function call */
+ call_param_type = il_default_variable_type;
+ if (call_param_type == NULL) {
+ STAGE3_ERROR(&call_param_name, &call_param_name, "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_name, "Could not determine data type of value being passed in function/FB call.");
+
+
+ check_formal_parameter(&call_param_name, call_param_type, fb_decl);
+// return NULL;
+}
+
+void visit_expression_type_c::check_formal_parameter(symbol_c *call_param_name, symbol_c *call_param_type, symbol_c *f_decl) {
+ symbol_c *param_type;
+ identifier_c *param_name;
+ function_param_iterator_c fp_iterator(f_decl);
+
+ /* Find the corresponding parameter of the function being called */
+ param_name = fp_iterator.search(call_param_name);
+ if(param_name == NULL) {
+ STAGE3_ERROR(call_param_name, call_param_name, "Invalid parameter in function/FB call.");
+ } else {
+ /* Get the parameter type */
+ param_type = fp_iterator.param_type();
+ /* If the declared parameter and the parameter from the function call have the same type */
+// if(!is_compatible_type(call_param_type, param_type)) STAGE3_ERROR(call_param_name, call_param_value, "Type mismatch function/FB call parameter.");
+ if(!is_compatible_type(call_param_type, param_type)) STAGE3_ERROR(call_param_name, call_param_name, "Type mismatch function/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); */
+void visit_expression_type_c::check_formal_call(symbol_c *f_call, symbol_c *f_decl) {
+ 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);
+
+ /* 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){
+ 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) {
+ 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) {
+ STAGE3_ERROR(call_param_name, call_param_name, "Invalid parameter in function/FB call.");
+ } else {
+ /* Get the parameter type */
+ param_type = fp_iterator.param_type();
+ /* If the declared parameter and the parameter from the function call have the same type */
+ if(!is_compatible_type(call_param_type, param_type)) STAGE3_ERROR(call_param_name, call_param_value, "Type mismatch function/FB call parameter.");
+ }
+ }
+}
+
+
+
+
+/* a helper function... */
+symbol_c *visit_expression_type_c::base_type(symbol_c *symbol) {
+ 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, "Il default variable can't be NULL.");
+ }
+ if(il_operand_type == NULL){
+ STAGE3_ERROR(symbol, symbol, "function requires an operand.");
+ }
+ return NULL;
+}
+
+
+
+
+/*********************/
+/* B 1.4 - Variables */
+/*********************/
+
+void *visit_expression_type_c::visit(symbolic_variable_c *symbol) {
+ return search_varfb_instance_type->get_type(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_type(symbol);
+}
+
+void *visit_expression_type_c::visit(structured_variable_c *symbol) {
+ return search_varfb_instance_type->get_type(symbol);
+}
+
+
+
+/****************************************/
+/* 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 */
+ 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;
+ 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;
+
+ /* First find the declaration of the function being called! */
+ function_declaration_c *f_decl = function_symtable.find_value(symbol->function_name);
+
+ symbol_c *return_data_type = NULL;
+
+ if (f_decl == function_symtable.end_value()) {
+ function_type_t current_function_type = get_function_type((identifier_c *)symbol->function_name);
+ if (current_function_type == function_none) ERROR;
+ /* This code is for the functions that the user did not declare and that are
+ * part of the IL or ST languagem (built-in functions).
+ * For now we won't do the semantics analysis for that kind of functions.
+ */
+ /*
+ return_data_type = (symbol_c *)search_expression_type->compute_standard_function_default(NULL, symbol);
+ if (NULL == return_data_type) ERROR;
+
+ function_call_param_iterator_c fcp_iterator(symbol);
+
+ int nb_param = 0;
+ if (symbol->il_param_list != NULL)
+ nb_param += ((list_c *)symbol->il_param_list)->n;
+
+ identifier_c en_param_name("EN");*/
+ /* Get the value from EN param */
+ /*symbol_c *EN_param_value = fcp_iterator.search(&en_param_name);
+ if (EN_param_value == NULL)
+ EN_param_value = (symbol_c*)(new boolean_literal_c((symbol_c*)(new bool_type_name_c()), new boolean_true_c()));
+ else
+ nb_param --;
+ ADD_PARAM_LIST(EN_param_value, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_in)
+
+ identifier_c eno_param_name("EN0");*/
+ /* Get the value from ENO param */
+ /*symbol_c *ENO_param_value = fcp_iterator.search(&eno_param_name);
+ if (ENO_param_value != NULL)
+ nb_param --;
+ ADD_PARAM_LIST(ENO_param_value, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_out)
+
+ #include "st_code_gen.c"
+ */
+ } else {
+ /* determine the base data type returned by the function being called... */
+ return_data_type = base_type(f_decl->type_name);
+ /* If the following occurs, then we must have some big bug in the syntax parser (stage 2)... */
+ if (NULL == return_data_type) ERROR;
+
+ /* check semantics of data passed in the function call... */
+ check_nonformal_call(symbol, f_decl, true);
+
+ /* set the new ddata 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_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)
+ return NULL;
+ symbol->il_expr_operator->accept(*this);
+
+ 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_type( 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_type(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_type(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;
+
+ function_declaration_c *f_decl = function_symtable.find_value(symbol->function_name);
+
+ symbol_c *return_data_type = NULL;
+
+ if (f_decl == function_symtable.end_value()) {
+ function_type_t current_function_type = get_function_type((identifier_c *)symbol->function_name);
+ if (current_function_type == function_none) ERROR;
+
+ /* This code is for the functions that the user did not declare and that are
+ * part of the IL or ST languagem (built-in functions).
+ * For now we won't do the semantics analysis for that kind of functions.
+ */
+ #if 0
+ return_data_type = (symbol_c *)search_expression_type->compute_standard_function_default(NULL, symbol);
+ if (NULL == return_data_type) ERROR;
+
+ function_call_param_iterator_c fcp_iterator(symbol);
+
+ int nb_param = 0;
+ if (symbol->il_param_list != NULL)
+ nb_param += ((list_c *)symbol->il_param_list)->n;
+
+ identifier_c en_param_name("EN");
+ /* Get the value from EN param */
+ symbol_c *EN_param_value = fcp_iterator.search(&en_param_name);
+ if (EN_param_value == NULL)
+ EN_param_value = (symbol_c*)(new boolean_literal_c((symbol_c*)(new bool_type_name_c()), new boolean_true_c()));
+ else
+ nb_param --;
+ ADD_PARAM_LIST(EN_param_value, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_in)
+
+ identifier_c eno_param_name("EN0");
+ /* Get the value from ENO param */
+ symbol_c *ENO_param_value = fcp_iterator.search(&eno_param_name);
+ if (ENO_param_value != NULL)
+ nb_param --;
+ ADD_PARAM_LIST(ENO_param_value, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_out)
+
+ #include "st_code_gen.c"
+ #endif
+ } else {
+ /* determine the base data type returned by the function being called... */
+ return_data_type = base_type(f_decl->type_name);
+ /* 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;
+
+ /* check semantics of data passed in the function call... */
+ check_formal_call(symbol, f_decl);
+
+ /* 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_type(il_operand_type))
+ STAGE3_ERROR(symbol, symbol, "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_compatible_type(il_default_variable_type, il_operand_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_compatible_type(il_default_variable_type, il_operand_type))
+ STAGE3_ERROR(symbol, symbol, "Type mismatch in ST operation.");
+ /* TODO: check whether il_operand_type is an LVALUE !! */
+ if(!is_ANY_BIT_type(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_type(il_operand_type))
+ STAGE3_ERROR(symbol, symbol, "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, symbol, "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_type(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, symbol, "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, symbol, "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){
+ compute_input_operatores(symbol, "S1");
+ return NULL;
+}
+
+// SYM_REF0(R1_operator_c)
+void *visit_expression_type_c::visit(R1_operator_c *symbol) {
+ compute_input_operatores(symbol, "R1");
+ return NULL;
+}
+
+// SYM_REF0(CLK_operator_c)
+void *visit_expression_type_c::visit(CLK_operator_c *symbol) {
+ compute_input_operatores(symbol, "CLK");
+ return NULL;
+}
+
+// SYM_REF0(CU_operator_c)
+void *visit_expression_type_c::visit(CU_operator_c *symbol) {
+ compute_input_operatores(symbol, "CU");
+ return NULL;
+}
+
+// SYM_REF0(CD_operator_c)
+void *visit_expression_type_c::visit(CD_operator_c *symbol) {
+ compute_input_operatores(symbol, "CD");
+ return NULL;
+}
+
+// SYM_REF0(PV_operator_c)
+void *visit_expression_type_c::visit(PV_operator_c *symbol) {
+ compute_input_operatores(symbol, "PV");
+ return NULL;
+}
+
+// SYM_REF0(IN_operator_c)
+void *visit_expression_type_c::visit(IN_operator_c *symbol) {
+ compute_input_operatores(symbol, "IN");
+ return NULL;
+}
+
+// SYM_REF0(PT_operator_c)
+void *visit_expression_type_c::visit(PT_operator_c *symbol) {
+ compute_input_operatores(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_boolean_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_BIT_type);
+ 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_boolean_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_BIT_type);
+ 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_boolean_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_BIT_type);
+ 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_boolean_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_BIT_type);
+ 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_boolean_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_BIT_type);
+ 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_boolean_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_BIT_type);
+ 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;
+ if (typeid(*left_type) == typeid(time_type_name_c) && typeid(*right_type) == typeid(time_type_name_c))
+ il_default_variable_type = &time_type_name;
+ else if (typeid(*left_type) == typeid(tod_type_name_c) && typeid(*right_type) == typeid(time_type_name_c))
+ il_default_variable_type = &tod_type_name;
+ else if (typeid(*left_type) == typeid(dt_type_name_c) && typeid(*right_type) == typeid(time_type_name_c))
+ il_default_variable_type = &dt_type_name;
+ else il_default_variable_type = compute_numeric_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_MAGNITUDE_type);
+ 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;;
+ if (typeid(*left_type) == typeid(time_type_name_c) && typeid(*right_type) == typeid(time_type_name_c))
+ il_default_variable_type = &time_type_name;
+ else if (typeid(*left_type) == typeid(date_type_name_c) && typeid(*right_type) == typeid(date_type_name_c))
+ il_default_variable_type = &time_type_name;
+ else if (typeid(*left_type) == typeid(tod_type_name_c) && typeid(*right_type) == typeid(time_type_name_c))
+ il_default_variable_type = &tod_type_name;
+ else if (typeid(*left_type) == typeid(tod_type_name_c) && typeid(*right_type) == typeid(tod_type_name_c))
+ il_default_variable_type = &time_type_name;
+ else if (typeid(*left_type) == typeid(dt_type_name_c) && typeid(*right_type) == typeid(time_type_name_c))
+ il_default_variable_type = &dt_type_name;
+ else if (typeid(*left_type) == typeid(dt_type_name_c) && typeid(*right_type) == typeid(dt_type_name_c))
+ il_default_variable_type = &time_type_name;
+ else il_default_variable_type = compute_numeric_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_MAGNITUDE_type);
+ 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 (typeid(*left_type) == typeid(time_type_name_c) && is_ANY_NUM_type(right_type))
+ il_default_variable_type = &time_type_name;
+ else il_default_variable_type = compute_numeric_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_NUM_type);
+ 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 (typeid(*left_type) == typeid(time_type_name_c) && is_ANY_NUM_type(right_type))
+ il_default_variable_type = &time_type_name;
+ else il_default_variable_type = compute_numeric_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_NUM_type);
+ 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_numeric_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_INT_type);
+ return NULL;
+}
+
+// SYM_REF0(GT_operator_c)
+void *visit_expression_type_c::visit(GT_operator_c *symbol) {
+ verify_null(symbol);
+ compute_boolean_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_ELEMENTARY_type);
+ 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_boolean_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_ELEMENTARY_type);
+ 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_boolean_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_ELEMENTARY_type);
+ 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_boolean_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_ELEMENTARY_type);
+ 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_boolean_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_ELEMENTARY_type);
+ 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_boolean_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_ELEMENTARY_type);
+ 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_boolean_expression(left_type, right_type, &visit_expression_type_c::is_ANY_BIT_type);
+}
+
+
+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_boolean_expression(left_type, right_type, &visit_expression_type_c::is_ANY_BIT_type);
+}
+
+
+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_boolean_expression(left_type, right_type, &visit_expression_type_c::is_ANY_BIT_type);
+}
+
+
+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_boolean_expression(left_type, right_type, &visit_expression_type_c::is_ANY_ELEMENTARY_type);
+ 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_boolean_expression(left_type, right_type, &visit_expression_type_c::is_ANY_ELEMENTARY_type);
+ 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_boolean_expression(left_type, right_type, &visit_expression_type_c::is_ANY_ELEMENTARY_type);
+ 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_boolean_expression(left_type, right_type, &visit_expression_type_c::is_ANY_ELEMENTARY_type);
+ 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_boolean_expression(left_type, right_type, &visit_expression_type_c::is_ANY_ELEMENTARY_type);
+ 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_boolean_expression(left_type, right_type, &visit_expression_type_c::is_ANY_ELEMENTARY_type);
+ 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));
+ if (typeid(*left_type) == typeid(time_type_name_c) && typeid(*right_type) == typeid(time_type_name_c)) {return (void *)&time_type_name;}
+ if (typeid(*left_type) == typeid(tod_type_name_c) && typeid(*right_type) == typeid(time_type_name_c)) {return (void *)&tod_type_name;}
+ if (typeid(*left_type) == typeid(dt_type_name_c) && typeid(*right_type) == typeid(time_type_name_c)) {return (void *)&dt_type_name;}
+ return compute_numeric_expression(left_type, right_type, &visit_expression_type_c::is_ANY_MAGNITUDE_type);
+}
+
+
+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));
+ if (typeid(*left_type) == typeid(time_type_name_c) && typeid(*right_type) == typeid(time_type_name_c)) {return (void *)&time_type_name;}
+ if (typeid(*left_type) == typeid(date_type_name_c) && typeid(*right_type) == typeid(date_type_name_c)) {return (void *)&time_type_name;}
+ if (typeid(*left_type) == typeid(tod_type_name_c) && typeid(*right_type) == typeid(time_type_name_c)) {return (void *)&tod_type_name;}
+ if (typeid(*left_type) == typeid(tod_type_name_c) && typeid(*right_type) == typeid(tod_type_name_c)) {return (void *)&time_type_name;}
+ if (typeid(*left_type) == typeid(dt_type_name_c) && typeid(*right_type) == typeid(time_type_name_c)) {return (void *)&dt_type_name;}
+ if (typeid(*left_type) == typeid(dt_type_name_c) && typeid(*right_type) == typeid(dt_type_name_c)) {return (void *)&time_type_name;}
+ return compute_numeric_expression(left_type, right_type, &visit_expression_type_c::is_ANY_MAGNITUDE_type);
+}
+
+
+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 (typeid(*left_type) == typeid(time_type_name_c) && is_ANY_NUM_type(right_type)) {return (void *)&time_type_name;}
+ return compute_numeric_expression(left_type, right_type, &visit_expression_type_c::is_ANY_NUM_type);
+}
+
+
+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 (typeid(*left_type) == typeid(time_type_name_c) && is_ANY_NUM_type(right_type)){return (void *)&time_type_name;}
+ return compute_numeric_expression(left_type, right_type, &visit_expression_type_c::is_ANY_NUM_type);
+}
+
+
+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_numeric_expression(left_type, right_type, &visit_expression_type_c::is_ANY_INT_type);
+}
+
+
+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_type(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_type(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_type(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_boolean_expression(type, type, &visit_expression_type_c::is_ANY_BIT_type);
+}
+
+
+void *visit_expression_type_c::visit(function_invocation_c *symbol) {
+ function_declaration_c *f_decl = function_symtable.find_value(symbol->function_name);
+ if (f_decl == function_symtable.end_value()) {
+ /* TODO: the following code is for standard library functions. We do not yet support this... */
+ void *res = compute_standard_function_default(symbol);
+ if (res != NULL) return res;
+ ERROR;
+ }
+
+ /* 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.
+ */
+ if (symbol-> formal_param_list != NULL) check_formal_call (symbol, f_decl);
+ if (symbol->nonformal_param_list != NULL) check_nonformal_call(symbol, f_decl);
+
+ return base_type(f_decl->type_name);
+}
+
+/********************/
+/* 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 (!is_compatible_type(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_type(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,symbol,"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,symbol,"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){
+ 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) {
+ if(!is_compatible_type(var_type,beg_expr_type))
+ STAGE3_ERROR(symbol, symbol, "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) {
+ if(!is_compatible_type(var_type,end_expr_type))
+ STAGE3_ERROR(symbol, symbol, "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) {
+ if(!is_compatible_type(var_type,by_expr_type))
+ STAGE3_ERROR(symbol, symbol, "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,symbol,"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,symbol,"REPEAT conditional expression is not of boolean type.");
+ }
+ return NULL;
+}
+
+/* EXIT */
+// SYM_REF0(exit_statement_c)
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/stage3/visit_expression_type.hh Wed Sep 02 14:05:27 2009 +0200
@@ -0,0 +1,294 @@
+/*
+ * (c) 2003 Mario de Sousa
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * 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 IL and ST 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;
+
+ symbol_c *il_default_variable_type;
+ symbol_c *il_operand_type;
+
+
+ public:
+ visit_expression_type_c(symbol_c *search_scope);
+ virtual ~visit_expression_type_c(void);
+
+ /* A helper function... */
+ bool is_ANY_ELEMENTARY_type(symbol_c *type_symbol);
+ bool is_ANY_MAGNITUDE_type(symbol_c *type_symbol);
+ bool is_ANY_DATE_type(symbol_c *type_symbol);
+ bool is_ANY_STRING_type(symbol_c *type_symbol);
+ bool is_ANY_INT_type(symbol_c *type_symbol);
+ bool is_ANY_REAL_type(symbol_c *type_symbol);
+ bool is_ANY_NUM_type(symbol_c *type_symbol);
+ bool is_ANY_BIT_type(symbol_c *type_symbol);
+ bool is_BOOL_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);
+
+ /* 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);
+ /* Return TRUE if there is a common data type, otherwise return FALSE */
+ bool is_compatible_type(symbol_c *first_type, symbol_c *second_type);
+
+ void compute_input_operatores(symbol_c *symbol, const char *input_operator);
+ void check_formal_parameter(symbol_c *call_param_name, symbol_c *call_param_type, symbol_c *f_decl);
+
+ /* check the semantics of a FB or Function non-formal call */
+ /* e.g. foo(1, 2, 3, 4); */
+ void check_nonformal_call(symbol_c *f_call, symbol_c *f_decl, bool use_il_defvar = false);
+ /* check the semantics of a FB or Function formal call */
+ /* e.g. foo(IN1 := 1, OUT1 =>x, EN := true); */
+ void check_formal_call(symbol_c *f_call, symbol_c *f_decl);
+
+
+ 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);
+
+ /* a helper function... */
+ symbol_c *base_type(symbol_c *symbol);
+
+ /* a helper function... */
+ void *verify_null(symbol_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.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 Wed Sep 02 13:39:05 2009 +0200
+++ b/stage4/generate_c/generate_c.cc Wed Sep 02 14:05:27 2009 +0200
@@ -149,8 +149,6 @@
#define TEMP_VAR VAR_LEADER "TMP_"
#define SOURCE_VAR VAR_LEADER "SRC_"
-#include "generate_c_tempvardecl.cc"
-
#include "generate_c_st.cc"
#include "generate_c_il.cc"
@@ -498,13 +496,13 @@
/* (A.3) Function parameters */
s4o.indent_right();
vardecl = new generate_c_vardecl_c(&s4o,
- generate_c_vardecl_c::finterface_vf,
- generate_c_vardecl_c::input_vt |
- generate_c_vardecl_c::output_vt |
- generate_c_vardecl_c::inoutput_vt |
- generate_c_vardecl_c::eneno_vt);
+ generate_c_vardecl_c::finterface_vf,
+ generate_c_vardecl_c::input_vt |
+ generate_c_vardecl_c::output_vt |
+ generate_c_vardecl_c::inoutput_vt |
+ generate_c_vardecl_c::en_vt |
+ generate_c_vardecl_c::eno_vt);
vardecl->print(symbol->var_declarations_list);
- vardecl->print_eneno();
delete vardecl;
s4o.indent_left();
@@ -515,11 +513,12 @@
/* (B.1) Variables declared in ST source code */
s4o.indent_right();
- vardecl = new generate_c_vardecl_c(&s4o,
- generate_c_vardecl_c::localinit_vf,
- generate_c_vardecl_c::output_vt |
+ vardecl = new generate_c_vardecl_c(&s4o,
+ generate_c_vardecl_c::localinit_vf,
+ generate_c_vardecl_c::output_vt |
generate_c_vardecl_c::inoutput_vt |
- generate_c_vardecl_c::private_vt);
+ generate_c_vardecl_c::private_vt |
+ generate_c_vardecl_c::eno_vt);
vardecl->print(symbol->var_declarations_list);
delete vardecl;
@@ -541,9 +540,9 @@
s4o.print(s4o.indent_spaces + "// Control execution\n");
s4o.print(s4o.indent_spaces + "if (!EN) {\n");
s4o.indent_right();
- s4o.print(s4o.indent_spaces + "if (ENO != NULL) {\n");
+ s4o.print(s4o.indent_spaces + "if (__ENO != NULL) {\n");
s4o.indent_right();
- s4o.print(s4o.indent_spaces + "*ENO = __BOOL_LITERAL(FALSE);\n");
+ s4o.print(s4o.indent_spaces + "*__ENO = __BOOL_LITERAL(FALSE);\n");
s4o.indent_left();
s4o.print(s4o.indent_spaces + "}\n");
s4o.print(s4o.indent_spaces + "return ");
@@ -551,24 +550,16 @@
s4o.print(";\n");
s4o.indent_left();
s4o.print(s4o.indent_spaces + "}\n");
- s4o.print(s4o.indent_spaces + "else {\n");
- s4o.indent_right();
- s4o.print(s4o.indent_spaces + "if (ENO != NULL) {\n");
- s4o.indent_right();
- s4o.print(s4o.indent_spaces + "*ENO = __BOOL_LITERAL(TRUE);\n");
- s4o.indent_left();
- s4o.print(s4o.indent_spaces + "}\n");
- s4o.indent_left();
- s4o.print(s4o.indent_spaces + "}\n");
-
+
/* (C) Function body */
generate_c_SFC_IL_ST_c generate_c_code(&s4o, symbol);
symbol->function_body->accept(generate_c_code);
vardecl = new generate_c_vardecl_c(&s4o,
generate_c_vardecl_c::foutputassign_vf,
- generate_c_vardecl_c::output_vt |
- generate_c_vardecl_c::inoutput_vt);
+ generate_c_vardecl_c::output_vt |
+ generate_c_vardecl_c::inoutput_vt |
+ generate_c_vardecl_c::eno_vt);
vardecl->print(symbol->var_declarations_list);
delete vardecl;
@@ -610,23 +601,23 @@
/* (A.2) Public variables: i.e. the function parameters... */
s4o_incl.print(s4o_incl.indent_spaces + "// FB Interface - IN, OUT, IN_OUT variables\n");
vardecl = new generate_c_vardecl_c(&s4o_incl,
- generate_c_vardecl_c::local_vf,
- generate_c_vardecl_c::input_vt |
- generate_c_vardecl_c::output_vt |
- generate_c_vardecl_c::inoutput_vt |
- generate_c_vardecl_c::eneno_vt);
+ generate_c_vardecl_c::local_vf,
+ generate_c_vardecl_c::input_vt |
+ generate_c_vardecl_c::output_vt |
+ generate_c_vardecl_c::inoutput_vt |
+ generate_c_vardecl_c::en_vt |
+ generate_c_vardecl_c::eno_vt);
vardecl->print(symbol->var_declarations);
- vardecl->print_eneno();
delete vardecl;
s4o_incl.print("\n");
/* (A.3) Private internal variables */
s4o_incl.print(s4o_incl.indent_spaces + "// FB private variables - TEMP, private and located variables\n");
vardecl = new generate_c_vardecl_c(&s4o_incl,
- generate_c_vardecl_c::local_vf,
- generate_c_vardecl_c::temp_vt |
- generate_c_vardecl_c::private_vt |
- generate_c_vardecl_c::located_vt |
- generate_c_vardecl_c::external_vt);
+ generate_c_vardecl_c::local_vf,
+ generate_c_vardecl_c::temp_vt |
+ generate_c_vardecl_c::private_vt |
+ generate_c_vardecl_c::located_vt |
+ generate_c_vardecl_c::external_vt);
vardecl->print(symbol->var_declarations);
delete vardecl;
@@ -660,25 +651,16 @@
/* (B.2) Member initializations... */
s4o.print(s4o.indent_spaces);
vardecl = new generate_c_vardecl_c(&s4o,
- generate_c_vardecl_c::constructorinit_vf,
- generate_c_vardecl_c::input_vt |
- generate_c_vardecl_c::output_vt |
- generate_c_vardecl_c::inoutput_vt |
- generate_c_vardecl_c::private_vt |
- generate_c_vardecl_c::located_vt |
- generate_c_vardecl_c::external_vt |
- generate_c_vardecl_c::eneno_vt);
+ generate_c_vardecl_c::constructorinit_vf,
+ generate_c_vardecl_c::input_vt |
+ generate_c_vardecl_c::output_vt |
+ generate_c_vardecl_c::inoutput_vt |
+ generate_c_vardecl_c::private_vt |
+ generate_c_vardecl_c::located_vt |
+ generate_c_vardecl_c::external_vt |
+ generate_c_vardecl_c::en_vt |
+ generate_c_vardecl_c::eno_vt);
vardecl->print(symbol->var_declarations, NULL, FB_FUNCTION_PARAM"->");
- if (!vardecl->is_en_declared()) {
- s4o.print("\n" + s4o.indent_spaces);
- s4o.print(FB_FUNCTION_PARAM);
- s4o.print("->EN = __BOOL_LITERAL(TRUE);");
- }
- if (!vardecl->is_eno_declared()) {
- s4o.print("\n" + s4o.indent_spaces);
- s4o.print(FB_FUNCTION_PARAM);
- s4o.print("->ENO = __BOOL_LITERAL(TRUE);");
- }
delete vardecl;
s4o.print("\n");
/* (B.3) Generate private internal variables for SFC */
@@ -737,8 +719,8 @@
/* function body */
s4o.print(s4o.indent_spaces + "// Initialise TEMP variables\n");
vardecl = new generate_c_vardecl_c(&s4o,
- generate_c_vardecl_c::init_vf,
- generate_c_vardecl_c::temp_vt);
+ generate_c_vardecl_c::init_vf,
+ generate_c_vardecl_c::temp_vt);
vardecl->print(symbol->var_declarations, NULL, FB_FUNCTION_PARAM"->");
delete vardecl;
s4o.print("\n");
@@ -801,10 +783,10 @@
/* (A.2) Public variables: i.e. the program parameters... */
s4o_incl.print(s4o_incl.indent_spaces + "// PROGRAM Interface - IN, OUT, IN_OUT variables\n");
vardecl = new generate_c_vardecl_c(&s4o_incl,
- generate_c_vardecl_c::local_vf,
- generate_c_vardecl_c::input_vt |
- generate_c_vardecl_c::output_vt |
- generate_c_vardecl_c::inoutput_vt);
+ generate_c_vardecl_c::local_vf,
+ generate_c_vardecl_c::input_vt |
+ generate_c_vardecl_c::output_vt |
+ generate_c_vardecl_c::inoutput_vt);
vardecl->print(symbol->var_declarations);
delete vardecl;
s4o_incl.print("\n");
@@ -812,7 +794,7 @@
s4o_incl.print(s4o_incl.indent_spaces + "// PROGRAM private variables - TEMP, private and located variables\n");
vardecl = new generate_c_vardecl_c(&s4o_incl,
generate_c_vardecl_c::local_vf,
- generate_c_vardecl_c::temp_vt |
+ generate_c_vardecl_c::temp_vt |
generate_c_vardecl_c::private_vt |
generate_c_vardecl_c::located_vt |
generate_c_vardecl_c::external_vt);
@@ -847,13 +829,13 @@
/* (B.2) Member initializations... */
s4o.print(s4o.indent_spaces);
vardecl = new generate_c_vardecl_c(&s4o,
- generate_c_vardecl_c::constructorinit_vf,
- generate_c_vardecl_c::input_vt |
- generate_c_vardecl_c::output_vt |
- generate_c_vardecl_c::inoutput_vt |
- generate_c_vardecl_c::private_vt |
- generate_c_vardecl_c::located_vt |
- generate_c_vardecl_c::external_vt);
+ generate_c_vardecl_c::constructorinit_vf,
+ generate_c_vardecl_c::input_vt |
+ generate_c_vardecl_c::output_vt |
+ generate_c_vardecl_c::inoutput_vt |
+ generate_c_vardecl_c::private_vt |
+ generate_c_vardecl_c::located_vt |
+ generate_c_vardecl_c::external_vt);
vardecl->print(symbol->var_declarations, NULL, FB_FUNCTION_PARAM"->");
delete vardecl;
s4o.print("\n");
@@ -894,8 +876,8 @@
/* function body */
s4o.print(s4o.indent_spaces + "// Initialise TEMP variables\n");
vardecl = new generate_c_vardecl_c(&s4o,
- generate_c_vardecl_c::init_vf,
- generate_c_vardecl_c::temp_vt);
+ generate_c_vardecl_c::init_vf,
+ generate_c_vardecl_c::temp_vt);
vardecl->print(symbol->var_declarations, NULL, FB_FUNCTION_PARAM"->");
delete vardecl;
s4o.print("\n");
@@ -987,8 +969,8 @@
/* (A.2) Global variables */
vardecl = new generate_c_vardecl_c(&s4o,
- generate_c_vardecl_c::local_vf,
- generate_c_vardecl_c::global_vt);
+ generate_c_vardecl_c::local_vf,
+ generate_c_vardecl_c::global_vt);
vardecl->print(symbol);
delete vardecl;
s4o.print("\n");
@@ -1008,8 +990,8 @@
/* (B.3) Global variables initializations... */
s4o.print(s4o.indent_spaces);
vardecl = new generate_c_vardecl_c(&s4o,
- generate_c_vardecl_c::constructorinit_vf,
- generate_c_vardecl_c::global_vt);
+ generate_c_vardecl_c::constructorinit_vf,
+ generate_c_vardecl_c::global_vt);
vardecl->print(symbol);
delete vardecl;
s4o.print("\n");
@@ -1125,7 +1107,7 @@
public:
generate_c_resources_c(stage4out_c *s4o_ptr, symbol_c *config_scope, symbol_c *resource_scope, unsigned long time)
: generate_c_typedecl_c(s4o_ptr) {
- search_config_instance = new search_var_instance_decl_c(config_scope);
+ search_config_instance = new search_var_instance_decl_c(config_scope);
search_resource_instance = new search_var_instance_decl_c(resource_scope);
common_ticktime = time;
current_resource_name = NULL;
@@ -1181,7 +1163,7 @@
/* task_configuration_list program_configuration_list */
// SYM_REF2(single_resource_declaration_c, task_configuration_list, program_configuration_list)
void *visit(single_resource_declaration_c *symbol) {
- bool single_resource = current_resource_name == NULL;
+ bool single_resource = current_resource_name == NULL;
if (single_resource)
current_resource_name = new identifier_c("RESOURCE");
generate_c_vardecl_c *vardecl;
@@ -1204,9 +1186,9 @@
/* (A.2) Global variables... */
if (current_global_vars != NULL) {
vardecl = new generate_c_vardecl_c(&s4o,
- generate_c_vardecl_c::local_vf,
- generate_c_vardecl_c::global_vt,
- current_resource_name);
+ generate_c_vardecl_c::local_vf,
+ generate_c_vardecl_c::global_vt,
+ current_resource_name);
vardecl->print(current_global_vars);
delete vardecl;
s4o.print("\n");
@@ -1238,8 +1220,8 @@
if (current_global_vars != NULL) {
s4o.print(s4o.indent_spaces);
vardecl = new generate_c_vardecl_c(&s4o,
- generate_c_vardecl_c::constructorinit_vf,
- generate_c_vardecl_c::global_vt);
+ generate_c_vardecl_c::constructorinit_vf,
+ generate_c_vardecl_c::global_vt);
vardecl->print(current_global_vars);
delete vardecl;
}
@@ -1475,10 +1457,10 @@
s4o.print(s4o.indent_spaces + "{extern ");
var_decl->accept(*this);
- s4o.print(" ");
+ s4o.print(" *");
symbol->prog_data_source->accept(*this);
s4o.print("; ");
- s4o.print(current_program_name);
+ s4o.printupper(current_program_name);
s4o.print(".");
symbol->symbolic_variable->accept(*this);
s4o.print(" = ");
@@ -1508,20 +1490,19 @@
else
vartype = search_resource_instance->get_vartype();
- s4o.print(s4o.indent_spaces);
s4o.print(s4o.indent_spaces + "{extern ");
var_decl->accept(*this);
- s4o.print(" ");
+ s4o.print(" *");
symbol->data_sink->accept(*this);
s4o.print("; ");
if (vartype || search_var_instance_decl_c::global_vt)
s4o.print("*");
symbol->data_sink->accept(*this);
s4o.print(" = ");
- s4o.print(current_program_name);
+ s4o.printupper(current_program_name);
s4o.print(".");
symbol->symbolic_variable->accept(*this);
- s4o.print("};\n");
+ s4o.print(";};\n");
}
return NULL;
}
@@ -1668,18 +1649,18 @@
}
void *visit(resource_declaration_c *symbol) {
- symbol->resource_name->accept(*this);
- stage4out_c resources_s4o(current_builddir, current_name, "c");
+ symbol->resource_name->accept(*this);
+ stage4out_c resources_s4o(current_builddir, current_name, "c");
generate_c_resources_c generate_c_resources(&resources_s4o, current_configuration, symbol, common_ticktime);
- symbol->accept(generate_c_resources);
- return NULL;
+ symbol->accept(generate_c_resources);
+ return NULL;
}
void *visit(single_resource_declaration_c *symbol) {
- stage4out_c resources_s4o(current_builddir, "RESOURCE", "c");
+ stage4out_c resources_s4o(current_builddir, "RESOURCE", "c");
generate_c_resources_c generate_c_resources(&resources_s4o, current_configuration, symbol, common_ticktime);
- symbol->accept(generate_c_resources);
- return NULL;
+ symbol->accept(generate_c_resources);
+ return NULL;
}
};
--- a/stage4/generate_c/generate_c_base.cc Wed Sep 02 13:39:05 2009 +0200
+++ b/stage4/generate_c/generate_c_base.cc Wed Sep 02 14:05:27 2009 +0200
@@ -255,7 +255,6 @@
void *visit(octal_integer_c *symbol) {s4o.print("0"); return print_striped_token(symbol, 2);}
void *visit(hex_integer_c *symbol) {s4o.print("0x"); return print_striped_token(symbol, 3);}
- void *visit(numeric_literal_c *symbol) {return print_literal(symbol->type, symbol->value);}
void *visit(integer_literal_c *symbol) {return print_literal(symbol->type, symbol->value);}
void *visit(real_literal_c *symbol) {return print_literal(symbol->type, symbol->value);}
void *visit(bit_string_literal_c *symbol) {return print_literal(symbol->type, symbol->value);}
--- a/stage4/generate_c/generate_c_il.cc Wed Sep 02 13:39:05 2009 +0200
+++ b/stage4/generate_c/generate_c_il.cc Wed Sep 02 14:05:27 2009 +0200
@@ -54,34 +54,6 @@
* the possible il_operand variable instance was declared).
*/
-class search_il_operand_type_c {
-
- private:
- search_varfb_instance_type_c search_varfb_instance_type;
- search_constant_type_c search_constant_type;
-
- public:
- search_il_operand_type_c(symbol_c *search_scope): search_varfb_instance_type(search_scope) {}
-
- public:
- symbol_c *get_type(symbol_c *il_operand) {
- symbol_c *res;
-
- /* We first assume that it is a constant... */
- res = search_constant_type.get_type(il_operand);
- if (res != NULL) return res;
-
- /* Nope, now we assume it is a variable, and determine its type... */
- res = search_varfb_instance_type.get_type(il_operand);
- if (NULL != res) return res;
-
- /* not found */
- return NULL;
- }
-};
-
-
-
/***********************************************************************/
/***********************************************************************/
/***********************************************************************/
@@ -176,7 +148,6 @@
* This object instance will then later be called while the
* remaining il code is being handled.
*/
- //search_il_operand_type_c *search_il_operand_type;
search_expression_type_c *search_expression_type;
/* The initial value that should be given to the IL default variable
@@ -244,38 +215,6 @@
il_default_variable_c default_variable_name;
il_default_variable_c default_variable_back_name;
- /* Some function calls in the body of functions or function blocks
- * may leave some parameters to their default values, and
- * ignore some output parameters of the function being called.
- * Our conversion of ST functions to C++ does not contemplate that,
- * i.e. each called function must get all it's input and output
- * parameters set correctly.
- * For input parameters we merely need to call the function with
- * the apropriate default value, but for output parameters
- * we must create temporary variables to hold the output value.
- *
- * We declare all the temporary output variables at the begining of
- * the body of each function or function block, and use them as
- * in function calls later on as they become necessary...
- * Note that we cannot create these variables just before a function
- * call, as the function call itself may be integrated within an
- * expression, or another function call!
- *
- * The variables are declared in the exact same order in which they
- * will be used later on during the function calls, which allows us
- * to simply re-create the name that was used for the temporary variable
- * instead of keeping it in some list.
- * The names are recreated by the temp_var_name_factory, after reset()
- * has been called!
- *
- * This function will genertae code similar to...
- *
- * INT __TMP_0 = 23;
- * REAL __TMP_1 = 45.5;
- * ...
- */
- temp_var_name_c temp_var_name_factory;
-
/* When calling a function block, we must first find it's type,
* by searching through the declarations of the variables currently
* in scope.
@@ -303,7 +242,6 @@
default_variable_name(IL_DEFVAR, NULL),
default_variable_back_name(IL_DEFVAR_BACK, NULL)
{
- //search_il_operand_type = new search_il_operand_type_c(scope);
search_expression_type = new search_expression_type_c(scope);
search_fb_instance_decl = new search_fb_instance_decl_c(scope);
search_varfb_instance_type = new search_varfb_instance_type_c(scope);
@@ -316,14 +254,11 @@
virtual ~generate_c_il_c(void) {
delete search_fb_instance_decl;
- //delete search_il_operand_type;
delete search_expression_type;
delete search_varfb_instance_type;
}
void generate(instruction_list_c *il) {
- generate_c_tempvardecl_c generate_c_tempvardecl(&s4o);
- generate_c_tempvardecl.generate(il, &temp_var_name_factory);
il->accept(*this);
}
@@ -384,13 +319,14 @@
if (NULL == sv) ERROR;
identifier_c *id = dynamic_cast<identifier_c *>(sv->var_name);
if (NULL == id) ERROR;
-
+
identifier_c param(param_name);
//SYM_REF3(il_param_assignment_c, il_assign_operator, il_operand, simple_instr_list)
- il_param_assignment_c il_param_assignment(¶m, &this->default_variable_name, NULL);
+ il_assign_operator_c il_assign_operator(¶m);
+ il_param_assignment_c il_param_assignment(&il_assign_operator, &this->default_variable_name, NULL);
// SYM_LIST(il_param_list_c)
- il_param_list_c il_param_list;
+ il_param_list_c il_param_list;
il_param_list.add_element(&il_param_assignment);
CAL_operator_c CAL_operator;
// SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list)
@@ -461,6 +397,9 @@
private:
+#if 0
+I NEED TO FIX THIS!!!
+TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO
void *visit(eno_param_c *symbol) {
if (this->is_variable_prefix_null()) {
s4o.print("*");
@@ -471,6 +410,9 @@
s4o.print("ENO");
return NULL;
}
+TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO
+#endif
+
/*********************/
/* B 1.4 - Variables */
@@ -632,7 +574,15 @@
if (symbol->il_operand_list != NULL)
nb_param += ((list_c *)symbol->il_operand_list)->n;
+ #define search(x) search_f(x)
+ #define next() next_nf()
+// #define search_constant_type_c::constant_int_type_name search_expression_type_c::integer
+ #define constant_int_type_name integer
#include "il_code_gen.c"
+ #undef constant_int_type_name
+// #undef search_constant_type_c::constant_int_type_name
+ #undef next
+ #undef search
}
else {
@@ -673,11 +623,11 @@
* the following line...
*/
if (param_value == NULL)
- param_value = function_call_param_iterator.search(param_name);
+ param_value = function_call_param_iterator.search_f(param_name);
/* Get the value from a foo(<param_value>) style call */
if (param_value == NULL)
- param_value = function_call_param_iterator.next();
+ param_value = function_call_param_iterator.next_nf();
if (param_value == NULL && param_direction == function_param_iterator_c::direction_in) {
/* No value given for parameter, so we must use the default... */
@@ -844,11 +794,11 @@
function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction();
/* Get the value from a foo(<param_name> = <param_value>) style call */
- symbol_c *param_value = function_call_param_iterator.search(param_name);
+ symbol_c *param_value = function_call_param_iterator.search_f(param_name);
/* Get the value from a foo(<param_value>) style call */
if (param_value == NULL)
- param_value = function_call_param_iterator.next();
+ param_value = function_call_param_iterator.next_nf();
symbol_c *param_type = fp_iterator.param_type();
if (param_type == NULL) ERROR;
@@ -889,18 +839,18 @@
function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction();
/* Get the value from a foo(<param_name> = <param_value>) style call */
- symbol_c *param_value = function_call_param_iterator.search(param_name);
+ symbol_c *param_value = function_call_param_iterator.search_f(param_name);
/* Get the value from a foo(<param_value>) style call */
if (param_value == NULL)
- param_value = function_call_param_iterator.next();
+ param_value = function_call_param_iterator.next_nf();
/* now output the value assignment */
if (param_value != NULL)
if ((param_direction == function_param_iterator_c::direction_out) ||
(param_direction == function_param_iterator_c::direction_inout)) {
symbol_c *param_type = search_varfb_instance_type->get_type(param_value, false);
-
+
s4o.print(";\n"+ s4o.indent_spaces);
param_value->accept(*this);
s4o.print(" = ");
@@ -955,7 +905,7 @@
identifier_c en_param_name("EN");
/* Get the value from EN param */
- symbol_c *EN_param_value = function_call_param_iterator.search(&en_param_name);
+ symbol_c *EN_param_value = function_call_param_iterator.search_f(&en_param_name);
if (EN_param_value == NULL)
EN_param_value = (symbol_c*)(new boolean_literal_c((symbol_c*)(new bool_type_name_c()), new boolean_true_c()));
else
@@ -964,12 +914,20 @@
identifier_c eno_param_name("EN0");
/* Get the value from ENO param */
- symbol_c *ENO_param_value = function_call_param_iterator.search(&eno_param_name);
+ symbol_c *ENO_param_value = function_call_param_iterator.search_f(&eno_param_name);
if (ENO_param_value != NULL)
nb_param --;
ADD_PARAM_LIST(ENO_param_value, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_out)
+ #define search(x) search_f(x)
+ #define next() next_nf()
+// #define search_constant_type_c::constant_int_type_name search_expression_type_c::integer
+ #define constant_int_type_name integer
#include "st_code_gen.c"
+ #undef constant_int_type_name
+// #undef search_constant_type_c::constant_int_type_name
+ #undef next
+ #undef search
}
else {
@@ -998,7 +956,7 @@
/* Get the value from a foo(<param_name> = <param_value>) style call */
if (param_value == NULL)
- param_value = function_call_param_iterator.search(param_name);
+ param_value = function_call_param_iterator.search_f(param_name);
/* Get the value from a foo(<param_value>) style call */
/* NOTE: the following line of code is not required in this case, but it doesn't
@@ -1009,7 +967,7 @@
* the following line...
*/
if (param_value == NULL)
- param_value = function_call_param_iterator.next();
+ param_value = function_call_param_iterator.next_nf();
if (param_value == NULL) {
/* No value given for parameter, so we must use the default... */
--- a/stage4/generate_c/generate_c_st.cc Wed Sep 02 13:39:05 2009 +0200
+++ b/stage4/generate_c/generate_c_st.cc Wed Sep 02 14:05:27 2009 +0200
@@ -92,58 +92,13 @@
}
- private:
- /* Some function calls in the body of functions or function blocks
- * may leave some parameters to their default values, and
- * ignore some output parameters of the function being called.
- * Our conversion of ST functions to C++ does not contemplate that,
- * i.e. each called function must get all it's input and output
- * parameters set correctly.
- * For input parameters we merely need to call the function with
- * the apropriate default value, but for output parameters
- * we must create temporary variables to hold the output value.
- *
- * We declare all the temporary output variables at the begining of
- * the body of each function or function block, and use them as
- * in function calls later on as they become necessary...
- * Note that we cannot create these variables just before a function
- * call, as the function call itself may be integrated within an
- * expression, or another function call!
- *
- * The variables are declared in the exact same order in which they
- * will be used later on during the function calls, which allows us
- * to simply re-create the name that was used for the temporary variable
- * instead of keeping it in some list.
- * The names are recreated by the temp_var_name_factory, after reset()
- * has been called!
- *
- * This function will genertae code similar to...
- *
- * INT __TMP_0 = 23;
- * REAL __TMP_1 = 45.5;
- * ...
- */
- temp_var_name_c temp_var_name_factory;
-
public:
void generate(statement_list_c *stl) {
- generate_c_tempvardecl_c generate_c_tempvardecl(&s4o);
- generate_c_tempvardecl.generate(stl, &temp_var_name_factory);
stl->accept(*this);
}
private:
-void *visit(eno_param_c *symbol) {
- if (this->is_variable_prefix_null()) {
- s4o.print("*");
- }
- else {
- this->print_variable_prefix();
- }
- s4o.print("ENO");
- return NULL;
-}
/*********************/
/* B 1.4 - Variables */
@@ -446,45 +401,57 @@
}
void *visit(function_invocation_c *symbol) {
- function_declaration_c *f_decl = function_symtable.find_value(symbol->function_name);
-
symbol_c* function_type_prefix = NULL;
symbol_c* function_name = NULL;
symbol_c* function_type_suffix = NULL;
std::list<FUNCTION_PARAM> param_list;
FUNCTION_PARAM *param;
-
+
+ symbol_c *parameter_assignment_list = NULL;
+ if (NULL != symbol-> formal_param_list) parameter_assignment_list = symbol-> formal_param_list;
+ if (NULL != symbol->nonformal_param_list) parameter_assignment_list = symbol->nonformal_param_list;
+ if (NULL == parameter_assignment_list) ERROR;
+
+ function_declaration_c *f_decl = function_symtable.find_value(symbol->function_name);
if (f_decl == function_symtable.end_value()) {
/* The function called is not in the symtable, so we test if it is a
* standard function defined in standard */
-
+
function_type_t current_function_type = get_function_type((identifier_c *)symbol->function_name);
if (current_function_type == function_none) ERROR;
-
+
symbol_c *function_return_type = search_expression_type->get_type(symbol);
-
+
function_call_param_iterator_c function_call_param_iterator(symbol);
- int nb_param = ((list_c *)symbol->parameter_assignment_list)->n;
-
+ int nb_param = ((list_c *)parameter_assignment_list)->n;
+
identifier_c en_param_name("EN");
/* Get the value from EN param */
- symbol_c *EN_param_value = function_call_param_iterator.search(&en_param_name);
+ symbol_c *EN_param_value = function_call_param_iterator.search_f(&en_param_name);
if (EN_param_value == NULL)
EN_param_value = (symbol_c*)(new boolean_literal_c((symbol_c*)(new bool_type_name_c()), new boolean_true_c()));
else
nb_param --;
ADD_PARAM_LIST(EN_param_value, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_in)
-
+
identifier_c eno_param_name("ENO");
/* Get the value from ENO param */
- symbol_c *ENO_param_value = function_call_param_iterator.search(&eno_param_name);
+ symbol_c *ENO_param_value = function_call_param_iterator.search_f(&eno_param_name);
if (ENO_param_value != NULL)
nb_param --;
ADD_PARAM_LIST(ENO_param_value, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_out)
-
+
+ #define search(x) search_f(x)
+ #define next() next_nf()
+// #define search_constant_type_c::constant_int_type_name search_expression_type_c::integer
+ #define constant_int_type_name integer
#include "st_code_gen.c"
-
+ #undef constant_int_type_name
+// #undef search_constant_type_c::constant_int_type_name
+ #undef next
+ #undef search
+
}
else {
/* loop through each function parameter, find the value we should pass
@@ -501,11 +468,11 @@
function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction();
/* Get the value from a foo(<param_name> = <param_value>) style call */
- symbol_c *param_value = function_call_param_iterator.search(param_name);
+ symbol_c *param_value = function_call_param_iterator.search_f(param_name);
/* Get the value from a foo(<param_value>) style call */
if (param_value == NULL)
- param_value = function_call_param_iterator.next();
+ param_value = function_call_param_iterator.next_nf();
if (param_value == NULL && param_direction == function_param_iterator_c::direction_in) {
/* No value given for parameter, so we must use the default... */
@@ -636,11 +603,11 @@
/*fprintf(stderr, "param : %s\n", param_name->value);*/
/* Get the value from a foo(<param_name> = <param_value>) style call */
- symbol_c *param_value = function_call_param_iterator.search(param_name);
+ symbol_c *param_value = function_call_param_iterator.search_f(param_name);
/* Get the value from a foo(<param_value>) style call */
if (param_value == NULL)
- param_value = function_call_param_iterator.next();
+ param_value = function_call_param_iterator.next_nf();
symbol_c *param_type = fp_iterator.param_type();
if (param_type == NULL) ERROR;
@@ -683,11 +650,11 @@
function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction();
/* Get the value from a foo(<param_name> = <param_value>) style call */
- symbol_c *param_value = function_call_param_iterator.search(param_name);
+ symbol_c *param_value = function_call_param_iterator.search_f(param_name);
/* Get the value from a foo(<param_value>) style call */
if (param_value == NULL)
- param_value = function_call_param_iterator.next();
+ param_value = function_call_param_iterator.next_nf();
/* now output the value assignment */
if (param_value != NULL)
--- a/stage4/generate_c/generate_c_tempvardecl.cc Wed Sep 02 13:39:05 2009 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,179 +0,0 @@
-/*
- * (c) 2003 Mario de Sousa
- *
- * Offered to the public under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- * Public License for more details.
- *
- * 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 IL and ST compiler.
- *
- * Based on the
- * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
- *
- */
-
-
-/*
- * Declare temporary variables to be later used as output parameters
- * in function calls for which not all output parameters were
- * defined in the original (st or il) source code.
- *
- * This is part of the 4th stage that generates
- * a c++ source program equivalent to the IL and ST
- * code.
- */
-
-
-
-
-class temp_var_name_c {
- private:
- int counter;
-
- public:
- void reset(void) {counter = 0;}
- temp_var_name_c(void) {reset();}
-
- public:
- std::string *new_name(void) {
- std::string *new_str = new std::string(TEMP_VAR);
- /* yikes!!! How to convert an int to a string elegantly???
- * Right now I (Mario) can only think of snprintf()
- * C++ must have a more elegant method!
- */
- int int_str_size = snprintf(NULL, 0, "%d", counter);
- if (int_str_size <= 0) ERROR;
- char *int_str = (char *)malloc(int_str_size+1);
- if (snprintf(int_str, int_str_size+1, "%d", counter++) >= int_str_size+1) ERROR;
- *new_str += int_str;
- free(int_str);
- return new_str;
- }
-
-};
-
-
-
-/***********************************************************************/
-/***********************************************************************/
-/***********************************************************************/
-/***********************************************************************/
-
-
-
-/* Some function calls in the body of functions or function blocks
- * may leave some parameters to their default values, and
- * ignore some output parameters of the function being called.
- * Our conversion of ST functions to C++ does not contemplate that,
- * i.e. each called function must get all it's input and output
- * parameters set correctly.
- * For input parameters we merely need to call the function with
- * the apropriate default value, but for output parameters
- * we must create temporary variables to hold the output value.
- *
- * We declare all the temporary output variables at the begining of
- * the body of each function or function block, and use them as
- * in function calls later on as they become necessary...
- * Note that we cannot create these variables just before a function
- * call, as the function call itself may be integrated within an
- * expression, or another function call!
- *
- * The variables are declared in the exact same order in which they
- * will be used later on during the function calls, which allows us
- * to simply re-create the name that was used for the temporary variable
- * instead of keeping it in some list.
- * The names are recreated by the temp_var_name_factory, after reset()
- * has been called!
- *
- * This function will genertae code similar to...
- *
- * INT __TMP_0 = 23;
- * REAL __TMP_1 = 45.5;
- * ...
- */
-
-class generate_c_tempvardecl_c: generate_c_typedecl_c {
- public:
- generate_c_tempvardecl_c(stage4out_c *s4o_ptr): generate_c_typedecl_c(s4o_ptr) {}
-
- void generate(symbol_c *body, temp_var_name_c *temp_var_name_factory) {
- temp_var_name_factory->reset();
- function_call_iterator_c fcall_iterator(body);
- for(symbol_c *finvocation = NULL; (finvocation = fcall_iterator.next()) != NULL;) {
- /* get the name of the next function that gets called */
- identifier_c *fcalled_name = fcall_iterator.fname();
- /* get that function's declaration... */
- function_declaration_c *fdecl = function_symtable.find_value(fcalled_name);
- if (fdecl == function_symtable.end_value()) {
- function_type_t function_type = get_function_type(fcalled_name);
- if (function_type == function_none) ERROR;
- return;
- }
- /* create iterator to iterate through each of the called function's parameters... */
- function_param_iterator_c fp_iterator(fdecl);
-
- /* iterate through each of the called function's parameters... */
- identifier_c *param_name = NULL;
- function_call_param_iterator_c function_call_param_iterator(finvocation);
- for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) {
-
- function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction();
- if (param_direction == function_param_iterator_c::direction_in)
- /* ignore input only parameters...
- * we do not need to create temporary variables for these!
- */
- continue;
-
- /* Get the value from a foo(<param_name> = <param_value>) style call */
- symbol_c *param_value = function_call_param_iterator.search(param_name);
-
- /* Get the value from a foo(<param_value>) style call */
- if (param_value == NULL)
- param_value = function_call_param_iterator.next();
-
- if (param_value != NULL)
- /* ignore output parameters to which a variable is passed...
- * we do not need to create temporary variables for these!
- */
- continue;
-
- symbol_c *param_type = fp_iterator.param_type();
-
- /* get the parameter's default value */
- param_value = fp_iterator.default_value();
-
- /* If no default value specified in function declaration,
- * get the default value of this variable's type
- */
- if (param_value == NULL)
- param_value = (symbol_c *)param_type->accept(*type_initial_value_c::instance());
- if (param_value == NULL) ERROR;
-
- /* now declare a temporary variable, with the correct default value... */
- s4o.print(s4o.indent_spaces);
- param_type->accept(*this);
- s4o.print(" ");
-
- std::string *temp_var_name = temp_var_name_factory->new_name();
- s4o.print(*temp_var_name);
- delete temp_var_name;
-
- s4o.print(" = ");
- param_value->accept(*this);
- s4o.print(";\n");
- }
- }
- temp_var_name_factory->reset();
- s4o.print("\n");
- }
-};
--- a/stage4/generate_c/generate_c_vardecl.cc Wed Sep 02 13:39:05 2009 +0200
+++ b/stage4/generate_c/generate_c_vardecl.cc Wed Sep 02 14:05:27 2009 +0200
@@ -741,9 +741,8 @@
static const unsigned int program_vt = 0x0100; // PROGRAM (inside a configuration!)
// Programs declared inside a resource will not be declared
// unless program_vt is acompanied by resource_vt
-
- static const unsigned int eneno_vt = 0x0200; // EN/ENO declaration
-
+ static const unsigned int en_vt = 0x0200; // EN declaration
+ static const unsigned int eno_vt = 0x0400; // ENO declaration
static const unsigned int resource_vt = 0x8000; // RESOURCE (inside a configuration!)
// This, just of itself, will not print out any declarations!!
// It must be acompanied by either program_vt and/or global_vt
@@ -802,11 +801,11 @@
typedef enum {finterface_vf,
foutputassign_vf,
local_vf,
- localinit_vf,
- init_vf,
- constructorinit_vf,
- globalinit_vf
- } varformat_t;
+ localinit_vf,
+ init_vf,
+ constructorinit_vf,
+ globalinit_vf
+ } varformat_t;
private:
@@ -832,10 +831,6 @@
* specific global variable declaration (with #define...)*/
symbol_c *resource_name;
- /* Store if En and ENO parameters have been defined by user */
- bool en_declared;
- bool eno_declared;
-
/* Holds the references to the type and initial value
* of the variables currently being declared.
* Please read the comment under var1_init_decl_c for further
@@ -878,8 +873,9 @@
symbol_c *globalnamespace;
/* Actually produce the output where variables are declared... */
- /* Note that located variables are the exception, they
- * being declared in the located_var_decl_c visitor...
+ /* Note that located variables and EN/ENO are the exception, they
+ * being declared in the located_var_decl_c,
+ * en_param_declaration_c and eno_param_declaration_c visitors...
*/
void *declare_variables(symbol_c *symbol, bool is_fb = false) {
list_c *list = dynamic_cast<list_c *>(symbol);
@@ -986,20 +982,10 @@
globalnamespace = NULL;
nv = NULL;
resource_name = res_name;
- en_declared = false;
- eno_declared = false;
}
~generate_c_vardecl_c(void) {}
- bool is_en_declared(void) {
- return en_declared;
- }
-
- bool is_eno_declared(void) {
- return eno_declared;
- }
-
void print(symbol_c *symbol, symbol_c *scope = NULL, const char *variable_prefix = NULL) {
this->set_variable_prefix(variable_prefix);
if (globalinit_vf == wanted_varformat)
@@ -1022,24 +1008,6 @@
globalnamespace = NULL;
}
- void print_eneno(void) {
- if (!en_declared) {
- if (wanted_varformat == finterface_vf) {
- if (finterface_var_count > 0)
- s4o.print(",\n" + s4o.indent_spaces);
- s4o.print("BOOL EN");
- }
- else
- s4o.print(s4o.indent_spaces + "BOOL EN;\n");
- }
- if (!eno_declared) {
- if (wanted_varformat == finterface_vf)
- s4o.print(",\n" + s4o.indent_spaces + "BOOL *ENO");
- else
- s4o.print(s4o.indent_spaces + "BOOL ENO;\n");
- }
- }
-
protected:
/***************************/
/* B 0 - Programming Model */
@@ -1157,24 +1125,108 @@
void *visit(en_param_declaration_c *symbol) {
TRACE("en_declaration_c");
- if (en_declared) ERROR;
if (wanted_varformat == finterface_vf) {
finterface_var_count++;
}
- if ((current_vartype & eneno_vt) != 0) {
+ if ((wanted_vartype & en_vt) != 0) {
if (wanted_varformat == finterface_vf) {
s4o.print(nv->get());
- s4o.print("\n" + s4o.indent_spaces + "BOOL EN");
- }
+ s4o.print("\n" + s4o.indent_spaces);
+ symbol->type->accept(*this);
+ s4o.print(" ");
+ symbol->name->accept(*this);
+ }
+
+ if ((wanted_varformat == local_vf) ||
+ (wanted_varformat == init_vf) ||
+ (wanted_varformat == localinit_vf)) {
+ s4o.print(s4o.indent_spaces);
+ if (wanted_varformat != init_vf) {
+ symbol->type->accept(*this);
+ s4o.print(" ");
+ }
+ print_variable_prefix();
+ symbol->name->accept(*this);
+ if (wanted_varformat != local_vf) {
+ s4o.print(" = ");
+ symbol->value->accept(*this);
+ s4o.print(";");
+ }
+ s4o.print(";\n");
+ }
+
if (wanted_varformat == constructorinit_vf) {
+ /* NOTE: I (Mario) think this is dead code - never gets executed. Must confirm it before deleting it... */
s4o.print(nv->get());
this->print_variable_prefix();
- s4o.print("ENO = __BOOL_LITERAL(TRUE);");
+ // s4o.print("EN = __BOOL_LITERAL(TRUE);");
+ symbol->name->accept(*this);
+ s4o.print(" = ");
+ symbol->value->accept(*this);
+ s4o.print(";");
}
}
- en_declared = true;
- return NULL;
-}
+ return NULL;
+}
+
+
+void *visit(eno_param_declaration_c *symbol) {
+ TRACE("eno_declaration_c");
+ if (wanted_varformat == finterface_vf) {
+ finterface_var_count++;
+ }
+ if ((wanted_vartype & eno_vt) != 0) {
+ if (wanted_varformat == finterface_vf) {
+ s4o.print(nv->get());
+ // s4o.print("\n" + s4o.indent_spaces + "BOOL *ENO");
+ s4o.print("\n" + s4o.indent_spaces);
+ symbol->type->accept(*this);
+ s4o.print(" *__");
+ symbol->name->accept(*this);
+ }
+
+ if ((wanted_varformat == local_vf) ||
+ (wanted_varformat == init_vf) ||
+ (wanted_varformat == localinit_vf)) {
+ s4o.print(s4o.indent_spaces);
+ if (wanted_varformat != init_vf) {
+ symbol->type->accept(*this);
+ s4o.print(" ");
+ }
+ print_variable_prefix();
+ symbol->name->accept(*this);
+ if (wanted_varformat != local_vf) {
+ s4o.print(" = __BOOL_LITERAL(TRUE);");
+ }
+ s4o.print(";\n");
+ }
+
+ if (wanted_varformat == foutputassign_vf) {
+ s4o.print(s4o.indent_spaces + "if (__");
+ symbol->name->accept(*this);
+ s4o.print(" != NULL) {\n");
+ s4o.indent_right();
+ s4o.print(s4o.indent_spaces + "*__");
+ symbol->name->accept(*this);
+ s4o.print(" = ");
+ symbol->name->accept(*this);
+ s4o.print(";\n");
+ s4o.indent_left();
+ s4o.print(s4o.indent_spaces + "}\n");
+ }
+
+ if (wanted_varformat == constructorinit_vf) {
+ /* NOTE: I (Mario) think this is dead code - never gets executed. Must confirm it before deleting it... */
+ s4o.print(nv->get());
+ this->print_variable_prefix();
+ // s4o.print("ENO = __BOOL_LITERAL(TRUE);");
+ symbol->name->accept(*this);
+ s4o.print(" = __BOOL_LITERAL(TRUE);");
+ }
+ }
+ return NULL;
+}
+
void *visit(raising_edge_option_c *symbol) {
// TO DO ...
@@ -1298,26 +1350,6 @@
return NULL;
}
-void *visit(eno_param_declaration_c *symbol) {
- TRACE("eno_declaration_c");
- if (eno_declared) ERROR;
- if (wanted_varformat == finterface_vf) {
- finterface_var_count++;
- }
- if ((current_vartype & eneno_vt) != 0) {
- if (wanted_varformat == finterface_vf) {
- s4o.print(nv->get());
- s4o.print("\n" + s4o.indent_spaces + "BOOL *EN0");
- }
- if (wanted_varformat == constructorinit_vf) {
- s4o.print(nv->get());
- this->print_variable_prefix();
- s4o.print("ENO = __BOOL_LITERAL(TRUE);");
- }
- }
- eno_declared = true;
- return NULL;
-}
/* VAR_IN_OUT var_declaration_list END_VAR */
void *visit(input_output_declarations_c *symbol) {
@@ -2213,7 +2245,9 @@
* to it, and then output the c equivalent...
*/
function_param_iterator_c fp_iterator(p_decl);
+#if 0
function_call_param_iterator_c function_call_param_iterator(symbol);
+#endif
identifier_c *param_name;
nv->push("", ", ");
for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) {
@@ -2251,17 +2285,6 @@
param_value->accept(*this);
#endif
break;
-#if 0
- if (param_value == NULL) {
- /* no parameter value given, so we pass a previously declared temporary variable. */
- std::string *temp_var_name = temp_var_name_factory.new_name();
- s4o.print(*temp_var_name);
- delete temp_var_name;
- } else {
- param_value->accept(*this);
- }
-#endif
- break;
} /* switch */
} /* for(...) */
--- a/stage4/generate_iec/generate_iec.cc Wed Sep 02 13:39:05 2009 +0200
+++ b/stage4/generate_iec/generate_iec.cc Wed Sep 02 14:05:27 2009 +0200
@@ -43,6 +43,7 @@
#include <string>
#include <iostream>
#include <sstream>
+#include <typeinfo>
#include "generate_iec.hh"
#include "../stage4.hh"
@@ -122,6 +123,7 @@
public:
/* EN/ENO */
+#if 0
void *visit(en_param_c *symbol) {
s4o.print("EN");
return NULL;
@@ -131,6 +133,17 @@
s4o.print("ENO");
return NULL;
}
+void *visit(en_param_c *symbol) {
+ return symbol->param_name->accept(*this);
+}
+
+void *visit(eno_param_c *symbol) {
+ return symbol->param_name->accept(*this);
+}
+#endif
+
+
+
/***************************/
/* 2.1.6 Pragmas */
@@ -161,7 +174,6 @@
void *visit(octal_integer_c *symbol) {return print_token(symbol);}
void *visit(hex_integer_c *symbol) {return print_token(symbol);}
-void *visit(numeric_literal_c *symbol) {return print_literal(symbol->type, symbol->value);}
void *visit(integer_literal_c *symbol) {return print_literal(symbol->type, symbol->value);}
void *visit(real_literal_c *symbol) {return print_literal(symbol->type, symbol->value);}
void *visit(bit_string_literal_c *symbol) {return print_literal(symbol->type, symbol->value);}
@@ -314,9 +326,10 @@
void *visit(dword_type_name_c *symbol) {s4o.print("DWORD"); return NULL;}
void *visit(string_type_name_c *symbol) {s4o.print("STRING"); return NULL;}
void *visit(wstring_type_name_c *symbol) {s4o.print("WSTRING"); return NULL;}
+/*
void *visit(constant_int_type_name_c *symbol) {return NULL;}
void *visit(constant_real_type_name_c *symbol) {return NULL;}
-
+*/
/********************************/
/* B 1.3.3 - Derived data types */
@@ -589,14 +602,16 @@
/* VAR_INPUT [RETAIN | NON_RETAIN] input_declaration_list END_VAR */
/* option -> the RETAIN/NON_RETAIN/<NULL> directive... */
void *visit(input_declarations_c *symbol) {
- s4o.print(s4o.indent_spaces); s4o.print("VAR_INPUT ");
- if (symbol->option != NULL)
- symbol->option->accept(*this);
- s4o.print("\n");
- s4o.indent_right();
- symbol->input_declaration_list->accept(*this);
- s4o.indent_left();
- s4o.print(s4o.indent_spaces); s4o.print("END_VAR\n");
+ if (typeid(*(symbol->method)) == typeid(explicit_definition_c)) {
+ s4o.print(s4o.indent_spaces); s4o.print("VAR_INPUT ");
+ if (symbol->option != NULL)
+ symbol->option->accept(*this);
+ s4o.print("\n");
+ s4o.indent_right();
+ symbol->input_declaration_list->accept(*this);
+ s4o.indent_left();
+ s4o.print(s4o.indent_spaces); s4o.print("END_VAR\n");
+ }
return NULL;
}
@@ -614,8 +629,29 @@
return NULL;
}
+/* dummy classes only used as flags! */
+void *visit(explicit_definition_c *symbol) {return NULL;}
+void *visit(implicit_definition_c *symbol) {return NULL;}
+
+/* EN : BOOL := 1 */
void *visit(en_param_declaration_c *symbol) {
- s4o.print("EN : BOOL := 1");
+ if (typeid(*(symbol->method)) == typeid(explicit_definition_c)) {
+ symbol->name->accept(*this);
+ s4o.print(" : ");
+ symbol->type->accept(*this);
+ s4o.print(" := ");
+ symbol->value->accept(*this);
+ }
+ return NULL;
+}
+
+/* ENO : BOOL */
+void *visit(eno_param_declaration_c *symbol) {
+ if (typeid(*(symbol->method)) == typeid(explicit_definition_c)) {
+ symbol->name->accept(*this);
+ s4o.print(" : ");
+ symbol->type->accept(*this);
+ }
return NULL;
}
@@ -682,19 +718,16 @@
/* VAR_OUTPUT [RETAIN | NON_RETAIN] var_init_decl_list END_VAR */
/* option -> may be NULL ! */
void *visit(output_declarations_c *symbol) {
- s4o.print(s4o.indent_spaces); s4o.print("VAR_OUTPUT ");
- if (symbol->option != NULL)
- symbol->option->accept(*this);
- s4o.print("\n");
- s4o.indent_right();
- symbol->var_init_decl_list->accept(*this);
- s4o.indent_left();
- s4o.print(s4o.indent_spaces); s4o.print("END_VAR\n");
- return NULL;
-}
-
-void *visit(eno_param_declaration_c *symbol) {
- s4o.print("EN0 : BOOL");
+ if (typeid(*(symbol->method)) == typeid(explicit_definition_c)) {
+ s4o.print(s4o.indent_spaces); s4o.print("VAR_OUTPUT ");
+ if (symbol->option != NULL)
+ symbol->option->accept(*this);
+ s4o.print("\n");
+ s4o.indent_right();
+ symbol->var_init_decl_list->accept(*this);
+ s4o.indent_left();
+ s4o.print(s4o.indent_spaces); s4o.print("END_VAR\n");
+ }
return NULL;
}
@@ -1689,7 +1722,13 @@
void *visit(function_invocation_c *symbol) {
symbol->function_name->accept(*this);
s4o.print("(");
- symbol->parameter_assignment_list->accept(*this);
+
+ /* 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) symbol-> formal_param_list->accept(*this);
+ if (symbol->nonformal_param_list != NULL) symbol->nonformal_param_list->accept(*this);
+
s4o.print(")");
return NULL;
}
@@ -1726,8 +1765,13 @@
void *visit(fb_invocation_c *symbol) {
symbol->fb_name->accept(*this);
s4o.print("(");
- if (symbol->param_assignment_list != NULL)
- symbol->param_assignment_list->accept(*this);
+ /* If the syntax parser is working correctly, at most one of the
+ * following two symbols will be NULL, while the other is != NULL.
+ * The two may be NULL simultaneously!
+ */
+ if (symbol-> formal_param_list != NULL) symbol-> formal_param_list->accept(*this);
+ if (symbol->nonformal_param_list != NULL) symbol->nonformal_param_list->accept(*this);
+
s4o.print(")");
return NULL;
}
--- a/stage4/stage4.cc Wed Sep 02 13:39:05 2009 +0200
+++ b/stage4/stage4.cc Wed Sep 02 14:05:27 2009 +0200
@@ -157,6 +157,8 @@
#endif
return NULL;
}
+
+
void *stage4out_c::printlocation(std::string str) {
return printlocation(str.c_str());
}