stage4/generate_c/generate_c.cc
changeset 625 c0bda77b37a0
parent 412 aad38592bdde
parent 624 c2546c6e0cfa
child 631 1a4f5ce62962
--- a/stage4/generate_c/generate_c.cc	Tue Aug 14 19:40:01 2012 +0200
+++ b/stage4/generate_c/generate_c.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -31,10 +31,12 @@
 #include <sstream>
 #include <strings.h>
 
+
 #include "../../util/symtable.hh"
 #include "../../util/dsymtable.hh"
 #include "../../absyntax/visitor.hh"
 #include "../../absyntax_utils/absyntax_utils.hh"
+#include "../../main.hh" // required for ERROR() and ERROR_MSG() macros.
 
 #include "../stage4.hh"
 
@@ -45,9 +47,16 @@
 #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);
+
+
+#define STAGE4_ERROR(symbol1, symbol2, ...) {stage4err("while generating C code", symbol1, symbol2, __VA_ARGS__); exit(EXIT_FAILURE);}
+
+
+/* Macros to access the constant value of each expression (if it exists) from the annotation introduced to the symbol_c object by constant_folding_c in stage3! */
+#define VALID_CVALUE(dtype, symbol)           (symbol_c::cs_const_value == (symbol)->const_value._##dtype.status)
+#define GET_CVALUE(dtype, symbol)             ((symbol)->const_value._##dtype.value) 
+
+
 
 /***********************************************************************/
 
@@ -197,10 +206,9 @@
     }
     
   public:
-    print_function_parameter_data_types_c(stage4out_c *s4o_ptr):
-      generate_c_base_c(s4o_ptr) {
-    	current_type = NULL;
-      }
+    print_function_parameter_data_types_c(stage4out_c *s4o_ptr): 
+      generate_c_base_c(s4o_ptr)
+      {current_type = NULL;}
 
     /**************************************/
     /* B.1.5 - Program organization units */
@@ -211,8 +219,7 @@
     /*   FUNCTION derived_function_name ':' elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION */
     /* | FUNCTION derived_function_name ':' derived_type_name io_OR_function_var_declarations_list function_body END_FUNCTION */
     void *visit(function_declaration_c *symbol) {
-      /* return type */
-      symbol->type_name->accept(*this);
+      symbol->type_name->accept(*this); /* return type */
       symbol->var_declarations_list->accept(*this);
       return NULL;
     }
@@ -339,94 +346,75 @@
 #define MILLISECOND 1000000
 #define SECOND 1000 * MILLISECOND
 
