Changes made since Mario visit at LOLITECH. Thanks again !
authoretisserant
Wed, 31 Jan 2007 16:00:18 +0100
changeset 1 5d893a68be6e
parent 0 fb772792efd1
child 2 cecf2a950ec8
Changes made since Mario visit at LOLITECH. Thanks again !
absyntax/absyntax.def
stage1_2/iec.flex
stage1_2/iec.y
stage4/generate_cc/plc.h
stage4/generate_cc/types.h
stage4/generate_iec/generate_iec.cc
--- a/absyntax/absyntax.def	Wed Jan 31 15:32:38 2007 +0100
+++ b/absyntax/absyntax.def	Wed Jan 31 16:00:18 2007 +0100
@@ -337,7 +337,7 @@
 
 /*  record_variable '.' field_selector */
 /*  WARNING: input and/or output variables of function blocks
- *           may be accessed as fields of a tructured variable!
+ *           may be accessed as fields of a structured variable!
  *           Code handling a structured_variable_c must take
  *           this into account!
  */
@@ -554,6 +554,32 @@
 /* B.1.6  Sequential function chart elements */
 /*********************************************/
 
+SYM_LIST(sequential_function_chart_c)
+
+SYM_LIST(sfc_network_c)
+
+SYM_REF2(initial_step_c, step_name, action_association_list)
+
+SYM_LIST(action_association_list_c)
+SYM_REF2(step_c, step_name, action_association_list)
+SYM_REF4(action_association_c, action_name, action_qualifier, indicator_name_list, unused)
+
+SYM_TOKEN(qualifier_c)
+SYM_TOKEN(timed_qualifier_c)
+
+SYM_LIST(indicator_name_list_c)
+
+SYM_REF2(action_qualifier_c, action_qualifier, action_time)
+
+SYM_REF6(transition_c, transition_name, integer, from_steps, to_steps, transition_condition, unused)
+
+SYM_REF2(steps_c, step_name, step_name_list)
+
+SYM_LIST(step_name_list_c)
+
+SYM_REF2(transition_condition_c, simple_instr_list, expression)
+
+SYM_REF2(action_c, action_name, function_block_body)
 
 /********************************/
 /* B 1.7 Configuration elements */
--- a/stage1_2/iec.flex	Wed Jan 31 15:32:38 2007 +0100
+++ b/stage1_2/iec.flex	Wed Jan 31 16:00:18 2007 +0100
@@ -276,10 +276,12 @@
  *                    and _not_ followed by a VAR declaration)
  *   INITIAL -> config (when a CONFIGURATION is found)
  *   decl    -> body (when the last END_VAR is found, i.e. the function body starts)
+ *   body    -> sfc (when it figures out it is parsing sfc language)
  *   body    -> st (when it figures out it is parsing st language)
  *   body    -> il (when it figures out it is parsing il language)
  *   decl    -> INITIAL (when a END_FUNCTION, END_FUNCTION_BLOCK, or END_PROGRAM is found)
  *   st      -> INITIAL (when a END_FUNCTION, END_FUNCTION_BLOCK, or END_PROGRAM is found)
+ *   sfc     -> INITIAL (when a END_FUNCTION, END_FUNCTION_BLOCK, or END_PROGRAM is found)
  *   il      -> INITIAL (when a END_FUNCTION, END_FUNCTION_BLOCK, or END_PROGRAM is found)
  *   config  -> INITIAL (when a END_CONFIGURATION is found)
  */
@@ -298,6 +300,8 @@
 /* we are parsing st code -> flex must not return the EOL tokens!   */
 %s st
 
+/* we are parsing sfc code -> flex must not return the EOL tokens!   */
+%s sfc
 
 
 
@@ -690,7 +694,7 @@
 			    yylineno = include_stack[include_stack_ptr].lineno;
 			      /* removing constness of char *. This is safe actually,
 			       * since the only real const char * that is stored on the stack is
-			       * the first one (i.e. the opne that gets stored in include_stack[0],
+			       * the first one (i.e. the one that gets stored in include_stack[0],
 			       * which is never free'd!
 			       */
 			    free((char *)current_filename);
