Support for struct Time data Types manipulation into ST and IL added
authorlbessard
Tue, 20 Feb 2007 18:17:21 +0100
changeset 16 e8b99f896416
parent 15 0b472e25eb16
child 17 38754701ac41
Support for struct Time data Types manipulation into ST and IL added
stage4/generate_cc/generate_cc.cc
stage4/generate_cc/generate_cc_base.cc
stage4/generate_cc/generate_cc_il.cc
stage4/generate_cc/generate_cc_st.cc
stage4/generate_cc/plciec.h
stage4/generate_cc/search_expression_type.cc
stage4/generate_iec/generate_iec.cc
--- a/stage4/generate_cc/generate_cc.cc	Wed Feb 14 19:57:01 2007 +0100
+++ b/stage4/generate_cc/generate_cc.cc	Tue Feb 20 18:17:21 2007 +0100
@@ -38,6 +38,7 @@
 // #include <stdio.h>  /* required for NULL */
 #include <string>
 #include <iostream>
+#include <typeinfo>
 
 #include "../../util/symtable.hh"
 #include "../../util/dsymtable.hh"
@@ -176,6 +177,7 @@
 #include "decompose_var_instance_name.cc"
 #include "search_varfb_instance_type.cc"
 #include "search_constant_type.cc"
+#include "search_expression_type.cc"
 
 #include "generate_cc_base.cc"
 #include "generate_cc_typedecl.cc"
@@ -523,7 +525,7 @@
   symbol->fblock_name->accept(*this);
   s4o.print(FB_FUNCTION_SUFFIX);
   s4o.print("(");
-    /* first and only parameter is a pointer to the data */
+  /* first and only parameter is a pointer to the data */
   symbol->fblock_name->accept(*this);
   s4o.print(" *");
   s4o.print(FB_FUNCTION_PARAM);
@@ -549,23 +551,46 @@
   s4o.print(FB_FUNCTION_SUFFIX);
   s4o.print(s4o.indent_spaces + "() \n\n");
 
-
-
-
-
-
-
-#if 0
-
-+++++++++++++++++++++++++++++++++++++
-  s4o.print(s4o.indent_spaces + "class ");
-  symbol->fblock_name->accept(*this);
-  s4o.print(" {\n");
-  s4o.indent_right();
-
-  /* (A.2) Public variables: i.e. the function parameters... */
-  s4o.print(s4o.indent_spaces + "public:\n");
-  s4o.indent_right();
+  s4o.indent_left();
+  s4o.print("\n\n\n\n");
+
+  return NULL;
+}
+
+
+/* The remaining temp_var_decls_c, temp_var_decls_list_c
+ * and non_retentive_var_decls_c are handled in the generate_cc_vardecl_c class
+ */
+
+
+/**********************/
+/* B 1.5.3 - Programs */
+/**********************/
+
+
+
+public:
+/*  PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM */
+//SYM_REF4(program_declaration_c, program_type_name, var_declarations, function_block_body, unused)
+void *visit(program_declaration_c *symbol) {
+  generate_cc_vardecl_c *vardecl;
+  TRACE("program_declaration_c");
+
+  /* start off by adding this declaration to the global
+   * program declaration symbol table...
+   */
+  program_type_symtable.insert(symbol->program_type_name, symbol);
+
+  /* (A) Program data structure declaration... */
+  /* (A.1) Data structure declaration */
+  s4o.print("// PROGRAM ");
+  symbol->program_type_name->accept(*this);
+  s4o.print("\n// Data part\n");
+  s4o.print("typedef struct {\n");
+  s4o.indent_right();
+
+  /* (A.2) Public variables: i.e. the program parameters... */
+  s4o.print(s4o.indent_spaces + "// PROGRAM Interface - IN, OUT, IN_OUT variables\n");
   vardecl = new generate_cc_vardecl_c(&s4o,
   				      generate_cc_vardecl_c::local_vf,
   				      generate_cc_vardecl_c::input_vt |
@@ -573,226 +598,60 @@
   				      generate_cc_vardecl_c::inoutput_vt);
   vardecl->print(symbol->var_declarations);
   delete vardecl;
-  s4o.indent_left();
   s4o.print("\n");
-
   /* (A.3) Private internal variables */
-  s4o.print(s4o.indent_spaces + "private:\n");
-  s4o.indent_right();
+  s4o.print(s4o.indent_spaces + "// PROGRAM private variables - TEMP, private and located variables\n");
   vardecl = new generate_cc_vardecl_c(&s4o,
   				      generate_cc_vardecl_c::local_vf,
-  				      generate_cc_vardecl_c::private_vt |
-  				      generate_cc_vardecl_c::located_vt);
-  vardecl->print(symbol->var_declarations);
-  delete vardecl;
-  s4o.indent_left();
-  s4o.print("\n");
-
----------------------------------
-  /* (B) Constructor */
-  s4o.print(s4o.indent_spaces + "public:\n");
-  s4o.indent_right();
-  s4o.print(s4o.indent_spaces);
-  symbol->fblock_name->accept(*this);
-  s4o.print("(void)\n");
-  s4o.indent_right();
-  s4o.print(s4o.indent_spaces);
-  vardecl = new generate_cc_vardecl_c(&s4o,
-  				      generate_cc_vardecl_c::constructorinit_vf,
-  				      generate_cc_vardecl_c::input_vt |
-  				      generate_cc_vardecl_c::output_vt |
-  				      generate_cc_vardecl_c::inoutput_vt |
-  				      generate_cc_vardecl_c::private_vt);
-  vardecl->print(symbol->var_declarations);
-  delete vardecl;
-  s4o.print("\n" + s4o.indent_spaces + "{}\n\n");
-  s4o.indent_left();
-  s4o.indent_left();
----------------------------------
-
-
-  /* (C) Public Function*/
-  /* (C.1) Public Function declaration */
-  s4o.print(s4o.indent_spaces + "public:\n");
-  s4o.indent_right();
-  s4o.print(s4o.indent_spaces + "void f(void) {\n");
-
-  /* (C.2) Temporary variables */
-  s4o.indent_right();
-  vardecl = new generate_cc_vardecl_c(&s4o, generate_cc_vardecl_c::localinit_vf, generate_cc_vardecl_c::temp_vt);
-  vardecl->print(symbol->var_declarations);
-  delete vardecl;
-  s4o.indent_left();
-  s4o.print("\n");
-
-  /* (C.3) Public Function body */
-  s4o.indent_right();
-  this->current_scope = symbol;
-  symbol->fblock_body->accept(*this);
-  this->current_scope = NULL;
-  s4o.indent_left();
-  s4o.print(s4o.indent_spaces + "} /* f() */\n\n");
-  s4o.indent_left();
-
-  /* (D) Close the class declaration... */
-  s4o.indent_left();
-  s4o.print(s4o.indent_spaces + "}; /* class ");
-  symbol->fblock_name->accept(*this);
-  s4o.print(" */\n");
-
----------------------------------
-  /* (E) Initialise the static member variables... */
-  vardecl = new generate_cc_vardecl_c(&s4o,
-  				      generate_cc_vardecl_c::globalinit_vf,
-  				      generate_cc_vardecl_c::located_vt);
-  vardecl->print(symbol->var_declarations, symbol->fblock_name);
-  delete vardecl;
-
-#endif
-
-  s4o.indent_left();
-  s4o.print("\n\n\n\n");
-
-  return NULL;
-}
-
-
-/* The remaining temp_var_decls_c, temp_var_decls_list_c
- * and non_retentive_var_decls_c are handled in the generate_cc_vardecl_c class
- */
-
-
-/**********************/
-/* B 1.5.3 - Programs */
-/**********************/
-
-
-
-public:
-/*  PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM */
-//SYM_REF4(program_declaration_c, program_type_name, var_declarations, function_block_body, unused)
-void *visit(program_declaration_c *symbol) {
-  generate_cc_vardecl_c *vardecl;
-  TRACE("program_declaration_c");
-
-  /* start off by adding this declaration to the global
-   * program declaration symbol table...
-   */
-  program_type_symtable.insert(symbol->program_type_name, symbol);
-
-  /* (A) Class (Function Block) declaration... */
-  /* (A.1) Class (Function Block) name */
-  s4o.print("// PROGRAM\n");
-  s4o.print(s4o.indent_spaces);
-  symbol->program_type_name->accept(*this);
-  s4o.print("\n //Data part\n");
-  s4o.print("typedef struct {\n");
-  s4o.indent_right();
-
-  /* (A.2) Public variables: i.e. the program parameters... */
-  s4o.print(s4o.indent_spaces + "//PROGRAM interface IN OUT IN_OUT variables\n");
-  s4o.indent_right();
-  vardecl = new generate_cc_vardecl_c(&s4o,
-  				      generate_cc_vardecl_c::local_vf,
-  				      generate_cc_vardecl_c::input_vt |
-  				      generate_cc_vardecl_c::output_vt |
-  				      generate_cc_vardecl_c::inoutput_vt);
-  vardecl->print(symbol->var_declarations);
-  delete vardecl;
-  s4o.indent_left();
-  s4o.print("\n");
-
-  /* (A.3) Private internal variables */
-  s4o.print(s4o.indent_spaces + "// PROGRAM private variables - TEMP, private and located variables\n");
-  s4o.indent_right();
-  vardecl = new generate_cc_vardecl_c(&s4o,
-  				      generate_cc_vardecl_c::local_vf,
+				      generate_cc_vardecl_c::temp_vt |
   				      generate_cc_vardecl_c::private_vt |
   				      generate_cc_vardecl_c::located_vt |
-				      generate_cc_vardecl_c::external_vt);
+  				      generate_cc_vardecl_c::external_vt);
   vardecl->print(symbol->var_declarations);
   delete vardecl;