-/* A helper class that knows how to generate code for both the IL and ST languages... */
-class calculate_time_c: public iterator_visitor_c {
-  private:
-    unsigned long long time;
-    float current_value;
+unsigned long long calculate_time(symbol_c *symbol) {
+  if (NULL == symbol) return 0;
   
-  public:
-    calculate_time_c(void){time = 0;};
-    
-    unsigned long long get_time(void) {return time;};
-
-    void *get_integer_value(token_c *token) {
-      std::string str = "";
-      for (unsigned int i = 0; i < strlen(token->value); i++)
-        if (token->value[i] != '_')
-          str += token->value[i];
-      current_value = atof(str.c_str());
-      return NULL;
-    }
-
-    void *get_float_value(token_c *token) {
-      current_value = atof(token->value);
-      return NULL;
-    }
-
-/******************************/
-/* B 1.2.1 - Numeric Literals */
-/******************************/
-
-    void *visit(integer_c *symbol) {return get_integer_value(symbol);}
-    
-/************************/
-/* B 1.2.3.1 - Duration */
-/************************/
+  interval_c *interval = dynamic_cast<interval_c *>(symbol);
+  duration_c *duration = dynamic_cast<duration_c *>(symbol);
   
+  if ((NULL == interval) && (NULL == duration)) ERROR;
+
+  if (NULL != duration) {
     /* SYM_REF2(duration_c, neg, interval) */
-    void *visit(duration_c *symbol) {
-      if (symbol->neg != NULL)
-        ERROR;
-      symbol->interval->accept(*this);
-      return NULL;
-    }
-    
-    /* SYM_TOKEN(fixed_point_c) */
-    void *visit(fixed_point_c *symbol) {return get_float_value(symbol);}
-    
-    /* SYM_REF2(days_c, days, hours) */
-    void *visit(days_c *symbol) {
-      if (symbol->hours)
-        symbol->hours->accept(*this);
-      symbol->days->accept(*this);
-      time += (unsigned long long)(current_value * 24 * 3600 * SECOND);
-      return NULL;
-    }
-    
-    /* SYM_REF2(hours_c, hours, minutes) */
-    void *visit(hours_c *symbol) {
-      if (symbol->minutes)
-        symbol->minutes->accept(*this);
-      symbol->hours->accept(*this);
-      time += (unsigned long long)(current_value * 3600 * SECOND);
-      return NULL;
-    }
-    
-    /* SYM_REF2(minutes_c, minutes, seconds) */
-    void *visit(minutes_c *symbol) {
-      if (symbol->seconds)
-        symbol->seconds->accept(*this);
-      symbol->minutes->accept(*this);
-      time += (unsigned long long)(current_value * 60 * SECOND);
-      return NULL;
-    }
-    
-    /* SYM_REF2(seconds_c, seconds, milliseconds) */
-    void *visit(seconds_c *symbol) {
-      if (symbol->milliseconds)
-        symbol->milliseconds->accept(*this);
-      symbol->seconds->accept(*this);
-      time += (unsigned long long)(current_value * SECOND);
-      return NULL;
-    }
-    
-    /* SYM_REF2(milliseconds_c, milliseconds, unused) */
-    void *visit(milliseconds_c *symbol) {
-      symbol->milliseconds->accept(*this);
-      time += (unsigned long long)(current_value * MILLISECOND);
-      return NULL;
-    }
+    if (duration->neg != NULL)
+      {STAGE4_ERROR(duration, duration, "Negative TIME literals are not currently supported"); ERROR;}
+    return calculate_time(duration->interval);
+  }
+
+  if (NULL != interval) {
+    /* SYM_REF5(interval_c, days, hours, minutes, seconds, milliseconds) */
+      unsigned long long int time_ull = 0; 
+      long double            time_ld  = 0;
+      /*
+      const unsigned long long int MILLISECOND = 1000000;
+      const unsigned long long int      SECOND = 1000 * MILLISECOND
+      */
+      
+      if (NULL != interval->milliseconds) {
+        if      (VALID_CVALUE( int64, interval->milliseconds) &&           GET_CVALUE( int64, interval->milliseconds) < 0) ERROR; // interval elements should always be positive!
+        if      (VALID_CVALUE( int64, interval->milliseconds)) time_ull += GET_CVALUE( int64, interval->milliseconds) * MILLISECOND;
+        else if (VALID_CVALUE(uint64, interval->milliseconds)) time_ull += GET_CVALUE(uint64, interval->milliseconds) * MILLISECOND;
+        else if (VALID_CVALUE(real64, interval->milliseconds)) time_ld  += GET_CVALUE(real64, interval->milliseconds) * MILLISECOND;
+        else ERROR; // if (NULL != interval->milliseconds) is true, then it must have a valid constant value!
+      }
+   
+      if (NULL != interval->seconds     ) {
+        if      (VALID_CVALUE( int64, interval->seconds     ) &&           GET_CVALUE( int64, interval->seconds     ) < 0) ERROR; // interval elements should always be positive!
+        if      (VALID_CVALUE( int64, interval->seconds     )) time_ull += GET_CVALUE( int64, interval->seconds     ) * SECOND;
+        else if (VALID_CVALUE(uint64, interval->seconds     )) time_ull += GET_CVALUE(uint64, interval->seconds     ) * SECOND;
+        else if (VALID_CVALUE(real64, interval->seconds     )) time_ld  += GET_CVALUE(real64, interval->seconds     ) * SECOND;
+        else ERROR; // if (NULL != interval->seconds) is true, then it must have a valid constant value!
+      }
+
+      if (NULL != interval->minutes     ) {
+        if      (VALID_CVALUE( int64, interval->minutes     ) &&           GET_CVALUE( int64, interval->minutes     ) < 0) ERROR; // interval elements should always be positive!
+        if      (VALID_CVALUE( int64, interval->minutes     )) time_ull += GET_CVALUE( int64, interval->minutes     ) * SECOND * 60;
+        else if (VALID_CVALUE(uint64, interval->minutes     )) time_ull += GET_CVALUE(uint64, interval->minutes     ) * SECOND * 60;
+        else if (VALID_CVALUE(real64, interval->minutes     )) time_ld  += GET_CVALUE(real64, interval->minutes     ) * SECOND * 60;
+        else ERROR; // if (NULL != interval->minutes) is true, then it must have a valid constant value!
+      }
+
+      if (NULL != interval->hours       ) {
+        if      (VALID_CVALUE( int64, interval->hours       ) &&           GET_CVALUE( int64, interval->hours       ) < 0) ERROR; // interval elements should always be positive!
+        if      (VALID_CVALUE( int64, interval->hours       )) time_ull += GET_CVALUE( int64, interval->hours       ) * SECOND * 60 * 60;
+        else if (VALID_CVALUE(uint64, interval->hours       )) time_ull += GET_CVALUE(uint64, interval->hours       ) * SECOND * 60 * 60;
+        else if (VALID_CVALUE(real64, interval->hours       )) time_ld  += GET_CVALUE(real64, interval->hours       ) * SECOND * 60 * 60;
+        else ERROR; // if (NULL != interval->hours) is true, then it must have a valid constant value!
+      }
+
+      if (NULL != interval->days        ) {
+        if      (VALID_CVALUE( int64, interval->days        ) &&           GET_CVALUE( int64, interval->days        ) < 0) ERROR; // interval elements should always be positive!
+        if      (VALID_CVALUE( int64, interval->days        )) time_ull += GET_CVALUE( int64, interval->days        ) * SECOND * 60 * 60 * 24;
+        else if (VALID_CVALUE(uint64, interval->days        )) time_ull += GET_CVALUE(uint64, interval->days        ) * SECOND * 60 * 60 * 24;
+        else if (VALID_CVALUE(real64, interval->days        )) time_ld  += GET_CVALUE(real64, interval->days        ) * SECOND * 60 * 60 * 24;
+        else ERROR; // if (NULL != interval->days) is true, then it must have a valid constant value!
+      }
+
+      time_ull += time_ld;
+      return time_ull;
+  };
+  ERROR; // should never reach this point!
+  return 0; // humour the compiler!
 };
 
 /***********************************************************************/
@@ -480,14 +468,9 @@
 /*  TASK task_name task_initialization */
 //SYM_REF2(task_configuration_c, task_name, task_initialization)  
     void *visit(task_initialization_c *symbol) {
-      calculate_time_c calculate_time;
-      unsigned long long time = 0;
-      if (symbol->interval_data_source != NULL) {
-        symbol->interval_data_source->accept(calculate_time);
-        time = calculate_time.get_time();
-      }
-      if (time > 0)
-        update_ticktime(time);
+      unsigned long long time = calculate_time(symbol->interval_data_source);
+      if (time < 0)  ERROR;
+      else           update_ticktime(time);
       return NULL;
     }
 };    
