Fix parsing os TIME literals & rename the extract_integer() function.
authormjsousa <msousa@fe.up.pt>
Wed, 09 May 2012 23:00:10 +0100
changeset 547 dab341e80664
parent 546 8cc4c51c4bfc
child 548 7cc08964e0a7
Fix parsing os TIME literals & rename the extract_integer() function.
absyntax/absyntax.def
absyntax_utils/absyntax_utils.cc
absyntax_utils/absyntax_utils.hh
absyntax_utils/function_param_iterator.cc
absyntax_utils/search_constant_type.cc
absyntax_utils/search_constant_type.hh
absyntax_utils/type_initial_value.cc
stage1_2/iec_bison.yy
stage1_2/iec_flex.ll
stage4/generate_c/generate_c.cc
stage4/generate_c/generate_c_base.cc
stage4/generate_c/generate_c_typedecl.cc
stage4/generate_c/generate_c_vardecl.cc
stage4/generate_iec/generate_iec.cc
--- a/absyntax/absyntax.def	Wed May 09 22:59:10 2012 +0100
+++ b/absyntax/absyntax.def	Wed May 09 23:00:10 2012 +0100
@@ -210,13 +210,15 @@
 /************************/
 SYM_REF0(neg_time_c)
 SYM_REF3(duration_c, type_name, neg, interval)
+SYM_REF5(interval_c, days, hours, minutes, seconds, milliseconds)
 SYM_TOKEN(fixed_point_c)
+/*
 SYM_REF2(days_c, days, hours)
 SYM_REF2(hours_c, hours, minutes)
 SYM_REF2(minutes_c, minutes, seconds)
 SYM_REF2(seconds_c, seconds, milliseconds)
 SYM_REF1(milliseconds_c, milliseconds)
-
+*/
 
 /************************************/
 /* B 1.2.3.2 - Time of day and Date */
--- a/absyntax_utils/absyntax_utils.cc	Wed May 09 22:59:10 2012 +0100
+++ b/absyntax_utils/absyntax_utils.cc	Wed May 09 23:00:10 2012 +0100
@@ -98,20 +98,21 @@
 
 /* extract the value of an integer from an integer_c object !! */
 /* NOTE: it must ignore underscores! */