@@ -745,7 +749,9 @@
 END_VAR{st_whitespace}				unput_text(strlen("END_VAR")); BEGIN(body); return END_VAR;
 }
 
-	/* body -> (il | st) */
+	/* body -> (il | st | sfc) */
+<body>INITIAL_STEP				unput_text(0); BEGIN(sfc);
+
 <body>{
 {qualified_identifier}{st_whitespace}":="	unput_text(0); BEGIN(st);
 {qualified_identifier}"["			unput_text(0); BEGIN(st);
@@ -772,7 +778,7 @@
 
 }	/* end of body lexical parser */
 
-	/* (decl | body | il | st) -> INITIAL */
+	/* (decl | body | il | st | sfc) -> INITIAL */
 END_FUNCTION		BEGIN(INITIAL); return END_FUNCTION;
 END_FUNCTION_BLOCK	BEGIN(INITIAL); return END_FUNCTION_BLOCK;
 END_PROGRAM		BEGIN(INITIAL); return END_PROGRAM;
@@ -787,7 +793,7 @@
 	/***************************************/
 	/* NOTE: pragmas are handled right at the beginning... */
 
-<INITIAL,config,decl,st,body>{st_whitespace_no_pragma}	/* Eat any whitespace */
+<INITIAL,config,decl,st,sfc,body>{st_whitespace_no_pragma}	/* Eat any whitespace */
 <il,body>{il_whitespace_no_pragma}		/* Eat any whitespace */
 
 
@@ -993,7 +999,8 @@
 	 * They will have to be handled when we include parsing of SFC... For now, simply
 	 * ignore them!
 	 */
-	 /*
+	 
+<sfc>{
 ACTION		return ACTION;
 END_ACTION	return END_ACTION;
 
@@ -1018,7 +1025,7 @@
 
 R		return R;
 S		return S;
-	*/
+}
 
 
 	/********************************/
--- a/stage1_2/iec.y	Wed Jan 31 15:32:38 2007 +0100
+++ b/stage1_2/iec.y	Wed Jan 31 16:00:18 2007 +0100
@@ -790,18 +790,19 @@
 /* B 1.6 Sequential Function Chart elements */
 /********************************************/
 /* TODO */
-/*
+
 %type  <list>	sequential_function_chart
-%type  <leaf>	sfc_network
+%type  <list>	sfc_network
 %type  <leaf>	initial_step
 %type  <leaf>	step
-%type  <leaf>	action_association_list
+%type  <list>	action_association_list
 %type  <leaf>	step_name
 %type  <leaf>	action_association
-/* helper symbol for action_association *
+/* helper symbol for action_association */
 %type  <list>	indicator_name_list
 %type  <leaf>	action_name
 %type  <leaf>	action_qualifier
+%type  <leaf>	qualifier
 %type  <leaf>	timed_qualifier
 %type  <leaf>	action_time
 %type  <leaf>	indicator_name
@@ -810,7 +811,8 @@
 %type  <list>	step_name_list
 %type  <leaf>	transition_condition
 %type  <leaf>	action
-*/
+%type  <leaf>	transition_name
+
 
 %token ASSIGN
 %token ACTION
@@ -1542,22 +1544,6 @@
 | JMP_operator		{$$ = il_operator_c_2_identifier_c($1);}
 | JMPC_operator		{$$ = il_operator_c_2_identifier_c($1);}
 | JMPCN_operator	{$$ = il_operator_c_2_identifier_c($1);}
-/**/
-| L		{$$ = new identifier_c(strdup("L"));}
-| D		{$$ = new identifier_c(strdup("D"));}
-| SD		{$$ = new identifier_c(strdup("SD"));}
-| DS		{$$ = new identifier_c(strdup("DS"));}
-| SL		{$$ = new identifier_c(strdup("SL"));}
-| N		{$$ = new identifier_c(strdup("N"));}
-/* NOTE: the following two clash with the R and S IL operators.
- * It will have to be handled when we include parsing of SFC...
- */
-/*
-| R		{$$ = new identifier_c(strdup("R"));}
-| S		{$$ = new identifier_c(strdup("S"));}
-*/
-| P		{$$ = new identifier_c(strdup("P"));}
-
 ;
 
 /*********************/