@@ -788,19 +771,18 @@
     /*  signed_integer DOTDOT signed_integer */
     //SYM_REF2(subrange_c, lower_limit, upper_limit)
     void *visit(subrange_c *symbol) {
-      int dimension = extract_integer(symbol->upper_limit) - extract_integer(symbol->lower_limit) + 1;
       switch (current_mode) {
         case arrayname_im:
           current_array_name += "_";
           {
             std::stringstream ss;
-            ss << dimension;
+            ss << symbol->dimension;
             current_array_name += ss.str();
           }
           break;
         case arraydeclaration_im:
           s4o_incl.print("[");
-          s4o_incl.print_integer(dimension);
+          s4o_incl.print(symbol->dimension);
           s4o_incl.print("]");
         default:
           generate_c_typedecl_c::visit(symbol);
@@ -809,11 +791,6 @@
       return NULL;
     }
 
-    /*  var1_list ':' structure_type_name */
-	void *visit(structured_var_declaration_c *symbol) {
-	  return NULL;
-	}
-
     /*  var1_list ':' initialized_structure */
     // SYM_REF2(structured_var_init_decl_c, var1_list, initialized_structure)
     void *visit(structured_var_init_decl_c *symbol) {
@@ -851,6 +828,12 @@
       return NULL;
     }
 
+    /*  var1_list ':' structure_type_name */
+    //SYM_REF2(structured_var_declaration_c, var1_list, structure_type_name)
+    void *visit(structured_var_declaration_c *symbol) {
+      return NULL;
+    }
+
     /* VAR [CONSTANT] var_init_decl_list END_VAR */
     /* option -> may be NULL ! */
     /* helper symbol for input_declarations */
@@ -1676,7 +1659,8 @@
   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::global_vt,
+                                     symbol->configuration_name);
   vardecl->print(symbol);
   delete vardecl;
   s4o.print("\n");