-int extract_integer(symbol_c *sym) {
+long long extract_integer_value(symbol_c *sym) {
   std::string str = "";
   integer_c *integer;
   neg_integer_c * neg_integer;
 
   if ((neg_integer = dynamic_cast<neg_integer_c *>(sym)) != NULL)
-    return - extract_integer((integer_c *)neg_integer->exp);
+    return - extract_integer_value(neg_integer->exp);
   
   if ((integer = dynamic_cast<integer_c *>(sym)) == NULL) ERROR;
 
   for(unsigned int i = 0; i < strlen(integer->value); i++)
     if (integer->value[i] != '_')  str += integer->value[i];
 
-  return atoi(str.c_str());
+  /* return atoi(str.c_str()); */
+  return atoll(str.c_str());
 }
 
 
--- a/absyntax_utils/absyntax_utils.hh	Wed May 09 22:59:10 2012 +0100
+++ b/absyntax_utils/absyntax_utils.hh	Wed May 09 23:00:10 2012 +0100
@@ -56,7 +56,7 @@
 int compare_identifiers(symbol_c *ident1, symbol_c *ident2);
 
 /* extract the value of an integer from an integer_c object !! */
-int extract_integer(symbol_c *integer);
+long long extract_integer_value(symbol_c *integer);
   
 /* A symbol table with all globally declared functions... */
 extern function_declaration_c null_symbol1;
@@ -119,7 +119,6 @@
 #include "search_expression_type.hh"
 #include "add_en_eno_param_decl.hh"
 #include "get_sizeof_datatype.hh"
-#include "get_function_type.h"
 #include "search_il_label.hh"
 #include "get_var_name.hh"
 
--- a/absyntax_utils/function_param_iterator.cc	Wed May 09 22:59:10 2012 +0100
+++ b/absyntax_utils/function_param_iterator.cc	Wed May 09 23:00:10 2012 +0100
@@ -130,7 +130,7 @@
         if (extensible_parameter != NULL) {
           sym = extensible_parameter->var_name;
           current_param_is_extensible = true;
-          _first_extensible_param_index = extract_integer(extensible_parameter->first_index);
+          _first_extensible_param_index = extract_integer_value(extensible_parameter->first_index);
         }
         identifier_c *variable_name = dynamic_cast<identifier_c *>(sym);
         if (variable_name == NULL) ERROR;
@@ -167,7 +167,7 @@
       if (extensible_parameter != NULL) {
         var_name = extensible_parameter->var_name;
         current_param_is_extensible = true;
-        _first_extensible_param_index = extract_integer(extensible_parameter->first_index);
+        _first_extensible_param_index = extract_integer_value(extensible_parameter->first_index);
       }
       identifier_c *variable_name = dynamic_cast<identifier_c *>(var_name);
       if (variable_name == NULL) ERROR;
@@ -265,7 +265,7 @@
   if (extensible_parameter != NULL) {
     sym = extensible_parameter->var_name;
     current_param_is_extensible = true;
-    _first_extensible_param_index = extract_integer(extensible_parameter->first_index);
+    _first_extensible_param_index = extract_integer_value(extensible_parameter->first_index);
     current_extensible_param_index = _first_extensible_param_index;
   }
   identifier = dynamic_cast<identifier_c *>(sym);
--- a/absyntax_utils/search_constant_type.cc	Wed May 09 22:59:10 2012 +0100
+++ b/absyntax_utils/search_constant_type.cc	Wed May 09 23:00:10 2012 +0100
@@ -105,11 +105,7 @@
 void *search_constant_type_c::visit(neg_time_c *symbol) {ERROR; return NULL;}  /* this member function should never be called. */
 void *search_constant_type_c::visit(duration_c *symbol) {return (void *)(symbol->type_name);}
 void *search_constant_type_c::visit(fixed_point_c *symbol) {ERROR; return NULL;}  /* this member function should never be called. */
-void *search_constant_type_c::visit(days_c *symbol) {ERROR; return NULL;}  /* this member function should never be called. */
-void *search_constant_type_c::visit(hours_c *symbol) {ERROR; return NULL;}  /* this member function should never be called. */
-void *search_constant_type_c::visit(minutes_c *symbol) {ERROR; return NULL;}  /* this member function should never be called. */
-void *search_constant_type_c::visit(seconds_c *symbol) {ERROR; return NULL;}  /* this member function should never be called. */
-void *search_constant_type_c::visit(milliseconds_c *symbol) {ERROR; return NULL;}  /* this member function should never be called. */
+void *search_constant_type_c::visit(interval_c *symbol) {ERROR; return NULL;}  /* this member function should never be called. */
 
 /************************************/
 /* B 1.2.3.2 - Time of day and Date */
--- a/absyntax_utils/search_constant_type.hh	Wed May 09 22:59:10 2012 +0100
+++ b/absyntax_utils/search_constant_type.hh	Wed May 09 23:00:10 2012 +0100
@@ -168,12 +168,8 @@
     /************************/
     void *visit(neg_time_c *symbol);
     void *visit(duration_c *symbol);
+    void *visit(interval_c *symbol);
     void *visit(fixed_point_c *symbol);
-    void *visit(days_c *symbol);
-    void *visit(hours_c *symbol);
-    void *visit(minutes_c *symbol);
-    void *visit(seconds_c *symbol);
-    void *visit(milliseconds_c *symbol);
 
     /************************************/
     /* B 1.2.3.2 - Time of day and Date */
--- a/absyntax_utils/type_initial_value.cc	Wed May 09 22:59:10 2012 +0100
+++ b/absyntax_utils/type_initial_value.cc	Wed May 09 23:00:10 2012 +0100
@@ -84,7 +84,7 @@
     date_literal_0 =  new date_literal_c(integer_1, integer_1, integer_1);
   date_literal_0 =  new date_literal_c(new integer_c("1970"), integer_1, integer_1);
   daytime_literal_0 = new daytime_c(integer_0, integer_0, real_0);
-  time_0 = new duration_c(new time_type_name_c(), NULL, new seconds_c(integer_0, NULL));  // T#0S
+  time_0 = new duration_c(new time_type_name_c(), NULL, new interval_c(NULL, NULL, NULL, integer_0, NULL));  // T#0s
   date_0 = new date_c(new date_type_name_c(), date_literal_0);  //  D#0001-01-01
   tod_0 = new time_of_day_c(new tod_type_name_c(), daytime_literal_0);  //  TOD#00:00:00
   dt_0 = new date_and_time_c(new dt_type_name_c(), date_literal_0, daytime_literal_0);  //  DT#0001-01-01-00:00:00
--- a/stage1_2/iec_bison.yy	Wed May 09 22:59:10 2012 +0100
+++ b/stage1_2/iec_bison.yy	Wed May 09 23:00:10 2012 +0100
@@ -58,6 +58,17 @@
 /**********************************************************************/
 /**********************************************************************/
 
+/* NOTE: the following file contains many rules used merely for detecting errors in
+ * the IEC source code being parsed.
+ * To remove all these rules, simply execute the command (first replace all '%' with '/'):
+ * $sed '\:%\* ERROR_CHECK_BEGIN \*%:,\:%\* ERROR_CHECK_END \*%: d' iec_bison.yy
+ *
+ * The above command had to be edited ('/' replaced by '%') so as not to include the C syntax that closes
+ * comments inside this comment!
+ * If you place the command in a shell script, be sure to remove the backslashes '\' before each asterisk '*' !!
+ */
+
+
 
 
 
@@ -490,17 +501,6 @@
 %type  <leaf>	seconds
 %type  <leaf>	milliseconds
 
-%type  <leaf>	integer_d
-%type  <leaf>	integer_h
-%type  <leaf>	integer_m
-%type  <leaf>	integer_s
-%type  <leaf>	integer_ms
-%type  <leaf>	fixed_point_d
-%type  <leaf>	fixed_point_h
-%type  <leaf>	fixed_point_m
-%type  <leaf>	fixed_point_s
-%type  <leaf>	fixed_point_ms
-
 %token <ID>	fixed_point_token
 %token <ID>	fixed_point_d_token
 %token <ID>	integer_d_token
@@ -512,7 +512,8 @@
 %token <ID>	integer_s_token
 %token <ID>	fixed_point_ms_token
 %token <ID>	integer_ms_token
-
+%token <ID>	end_interval_token
+%token <ID>	erroneous_interval_token
 // %token TIME
 %token T_SHARP
 
@@ -2138,156 +2139,56 @@
 	{$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between 'TIME' and interval in duration."); yynerrs++;}
 | TIME '-' interval
 	{$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between 'TIME' and interval in duration."); yynerrs++;}
-| TIME '#' error
-	{$$ = NULL;
-	 if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for duration.");}
-	 else {print_err_msg(locf(@3), locl(@3), "invalid value for duration."); yyclearin;}
-	 yyerrok;
-	}
-| T_SHARP error
-	{$$ = NULL;
-	 if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no value defined for duration.");}
-	 else {print_err_msg(locf(@2), locl(@2), "invalid value for duration."); yyclearin;}
-	 yyerrok;
-	}
-/* ERROR_CHECK_END */
-;
+| TIME '#' erroneous_interval_token
+	{$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid value for duration."); yynerrs++;}
+| T_SHARP erroneous_interval_token
+	{$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid value for duration."); yynerrs++;}
+| TIME '#' '-' erroneous_interval_token
+	{$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid value for duration."); yynerrs++;}
+| T_SHARP '-' erroneous_interval_token
+	{$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid value for duration."); yynerrs++;}
+/* ERROR_CHECK_END */
+;
+
+fixed_point:
+  integer
+| fixed_point_token	{$$ = new fixed_point_c($1, locloc(@$));};
 
 
 interval:
-  days
-| hours
-| minutes
-| seconds
-| milliseconds
-;
-
-integer_d:  integer_d_token  {$$ = new integer_c($1, locloc(@$));};
-integer_h:  integer_h_token  {$$ = new integer_c($1, locloc(@$));};
-integer_m:  integer_m_token  {$$ = new integer_c($1, locloc(@$));};
-integer_s:  integer_s_token  {$$ = new integer_c($1, locloc(@$));};
-integer_ms: integer_ms_token {$$ = new integer_c($1, locloc(@$));};
-
-fixed_point_d:
-  fixed_point_d_token
-	{$$ = new fixed_point_c($1, locloc(@$));}
-| integer_d
-;
-
-fixed_point_h:
-  fixed_point_h_token
-	{$$ = new fixed_point_c($1, locloc(@$));}
-| integer_h
-;
-
-fixed_point_m:
-  fixed_point_m_token
-	{$$ = new fixed_point_c($1, locloc(@$));}
-| integer_m
-;
-
-fixed_point_s:
-  fixed_point_s_token
-	{$$ = new fixed_point_c($1, locloc(@$));}
-| integer_s
-;
-
-fixed_point_ms:
-  fixed_point_ms_token
-	{$$ = new fixed_point_c($1, locloc(@$));}
-| integer_ms
-;
-
-
-fixed_point:
-  fixed_point_token
-	{$$ = new fixed_point_c($1, locloc(@$));}
-| integer
-;
-
-
-days:
-/*  fixed_point ('d') */
-  fixed_point_d
-	{$$ = new days_c($1, NULL, locloc(@$));}
-/*| integer ('d') ['_'] hours */
-| integer_d hours
-	{$$ = new days_c($1, $2, locloc(@$));}
-| integer_d '_' hours
-	{$$ = new days_c($1, $3, locloc(@$));}
-/* ERROR_CHECK_BEGIN */
-| integer_d '_' error
-	{$$ = NULL;
-	 if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for hours in duration.");}
-	 else {print_err_msg(locf(@3), locl(@3), "invalid value for hours in duration."); yyclearin;}
-	 yyerrok;
-	}
-/* ERROR_CHECK_END */
-;
-
-
-hours:
-/*  fixed_point ('h') */
-  fixed_point_h
-	{$$ = new hours_c($1, NULL, locloc(@$));}
-/*| integer ('h') ['_'] minutes */
-| integer_h minutes
-	{$$ = new hours_c($1, $2, locloc(@$));}
-| integer_h '_' minutes
-	{$$ = new hours_c($1, $3, locloc(@$));}
-/* ERROR_CHECK_BEGIN */
-| integer_h '_' error
-	{$$ = NULL;
-	 if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for minutes in duration.");}
-	 else {print_err_msg(locf(@3), locl(@3), "invalid value for minutes in duration."); yyclearin;}
-	 yyerrok;
-	}
-/* ERROR_CHECK_END */
-
-;
-
-minutes:
-/*  fixed_point ('m') */
-  fixed_point_m
-	{$$ = new minutes_c($1, NULL, locloc(@$));}
-/*| integer ('m') ['_'] seconds */
-| integer_m seconds
-	{$$ = new minutes_c($1, $2, locloc(@$));}
-| integer_m '_' seconds
-	{$$ = new minutes_c($1, $3, locloc(@$));}
-/* ERROR_CHECK_BEGIN */
-| integer_m '_' error
-	{$$ = NULL;
-	 if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for seconds in duration.");}
-	 else {print_err_msg(locf(@3), locl(@3), "invalid value for seconds in duration."); yyclearin;}
-	 yyerrok;
-	}
-/* ERROR_CHECK_END */
-;
-
-seconds:
-/*  fixed_point ('s') */
-  fixed_point_s
-	{$$ = new seconds_c($1, NULL, locloc(@$));}
-/*| integer ('s') ['_'] milliseconds */
-| integer_s milliseconds
-	{$$ = new seconds_c($1, $2, locloc(@$));}
-| integer_s '_' milliseconds
-	{$$ = new seconds_c($1, $3, locloc(@$));}
-/* ERROR_CHECK_BEGIN */
-| integer_s '_' error
-	{$$ = NULL;
-	 if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for milliseconds in duration.");}
-	 else {print_err_msg(locf(@3), locl(@3), "invalid value for milliseconds in duration."); yyclearin;}
-	 yyerrok;
-	}
-/* ERROR_CHECK_END */
-;
-
-milliseconds:
-/*  fixed_point ('ms') */
-  fixed_point_ms
-	{$$ = new milliseconds_c($1, locloc(@$));}
+  days hours minutes seconds milliseconds end_interval_token
+	{$$ = new interval_c($1, $2, $3, $4, $5, locloc(@$));};
+;
+
+
+days:   /*  fixed_point ('d') */
+  /* empty */		{$$ = NULL;}
+| fixed_point_d_token	{$$ = new fixed_point_c($1, locloc(@$));};
+| integer_d_token	{$$ = new integer_c($1, locloc(@$));};
+;
+
+hours:  /*  fixed_point ('h') */
+  /* empty */		{$$ = NULL;}
+| fixed_point_h_token	{$$ = new fixed_point_c($1, locloc(@$));};
+| integer_h_token	{$$ = new integer_c($1, locloc(@$));};
+;
+
+minutes: /*  fixed_point ('m') */
+  /* empty */		{$$ = NULL;}
+| fixed_point_m_token	{$$ = new fixed_point_c($1, locloc(@$));};
+| integer_m_token	{$$ = new integer_c($1, locloc(@$));};
+;
+
+seconds: /*  fixed_point ('s') */
+  /* empty */		{$$ = NULL;}
+| fixed_point_s_token	{$$ = new fixed_point_c($1, locloc(@$));};
+| integer_s_token	{$$ = new integer_c($1, locloc(@$));};
+;
+
+milliseconds: /*  fixed_point ('ms') */
+  /* empty */		{$$ = NULL;}
+| fixed_point_ms_token	{$$ = new fixed_point_c($1, locloc(@$));};
+| integer_ms_token	{$$ = new integer_c($1, locloc(@$));};
 ;
 
 
@@ -2985,13 +2886,18 @@
 	{$$ = new array_initial_elements_list_c(locloc(@$)); $$->add_element($1);}
 | array_initial_elements_list ',' array_initial_elements
 	{$$ = $1; $$->add_element($3);}
-/* ERROR_CHECK_BEGIN 
+/* ERROR_CHECK_BEGIN */
+/* The following error checking rules have been commented out. Why? Was it a typo? 
+ * Lets keep them commented out for now...
+ */
+/*
 | array_initial_elements_list ',' error
 	{$$ = $1;
 	 if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no array initial value in array initial values list.");}
 	 else {print_err_msg(locf(@3), locl(@3), "invalid array initial value in array initial values list."); yyclearin;}
 	 yyerrok;
 	}
+*/
 /* ERROR_CHECK_END */
 ;
 
@@ -3145,7 +3051,11 @@
 	{$$ = new structure_element_initialization_list_c(locloc(@$)); $$->add_element($1);}
 | structure_element_initialization_list ',' structure_element_initialization
 	{$$ = $1; $$->add_element($3);}
-/* ERROR_CHECK_BEGIN 
+/* ERROR_CHECK_BEGIN */
+/* The following error checking rules have been commented out. Why? Was it a typo? 
+ * Lets keep them commented out for now...
+ */
+/*
 | structure_element_initialization_list structure_element_initialization
 	{$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in structure element initialization list in structure initialization."); yynerrs++;}
 | structure_element_initialization_list ',' error
@@ -3154,6 +3064,7 @@
 	 else {print_err_msg(locf(@3), locl(@3), "invalid structure element initialization in structure initialization."); yyclearin;}
 	 yyerrok;
 	}
+*/
 /* ERROR_CHECK_END */
 ;
 
@@ -5454,12 +5365,15 @@
   {$$ = NULL;}
 | '(' {cmd_goto_sfc_priority_state();} PRIORITY {cmd_pop_state();} ASSIGN integer ')'
 	{$$ = $6;}
-/* ERROR_CHECK_BEGIN 
+/* ERROR_CHECK_BEGIN */
+/* The following error checking rules have been intentionally commented out. */
+/*
 | '(' ASSIGN integer ')'
 	{$$ = NULL; print_err_msg(locl(@1), locf(@2), "'PRIORITY' missing between '(' and ':=' in transition declaration with priority."); yynerrs++;}
 | '(' error ASSIGN integer ')'
 	{$$ = NULL; print_err_msg(locf(@2), locl(@2), "expecting 'PRIORITY' between '(' and ':=' in transition declaration with priority."); yyerrok;}
- ERROR_CHECK_END */
+*/
+/* ERROR_CHECK_END */
 ;
 
 
@@ -8250,6 +8164,7 @@
   }
 
   /* first parse the standard library file... */
+  /* Do not debug the standard library, even if debug flag is set! */
   /*
   #if YYDEBUG
     yydebug = 1;
--- a/stage1_2/iec_flex.ll	Wed May 09 22:59:10 2012 +0100
+++ b/stage1_2/iec_flex.ll	Wed May 09 23:00:10 2012 +0100
@@ -91,8 +91,10 @@
  */
 %option noyy_top_state
 
-/* We will not be using unput() in our flex code... */
+/* We will be using unput() in our flex code, so we cannot set the following option!... */
+/*
 %option nounput
+*/
 
 /**************************************************/
 /* External Variable and Function declarations... */
@@ -241,6 +243,10 @@
 %{
 /* return all the text in the current token back to the input stream. */
 void unput_text(unsigned int n);
+/* return all the text in the current token back to the input stream, 
+ * but first return to the stream an additional character to mark the end of the token. 
+ */
+void unput_and_mark(const char c);
 %}
 
 
@@ -340,6 +346,16 @@
  * expecting any action qualifiers, flex does not return these tokens, and is free
  * to interpret them as previously defined variables/functions/... as the case may be.
  *
+ * The time_literal_state is required because TIME# literals are decomposed into 
+ * portions, and wewant to send these portions one by one to bison. Each poertion will 
+ * represent the value in days/hours/minutes/seconds/ms.
+ * Unfortunately, some of these portions may also be lexically analysed as an identifier. So,
+ * we need to disable lexical identification of identifiers while parsing TIME# literals!
+ * e.g.:  TIME#55d_4h_56m
+ *       We would like to return to bison the tokens 'TIME' '#' '55d' '_' '4h' '_' '56m'
+ *       Unfortunately, flex will join '_' and '4h' to create a legal {identifier} '_4h',
+ *       and return that identifier instead! So, we added this state!
+ *
  * The state machine has 7 possible states (INITIAL, config, decl, body, st, il, sfc)
  * Possible state changes are:
  *   INITIAL -> goto(decl_state)
@@ -418,7 +434,8 @@
 /* we are parsing sfc code, and expecting the priority token.       */
 %s sfc_priority_state
 
-
+/* we are parsing a TIME# literal. We must not return any {identifier} tokens. */
+%x time_literal_state
 
 
 /*******************/
@@ -598,6 +615,15 @@
 /* B.1.2.1   Numeric literals */
 /******************************/
 integer         {digit}((_?{digit})*)
+
+/* Some helper symbols for parsing TIME literals... */
+integer_0_59    (0(_?))*([0-5](_?))?{digit}
+integer_0_19    (0(_?))*([0-1](_?))?{digit}
+integer_20_23   (0(_?))*2(_?)[0-3]
+integer_0_23    {integer_0_19}|{integer_20_23}
+integer_0_999   {digit}((_?{digit})?)((_?{digit})?)
+
+
 binary_integer  2#{bit}((_?{bit})*)
 bit		[0-1]
 octal_integer   8#{octal_digit}((_?{octal_digit})*)
@@ -673,21 +699,54 @@
 /************************/
 fixed_point		{integer}\.{integer}
 
-fixed_point_d		{fixed_point}d
-integer_d		{integer}d
-
-fixed_point_h		{fixed_point}h
-integer_h		{integer}h
-
-fixed_point_m		{fixed_point}m
-integer_m		{integer}m
-
-fixed_point_s		{fixed_point}s
-integer_s		{integer}s
-
-fixed_point_ms		{fixed_point}ms
-integer_ms		{integer}ms
-
+
+/* NOTE: The IEC 61131-3 v2 standard has an incorrect formal syntax definition of duration,
+ *       as its definition does not match the standard's text.
+ *       IEC 61131-3 v3 (committee draft) seems to have this fixed, so we use that
+ *       definition instead!
+ *
+ *       duration::= ('T' | 'TIME') '#' ['+'|'-'] interval
+ *       interval::= days | hours | minutes | seconds | milliseconds
+ *       fixed_point  ::= integer [ '.' integer]
+ *       days         ::= fixed_point 'd' | integer 'd' ['_'] [ hours ]
+ *       hours        ::= fixed_point 'h' | integer 'h' ['_'] [ minutes ]
+ *       minutes      ::= fixed_point 'm' | integer 'm' ['_'] [ seconds ]
+ *       seconds      ::= fixed_point 's' | integer 's' ['_'] [ milliseconds ]
+ *       milliseconds ::= fixed_point 'ms'
+ * 
+ * 
+ *  The original IEC 61131-3 v2 definition is:
+ *       duration ::= ('T' | 'TIME') '#' ['-'] interval
+ *       interval ::= days | hours | minutes | seconds | milliseconds
+ *       fixed_point  ::= integer [ '.' integer]
+ *       days         ::= fixed_point 'd' | integer 'd' ['_'] hours
+ *       hours        ::= fixed_point 'h' | integer 'h' ['_'] minutes
+ *       minutes      ::= fixed_point 'm' | integer 'm' ['_'] seconds
+ *       seconds      ::= fixed_point 's' | integer 's' ['_'] milliseconds
+ *       milliseconds ::= fixed_point 'ms'
+
+ */
+
+interval_ms_X		({integer_0_999}(\.{integer})?)ms
+interval_s_X		{integer_0_59}s(_?{interval_ms_X})?
+interval_m_X		{integer_0_59}m(_?{interval_s_X})?
+interval_h_X		{integer_0_23}h(_?{interval_m_X})?
+
+interval_ms		{integer}ms|({fixed_point}ms)
+interval_s		{integer}s(_?{interval_ms_X})?|({fixed_point}s)
+interval_m		{integer}m(_?{interval_s_X})?|({fixed_point}m)
+interval_h		{integer}h(_?{interval_m_X})?|({fixed_point}h)
+interval_d		{integer}d(_?{interval_h_X})?|({fixed_point}d)
+
+interval		{interval_ms}|{interval_s}|{interval_m}|{interval_h}|{interval_d}
+
+/* to help provide nice error messages, we also parse an incorrect but plausible interval... */
+/* NOTE that this erroneous interval will be parsed outside the time_literal_state, so must not 
+ *      be able to parse any other legal lexcial construct (besides a legal interval, but that
+ *      is OK as this rule will appear _after_ the rule to parse legal intervals!).
+ */
+fixed_point_or_integer  {fixed_point}|{integer}
+erroneous_interval	({fixed_point_or_integer}d_?)?({fixed_point_or_integer}h_?)?({fixed_point_or_integer}m_?)?({fixed_point_or_integer}s_?)?({fixed_point_or_integer}ms)?
 
 /********************************************/
 /* B.1.4.1   Directly Represented Variables */
@@ -719,9 +778,9 @@
  *    in which case we are currently using "%I3" as the variable
  *    name.
  */
-direct_variable_matplc		%{identifier}
-
-direct_variable			{direct_variable_standard}|{direct_variable_matplc}
+/* direct_variable_matplc		%{identifier} */
+/* direct_variable			{direct_variable_standard}|{direct_variable_matplc} */
+direct_variable			{direct_variable_standard}
 
 /******************************************/
 /* B 1.4.3 - Declaration & Initialisation */
@@ -1541,23 +1600,26 @@
 	/* B 1.2.3.1 - Duration */
 	/************************/
 {fixed_point}		{yylval.ID=strdup(yytext); return fixed_point_token;}
-
-{fixed_point_d}		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return fixed_point_d_token;}
-{integer_d}		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return integer_d_token;}
-
-{fixed_point_h}		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return fixed_point_h_token;}
-{integer_h}		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return integer_h_token;}
-
-{fixed_point_m}		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return fixed_point_m_token;}
-{integer_m}		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return integer_m_token;}
-
-{fixed_point_s}		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return fixed_point_s_token;}
-{integer_s}		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return integer_s_token;}
-
-{fixed_point_ms}	{yylval.ID=strdup(yytext); yylval.ID[yyleng-2] = '\0'; return fixed_point_ms_token;}
-{integer_ms}		{yylval.ID=strdup(yytext); yylval.ID[yyleng-2] = '\0'; return integer_ms_token;}
-
-
+{interval}		{/*fprintf(stderr, "entering time_literal_state ##%s##\n", yytext);*/ unput_and_mark('#'); yy_push_state(time_literal_state);}
+{erroneous_interval}	{return erroneous_interval_token;}
+
+<time_literal_state>{
+{integer}d		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return integer_d_token;}
+{integer}h		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return integer_h_token;}
+{integer}m		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return integer_m_token;}
+{integer}s		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return integer_s_token;}
+{integer}ms		{yylval.ID=strdup(yytext); yylval.ID[yyleng-2] = '\0'; return integer_ms_token;}
+{fixed_point}d		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return fixed_point_d_token;}
+{fixed_point}h		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return fixed_point_h_token;}
+{fixed_point}m		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return fixed_point_m_token;}
+{fixed_point}s		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return fixed_point_s_token;}
+{fixed_point}ms		{yylval.ID=strdup(yytext); yylval.ID[yyleng-2] = '\0'; return fixed_point_ms_token;}
+
+_			/* do nothing - eat it up!*/
+\#			{/*fprintf(stderr, "poping from time_literal_state (###)\n");*/ yy_pop_state(); return end_interval_token;}
+.			{ERROR;}
+\n			{ERROR;}
+}
 	/*******************************/
 	/* B.1.2.2   Character Strings */
 	/*******************************/