@@ -3566,8 +3552,8 @@
 function_block_body:
   statement_list	{$$ = $1;}
 | instruction_list	{$$ = $1;}
+| sequential_function_chart	{$$ = $1;}
 /*
-| sequential_function_chart
 | ladder_diagram
 | function_block_diagram
 | <other languages>
@@ -3642,110 +3628,145 @@
 
 
 /********************************************/
-/* B 1.6 Sequential Function Chart elements */
-/********************************************/
+/* B 1.6 Sequential Function Chart elements *
+/********************************************/////////////////////////////////////////////////////////////////////////////////////////////
 /* TODO ... */
 
-/*
 sequential_function_chart:
   sfc_network
+	{$$ = new sequential_function_chart_c(); $$->add_element($1);}
 | sequential_function_chart sfc_network
+	{$$ = $1; $$->add_element($2);}
 ;
 
 sfc_network:
   initial_step
+	{$$ = new sfc_network_c(); $$->add_element($1);}
 | sfc_network step
+	{$$ = $1; $$->add_element($2);}
 | sfc_network transition
+	{$$ = $1; $$->add_element($2);}
 | sfc_network action
+	{$$ = $1; $$->add_element($2);}
 ;
 
 initial_step:
   INITIAL_STEP step_name ':' action_association_list END_STEP
+	{$$ = new initial_step_c($2, $4);}
 ;
 
 step:
   STEP step_name ':' action_association_list END_STEP
+	{$$ = new step_c($2, $4);}
 ;
 
 /* helper symbol for:
  *  - initial_step
  *  - step
- *
+ */
 action_association_list:
-  /* empty *
+  /* empty */
+	{$$ = new action_association_list_c();}
 | action_association_list action_association ';'
-;
+	{$$ = $1; $$->add_element($2);}
+;
+
 
 step_name: identifier;
 
 action_association:
   action_name '(' action_qualifier indicator_name_list ')'
-;
-
-/* helper symbol for action_association *
+	{$$ = new action_association_c($1, $3, $4, NULL);}
+;
+
+/* helper symbol for action_association */
 indicator_name_list:
-  /* empty *
+  /* empty */
+	{$$ = new indicator_name_list_c();}
 | indicator_name_list ',' indicator_name
+	{$$ = $1; $$->add_element($3);}
 ;
 
 action_name: identifier;
 
 action_qualifier:
-  /* empty *
-| N
-| R
-| S
-| P
+  /* empty */
+	{$$ = NULL;}
+| qualifier
+	{$$ = new action_qualifier_c($1, NULL);}
 | timed_qualifier ',' action_time
+	{$$ = new action_qualifier_c($1, $3);}
+;
+
+//N_token: N 	{$$ = new N_token_c();};
+
+qualifier:
+N		{$$ = new qualifier_c(strdup("N"));}
+/* NOTE: the following two clash with the R and S IL operators.
+ * It will have to be handled when we include parsing of SFC...
+ */
+/*
+| R		{$$ = new identifier_c(strdup("R"));}
+| S		{$$ = new identifier_c(strdup("S"));}
+*/
+| P		{$$ = new qualifier_c(strdup("P"));}
 ;
 
 timed_qualifier:
-  L
-| D
-| SD
-| DS
-| SL
+L		{$$ = new timed_qualifier_c(strdup("L"));}
+| D		{$$ = new timed_qualifier_c(strdup("D"));}
+| SD		{$$ = new timed_qualifier_c(strdup("SD"));}
+| DS		{$$ = new timed_qualifier_c(strdup("DS"));}
+| SL		{$$ = new timed_qualifier_c(strdup("SL"));}
 ;
 
 action_time:
   duration
 | variable_name
+| transition_name
 ;
 
 indicator_name: variable_name;
 
 transition:
   TRANSITION FROM steps TO steps transition_condition END_TRANSITION
+	{$$ = new transition_c(NULL, NULL, $3, $5, $6, NULL);}
 | TRANSITION transition_name FROM steps TO steps transition_condition END_TRANSITION