-  s4o.print("\n ");
+  s4o.print("\n");
+
+  /* (A.4) Program data structure type name. */
   s4o.indent_left();
   s4o.print("} ");
   symbol->program_type_name->accept(*this);
-  s4o.print(";\n\n ");
-  /* (B) Constructor */
-  /* (B.1) Constructor name... */
-  s4o.print("// Code part");
-  /*PROGRAM Interface*/
-  s4o.indent_right();
-  s4o.print(s4o.indent_spaces);
+  s4o.print(";\n\n");
+
+  /* (B) Function with PROGRAM body */
+  /* (B.1) Function declaration */
+  s4o.print("// Code part\n");
+  /* function interface */
   s4o.print("void ");
   symbol->program_type_name->accept(*this);
   s4o.print(FB_FUNCTION_SUFFIX);
-  /* (B.2) Constructor parameters (i.e. the external variables)... */
   s4o.print("(");
+  /* first and only parameter is a pointer to the data */
   symbol->program_type_name->accept(*this);
-  s4o.indent_right();
-  s4o.print(" ");
+  s4o.print(" *");
+  s4o.print(FB_FUNCTION_PARAM);
+  s4o.print(") {\n");
+  s4o.indent_right();
+
+  /* (B.2) Initialize TEMP variables */
+  /* function body */
+  s4o.print(s4o.indent_spaces + "// Initialise TEMP variables\n");
   vardecl = new generate_cc_vardecl_c(&s4o,
-  				      generate_cc_vardecl_c::finterface_vf,
-  				      generate_cc_vardecl_c::external_vt);
-  vardecl->print(symbol->var_declarations);
-  delete vardecl;
-  s4o.print(")");
-  s4o.print("{\n");
-  s4o.indent_left();
-
-  /* (B.2) Member initializations... */
-  s4o.indent_right();
-  s4o.print(s4o.indent_spaces + "//Initialise PROGRAM variables\n");
-  vardecl = new generate_cc_vardecl_c(&s4o,
-  				      generate_cc_vardecl_c::constructorinit_vf,
-  				      generate_cc_vardecl_c::input_vt |
-  				      generate_cc_vardecl_c::output_vt |
-  				      generate_cc_vardecl_c::inoutput_vt |
-  				      generate_cc_vardecl_c::private_vt |
-				      generate_cc_vardecl_c::external_vt);
-  vardecl->print(symbol->var_declarations, NULL, FB_FUNCTION_PARAM"->");
-  delete vardecl;
-  s4o.print("\n" + s4o.indent_spaces);
-  s4o.indent_left();
-  s4o.indent_left();
-
-  /* (C) Public Function*/
-  /* (C.1) Public Function declaration */
-  s4o.print(s4o.indent_spaces);
-  //s4o.indent_right();
-  //s4o.print(s4o.indent_spaces + "void f(void) {\n");
-
-  /* (C.2) Temporary variables */
-  //s4o.indent_right();
-  //vardecl = new generate_cc_vardecl_c(&s4o, generate_cc_vardecl_c::localinit_vf, generate_cc_vardecl_c::temp_vt);
-  //vardecl->print(symbol->var_declarations);
-  //delete vardecl;
-  //s4o.indent_left();
+  				      generate_cc_vardecl_c::init_vf,
+				      generate_cc_vardecl_c::temp_vt);
+  vardecl->print(symbol->var_declarations, NULL,  FB_FUNCTION_PARAM"->");
+  delete vardecl;
   s4o.print("\n");
 
-  /* (C.3) Public Function body */
-  s4o.indent_right();
+  /* (B.3) Function code */
   generate_cc_IL_and_ST_c generate_cc_code(&s4o, symbol, FB_FUNCTION_PARAM"->");
   symbol->function_block_body->accept(generate_cc_code);
   s4o.indent_left();
-  s4o.print(s4o.indent_spaces + "} //");
+  s4o.print(s4o.indent_spaces + "} // ");
   symbol->program_type_name->accept(*this);
   s4o.print(FB_FUNCTION_SUFFIX);
-  s4o.print("()\n");
-  s4o.indent_left();
-
-  /* (D) Close the class declaration... */
-  s4o.indent_left();
-  s4o.print(s4o.indent_spaces + "}; /* void ");
-  symbol->program_type_name->accept(*this);
-  s4o.print(" */\n\n\n");
-
-  /* (E) Initialise the static member variables... */
-  vardecl = new generate_cc_vardecl_c(&s4o,
-  				      generate_cc_vardecl_c::globalinit_vf,
-  				      generate_cc_vardecl_c::located_vt);
-  vardecl->print(symbol->var_declarations, symbol->program_type_name);
-  delete vardecl;
+  s4o.print(s4o.indent_spaces + "() \n\n");
+
+  s4o.indent_left();
   s4o.print("\n\n\n\n");
 
   return NULL;