@@ -1645,6 +1707,20 @@
 }
 
 
+/* return all the text in the current token back to the input stream, 
+ * but first return to the stream an additional character to mark the end of the token. 
+ */
+void unput_and_mark(const char c) {
+  char *yycopy = strdup( yytext ); /* unput() destroys yytext, so we copy it first */
+  unput(c);
+  for (int i = yyleng-1; i >= 0; i--)
+    unput(yycopy[i]);
+
+  free(yycopy);
+}
+
+
+
 /* Called by flex when it reaches the end-of-file */
 int yywrap(void)
 {
--- a/stage4/generate_c/generate_c.cc	Wed May 09 22:59:10 2012 +0100
+++ b/stage4/generate_c/generate_c.cc	Wed May 09 23:00:10 2012 +0100
@@ -353,6 +353,10 @@
     
     unsigned long long get_time(void) {return time;};
 
+    /* NOTE: we should really remove this function, and replace it with  extract_integer_value() (in absyntax_utils.h)
+     *       but right now I don't want to spend time checking if this change will introduce some conversion bug
+     *       since it returns a long long, and not a float!
+     */
     void *get_integer_value(token_c *token) {
       std::string str = "";
       for (unsigned int i = 0; i < strlen(token->value); i++)
@@ -362,6 +366,10 @@
       return NULL;
     }
 
+    /* NOTE: this function is incomplete, as it should also be removing '_' inserted into the literal,
+     *       but we leave it for now.
+     *       In truth, we should really have an extract_real_value() in absyntax_util.h !!!
+     */
     void *get_float_value(token_c *token) {
       current_value = atof(token->value);
       return NULL;
@@ -388,48 +396,31 @@
     /* 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);
+    
+    /* SYM_REF5(interval_c, days, hours, minutes, seconds, milliseconds) */
+    void *visit(interval_c *symbol) {
+      current_value = 0;
+      if (NULL != symbol->milliseconds) symbol->milliseconds->accept(*this);
+      time += (unsigned long long)(current_value * MILLISECOND);
+   
+      current_value = 0;
+      if (NULL != symbol->seconds)      symbol->seconds->accept(*this);
+      time += (unsigned long long)(current_value * SECOND);
+   
+      current_value = 0;
+      if (NULL != symbol->minutes)      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;
-    }
+   
+      current_value = 0;
+      if (NULL != symbol->hours)        symbol->hours->accept(*this);
+      time += (unsigned long long)(current_value * 60 * 60 * SECOND);
+   
+      current_value = 0;
+      if (NULL != symbol->days)         symbol->days->accept(*this);
+      time += (unsigned long long)(current_value * 60 * 60 * 24 * SECOND);
+   
+      return NULL;
+    }      
 };
 
 /***********************************************************************/