+	{$$ = new transition_c($2, NULL, $4, $6, $7, NULL);}
 | TRANSITION '(' PRIORITY ASSIGN integer ')' FROM steps TO steps transition_condition END_TRANSITION
+	{$$ = new transition_c(NULL, $5, $8, $10, $11, NULL);}
 | TRANSITION transition_name '(' PRIORITY ASSIGN integer ')' FROM steps TO steps transition_condition END_TRANSITION
+	{$$ = new transition_c($2, $6, $9, $11, $12, NULL);}
 ;
 
 transition_name: identifier;
 
 steps:
   step_name
+	{$$ = new steps_c($1, NULL);}
 | '(' step_name_list ')'
-;
-
+	{$$ = new steps_c(NULL, $2);}
+;
 
 step_name_list:
   step_name ',' step_name
+	{$$ = new step_name_list_c(); $$->add_element($1); $$->add_element($3);}
 | step_name_list ',' step_name
-;
-
+	{$$ = $1; $$->add_element($3);}
+;
 
 transition_condition:
-  ':' simple_instruction_list
+  ':' simple_instr_list
+	{$$ = new transition_condition_c($2, NULL);} 
 | ASSIGN expression ';'
-| ':' fbd_network
-| ':' rung
+	{$$ = new transition_condition_c(NULL, $2);} 
 ;
 
 action:
   ACTION action_name ':' function_block_body END_ACTION
-;
-*/
+	{$$ = new action_c($2, $4);}
+;
+
 
 /********************************/
 /* B 1.7 Configuration elements */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stage4/generate_cc/plc.h	Wed Jan 31 16:00:18 2007 +0100