@@ -1819,7 +1803,7 @@
 
     declaretype_t wanted_declaretype;
 
-    unsigned long common_ticktime;
+    unsigned long long common_ticktime;
     
     const char *current_program_name;
 
@@ -2196,12 +2180,10 @@
             current_task_name->accept(*this);
             s4o.print(" = ");
             if (symbol->interval_data_source != NULL) {
-              calculate_time_c calculate_time;
-              symbol->interval_data_source->accept(calculate_time);
-              unsigned long time = calculate_time.get_time();
+              unsigned long long int time = calculate_time(symbol->interval_data_source);
               if (time != 0) {
                 s4o.print("!(tick % ");
-                s4o.print_integer((int)(time / common_ticktime));
+                s4o.print(time / common_ticktime);
                 s4o.print(")");
               }
               else
@@ -2231,10 +2213,10 @@
           if (var_decl == NULL)
             ERROR;
           else
-            vartype = search_config_instance->get_vartype();
+            vartype = search_config_instance->get_vartype(current_var_reference);
         }
         else
-          vartype = search_resource_instance->get_vartype();
+          vartype = search_resource_instance->get_vartype(current_var_reference);
         
         s4o.print(s4o.indent_spaces + "{extern ");
         var_decl->accept(*this);
@@ -2245,7 +2227,7 @@
         s4o.print(".");
         symbol->symbolic_variable->accept(*this);
         s4o.print(" = ");
-        if (vartype || search_var_instance_decl_c::global_vt)
+        if (vartype == search_var_instance_decl_c::global_vt)
           s4o.print("*");
         symbol->prog_data_source->accept(*this);
         s4o.print(";}\n");
@@ -2266,17 +2248,17 @@
           if (var_decl == NULL)
             ERROR;
           else
-            vartype = search_config_instance->get_vartype();
+            vartype = search_config_instance->get_vartype(current_var_reference);
         }
         else
-          vartype = search_resource_instance->get_vartype();
+          vartype = search_resource_instance->get_vartype(current_var_reference);
         
         s4o.print(s4o.indent_spaces + "{extern ");
         var_decl->accept(*this);
         s4o.print(" *");
         symbol->data_sink->accept(*this);
         s4o.print("; ");
-        if (vartype || search_var_instance_decl_c::global_vt)
+        if (vartype == search_var_instance_decl_c::global_vt)
           s4o.print("*");
         symbol->data_sink->accept(*this);
         s4o.print(" = ");
@@ -2491,6 +2473,7 @@
 
           if (configuration_count++) {
             /* the first configuration is the one we will use!! */
+            STAGE4_ERROR(symbol, symbol, "A previous CONFIGURATION has already been declared (C code generation currently only allows a single configuration).");
             ERROR;
           }
 
@@ -2501,7 +2484,7 @@
             symbol->accept(calculate_common_ticktime);
             common_ticktime = calculate_common_ticktime.get_common_ticktime();
             if (common_ticktime == 0) {
-              fprintf(stderr, "\nYou must at least define a periodic task to set cycle period!");
+              STAGE4_ERROR(symbol, symbol, "You must define at least one periodic task (to set cycle period)!");
               ERROR;
             }