@@ -791,7 +782,7 @@
     /*  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;
+      int dimension = extract_integer_value(symbol->upper_limit) - extract_integer_value(symbol->lower_limit) + 1;
       switch (current_mode) {
         case arrayname_im:
           current_array_name += "_";
--- a/stage4/generate_c/generate_c_base.cc	Wed May 09 22:59:10 2012 +0100
+++ b/stage4/generate_c/generate_c_base.cc	Wed May 09 23:00:10 2012 +0100
@@ -410,18 +410,12 @@
 void *visit(duration_c *symbol) {
   TRACE("duration_c");
   s4o.print("__time_to_timespec(");
-  if (NULL == symbol->neg)
-    s4o.print("1");  /* positive time value */
-  else
-    symbol->neg->accept(*this);  /* this will print '-1'   :-) */
-
-  s4o.print(", ");
-
+  
+  if (NULL == symbol->neg)    s4o.print("1");  /* positive time value */
+  else                        symbol->neg->accept(*this);  /* this will print '-1'   :-) */
+
+  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;
 }
@@ -430,73 +424,32 @@
 /* SYM_TOKEN(fixed_point_c) */
 void *visit(fixed_point_c *symbol) {return print_striped_token(symbol);}
 
-
-/* SYM_REF2(days_c, days, hours) */
-void *visit(days_c *symbol) {
-  TRACE("days_c");
-  if (NULL == symbol->hours)
-    s4o.print("0, 0, 0, 0");  /* milliseconds, seconds, minutes, hours */
-  else
-    symbol->hours->accept(*this);
-
-  s4o.print(", ");
-
-  symbol->days->accept(*this);
-  return NULL;
-}
-
-
-/* SYM_REF2(hours_c, hours, minutes) */
-void *visit(hours_c *symbol) {
-  TRACE("hours_c");
-  if (NULL == symbol->minutes)
-    s4o.print("0, 0, 0");  /* milliseconds, seconds, minutes */
-  else
-    symbol->minutes->accept(*this);
-
-  s4o.print(", ");
-
-  symbol->hours->accept(*this);
-  return NULL;
-}
-
-
-/* SYM_REF2(minutes_c, minutes, seconds) */
-void *visit(minutes_c *symbol) {
-  TRACE("minutes_c");
-  if (NULL == symbol->seconds)
-    s4o.print("0, 0");  /* milliseconds, seconds */
-  else
-    symbol->seconds->accept(*this);
-
-  s4o.print(", ");
-
-  symbol->minutes->accept(*this);
-  return NULL;
-}
-
-
-/* SYM_REF2(seconds_c, seconds, milliseconds) */
-void *visit(seconds_c *symbol) {
-  TRACE("seconds_c");
-  if (NULL == symbol->milliseconds)
-    s4o.print("0");  /* milliseconds */
-  else
-    symbol->milliseconds->accept(*this);
-
-  s4o.print(", ");
-
-  symbol->seconds->accept(*this);
-  return NULL;
-}
-
-
-/* SYM_REF2(milliseconds_c, milliseconds, unused) */
-void *visit(milliseconds_c *symbol) {
-  TRACE("milliseconds_c");
-  symbol->milliseconds->accept(*this);
-  return NULL;
-}
+/* SYM_REF5(interval_c, days, hours, minutes, seconds, milliseconds) */
+void *visit(interval_c *symbol) {
+  TRACE("interval_c");
+  /* s4o.print("0, 0, 0, 0, 0");  // milliseconds, seconds, minutes, hours, days */
+  if (NULL == symbol->milliseconds) s4o.print("0");  /* milliseconds */
+  else                              symbol->milliseconds->accept(*this);
+  s4o.print(", ");
+
+  if (NULL == symbol->seconds)      s4o.print("0");  /* seconds */
+  else                              symbol->seconds->accept(*this);
+  s4o.print(", ");
+
+  if (NULL == symbol->minutes)      s4o.print("0");  /* minutes */
+  else                              symbol->minutes->accept(*this);
+  s4o.print(", ");
+
+  if (NULL == symbol->hours)        s4o.print("0");  /* hours */
+  else                              symbol->hours->accept(*this);
+  s4o.print(", ");
+
+  if (NULL == symbol->days)         s4o.print("0");  /* days */
+  else                              symbol->days->accept(*this);
+
+  return NULL;
+}
+
 
 /************************************/
 /* B 1.2.3.2 - Time of day and Date */
