--- a/README.build Wed May 28 11:32:09 2014 +0200
+++ b/README.build Sat Jul 05 14:10:28 2014 +0100
@@ -4,6 +4,7 @@
1) Compiling under Linux
------------------------
+$ autoreconf -i
$ ./configure
$ make
--- a/lib/iec_std_lib.h Wed May 28 11:32:09 2014 +0200
+++ b/lib/iec_std_lib.h Sat Jul 05 14:10:28 2014 +0100
@@ -180,11 +180,36 @@
/**********************************************/
/* Time conversion to/from timespec functions */
/**********************************************/
-
+/* NOTE: The following function was turned into a macro, so it could be used to initialize the initial value of TIME variables.
+ * Since each macro parameter is evaluated several times, the macro may result in multiple function invocations if an expression
+ * containing a function invocation is passed as a parameter. However, currently matiec only uses this conversion macro with
+ * constant literals, so it is safe to change it into a macro.
+ */
+/* NOTE: I (Mario - msousa@fe.up.pt) believe that the following function contains a bug when handling negative times.
+ * The equivalent macro has this bug fixed.
+ * e.g.;
+ * T#3.8s
+ * using the function, will result in a timespec of 3.8s !!!:
+ * tv_sec = 4 <----- 1 * 3.8 is rounded up when converting a double to an int!
+ * tv_nsec = -200 000 000 <----- 1 * (3.8 - 4)*1e9
+ *
+ * -T#3.8s
+ * using the function, will result in a timespec of -11.8s !!!:
+ * tv_sec = -4 <----- -1 * 3.8 is rounded down when converting a double to an int!
+ * tv_nsec = -7 800 000 000 <----- -1 * (3.8 - -4)*1e9
+ */
+/* NOTE: Due to the fact that the C compiler may round a tv_sec number away from zero,
+ * the following macro may result in a timespec that is not normalized, i.e. with a tv_sec > 0, and a tv_nsec < 0 !!!!
+ * This is due to the rounding that C compiler applies when converting a (long double) to a (long int).
+ * To produce normalized timespec's we need to use floor(), but we cannot call any library functions since we want this macro to be
+ * useable as a variable initializer.
+ * VAR x : TIME = T#3.5h; END_VAR ---> IEC_TIME x = __time_to_timespec(1, 0, 0, 0, 3.5, 0);
+ */
+/*
static inline IEC_TIMESPEC __time_to_timespec(int sign, double mseconds, double seconds, double minutes, double hours, double days) {
IEC_TIMESPEC ts;
- /* sign is 1 for positive values, -1 for negative time... */
+ // sign is 1 for positive values, -1 for negative time...
long double total_sec = ((days*24 + hours)*60 + minutes)*60 + seconds + mseconds/1e3;
if (sign >= 0) sign = 1; else sign = -1;
ts.tv_sec = sign * (long int)total_sec;
@@ -192,8 +217,29 @@
return ts;
}
-
-
+*/
+/* NOTE: Unfortunately older versions of ANSI C (e.g. C99) do not allow explicit identification of elements in initializers
+ * e.g. {tv_sec = 1, tv_nsec = 300}
+ * They are therefore commented out. This however means that any change to the definition of IEC_TIMESPEC may require this
+ * macro to be updated too!
+ */
+#define ld long double
+#define __time_to_timespec(sign,mseconds,seconds,minutes,hours,days) \
+ ((IEC_TIMESPEC){\
+ /*tv_sec =*/ ((long int) (((sign>=0)?1:-1)*((((ld)days*24 + (ld)hours)*60 + (ld)minutes)*60 + (ld)seconds + (ld)mseconds/1e3))), \
+ /*tv_nsec =*/ ((long int)(( \
+ ((long double)(((sign>=0)?1:-1)*((((ld)days*24 + (ld)hours)*60 + (ld)minutes)*60 + (ld)seconds + (ld)mseconds/1e3))) - \
+ ((long int) (((sign>=0)?1:-1)*((((ld)days*24 + (ld)hours)*60 + (ld)minutes)*60 + (ld)seconds + (ld)mseconds/1e3))) \
+ )*1e9))\
+ })
+#undef ld
+
+
+
+
+/* NOTE: The following function was turned into a macro, so it could be used to initialize the initial value of TOD (TIME_OF_DAY) variables */
+/* NOTE: many (but not all) of the same comments made regarding __time_to_timespec() are also valid here, so go and read those comments too!
+/*
static inline IEC_TIMESPEC __tod_to_timespec(double seconds, double minutes, double hours) {
IEC_TIMESPEC ts;
@@ -203,6 +249,18 @@
return ts;
}
+*/
+#define ld long double
+#define __tod_to_timespec(seconds,minutes,hours) \
+ ((IEC_TIMESPEC){\
+ /*tv_sec =*/ ((long int) ((((ld)hours)*60 + (ld)minutes)*60 + (ld)seconds)), \
+ /*tv_nsec =*/ ((long int)(( \
+ ((long double)((((ld)hours)*60 + (ld)minutes)*60 + (ld)seconds)) - \
+ ((long int) ((((ld)hours)*60 + (ld)minutes)*60 + (ld)seconds)) \
+ )*1e9))\
+ })
+#undef ld
+
#define EPOCH_YEAR 1970
#define SECONDS_PER_MINUTE 60
@@ -221,10 +279,10 @@
typedef struct {
int tm_sec; /* Seconds. [0-60] (1 leap second) */
int tm_min; /* Minutes. [0-59] */
- int tm_hour; /* Hours. [0-23] */
+ int tm_hour; /* Hours. [0-23] */
int tm_day; /* Day. [1-31] */
int tm_mon; /* Month. [0-11] */
- int tm_year; /* Year */
+ int tm_year; /* Year */
} tm;
static inline tm convert_seconds_to_date_and_time(long int seconds) {
--- a/lib/iec_types.h Wed May 28 11:32:09 2014 +0200
+++ b/lib/iec_types.h Sat Jul 05 14:10:28 2014 +0100
@@ -29,6 +29,11 @@
typedef float IEC_REAL;
typedef double IEC_LREAL;
+/* WARNING: When editing the definition of IEC_TIMESPEC, take note that
+ * if the order of the two elements 'tv_sec' and 'tv_nsec' is changed, then the macros
+ * __time_to_timespec() and __tod_to_timespec() will need to be changed accordingly.
+ * (these macros may be found in iec_std_lib.h)
+ */
typedef struct {
long int tv_sec; /* Seconds. */
long int tv_nsec; /* Nanoseconds. */
--- a/lib/iec_types_all.h Wed May 28 11:32:09 2014 +0200
+++ b/lib/iec_types_all.h Sat Jul 05 14:10:28 2014 +0100
@@ -126,11 +126,12 @@
__ANY(__DECLARE_IEC_TYPE)
typedef struct {
- __IEC_BOOL_t state; // current step state. 0 : inative, 1: active
- BOOL prev_state; // previous step state. 0 : inative, 1: active
- TIME elapsed_time; // time since step is active
+ __IEC_BOOL_t X; // state; --> current step state. 0 : inative, 1: active. We name it 'X' as it may be accessed from IEC 61131.3 code using stepname.X syntax!!
+ BOOL prev_state; // previous step state. 0 : inative, 1: active
+ __IEC_TIME_t T; // elapsed_time; --> time since step is active. We name it 'T' as it may be accessed from IEC 61131.3 code using stepname.T syntax!!
} STEP;
+
typedef struct {
BOOL stored; // action storing state. 0 : not stored, 1: stored
__IEC_BOOL_t state; // current action state. 0 : inative, 1: active
--- a/stage3/fill_candidate_datatypes.hh Wed May 28 11:32:09 2014 +0200
+++ b/stage3/fill_candidate_datatypes.hh Sat Jul 05 14:10:28 2014 +0100
@@ -242,7 +242,6 @@
/********************************************/
/* B 1.6 Sequential function chart elements */
/********************************************/
-
void *visit(transition_condition_c *symbol);
/********************************/
--- a/stage3/narrow_candidate_datatypes.cc Wed May 28 11:32:09 2014 +0200
+++ b/stage3/narrow_candidate_datatypes.cc Sat Jul 05 14:10:28 2014 +0100
@@ -817,17 +817,16 @@
/********************************************/
/* B 1.6 Sequential function chart elements */
/********************************************/
-
void *narrow_candidate_datatypes_c::visit(transition_condition_c *symbol) {
- if (symbol->candidate_datatypes.size() != 1)
- return NULL;
- symbol->datatype = symbol->candidate_datatypes[0];
+ // We can safely ask for a BOOL type, as even if the result is a SAFEBOOL, in that case it will aslo include BOOL as a possible datatype.
+ set_datatype(&get_datatype_info_c::bool_type_name /* datatype*/, symbol /* symbol */);
+
if (symbol->transition_condition_il != NULL) {
- symbol->transition_condition_il->datatype = symbol->datatype;
+ set_datatype(symbol->datatype, symbol->transition_condition_il);
symbol->transition_condition_il->accept(*this);
}
if (symbol->transition_condition_st != NULL) {
- symbol->transition_condition_st->datatype = symbol->datatype;
+ set_datatype(symbol->datatype, symbol->transition_condition_st);
symbol->transition_condition_st->accept(*this);
}
return NULL;
--- a/stage3/narrow_candidate_datatypes.hh Wed May 28 11:32:09 2014 +0200
+++ b/stage3/narrow_candidate_datatypes.hh Sat Jul 05 14:10:28 2014 +0100
@@ -222,7 +222,6 @@
/********************************************/
/* B 1.6 Sequential function chart elements */
/********************************************/
-
void *visit(transition_condition_c *symbol);
/********************************/
--- a/stage3/print_datatypes_error.cc Wed May 28 11:32:09 2014 +0200
+++ b/stage3/print_datatypes_error.cc Sat Jul 05 14:10:28 2014 +0100
@@ -689,6 +689,18 @@
}
+/********************************************/
+/* B 1.6 Sequential function chart elements */
+/********************************************/
+void *print_datatypes_error_c::visit(transition_condition_c *symbol) {
+ if (symbol->transition_condition_il != NULL) symbol->transition_condition_il->accept(*this);
+ if (symbol->transition_condition_st != NULL) symbol->transition_condition_st->accept(*this);
+
+ if (!get_datatype_info_c::is_type_valid(symbol->datatype))
+ STAGE3_ERROR(0, symbol, symbol, "Transition condition has invalid data type (should be BOOL).");
+ return NULL;
+}
+
/********************************/
/* B 1.7 Configuration elements */
@@ -1163,7 +1175,7 @@
symbol->expression->accept(*this);
if ((!get_datatype_info_c::is_type_valid(symbol->expression->datatype)) &&
(symbol->expression->candidate_datatypes.size() > 0)) {
- STAGE3_ERROR(0, symbol, symbol, "Invalid data type for 'IF' condition.");
+ STAGE3_ERROR(0, symbol, symbol, "Invalid data type for 'IF' condition (should be BOOL).");
}
if (NULL != symbol->statement_list)
symbol->statement_list->accept(*this);
@@ -1178,7 +1190,7 @@
symbol->expression->accept(*this);
if ((!get_datatype_info_c::is_type_valid(symbol->expression->datatype)) &&
(symbol->expression->candidate_datatypes.size() > 0)) {
- STAGE3_ERROR(0, symbol, symbol, "Invalid data type for 'ELSIF' condition.");
+ STAGE3_ERROR(0, symbol, symbol, "Invalid data type for 'ELSIF' condition (should be BOOL).");
}
if (NULL != symbol->statement_list)
symbol->statement_list->accept(*this);
--- a/stage3/print_datatypes_error.hh Wed May 28 11:32:09 2014 +0200
+++ b/stage3/print_datatypes_error.hh Sat Jul 05 14:10:28 2014 +0100
@@ -203,6 +203,11 @@
/**********************/
void *visit(program_declaration_c *symbol);
+ /********************************************/
+ /* B 1.6 Sequential function chart elements */
+ /********************************************/
+ void *visit(transition_condition_c *symbol);
+
/********************************/
/* B 1.7 Configuration elements */
/********************************/
--- a/stage4/generate_c/generate_c.cc Wed May 28 11:32:09 2014 +0200
+++ b/stage4/generate_c/generate_c.cc Sat Jul 05 14:10:28 2014 +0100
@@ -386,131 +386,6 @@
/***********************************************************************/
/***********************************************************************/
/***********************************************************************/
-/* A helper class that analyses if the datatype of a variable is 'complex'. */
-/* 'complex' means that it is either a strcuture or an array! */
-class print_getter_c: public search_visitor_c {
- private:
- static print_getter_c *singleton_;
-
- public:
- print_getter_c(void) {};
-
- static bool is_complex_type(symbol_c *symbol) {
- if (NULL == symbol) ERROR;
- if (!get_datatype_info_c::is_type_valid (symbol->datatype)) return false;
- return ( get_datatype_info_c::is_structure(symbol->datatype)
- || get_datatype_info_c::is_array (symbol->datatype)
- );
- }
-
-
- private:
- symbol_c *last_fb, *first_non_fb_identifier;
-
- public:
- /* returns the first element (from left to right) in a structured variable that is not a FB, i.e. is either a structure or an array! */
- /* eg:
- * fb1.fb2.fb3.real returns ??????
- * fb1.fb2.struct1.real returns struct1
- * struct1.real returns struct1
- */
- static symbol_c *find_first_nonfb(symbol_c *symbol) {
- if (NULL == singleton_) singleton_ = new print_getter_c();
- if (NULL == singleton_) ERROR;
- if (NULL == symbol) ERROR;
-
- singleton_->last_fb = NULL;
- singleton_->first_non_fb_identifier = NULL;
- return (symbol_c *)symbol->accept(*singleton_);
- }
-
- /* returns true if a strcutured variable (e.g. fb1.fb2.strcut1.real) contains a structure or array */
- /* eg:
- * fb1.fb2.fb3.real returns FALSE
- * fb1.fb2.struct1.real returns TRUE
- * struct1.real returns TRUE
- */
- static bool contains_complex_type(symbol_c *symbol) {
- if (NULL == symbol) ERROR;
- if (!get_datatype_info_c::is_type_valid(symbol->datatype)) ERROR;
-
- symbol_c *first_non_fb = (symbol_c *)find_first_nonfb(symbol);
- return is_complex_type(first_non_fb->datatype);
- }
-
-
- /* returns the datatype of the variable returned by find_first_nonfb() */
- /* eg:
- * fb1.fb2.fb3.real returns ??????
- * fb1.fb2.struct1.real returns datatype of struct1
- * struct1.real returns datatype of struct1
- */
- static search_var_instance_decl_c::vt_t first_nonfb_vardecltype(symbol_c *symbol, symbol_c *scope) {
- if (NULL == symbol) ERROR;
- if (!get_datatype_info_c::is_type_valid(symbol->datatype)) ERROR;
-
- symbol_c *first_non_fb = (symbol_c *)find_first_nonfb(symbol);
- if (NULL != singleton_->last_fb) {
- scope = singleton_->last_fb->datatype;
- symbol = singleton_->first_non_fb_identifier;
- }
-
- search_var_instance_decl_c search_var_instance_decl(scope);
-
- return search_var_instance_decl.get_vartype(symbol);
- }
-
-
- /*********************/
- /* B 1.4 - Variables */
- /*********************/
- void *visit(symbolic_variable_c *symbol) {
- if (!get_datatype_info_c::is_type_valid (symbol->datatype)) ERROR;
- if (!get_datatype_info_c::is_function_block(symbol->datatype)) {
- first_non_fb_identifier = symbol;
- return (void *)symbol;
- }
- last_fb = symbol;
- return NULL;
- }
-
- /*************************************/
- /* B.1.4.2 Multi-element Variables */
- /*************************************/
-
- // SYM_REF2(structured_variable_c, record_variable, field_selector)
- void *visit(structured_variable_c *symbol) {
- symbol_c *res = (symbol_c *)symbol->record_variable->accept(*this);
- if (NULL != res) return res;
-
- if (!get_datatype_info_c::is_type_valid (symbol->datatype)) ERROR;
- if (!get_datatype_info_c::is_function_block(symbol->datatype)) {
- first_non_fb_identifier = symbol->field_selector;
- return (void *)symbol;
- }
-
- last_fb = symbol;
- return NULL;
- }
-
- /* subscripted_variable '[' subscript_list ']' */
- //SYM_REF2(array_variable_c, subscripted_variable, subscript_list)
- void *visit(array_variable_c *symbol) {
- void *res = symbol->subscripted_variable->accept(*this);
- if (NULL != res) return res;
- return (void *)symbol;
- }
-
-
-};
-
-print_getter_c *print_getter_c::singleton_ = NULL;
-
-
-
-
-
-
/* A helper class that analyses if the datatype of a variable is 'complex'. */
/* 'complex' means that it is either a strcuture or an array! */
--- a/stage4/generate_c/generate_c_sfc.cc Wed May 28 11:32:09 2014 +0200
+++ b/stage4/generate_c/generate_c_sfc.cc Sat Jul 05 14:10:28 2014 +0100
@@ -110,10 +110,8 @@
void print_step_argument(symbol_c *step_name, const char* argument, bool setter=false) {
print_variable_prefix();
if (setter) s4o.print(",");
- s4o.print("__step_list[");
- s4o.print(SFC_STEP_ACTION_PREFIX);
- step_name->accept(*this);
- s4o.print("].");
+ step_name->accept(*this); // in the generated C code, the 'step_name' will have been previously #define'd as equiv to '__step_list[<step_number>]", so now we simply print out the name!
+ s4o.print(".");
s4o.print(argument);
}
@@ -135,7 +133,7 @@
s4o.print(s4o.indent_spaces);
s4o.print(SET_VAR);
s4o.print("(");
- print_step_argument(step_name, "state", true);
+ print_step_argument(step_name, "X", true);
s4o.print(",,0);\n");
}
@@ -143,9 +141,9 @@
s4o.print(s4o.indent_spaces);
s4o.print(SET_VAR);
s4o.print("(");
- print_step_argument(step_name, "state", true);
+ print_step_argument(step_name, "X", true);
s4o.print(",,1);\n" + s4o.indent_spaces);
- print_step_argument(step_name, "elapsed_time");
+ print_step_argument(step_name, "T.value");
s4o.print(" = __time_to_timespec(1, 0, 0, 0, 0, 0);\n");
}
@@ -166,21 +164,21 @@
s4o.print(s4o.indent_spaces + "char activated = ");
s4o.print(GET_VAR);
s4o.print("(");
- print_step_argument(current_step, "state");
+ print_step_argument(current_step, "X");
s4o.print(") && !");
print_step_argument(current_step, "prev_state");
s4o.print(";\n");
s4o.print(s4o.indent_spaces + "char desactivated = !");
s4o.print(GET_VAR);
s4o.print("(");
- print_step_argument(current_step, "state");
+ print_step_argument(current_step, "X");
s4o.print(") && ");
print_step_argument(current_step, "prev_state");
s4o.print(";\n");
s4o.print(s4o.indent_spaces + "char active = ");
s4o.print(GET_VAR);
s4o.print("(");
- print_step_argument(current_step, "state");
+ print_step_argument(current_step, "X");
s4o.print(");\n");
symbol->action_association_list->accept(*this);
s4o.indent_left();
@@ -207,21 +205,21 @@
s4o.print(s4o.indent_spaces + "activated = ");
s4o.print(GET_VAR);
s4o.print("(");
- print_step_argument(current_step, "state");
+ print_step_argument(current_step, "X");
s4o.print(") && !");
print_step_argument(current_step, "prev_state");
s4o.print(";\n");
s4o.print(s4o.indent_spaces + "desactivated = !");
s4o.print(GET_VAR);
s4o.print("(");
- print_step_argument(current_step, "state");
+ print_step_argument(current_step, "X");
s4o.print(") && ");
print_step_argument(current_step, "prev_state");
s4o.print(";\n");
s4o.print(s4o.indent_spaces + "active = ");
s4o.print(GET_VAR);
s4o.print("(");
- print_step_argument(current_step, "state");
+ print_step_argument(current_step, "X");
s4o.print(");\n");
symbol->action_association_list->accept(*this);
s4o.indent_left();
@@ -437,7 +435,7 @@
case transitiontest_sg:
s4o.print(GET_VAR);
s4o.print("(");
- print_step_argument(symbol->step_name, "state");
+ print_step_argument(symbol->step_name, "X");
s4o.print(")");
break;
case stepset_sg:
@@ -462,7 +460,7 @@
for(int i = 0; i < symbol->n; i++) {
s4o.print(GET_VAR);
s4o.print("(");
- print_step_argument(symbol->elements[i], "state");
+ print_step_argument(symbol->elements[i], "X");
s4o.print(")");
if (i < symbol->n - 1) {
s4o.print(" && ");
@@ -507,7 +505,7 @@
s4o.print(s4o.indent_spaces + "if (");
s4o.print(GET_VAR);
s4o.print("(");
- print_step_argument(current_step, "state");
+ print_step_argument(current_step, "X");
s4o.print(")) {\n");
s4o.indent_right();
s4o.print(s4o.indent_spaces);
@@ -545,7 +543,7 @@
}
else if (strcmp(qualifier, "D") == 0 || strcmp(qualifier, "L") == 0) {
s4o.print("active && __time_cmp(");
- print_step_argument(current_step, "elapsed_time");
+ print_step_argument(current_step, "T.value");
s4o.print(", ");
symbol->action_time->accept(*this);
if (strcmp(qualifier, "D") == 0) {
@@ -744,20 +742,20 @@
s4o.print(GET_VAR);
s4o.print("(");
print_variable_prefix();
- s4o.print("__step_list[i].state);\n");
+ s4o.print("__step_list[i].X);\n");
s4o.print(s4o.indent_spaces + "if (");
s4o.print(GET_VAR);
s4o.print("(");
print_variable_prefix();
- s4o.print("__step_list[i].state)) {\n");
+ s4o.print("__step_list[i].X)) {\n");
s4o.indent_right();
s4o.print(s4o.indent_spaces);
print_variable_prefix();
// s4o.print("__step_list[i].elapsed_time = __time_add(__BOOL_LITERAL(TRUE), NULL, ");
// s4o.print("__step_list[i].elapsed_time = ADD_TIME(__BOOL_LITERAL(TRUE), NULL, ");
- s4o.print("__step_list[i].elapsed_time = __time_add(");
- print_variable_prefix();
- s4o.print("__step_list[i].elapsed_time, elapsed_time);\n");
+ s4o.print("__step_list[i].T.value = __time_add(");
+ print_variable_prefix();
+ s4o.print("__step_list[i].T.value, elapsed_time);\n");
s4o.indent_left();
s4o.print(s4o.indent_spaces + "}\n");
s4o.indent_left();
--- a/stage4/generate_c/generate_c_sfcdecl.cc Wed May 28 11:32:09 2014 +0200
+++ b/stage4/generate_c/generate_c_sfcdecl.cc Sat Jul 05 14:10:28 2014 +0100
@@ -252,11 +252,17 @@
print_variable_prefix();
s4o.print(",__step_list[");
s4o.print(step_number);
- s4o.print("].state,,1);\n");
+ s4o.print("].X,,1);\n");
step_number++;
break;
case stepdef_sd:
s4o.print("#define ");
+ symbol->step_name->accept(*this);
+ s4o.print(" __step_list[");
+ s4o.print(step_number);
+ s4o.print("]\n");
+
+ s4o.print("#define ");
s4o.print(SFC_STEP_ACTION_PREFIX);
symbol->step_name->accept(*this);
s4o.print(" ");
@@ -266,6 +272,10 @@
break;
case stepundef_sd:
s4o.print("#undef ");
+ symbol->step_name->accept(*this);
+ s4o.print("\n");
+
+ s4o.print("#undef ");
s4o.print(SFC_STEP_ACTION_PREFIX);
symbol->step_name->accept(*this);
s4o.print("\n");
@@ -289,6 +299,12 @@
break;
case stepdef_sd:
s4o.print("#define ");
+ symbol->step_name->accept(*this);
+ s4o.print(" __step_list[");
+ s4o.print(step_number);
+ s4o.print("]\n");
+
+ s4o.print("#define ");
s4o.print(SFC_STEP_ACTION_PREFIX);
symbol->step_name->accept(*this);
s4o.print(" ");
@@ -298,6 +314,10 @@
break;
case stepundef_sd:
s4o.print("#undef ");
+ symbol->step_name->accept(*this);
+ s4o.print("\n");
+
+ s4o.print("#undef ");
s4o.print(SFC_STEP_ACTION_PREFIX);
symbol->step_name->accept(*this);
s4o.print("\n");
--- a/stage4/generate_c/generate_c_st.cc Wed May 28 11:32:09 2014 +0200
+++ b/stage4/generate_c/generate_c_st.cc Sat Jul 05 14:10:28 2014 +0100
@@ -211,8 +211,7 @@
symbol->accept(*this);
s4o.print(",");
s4o.print(",");
- }
- else {
+ } else {
print_variable_prefix();
s4o.print(",");
wanted_variablegeneration = complextype_base_vg;
@@ -334,7 +333,19 @@
switch (wanted_variablegeneration) {
case complextype_base_vg:
symbol->record_variable->accept(*this);
- if ( get_datatype_info_c::is_function_block(symbol->record_variable->datatype)) {
+ /* NOTE: The following test includes a special case for SFC Steps. They are currently mapped onto a C data structure
+ * that does not follow the standard IEC_<typename> pattern used for user defined structure datatypes
+ * (i.e. it does not include the 'values' and 'flag' structure
+ * elements that are tested by __GET_VAR and __SET_VAR acessor macros defined in acessor.h). However, the
+ * STEP.T and STEP.X elements of this step structure are of the IEC_BOOL and IEC_TIME datatypes, and are
+ * actually structures that do have the 'value' and 'flags' elements. So, it is safe to say that any variable
+ * that is a STEPname is not of a complex type, as its .T and .X elements are and can later be safely accessed
+ * using the __SET_VAR and __GET_VAR macros.
+ *
+ * For the above reason, a STEP must be handled as a FB, i.e. it does NOT contain the 'flags' and 'value' elements!
+ */
+ if ( get_datatype_info_c::is_function_block(symbol->record_variable->datatype)
+ || get_datatype_info_c::is_sfc_step (symbol->record_variable->datatype)) {
if (NULL == symbol->record_variable->scope) ERROR;
search_var_instance_decl_c search_var_instance_decl(symbol->record_variable->scope);
if (search_var_instance_decl_c::external_vt == search_var_instance_decl.get_vartype(get_var_name_c::get_last_field(symbol->record_variable)))
@@ -346,7 +357,9 @@
break;
case complextype_suffix_vg:
symbol->record_variable->accept(*this);
- if (!get_datatype_info_c::is_function_block(symbol->record_variable->datatype)) { // if the record variable is not a FB, then it will certainly be a structure!
+ // the following condition MUST be a negation of the above condition used in the 'case complextype_base_vg:'
+ if (!( get_datatype_info_c::is_function_block(symbol->record_variable->datatype) // if the record variable is not a FB...
+ || get_datatype_info_c::is_sfc_step (symbol->record_variable->datatype))) { // ...nor an SFC step name, then it will certainly be a structure!
s4o.print(".");
symbol->field_selector->accept(*this);
}
--- a/stage4/generate_c/generate_var_list.cc Wed May 28 11:32:09 2014 +0200
+++ b/stage4/generate_c/generate_var_list.cc Sat Jul 05 14:10:28 2014 +0100
@@ -857,7 +857,7 @@
print_symbol_list();
s4o.print("__step_list[");
print_step_number();
- s4o.print("].state;BOOL;\n");
+ s4o.print("].X;BOOL;\n");
step_number++;
return NULL;
}
@@ -873,7 +873,7 @@
print_symbol_list();
s4o.print("__step_list[");
print_step_number();
- s4o.print("].state;BOOL;\n");
+ s4o.print("].X;BOOL;\n");
step_number++;
return NULL;
}