@@ -0,0 +1,85 @@
+/*
+ * (c) 2000 Jiri Baum
+ *          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.
+ */
+
+
+#ifndef __PLC_H
+#define __PLC_H
+
+#include <stdio.h>  /* required for declaration of FILE */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#include "types.h"
+#include "log/log.h"
+#include "conffile/conffile.h"
+#include "cmm/cmm.h"
+#include "gmm/gmm.h"
+#include "synch/synch.h"
+#include "period/period.h"
+#include "state/state.h"
+#include "rt/rt.h"
+
+
+#define PLC_PT_NAME_MAX_LEN CMM_NAME_MAX_LEN
+
+/*** GENERAL ***/
+int plc_init(char const *module_name, int argc, char **argv);
+int plc_done(void);
+
+/*** SYNCHING ***/
+int plc_scan_beg(void);
+int plc_scan_end(void);
+
+/* memory must be de-allocated with free() */
+const char *plc_module_name(void);
+
+/*
+ * UTIL functions;
+ */
+int plc_print_usage(FILE *output);
+/* prints the command line arguments the plc_init() function accepts */
+
+/* not to be used by general plc modules. This function is used by the
+ * plc_shutdown() function.
+ */
+int plc_init_try(char const *module_name, int argc, char **argv);
+
+
+/* plc command line options leader */
+#define CLO_LEADER "--PLC"
+
+/* plc command line options */
+#define CLO_plc_id             CLO_LEADER "plc_id="
+#define CLO_loc_local          CLO_LEADER "local"
+#define CLO_loc_isolate        CLO_LEADER "isolate"
+#define CLO_loc_shared         CLO_LEADER "shared"
+#define CLO_privmap_key        CLO_LEADER "local_map_key="
+#define CLO_log_level          CLO_LEADER "debug="
+#define CLO_log_file           CLO_LEADER "logfile="
+#define CLO_config_file        CLO_LEADER "conf="
+#define CLO_module_name        CLO_LEADER "module="
+#define CLO_force_init         CLO_LEADER "force-init"
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PLC_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stage4/generate_cc/types.h	Wed Jan 31 16:00:18 2007 +0100
@@ -0,0 +1,73 @@
+/*
+ * (c) 2000 Jiri Baum
+ *          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.
+ */
+
+
+#ifndef __PLC_TYPES_H
+#define __PLC_TYPES_H
+
+#include <limits.h>
+#include <float.h>   /* some limits related to floats are located here (?) */
+
+
+/*
+ * This will need to be conditional on the arquitecture or something.
+ * Anyone know where we can snarf the relevant magic easily?
+ */
+typedef double                 f64; /* 64-bit floating point   */
+typedef float                  f32; /* 32-bit floating point   */
+
+typedef unsigned long long int u64; /* 64-bit unsigned integer */
+typedef long long int          i64; /* 64-bit signed integer   */
+typedef unsigned int           u32; /* 32-bit unsigned integer */
+typedef int                    i32; /* 32-bit signed integer   */
+typedef unsigned short int     u16; /* 16-bit unsigned integer */
+typedef short int              i16; /* 16-bit signed integer   */
+typedef unsigned char          u8;  /*  8-bit unsigned integer */
+typedef signed char            i8;  /*  8-bit signed integer   */
+
+/* some platforms seem to be missing <float.h> with the definition of FLT_MAX */
+#ifndef FLT_MAX
+  /* this is the minimum value guaranteed by ANSI C++           */
+  /* does anybody know the minimum value guaranteed for ANSI C ? */
+#define FLT_MAX 1E+37
+#endif
+#ifndef FLT_MIN
+  /* this is the minimum value guaranteed by ANSI C++           */
+  /* does anybody know the minimum value guaranteed for ANSI C ? */
+#define FLT_MIN 1E-37
+#endif
+
+#define f32_MAX FLT_MAX
+#define f32_MIN FLT_MIN
+
+#define u32_MAX UINT_MAX
+#define u32_MIN 0
+#define i32_MAX INT_MAX
+#define i32_MIN INT_MIN
+
+#define u16_MAX USHRT_MAX
+#define u16_MIN 0
+#define i16_MAX SHRT_MAX
+#define i16_MIN SHRT_MIN
+
+#define u8_MAX UCHAR_MAX
+#define u8_MIN 0
+#define i8_MAX SCHAR_MAX
+#define i8_MIN SCHAR_MIN
+
+#endif /* __PLC_TYPES_H */
+
--- a/stage4/generate_iec/generate_iec.cc	Wed Jan 31 15:32:38 2007 +0100
+++ b/stage4/generate_iec/generate_iec.cc	Wed Jan 31 16:00:18 2007 +0100
@@ -945,7 +945,8 @@
 void *visit(var_declarations_list_c *symbol) {return print_list(symbol);}
 
 void *visit(function_var_decls_c *symbol) {
-  s4o.print(s4o.indent_spaces); s4o.print("VAR ");
+  //s4o.print(s4o.indent_spaces); 
+  s4o.print("VAR ");
   if (symbol->option != NULL)
     symbol->option->accept(*this);
   s4o.print("\n");
@@ -1012,12 +1013,180 @@
   symbol->program_type_name->accept(*this);
   s4o.print("\n");
   s4o.indent_right();
+  s4o.print(s4o.indent_spaces);
   symbol->var_declarations->accept(*this);
   s4o.print("\n");
   symbol->function_block_body->accept(*this);
   s4o.indent_left();
-  s4o.print(s4o.indent_spaces + "END_PROGRAM\n\n\n");
-  return NULL;
+  s4o.print("\n");
+  s4o.print("END_PROGRAM\n\n\n");
+  return NULL;
+}
+
+/***********************************/
+/* B 1.6 Sequential Function Chart */
+/***********************************/
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void *visit(sequential_function_chart_c *symbol) {
+  print_list(symbol, "", "\n\n", "");
+  return NULL;
+}
+
+void *visit(sfc_network_c *symbol) {
+  print_list(symbol, "", "\n\n", "");
+  return NULL;
+}
+
+void *visit(initial_step_c *symbol) {
+  s4o.print(s4o.indent_spaces);
+  s4o.print("INITIAL_STEP ");
+  symbol->step_name->accept(*this);
+  s4o.print(" :\n");
+  s4o.indent_right();
+  symbol->action_association_list->accept(*this);
+  s4o.print("\n");
+  s4o.indent_left();
+  s4o.print(s4o.indent_spaces);
+  s4o.print("END_STEP ");
+  return NULL;
+}
+
+void *visit(step_c *symbol) {
+  s4o.print(s4o.indent_spaces);
+  s4o.print("STEP ");
+  symbol->step_name->accept(*this);
+  s4o.print(" :\n");
+  s4o.indent_right();
+  symbol->action_association_list->accept(*this);
+  s4o.print("\n");
+  s4o.indent_left();
+  s4o.print(s4o.indent_spaces);
+  s4o.print("END_STEP ");
+  return NULL;
+}
+
+void *visit(action_association_list_c *symbol) {
+  print_list(symbol, "", "\n", "");
+  return NULL;
+}
+
+void *visit(action_association_c *symbol) {
+  if(symbol->action_qualifier != NULL){
+    symbol->action_name->accept(*this);
+  }
+  s4o.print(" (");
+  if(symbol->action_qualifier != NULL){
+    symbol->action_qualifier->accept(*this);
+  }
+  s4o.print(" ");
+  if(symbol->action_qualifier != NULL){
+    symbol->indicator_name_list->accept(*this);
+  }
+  s4o.print(" )");
+  return NULL;
+}
+
+void *visit(indicator_name_list_c *symbol) {
+ print_list(symbol, "", ", ", "");
+ return NULL;
+}
+
+void *visit(action_qualifier_c *symbol) {
+ symbol->action_qualifier->accept(*this);
+ symbol->action_time->accept(*this);
+ return NULL;
+}
+
+void *visit(qualifier_c *symbol) {
+ symbol->accept(*this);
+ return NULL;
+}
+
+void *visit(timed_qualifier_c *symbol) {
+ symbol->accept(*this);
+ return NULL;
+}
+
+void *visit(transition_c *symbol) {
+  s4o.print(s4o.indent_spaces);
+  s4o.print("TRANSITION ");
+  if (symbol->transition_name != NULL){
+    symbol->transition_name->accept(*this);
+    s4o.print(" ");
+  }
+  if (symbol->integer != NULL){
+    s4o.print("(PRIORITY := ");
+    symbol->integer->accept(*this);
+    s4o.print(") ");
+  }
+  s4o.print("FROM ");
+  symbol->from_steps->accept(*this);
+  s4o.print("TO ");
+  symbol->to_steps->accept(*this);
+  s4o.indent_right();
+  s4o.print(s4o.indent_spaces);
+  symbol->transition_condition->accept(*this);
+  s4o.indent_left();
+  s4o.print(s4o.indent_spaces);
+  s4o.print("END_TRANSITION");
+  return NULL;
+}
+
+void *visit(steps_c *symbol) {
+  if(symbol->step_name != NULL){
+    symbol->step_name->accept(*this);
+    s4o.print(" ");
+  }
+  if(symbol->step_name_list != NULL){
+    symbol->step_name_list->accept(*this);
+  }
+  return NULL;
+}
+
+void *visit(step_name_list_c *symbol) {
+  print_list(symbol, "(", ", ", ") ");
+  return NULL;
+}
+
+void *visit(transition_condition_c *symbol) {
+  if (symbol->simple_instr_list != NULL) {
+    s4o.print(s4o.indent_spaces);
+    s4o.print(":\n");
+    symbol->simple_instr_list->accept(*this);
+  }
+  if (symbol->expression != NULL) {
+    s4o.print("\n");
+    s4o.print(s4o.indent_spaces);
+    s4o.print(":= ");
+    symbol->expression->accept(*this);
+    s4o.print(";\n");
+  }
+  return NULL;
+}
+
+void *visit(action_c *symbol) {
+ s4o.print(s4o.indent_spaces);
+ s4o.print("ACTION ");
+ symbol->action_name->accept(*this);
+ s4o.print(": ");
+ s4o.indent_right();
+ s4o.print(s4o.indent_spaces);
+ symbol->function_block_body->accept(*this);
+ s4o.print("\n ");
+ s4o.indent_left();
+ s4o.print(s4o.indent_spaces);
+ s4o.print("END_ACTION");
+ return NULL;
 }