--- a/stage4/generate_cc/generate_cc_base.cc	Wed Feb 14 19:57:01 2007 +0100
+++ b/stage4/generate_cc/generate_cc_base.cc	Tue Feb 20 18:17:21 2007 +0100
@@ -172,7 +172,6 @@
       return NULL;
     }
 
-
     void *print_unary_expression(symbol_c *exp,
 				 const char *operation) {
       s4o.print(operation);
@@ -182,6 +181,32 @@
       return NULL;
     }
 
+    void *print_binary_function(const char *function,
+          symbol_c *l_exp,
+				  symbol_c *r_exp) {
+      s4o.print(function);
+      s4o.print("(");
+      l_exp->accept(*this);
+      s4o.print(", ");
+      r_exp->accept(*this);
+      s4o.print(")");
+      return NULL;
+   	}
+
+    void *print_compare_function(const char *function,
+          const char *compare_sign,
+          symbol_c *l_exp,
+          symbol_c *r_exp) {
+      s4o.print(function);
+      s4o.print("(");
+      s4o.print(compare_sign);
+      s4o.print(", ");
+      l_exp->accept(*this);
+      s4o.print(", ");
+      r_exp->accept(*this);
+      s4o.print(")");
+      return NULL;
+    }
 
 /***************************/
 /* 2.1.6 - Pragmas */
@@ -309,7 +334,7 @@
 /* SYM_REF2(duration_c, neg, interval) */
 void *visit(duration_c *symbol) {
   TRACE("duration_c");
-  s4o.print("TIME(");
+  s4o.print("__time_to_timespec(");
   if (NULL == symbol->neg)
     s4o.print("1");  /* positive time value */
   else
@@ -318,6 +343,10 @@
   s4o.print(", ");
 
   symbol->interval->accept(*this);
+  if (typeid(*symbol->interval) == typeid(hours_c)) {s4o.print(", 0");}
+  if (typeid(*symbol->interval) == typeid(minutes_c)) {s4o.print(", 0, 0");}
+  if (typeid(*symbol->interval) == typeid(seconds_c)) {s4o.print(", 0, 0, 0");}
+  if (typeid(*symbol->interval) == typeid(milliseconds_c)) {s4o.print(", 0, 0, 0, 0");}
   s4o.print(")");
   return NULL;
 }