--- a/stage4/generate_c/generate_c_typedecl.cc	Wed May 09 22:59:10 2012 +0100
+++ b/stage4/generate_c/generate_c_typedecl.cc	Wed May 09 23:00:10 2012 +0100
@@ -255,7 +255,7 @@
     case array_td:
       if (current_basetypedeclaration == arraysubrange_bd) {
         s4o_incl.print("[");
-        dimension = extract_integer(symbol->upper_limit) - extract_integer(symbol->lower_limit) + 1;
+        dimension = extract_integer_value(symbol->upper_limit) - extract_integer_value(symbol->lower_limit) + 1;
         print_integer_incl(dimension);
         s4o_incl.print("]");
       }
--- a/stage4/generate_c/generate_c_vardecl.cc	Wed May 09 22:59:10 2012 +0100
+++ b/stage4/generate_c/generate_c_vardecl.cc	Wed May 09 23:00:10 2012 +0100
@@ -211,7 +211,7 @@
     /*  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;
+      int dimension = extract_integer_value(symbol->upper_limit) - extract_integer_value(symbol->lower_limit) + 1;
       switch (current_mode) {
         case arraysize_am:
           array_size *= dimension;
@@ -264,7 +264,7 @@
       
       switch (current_mode) {
         case initializationvalue_am:
-          initial_element_number = extract_integer(symbol->integer);
+          initial_element_number = extract_integer_value(symbol->integer);
           if (current_initialization_count < defined_values_count) {
             int temp_element_number = 0;
             int diff = defined_values_count - current_initialization_count;
@@ -1407,7 +1407,7 @@
 /*  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;
+  long long dimension = extract_integer_value(symbol->upper_limit) - extract_integer_value(symbol->lower_limit) + 1;
   s4o.print("_");
   print_integer(dimension);
   return NULL;
--- a/stage4/generate_iec/generate_iec.cc	Wed May 09 22:59:10 2012 +0100
+++ b/stage4/generate_iec/generate_iec.cc	Wed May 09 23:00:10 2012 +0100
@@ -234,43 +234,37 @@
 
 void *visit(fixed_point_c *symbol) {return print_token(symbol);}
 
-void *visit(days_c *symbol) {
-  symbol->days->accept(*this);
-  s4o.print("d");
-  if (symbol->hours != NULL)
+/* SYM_REF5(interval_c, days, hours, minutes, seconds, milliseconds) */
+void *visit(interval_c *symbol) {
+  if (NULL != symbol->days) {
+    symbol->days->accept(*this);
+    s4o.print("d");
+  }
+
+  if (NULL != symbol->hours) {
     symbol->hours->accept(*this);
-  return NULL;
-}
-
-void *visit(hours_c *symbol) {
-  symbol->hours->accept(*this);
-  s4o.print("h");
-  if (symbol->minutes != NULL)
+    s4o.print("h");
+  }
+
+  if (NULL != symbol->minutes) {
     symbol->minutes->accept(*this);
-  return NULL;
-}
-
-void *visit(minutes_c *symbol) {
-  symbol->minutes->accept(*this);
-  s4o.print("m");
-  if (symbol->seconds != NULL)
+    s4o.print("m");
+  }
+
+  if (NULL != symbol->seconds) {
     symbol->seconds->accept(*this);
-  return NULL;
-}
-
-void *visit(seconds_c *symbol) {
-  symbol->seconds->accept(*this);
-  s4o.print("s");
-  if (symbol->milliseconds != NULL)
+    s4o.print("s");
+  }
+
+  if (NULL != symbol->milliseconds) {
     symbol->milliseconds->accept(*this);
-  return NULL;
-}
-
-void *visit(milliseconds_c *symbol) {
-  symbol->milliseconds->accept(*this);
-  s4o.print("ms");
-  return NULL;
-}
+    s4o.print("ms");
+  }
+
+  return NULL;
+}
+
+
 
 /************************************/
 /* B 1.2.3.2 - Time of day and Date */