@@ -401,7 +430,7 @@
 /* SYM_REF2(time_of_day_c, daytime, unused) */
 void *visit(time_of_day_c *symbol) {
   TRACE("time_of_day_c");
-  s4o.print("TOD(");
+  s4o.print("__tod_to_timespec(");
   symbol->daytime->accept(*this);
   s4o.print(")");
   return NULL;
@@ -423,7 +452,7 @@
 /* SYM_REF2(date_c, date_literal, unused) */
 void *visit(date_c *symbol) {
   TRACE("date_c");
-  s4o.print("DATE(");
+  s4o.print("__date_to_timespec(");
   symbol->date_literal->accept(*this);
   s4o.print(")");
   return NULL;
@@ -445,7 +474,7 @@
 /* SYM_REF2(date_and_time_c, date_literal, daytime) */
 void *visit(date_and_time_c *symbol) {
   TRACE("date_and_time_c");
-  s4o.print("DT(");
+  s4o.print("__dt_to_timespec(");
   symbol->daytime->accept(*this);
   s4o.print(", ");
   symbol->date_literal->accept(*this);
--- a/stage4/generate_cc/generate_cc_il.cc	Wed Feb 14 19:57:01 2007 +0100
+++ b/stage4/generate_cc/generate_cc_il.cc	Tue Feb 20 18:17:21 2007 +0100
@@ -53,6 +53,7 @@
  * (function, function block or program within which
  * the possible il_operand variable instance was declared).
  */
+
 class search_il_operand_type_c {
 
   private:
@@ -175,7 +176,8 @@
      * 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_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
      * imediately after a parenthesis is opened.
@@ -296,7 +298,8 @@
       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_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);
       current_operand = NULL;
       current_operand_type = NULL;
@@ -306,7 +309,8 @@
 
     virtual ~generate_cc_il_c(void) {
       delete search_fb_instance_decl;
-      delete search_il_operand_type;
+      //delete search_il_operand_type;
+      delete search_expression_type;
     }
 
     void generate(instruction_list_c *il) {
@@ -317,9 +321,11 @@
 
   private:
     /* A helper function... */
+    /*
     bool is_bool_type(symbol_c *type_symbol) {
       return (NULL != dynamic_cast<bool_type_name_c *>(type_symbol));
     }
+    */
 
     /* A helper function... */
     void *XXX_operator(symbol_c *lo, const char *op, symbol_c *ro) {
@@ -333,6 +339,22 @@
     }
 
     /* A helper function... */
+    void *XXX_function(const char *func, symbol_c *lo, symbol_c *ro) {
+      if ((NULL == lo) || (NULL == ro)) ERROR;
+      if (NULL == func) ERROR;
+
+      lo->accept(*this);
+      s4o.print(" = ");
+      s4o.print(func);
+      s4o.print("(");
+      lo->accept(*this);
+      s4o.print(", ");
+      ro->accept(*this);
+      s4o.print(")");
+      return NULL;
+    }
+
+    /* A helper function... */
     void *XXX_CAL_operator(const char *param_name, symbol_c *fb_name) {
       if (NULL == fb_name) ERROR;
       symbolic_variable_c *sv = dynamic_cast<symbolic_variable_c *>(fb_name);
@@ -365,12 +387,23 @@
       this->default_variable_name.accept(*this);
       this->default_variable_name.current_type = backup;
 
-      s4o.print(" = (");
-      this->default_variable_name.accept(*this);
-      s4o.print(operation);
-      o->accept(*this);
-      s4o.print(")");
-
+      if (search_expression_type->is_time_compatible(this->default_variable_name.current_type) &&
+          search_expression_type->is_time_compatible(this->current_operand_type)) {
+        s4o.print(" = __compare_timespec(");
+        s4o.print(operation);
+        s4o.print(", ");
+        this->default_variable_name.accept(*this);
+        s4o.print(", ");
+        o->accept(*this);
+        s4o.print(")");
+      }
+      else {
+        s4o.print(" = (");
+        this->default_variable_name.accept(*this);
+        s4o.print(operation);
+        o->accept(*this);
+        s4o.print(")");
+      }
       /* the data type resulting from this operation... */
       this->default_variable_name.current_type = &(this->bool_type);
       return NULL;
@@ -379,20 +412,22 @@
 
     /* A helper function... */
     void C_modifier(void) {
-      if (NULL == this->default_variable_name.current_type) ERROR;
-
-      s4o.print("if (");
-      this->default_variable_name.accept(*this);
-      s4o.print(") ");
+      if (search_expression_type->is_numeric_compatible(default_variable_name.current_type)) {
+        s4o.print("if (");
+        this->default_variable_name.accept(*this);
+        s4o.print(") ");
+      }
+      else {ERROR;}
     }
 
     /* A helper function... */
     void CN_modifier(void) {
-      if (NULL == this->default_variable_name.current_type) ERROR;
-
-      s4o.print("if (!");
-      this->default_variable_name.accept(*this);
-      s4o.print(") ");
+      if (search_expression_type->is_numeric_compatible(default_variable_name.current_type)) {
+        s4o.print("if (!");
+        this->default_variable_name.accept(*this);
+        s4o.print(") ");
+      }
+      else {ERROR;}
     }
 
 
@@ -486,7 +521,7 @@
   if (NULL == this->current_operand) {
     this->current_operand_type = NULL;
   } else {
-    this->current_operand_type = search_il_operand_type->get_type(this->current_operand);
+    this->current_operand_type = search_expression_type->get_type(this->current_operand);
     if (NULL == this->current_operand_type) ERROR;
   }
 
@@ -975,7 +1010,7 @@
   /* the data type resulting from this operation... */
   this->default_variable_name.current_type = this->current_operand_type;
   XXX_operator(&(this->default_variable_name),
-               is_bool_type(this->current_operand_type)?" = !":" = ~",
+               search_expression_type->is_bool_type(this->current_operand_type)?" = !":" = ~",
                this->current_operand);
   return NULL;
 }
@@ -988,7 +1023,7 @@
 
 void *visit(STN_operator_c *symbol)	{
   XXX_operator(this->current_operand,
-               is_bool_type(this->current_operand_type)?" = !":" = ~",
+               search_expression_type->is_bool_type(this->current_operand_type)?" = !":" = ~",
                &(this->default_variable_name));
   /* the data type resulting from this operation is unchamged. */
   return NULL;
@@ -997,7 +1032,7 @@
 void *visit(NOT_operator_c *symbol)	{
   if ((NULL != this->current_operand) || (NULL != this->current_operand_type)) ERROR;
   XXX_operator(&(this->default_variable_name),
-               is_bool_type(this->default_variable_name.current_type)?" = !":" = ~",
+               search_expression_type->is_bool_type(this->default_variable_name.current_type)?" = !":" = ~",
                &(this->default_variable_name));
   /* the data type resulting from this operation is unchanged. */
   return NULL;
@@ -1008,7 +1043,7 @@
 
   C_modifier();
   this->current_operand->accept(*this);
-  s4o.print(is_bool_type(this->current_operand_type)?" = true":" = 1");
+  s4o.print(search_expression_type->is_bool_type(this->current_operand_type)?" = true":" = 1");
   /* the data type resulting from this operation is unchanged! */
   return NULL;
 }
@@ -1018,7 +1053,7 @@
 
   C_modifier();
   this->current_operand->accept(*this);
-  s4o.print(is_bool_type(this->current_operand_type)?" = false":" = 0");
+  s4o.print(search_expression_type->is_bool_type(this->current_operand_type)?" = false":" = 0");
   /* the data type resulting from this operation is unchanged! */
   return NULL;
 }
@@ -1033,87 +1068,155 @@
 void *visit(PT_operator_c *symbol)	{return XXX_CAL_operator("PT", this->current_operand);}
 
 void *visit(AND_operator_c *symbol)	{
-  XXX_operator(&(this->default_variable_name), " &= ", this->current_operand);
-  /* the data type resulting from this operation... */
-  this->default_variable_name.current_type = this->current_operand_type;
+  if (search_expression_type->is_numeric_compatible(this->default_variable_name.current_type) &&
+      search_expression_type->is_numeric_compatible(this->current_operand_type)) {
+    XXX_operator(&(this->default_variable_name), " &= ", this->current_operand);
+    /* the data type resulting from this operation... */
+    this->default_variable_name.current_type = this->current_operand_type;
+  }
+  else {ERROR;}
   return NULL;
 }
 
 void *visit(OR_operator_c *symbol)	{
-  XXX_operator(&(this->default_variable_name), " |= ", this->current_operand);
-  /* the data type resulting from this operation... */
-  this->default_variable_name.current_type = this->current_operand_type;
+  if (search_expression_type->is_numeric_compatible(this->default_variable_name.current_type) &&
+      search_expression_type->is_numeric_compatible(this->current_operand_type)) {
+    XXX_operator(&(this->default_variable_name), " |= ", this->current_operand);
+    /* the data type resulting from this operation... */
+    this->default_variable_name.current_type = this->current_operand_type;
+  }
+  else {ERROR;}
   return NULL;
 }
 
 void *visit(XOR_operator_c *symbol)	{
-  // '^' is a bit by bit exclusive OR !! Also seems to work with boolean types!
-  XXX_operator(&(this->default_variable_name), " ^= ", this->current_operand);
-  /* the data type resulting from this operation... */
-  this->default_variable_name.current_type = this->current_operand_type;
+  if (search_expression_type->is_numeric_compatible(this->default_variable_name.current_type) &&
+      search_expression_type->is_numeric_compatible(this->current_operand_type)) {
+    // '^' is a bit by bit exclusive OR !! Also seems to work with boolean types!
+    XXX_operator(&(this->default_variable_name), " ^= ", this->current_operand);
+    /* the data type resulting from this operation... */
+    this->default_variable_name.current_type = this->current_operand_type;
+  }
+  else {ERROR;}
   return NULL;
 }
 
 void *visit(ANDN_operator_c *symbol)	{
-  XXX_operator(&(this->default_variable_name),
-               is_bool_type(this->current_operand_type)?" &= !":" &= ~",
-               this->current_operand);
-  /* the data type resulting from this operation... */
-  this->default_variable_name.current_type = this->current_operand_type;
+  if (search_expression_type->is_numeric_compatible(this->default_variable_name.current_type) &&
+      search_expression_type->is_numeric_compatible(this->current_operand_type)) {
+    XXX_operator(&(this->default_variable_name),
+                 search_expression_type->is_bool_type(this->current_operand_type)?" &= !":" &= ~",
+                 this->current_operand);
+    /* the data type resulting from this operation... */
+    this->default_variable_name.current_type = this->current_operand_type;
+  }
+  else {ERROR;}
   return NULL;
 }
 
 void *visit(ORN_operator_c *symbol)	{
-  XXX_operator(&(this->default_variable_name),
-               is_bool_type(this->current_operand_type)?" |= !":" |= ~",
-               this->current_operand);
-  /* the data type resulting from this operation... */
-  this->default_variable_name.current_type = this->current_operand_type;
+  if (search_expression_type->is_numeric_compatible(this->default_variable_name.current_type) &&
+      search_expression_type->is_numeric_compatible(this->current_operand_type)) {
+    XXX_operator(&(this->default_variable_name),
+                 search_expression_type->is_bool_type(this->current_operand_type)?" |= !":" |= ~",
+                 this->current_operand);
+    /* the data type resulting from this operation... */
+    this->default_variable_name.current_type = this->current_operand_type;
+  }
+  else {ERROR;}
   return NULL;
 }
 
 void *visit(XORN_operator_c *symbol)	{
-  XXX_operator(&(this->default_variable_name),
-               // bit by bit exclusive OR !! Also seems to work with boolean types!
-               is_bool_type(this->current_operand_type)?" ^= !":" ^= ~",
-               this->current_operand);
-  /* the data type resulting from this operation... */
-  this->default_variable_name.current_type = this->current_operand_type;
+  if (search_expression_type->is_numeric_compatible(this->default_variable_name.current_type) &&
+      search_expression_type->is_numeric_compatible(this->current_operand_type)) {
+    XXX_operator(&(this->default_variable_name),
+                 // bit by bit exclusive OR !! Also seems to work with boolean types!
+                 search_expression_type->is_bool_type(this->current_operand_type)?" ^= !":" ^= ~",
+                 this->current_operand);
+    /* the data type resulting from this operation... */
+    this->default_variable_name.current_type = this->current_operand_type;
+  }
+  else {ERROR;}
   return NULL;
 }
 
 void *visit(ADD_operator_c *symbol)	{
-  XXX_operator(&(this->default_variable_name), " += ", this->current_operand);
-  /* the data type resulting from this operation... */
-  this->default_variable_name.current_type = this->current_operand_type;
+  if (search_expression_type->is_time_compatible(this->default_variable_name.current_type) &&
+      search_expression_type->is_time_compatible(this->current_operand_type)) {
+    XXX_function("__add_timespec", &(this->default_variable_name), this->current_operand);
+    /* the data type resulting from this operation... */
+    this->default_variable_name.current_type = this->current_operand_type;
+    return NULL;
+  }
+  if (search_expression_type->is_numeric_compatible(this->default_variable_name.current_type) &&
+      search_expression_type->is_numeric_compatible(this->current_operand_type)) {
+    XXX_operator(&(this->default_variable_name), " += ", this->current_operand);
+    /* the data type resulting from this operation... */
+    this->default_variable_name.current_type = this->current_operand_type;
+    return NULL;
+  }
+  ERROR;
   return NULL;
 }
 
 void *visit(SUB_operator_c *symbol)	{
-  XXX_operator(&(this->default_variable_name), " -= ", this->current_operand);
-  /* the data type resulting from this operation... */
-  this->default_variable_name.current_type = this->current_operand_type;
+  if (search_expression_type->is_time_compatible(this->default_variable_name.current_type) &&
+      search_expression_type->is_time_compatible(this->current_operand_type)) {
+    XXX_function("__sub_timespec", &(this->default_variable_name), this->current_operand);
+    /* the data type resulting from this operation... */
+    this->default_variable_name.current_type = this->current_operand_type;
+    return NULL;
+  }
+  if (search_expression_type->is_numeric_compatible(this->default_variable_name.current_type) &&
+      search_expression_type->is_numeric_compatible(this->current_operand_type)) {
+    XXX_operator(&(this->default_variable_name), " -= ", this->current_operand);
+    /* the data type resulting from this operation... */
+    this->default_variable_name.current_type = this->current_operand_type;
+    return NULL;
+  }
+  ERROR;
   return NULL;
 }
 
 void *visit(MUL_operator_c *symbol)	{
-  XXX_operator(&(this->default_variable_name), " *= ", this->current_operand);
-  /* the data type resulting from this operation... */
-  this->default_variable_name.current_type = this->current_operand_type;
+  if (search_expression_type->is_time_compatible(this->default_variable_name.current_type) &&
+      search_expression_type->is_time_compatible(this->current_operand_type)) {
+    XXX_function("__mul_timespec", &(this->default_variable_name), this->current_operand);
+    /* the data type resulting from this operation... */
+    this->default_variable_name.current_type = this->current_operand_type;
+    return NULL;
+  }
+  if (search_expression_type->is_numeric_compatible(this->default_variable_name.current_type) &&
+      search_expression_type->is_numeric_compatible(this->current_operand_type)) {
+    XXX_operator(&(this->default_variable_name), " *= ", this->current_operand);
+    /* the data type resulting from this operation... */
+    this->default_variable_name.current_type = this->current_operand_type;
+    return NULL;
+  }
+  ERROR;
   return NULL;
 }
 
 void *visit(DIV_operator_c *symbol)	{
-  XXX_operator(&(this->default_variable_name), " /= ", this->current_operand);
-  /* the data type resulting from this operation... */
-  this->default_variable_name.current_type = this->current_operand_type;
+  if (search_expression_type->is_numeric_compatible(this->default_variable_name.current_type) &&
+      search_expression_type->is_numeric_compatible(this->current_operand_type)) {
+    XXX_operator(&(this->default_variable_name), " /= ", this->current_operand);
+    /* the data type resulting from this operation... */
+    this->default_variable_name.current_type = this->current_operand_type;
+  }
+  else {ERROR;}
   return NULL;
 }
 
 void *visit(MOD_operator_c *symbol)	{
-  XXX_operator(&(this->default_variable_name), " %= ", this->current_operand);
-  /* the data type resulting from this operation... */
-  this->default_variable_name.current_type = this->current_operand_type;
+  if (search_expression_type->is_numeric_compatible(this->default_variable_name.current_type) &&
+      search_expression_type->is_numeric_compatible(this->current_operand_type)) {
+    XXX_operator(&(this->default_variable_name), " %= ", this->current_operand);
+    /* the data type resulting from this operation... */
+    this->default_variable_name.current_type = this->current_operand_type;
+  }
+  else {ERROR;}
   return NULL;
 }
 
--- a/stage4/generate_cc/generate_cc_st.cc	Wed Feb 14 19:57:01 2007 +0100
+++ b/stage4/generate_cc/generate_cc_st.cc	Tue Feb 20 18:17:21 2007 +0100
@@ -32,7 +32,10 @@
  */
 
 
-
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
 
 
 class generate_cc_st_c: public generate_cc_typedecl_c {
@@ -53,16 +56,27 @@
      */
     search_fb_instance_decl_c *search_fb_instance_decl;
 
+    /* When compiling st code, it becomes necessary to determine the
+     * data type of st expressions. To do this, we must first find the
+     * st operand's declaration, within the scope of the function block
+     * or function currently being processed.
+     * The following object does just that...
+     * This object instance will then later be called while the
+     * remaining st code is being handled.
+     */
+    search_expression_type_c *search_expression_type;
 
   public:
     generate_cc_st_c(stage4out_c *s4o_ptr, symbol_c *scope, const char *variable_prefix = NULL)
     : generate_cc_typedecl_c(s4o_ptr) {
       search_fb_instance_decl = new search_fb_instance_decl_c(scope);
+      search_expression_type = new search_expression_type_c(scope);
       this->set_variable_prefix(variable_prefix);
     }
 
     virtual ~generate_cc_st_c(void) {
       delete search_fb_instance_decl;
+      delete search_expression_type;
     }
 
 
@@ -107,25 +121,141 @@
     }
 
   private:
+  
 /***************************************/
 /* B.3 - Language ST (Structured Text) */
 /***************************************/
 /***********************/
 /* B 3.1 - Expressions */
 /***********************/
-void *visit(or_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " || ");}
-/* TODO ...  XOR expression... */
-void *visit(xor_expression_c *symbol) {ERROR; return print_binary_expression(symbol->l_exp, symbol->r_exp, " XOR ");}
-void *visit(and_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " && ");}
-void *visit(equ_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " == ");}
-void *visit(notequ_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " != ");}
-void *visit(lt_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " < ");}
-void *visit(gt_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " > ");}
-void *visit(le_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " <= ");}
-void *visit(ge_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " >= ");}
-void *visit(add_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " + ");}
-void *visit(sub_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " - ");}
-void *visit(mul_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " * ");}
+void *visit(or_expression_c *symbol) {
+  symbol_c *left_type = search_expression_type->get_type(symbol->l_exp);
+  symbol_c *right_type = search_expression_type->get_type(symbol->r_exp);
+  if (typeid(*left_type) == typeid(bool_type_name_c) && typeid(*right_type) == typeid(bool_type_name_c)) {
+    return print_binary_expression(symbol->l_exp, symbol->r_exp, " || ");
+  }
+  if (search_expression_type->is_numeric_compatible(left_type) && search_expression_type->is_numeric_compatible(right_type)) {
+    return print_binary_expression(symbol->l_exp, symbol->r_exp, " | ");
+  }
+  ERROR;
+  return NULL;
+}
+
+void *visit(xor_expression_c *symbol) {
+  symbol_c *left_type = search_expression_type->get_type(symbol->l_exp);
+  symbol_c *right_type = search_expression_type->get_type(symbol->r_exp);
+  if (typeid(*left_type) == typeid(bool_type_name_c) && typeid(*right_type) == typeid(bool_type_name_c)) {
+    s4o.print("(");
+    symbol->l_exp->accept(*this);
+    s4o.print(" && !");
+    symbol->r_exp->accept(*this);
+    s4o.print(") || (!");
+    symbol->l_exp->accept(*this);
+    s4o.print(" && ");
+    symbol->r_exp->accept(*this);
+    s4o.print(")");
+  }
+  if (search_expression_type->is_numeric_compatible(left_type) && search_expression_type->is_numeric_compatible(right_type)) {
+    return print_binary_expression(symbol->l_exp, symbol->r_exp, " ^ ");
+  }
+  ERROR;
+  return NULL;
+}
+
+void *visit(and_expression_c *symbol) {
+  symbol_c *left_type = search_expression_type->get_type(symbol->l_exp);
+  symbol_c *right_type = search_expression_type->get_type(symbol->r_exp);
+  if (typeid(*left_type) == typeid(bool_type_name_c) && typeid(*right_type) == typeid(bool_type_name_c)) {
+    return print_binary_expression(symbol->l_exp, symbol->r_exp, " && ");
+  }
+  if (search_expression_type->is_numeric_compatible(left_type) && search_expression_type->is_numeric_compatible(right_type)) {
+    return print_binary_expression(symbol->l_exp, symbol->r_exp, " & ");
+  }
+  ERROR;
+  return NULL;
+}
+
+void *visit(equ_expression_c *symbol) {
+  symbol_c *left_type = search_expression_type->get_type(symbol->l_exp);
+  symbol_c *right_type = search_expression_type->get_type(symbol->r_exp);
+  if (search_expression_type->is_time_compatible(left_type) && search_expression_type->is_time_compatible(right_type)) {
+    return print_compare_function("__compare_timespec", "==", symbol->l_exp, symbol->r_exp);
+  }
+  return print_binary_expression(symbol->l_exp, symbol->r_exp, " == ");
+}
+
+void *visit(notequ_expression_c *symbol) {
+  symbol_c *left_type = search_expression_type->get_type(symbol->l_exp);
+  symbol_c *right_type = search_expression_type->get_type(symbol->r_exp);
+  if (search_expression_type->is_time_compatible(left_type) && search_expression_type->is_time_compatible(right_type)) {
+    return print_compare_function("__compare_timespec", "!=", symbol->l_exp, symbol->r_exp);
+  }
+  return print_binary_expression(symbol->l_exp, symbol->r_exp, " != ");
+}
+
+void *visit(lt_expression_c *symbol) {
+  symbol_c *left_type = search_expression_type->get_type(symbol->l_exp);
+  symbol_c *right_type = search_expression_type->get_type(symbol->r_exp);
+  if (search_expression_type->is_time_compatible(left_type) && search_expression_type->is_time_compatible(right_type)) {
+    return print_compare_function("__compare_timespec", "<", symbol->l_exp, symbol->r_exp);
+  }
+  return print_binary_expression(symbol->l_exp, symbol->r_exp, " < ");
+}
+
+void *visit(gt_expression_c *symbol) {
+  symbol_c *left_type = search_expression_type->get_type(symbol->l_exp);
+  symbol_c *right_type = search_expression_type->get_type(symbol->r_exp);
+  if (search_expression_type->is_time_compatible(left_type) && search_expression_type->is_time_compatible(right_type)) {
+    return print_compare_function("__compare_timespec", ">", symbol->l_exp, symbol->r_exp);
+  }
+  return print_binary_expression(symbol->l_exp, symbol->r_exp, " > ");
+}
+
+void *visit(le_expression_c *symbol) {
+  symbol_c *left_type = search_expression_type->get_type(symbol->l_exp);
+  symbol_c *right_type = search_expression_type->get_type(symbol->r_exp);
+  if (search_expression_type->is_time_compatible(left_type) && search_expression_type->is_time_compatible(right_type)) {
+    return print_compare_function("__compare_timespec", "<=", symbol->l_exp, symbol->r_exp);
+  }
+  return print_binary_expression(symbol->l_exp, symbol->r_exp, " <= ");
+}
+
+void *visit(ge_expression_c *symbol) {
+  symbol_c *left_type = search_expression_type->get_type(symbol->l_exp);
+  symbol_c *right_type = search_expression_type->get_type(symbol->r_exp);
+  if (search_expression_type->is_time_compatible(left_type) && search_expression_type->is_time_compatible(right_type)) {
+    return print_compare_function("__compare_timespec", ">=", symbol->l_exp, symbol->r_exp);
+  }
+  return print_binary_expression(symbol->l_exp, symbol->r_exp, " >= ");
+}
+
+void *visit(add_expression_c *symbol) {
+  symbol_c *left_type = search_expression_type->get_type(symbol->l_exp);
+	symbol_c *right_type = search_expression_type->get_type(symbol->r_exp);
+	if (search_expression_type->is_time_compatible(left_type) && search_expression_type->is_time_compatible(right_type)) {
+		return print_binary_function("__add_timespec", symbol->l_exp, symbol->r_exp);
+	}
+	return print_binary_expression(symbol->l_exp, symbol->r_exp, " + ");
+}
+
+void *visit(sub_expression_c *symbol) {
+  symbol_c *left_type = search_expression_type->get_type(symbol->l_exp);
+  symbol_c *right_type = search_expression_type->get_type(symbol->r_exp);
+  if (search_expression_type->is_time_compatible(left_type) && search_expression_type->is_time_compatible(right_type)) {
+    return print_binary_function("__sub_timespec", symbol->l_exp, symbol->r_exp);
+  }
+  return print_binary_expression(symbol->l_exp, symbol->r_exp, " - ");
+}
+
+void *visit(mul_expression_c *symbol) {
+  symbol_c *left_type = search_expression_type->get_type(symbol->l_exp);
+  symbol_c *right_type = search_expression_type->get_type(symbol->r_exp);
+  if (search_expression_type->is_time_compatible(left_type) && search_expression_type->is_time_compatible(right_type)) {
+    return print_binary_function("__mul_timespec", symbol->l_exp, symbol->r_exp);
+  }
+  return print_binary_expression(symbol->l_exp, symbol->r_exp, " * ");
+}
+
 void *visit(div_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " / ");}
 void *visit(mod_expression_c *symbol) {
   s4o.print("((");
--- a/stage4/generate_cc/plciec.h	Wed Feb 14 19:57:01 2007 +0100
+++ b/stage4/generate_cc/plciec.h	Tue Feb 20 18:17:21 2007 +0100
@@ -182,15 +182,100 @@
 
 
 /* Some necessary forward declarations... */
+/*
 class TIME;
 class TOD;
 class DT;
 class DATE;
 
 typedef struct timespec __timebase_t;
-
-
-
+*/
+
+typedef struct TIME timespec;
+typedef struct TOD timespec;
+typedef struct DT timespec;
+typedef struct DATE timespec;
+
+static inline struct timespec __time_to_timespec(int sign, double mseconds, double seconds, double minutes, double hours, double days) {
+  struct timespec ts;
+  
+  /* 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;
+  ts.tv_nsec = sign * (long int)((total_sec - ts.tv_sec)*1e9);
+
+  return ts;
+}
+
+
+static inline struct timespec __tod_to_timespec(double seconds, double minutes, double hours) {
+  struct timespec ts;
+  
+  long double total_sec = (hours*60 + minutes)*60 + seconds;
+  ts.tv_sec = (long int)total_sec;
+  ts.tv_nsec = (long int)((total_sec - ts.tv_sec)*1e9);
+  
+  return ts;
+}
+
+static inline struct timespec __date_to_timespec(int day, int month, int year) {
+  struct timespec ts;
+  struct tm broken_down_time;
+
+  broken_down_time.tm_sec = 0;
+  broken_down_time.tm_min = 0;
+  broken_down_time.tm_hour = 0;
+  broken_down_time.tm_mday = day;  /* day of month, from 1 to 31 */
+  broken_down_time.tm_mon = month - 1;   /* month since January, in the range 0 to 11 */
+  broken_down_time.tm_year = year - 1900;  /* number of years since 1900 */
+
+  time_t epoch_seconds = mktime(&broken_down_time); /* determine number of seconds since the epoch, i.e. Jan 1st 1970 */
+
+  if ((time_t)(-1) == epoch_seconds)
+    IEC_error();
+
+  ts.tv_sec = epoch_seconds;
+  ts.tv_nsec = 0;
+  
+  return ts;
+}
+
+static inline struct timespec __dt_to_timespec(double seconds,  double minutes, double hours, int day, int month, int year) {
+  struct timespec ts;
+  
+  long double total_sec = (hours*60 + minutes)*60 + seconds;
+  ts.tv_sec = (long int)total_sec;
+  ts.tv_nsec = (long int)((total_sec - ts.tv_sec)*1e9);
+
+  struct tm broken_down_time;
+  broken_down_time.tm_sec = 0;
+  broken_down_time.tm_min = 0;
+  broken_down_time.tm_hour = 0;
+  broken_down_time.tm_mday = day;  /* day of month, from 1 to 31 */
+  broken_down_time.tm_mon = month - 1;   /* month since January, in the range 0 to 11 */
+  broken_down_time.tm_year = year - 1900;  /* number of years since 1900 */
+
+  time_t epoch_seconds = mktime(&broken_down_time); /* determine number of seconds since the epoch, i.e. Jan 1st 1970 */
+  if ((time_t)(-1) == epoch_seconds)
+    IEC_error();
+
+  ts.tv_sec += epoch_seconds;
+  if (ts.tv_sec < epoch_seconds)
+    /* since the TOD is always positive, if the above happens then we had an overflow */
+    IEC_error();
+
+  return ts;
+}
+
+
+
+
+
+
+
+
+#ifdef 0
 class TIME{
   private:
     /* private variable that contains the value of time. */
@@ -451,6 +536,7 @@
 DT operator+ (const DATE &date, const TOD &tod) {return DT(__add_timespec(date.time, tod.time));};
 DT operator+ (const TOD &tod, const DATE &date) {return DT(__add_timespec(date.time, tod.time));};
 
+#endif
 
 /* global variable that will be used to implement the timers TON, TOFF and TP */
 extern TIME __CURRENT_TIME;
@@ -490,16 +576,18 @@
 	 *   member function to each class that allows it to be converted to that same base data type,
 	 *   acompanied by a constructor using that data type.
 	 */
-	/*
+	
 	TIME	TIMEvar;
 	TOD	TODvar;
 	DT	DTvar;
 	DATE	DATEvar;
-	*/
+	
+  /*
 	__timebase_t	TIMEvar;
 	__timebase_t	TODvar;
 	__timebase_t	DTvar;
 	__timebase_t	DATEvar;
+  */
 } __IL_DEFVAR_T;
   /*TODO TODO TODO TODO TODO TODO TODO TODO TODO
    * How do we add support for the possibility of storing
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stage4/generate_cc/search_expression_type.cc	Tue Feb 20 18:17:21 2007 +0100
@@ -0,0 +1,244 @@
+/*
+ * (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 data type of an ST expression.
+ * A reference to the relevant type definition is returned.
+ *
+ * For example:
+ *       2 + 3       -> returns reference to a int_type_name_c object.
+ *       22.2 - 5    -> returns reference to a real_type_name_c object.
+ *       etc...
+ */
+class search_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;
+
+  public:
+    search_expression_type_c(symbol_c *search_scope) {
+      search_varfb_instance_type = new search_varfb_instance_type_c(search_scope);
+    }
+
+    virtual ~search_expression_type_c(void) {
+      delete search_varfb_instance_type;
+    }
+
+    /* A helper function... */
+    bool is_bool_type(symbol_c *type_symbol) {
+      return (typeid(*type_symbol) == typeid(bool_type_name_c));
+    }
+
+    /* A helper function... */
+    bool is_time_compatible(symbol_c *type_symbol) {
+      if (typeid(*type_symbol) == typeid(time_type_name_c)) {return true;}
+      if (typeid(*type_symbol) == typeid(date_type_name_c)) {return true;}
+      if (typeid(*type_symbol) == typeid(tod_type_name_c)) {return true;}
+      if (typeid(*type_symbol) == typeid(dt_type_name_c)) {return true;}
+      return false;
+    }
+
+    /* A helper function... */
+    bool is_numeric_compatible(symbol_c *type_symbol) {
+      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 (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(byte_type_name_c)) {return true;}
+      if (typeid(*type_symbol) == typeid(word_type_name_c)) {return true;}
+      if (typeid(*type_symbol) == typeid(dword_type_name_c)) {return true;}
+      if (typeid(*type_symbol) == typeid(lword_type_name_c)) {return true;}
+      return false;
+    }
+    
+  private:
+
+  static bool_type_name_c bool_type_name;
+
+  /* A helper function... */
+  void *compute_boolean_expression(symbol_c *left_type, symbol_c *right_type) {
+    if (typeid(*left_type) == typeid(bool_type_name_c) and typeid(*right_type) == typeid(bool_type_name_c)) {return (void *)left_type;}
+    if (is_numeric_compatible(left_type) && is_numeric_compatible(right_type)) {return (void *)left_type;}
+    ERROR;
+    return NULL;
+  }
+
+  /* A helper function... */
+  void *compute_numeric_expression(symbol_c *left_type, symbol_c *right_type) {
+    if (is_numeric_compatible(left_type) && is_numeric_compatible(right_type)) {return (void *)left_type;}
+    ERROR;
+    return NULL;
+  }
+
+  /* a helper function... */
+  symbol_c *base_type(symbol_c *symbol) {
+    return (symbol_c *)symbol->accept(search_base_type);
+  }
+
+/*********************/
+/* B 1.4 - Variables */
+/*********************/
+
+  void *visit(symbolic_variable_c *symbol) {
+    symbol_c *res;
+    
+    /* Nope, now we assume it is a variable, and determine its type... */
+    res = search_varfb_instance_type->get_type(symbol);
+    if (NULL != res) return res;
+    
+    return NULL;
+  }
+
+
+/***************************************/
+/* B.3 - Language ST (Structured Text) */
+/***************************************/
+/***********************/
+/* B 3.1 - Expressions */
+/***********************/
+  void *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);
+  }
+
+  void *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);
+  }
+
+  void *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); 
+  }
+
+  void *visit(equ_expression_c *symbol) {return (void *)&bool_type_name;}
+  void *visit(notequ_expression_c *symbol) {return (void *)&bool_type_name;}
+  void *visit(lt_expression_c *symbol) {return (void *)&bool_type_name;}
+  void *visit(gt_expression_c *symbol) {return (void *)&bool_type_name;}
+  void *visit(le_expression_c *symbol) {return (void *)&bool_type_name;}
+  void *visit(ge_expression_c *symbol) {return (void *)&bool_type_name;}
+
+  void *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 (is_time_compatible(left_type) && is_time_compatible(right_type)) {return left_type;}
+    return compute_numeric_expression(left_type, right_type);
+  }
+
+  void *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 (is_time_compatible(left_type) && is_time_compatible(right_type)) {return left_type;}
+    return compute_numeric_expression(left_type, right_type);
+  }
+  
+  void *visit(mul_expression_c *symbol) {
+    symbol_c *left_type = base_type((symbol_c *)symbol->l_exp->accept(*this));
+    symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this));
+    if (is_time_compatible(left_type) && is_time_compatible(right_type)) {return left_type;}
+    return compute_numeric_expression(left_type, right_type);
+  }
+  
+  void *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));
+    return compute_numeric_expression(left_type, right_type);
+  }
+
+  void *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);
+  }
+
+  void *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 (typeid(*left_type) == typeid(real_type_name_c) and typeid(*right_type) == typeid(sint_type_name_c)) {return (void *)left_type;}
+    if (typeid(*left_type) == typeid(real_type_name_c) and typeid(*right_type) == typeid(int_type_name_c)) {return (void *)left_type;}
+    if (typeid(*left_type) == typeid(real_type_name_c) and typeid(*right_type) == typeid(dint_type_name_c)) {return (void *)left_type;}
+    if (typeid(*left_type) == typeid(real_type_name_c) and typeid(*right_type) == typeid(lint_type_name_c)) {return (void *)left_type;}
+    if (typeid(*left_type) == typeid(real_type_name_c) and typeid(*right_type) == typeid(usint_type_name_c)) {return (void *)left_type;}
+    if (typeid(*left_type) == typeid(real_type_name_c) and typeid(*right_type) == typeid(uint_type_name_c)) {return (void *)left_type;}
+    if (typeid(*left_type) == typeid(real_type_name_c) and typeid(*right_type) == typeid(udint_type_name_c)) {return (void *)left_type;}
+    if (typeid(*left_type) == typeid(real_type_name_c) and typeid(*right_type) == typeid(ulint_type_name_c)) {return (void *)left_type;}
+    if (typeid(*left_type) == typeid(lreal_type_name_c) and typeid(*right_type) == typeid(sint_type_name_c)) {return (void *)left_type;}
+    if (typeid(*left_type) == typeid(lreal_type_name_c) and typeid(*right_type) == typeid(int_type_name_c)) {return (void *)left_type;}
+    if (typeid(*left_type) == typeid(lreal_type_name_c) and typeid(*right_type) == typeid(dint_type_name_c)) {return (void *)left_type;}
+    if (typeid(*left_type) == typeid(lreal_type_name_c) and typeid(*right_type) == typeid(lint_type_name_c)) {return (void *)left_type;}
+    if (typeid(*left_type) == typeid(lreal_type_name_c) and typeid(*right_type) == typeid(usint_type_name_c)) {return (void *)left_type;}
+    if (typeid(*left_type) == typeid(lreal_type_name_c) and typeid(*right_type) == typeid(uint_type_name_c)) {return (void *)left_type;}
+    if (typeid(*left_type) == typeid(lreal_type_name_c) and typeid(*right_type) == typeid(udint_type_name_c)) {return (void *)left_type;}
+    if (typeid(*left_type) == typeid(lreal_type_name_c) and typeid(*right_type) == typeid(ulint_type_name_c)) {return (void *)left_type;}
+    ERROR;
+    return NULL;
+  }
+  
+  void *visit(neg_expression_c *symbol) {
+    symbol_c *exp_type = base_type((symbol_c *)symbol->exp->accept(*this));
+    if (typeid(*exp_type) == typeid(sint_type_name_c)) {return (void *)exp_type;}
+    if (typeid(*exp_type) == typeid(int_type_name_c)) {return (void *)exp_type;}
+    if (typeid(*exp_type) == typeid(dint_type_name_c)) {return (void *)exp_type;}
+    if (typeid(*exp_type) == typeid(lint_type_name_c)) {return (void *)exp_type;}
+    if (typeid(*exp_type) == typeid(usint_type_name_c)) {return (void *)exp_type;}
+    if (typeid(*exp_type) == typeid(uint_type_name_c)) {return (void *)exp_type;}
+    if (typeid(*exp_type) == typeid(udint_type_name_c)) {return (void *)exp_type;}
+    if (typeid(*exp_type) == typeid(ulint_type_name_c)) {return (void *)exp_type;}
+    if (typeid(*exp_type) == typeid(real_type_name_c)) {return (void *)exp_type;}
+    if (typeid(*exp_type) == typeid(lreal_type_name_c)) {return (void *)exp_type;}
+    if (typeid(*exp_type) == typeid(time_type_name_c)) {return (void *)exp_type;}
+    ERROR;
+    return NULL;
+  }
+  
+  void *visit(not_expression_c *symbol) {
+    symbol_c *exp_type = base_type((symbol_c *)symbol->exp->accept(*this));
+    if (typeid(*exp_type) == typeid(bool_type_name_c)) {return (void *)exp_type;}
+    ERROR;
+    return NULL;
+  }
+  
+  void *visit(function_invocation_c *symbol) {
+	  function_declaration_c *f_decl = function_symtable.find_value(symbol->function_name);
+	
+	  if (f_decl == function_symtable.end_value())
+	    /* should never occur. The function being called MUST be in the symtable... */
+	    ERROR;
+
+    return base_type(f_decl->type_name);
+  }
+
+};
+
+bool_type_name_c     search_expression_type_c::bool_type_name;
+
--- a/stage4/generate_iec/generate_iec.cc	Wed Feb 14 19:57:01 2007 +0100
+++ b/stage4/generate_iec/generate_iec.cc	Tue Feb 20 18:17:21 2007 +0100
@@ -1163,7 +1163,7 @@
 
 /* '(' step_name ',' step_name {',' step_name} ')' */
 void *visit(step_name_list_c *symbol) {
-  print_list(symbol, "(", ", ", ") ");
+  print_list(symbol, "(", ", ", ")");
   return NULL;
 }