stage4/generate_iec/generate_iec.cc
changeset 0 fb772792efd1
child 1 5d893a68be6e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stage4/generate_iec/generate_iec.cc	Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,1692 @@
+/*
+ * (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)
+ *
+ */
+
+
+/*
+ * Code to be included into the code generated by the 4th stage.
+ *
+ * This is part of the 4th stage that generates
+ * a ST and IL source program equivalent to the IL and ST
+ * code.
+ * This is expected to be used mainly in debuging the syntax
+ * and lexical parser, and as a starting point for other
+ * 4th stages.
+ */
+
+
+
+
+
+
+// #include <stdio.h>  /* required for NULL */
+#include <string>
+#include <iostream>
+#include "generate_iec.hh"
+
+#include "../stage4.hh"
+
+
+
+
+
+
+//class generate_iec_c: public iterator_visitor_c {
+class generate_iec_c: public visitor_c {
+  private:
+    stage4out_c &s4o;
+
+
+  public:
+    generate_iec_c(stage4out_c *s4o_ptr): s4o(*s4o_ptr) {}
+    ~generate_iec_c(void) {}
+
+
+  private:
+
+void *print_token(token_c *token) {
+  return s4o.print(token->value);
+}
+
+void *print_literal(symbol_c *type, symbol_c *value) {
+  type->accept(*this);
+  s4o.print("#");
+  value->accept(*this);
+  return NULL;
+}
+
+void *print_list(list_c *list,
+			       std::string pre_elem_str = "",
+			       std::string inter_elem_str = "",
+			       std::string post_elem_str = "") {
+  if (list->n > 0) {
+    s4o.print(pre_elem_str);
+    list->elements[0]->accept(*this);
+  }
+
+  for(int i = 1; i < list->n; i++) {
+    s4o.print(inter_elem_str);
+    list->elements[i]->accept(*this);
+  }
+
+  if (list->n > 0)
+    s4o.print(post_elem_str);
+
+  return NULL;
+}
+
+
+void *print_binary_expression(symbol_c *l_exp,
+			      symbol_c *r_exp,
+			      const char *operation) {
+  s4o.print("(");
+  l_exp->accept(*this);
+  s4o.print(operation);
+  r_exp->accept(*this);
+  s4o.print(")");
+  return NULL;
+}
+
+void *print_unary_expression(symbol_c *exp,
+			     const char *operation) {
+  s4o.print(operation);
+  exp->accept(*this);
+  return NULL;
+}
+
+
+
+
+
+  public:
+/***************************/
+/* 2.1.6 Pragmas */
+/***************************/
+void *visit(pragma_c *symbol) {return print_token(symbol);}
+
+
+/***************************/
+/* B 0 - Programming Model */
+/***************************/
+void *visit(library_c *symbol) {return print_list(symbol);}
+
+/*******************************************/
+/* B 1.1 - Letters, digits and identifiers */
+/*******************************************/
+void *visit(identifier_c *symbol) {return print_token(symbol);}
+
+/*********************/
+/* B 1.2 - Constants */
+/*********************/
+
+/******************************/
+/* B 1.2.1 - Numeric Literals */
+/******************************/
+void *visit(real_c *symbol) {return print_token(symbol);}
+void *visit(integer_c *symbol) {return print_token(symbol);}
+void *visit(binary_integer_c *symbol) {return print_token(symbol);}
+void *visit(octal_integer_c *symbol) {return print_token(symbol);}
+void *visit(hex_integer_c *symbol) {return print_token(symbol);}
+
+void *visit(numeric_literal_c *symbol) {return print_literal(symbol->type, symbol->value);}
+void *visit(integer_literal_c *symbol) {return print_literal(symbol->type, symbol->value);}
+void *visit(real_literal_c *symbol) {return print_literal(symbol->type, symbol->value);}
+void *visit(bit_string_literal_c *symbol) {return print_literal(symbol->type, symbol->value);}
+void *visit(boolean_literal_c *symbol) {return print_literal(symbol->type, symbol->value);}
+
+/* helper class for boolean_literal_c */
+void *visit(boolean_true_c *symbol) {s4o.print(/*"TRUE"*/"1"); return NULL;}
+void *visit(boolean_false_c *symbol) {s4o.print(/*"FALSE"*/"0"); return NULL;}
+
+/*******************************/
+/* B.1.2.2   Character Strings */
+/*******************************/
+void *visit(double_byte_character_string_c *symbol) {return print_token(symbol);}
+void *visit(single_byte_character_string_c *symbol) {return print_token(symbol);}
+
+
+/***************************/
+/* B 1.2.3 - Time Literals */
+/***************************/
+
+/************************/
+/* B 1.2.3.1 - Duration */
+/************************/
+void *visit(neg_time_c *symbol) {s4o.print("-"); return NULL;}
+
+void *visit(duration_c *symbol) {
+  s4o.print("TIME#");
+  if (symbol->neg != NULL)
+    symbol->neg->accept(*this);
+  symbol->interval->accept(*this);
+  return NULL;
+}
+
+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)
+    symbol->hours->accept(*this);
+  return NULL;
+}
+
+void *visit(hours_c *symbol) {
+  symbol->hours->accept(*this);
+  s4o.print("h");
+  if (symbol->minutes != NULL)
+    symbol->minutes->accept(*this);
+  return NULL;
+}
+
+void *visit(minutes_c *symbol) {
+  symbol->minutes->accept(*this);
+  s4o.print("m");
+  if (symbol->seconds != NULL)
+    symbol->seconds->accept(*this);
+  return NULL;
+}
+
+void *visit(seconds_c *symbol) {
+  symbol->seconds->accept(*this);
+  s4o.print("s");
+  if (symbol->milliseconds != NULL)
+    symbol->milliseconds->accept(*this);
+  return NULL;
+}
+
+void *visit(milliseconds_c *symbol) {
+  symbol->milliseconds->accept(*this);
+  s4o.print("ms");
+  return NULL;
+}
+
+/************************************/
+/* B 1.2.3.2 - Time of day and Date */
+/************************************/
+
+void *visit(time_of_day_c *symbol) {
+  s4o.print("TIME_OF_DAY#");
+  symbol->daytime->accept(*this);
+  return NULL;
+}
+
+void *visit(daytime_c *symbol) {
+  symbol->day_hour->accept(*this);
+  s4o.print(":");
+  symbol->day_minute->accept(*this);
+  s4o.print(":");
+  symbol->day_second->accept(*this);
+  return NULL;
+}
+
+
+void *visit(date_c *symbol) {
+  s4o.print("DATE#");
+  symbol->date_literal->accept(*this);
+  return NULL;
+}
+
+void *visit(date_literal_c *symbol) {
+  symbol->year->accept(*this);
+  s4o.print("-");
+  symbol->month->accept(*this);
+  s4o.print("-");
+  symbol->day->accept(*this);
+  return NULL;
+}
+
+void *visit(date_and_time_c *symbol) {
+  s4o.print("DATE_AND_TIME#");
+  symbol->date_literal->accept(*this);
+  s4o.print("-");
+  symbol->daytime->accept(*this);
+  return NULL;
+}
+
+
+
+/***********************************/
+/* B 1.3.1 - Elementary Data Types */
+/***********************************/
+void *visit(time_type_name_c *symbol) {s4o.print("TIME"); return NULL;}
+void *visit(bool_type_name_c *symbol) {s4o.print("BOOL"); return NULL;}
+void *visit(sint_type_name_c *symbol) {s4o.print("SINT"); return NULL;}
+void *visit(int_type_name_c *symbol) {s4o.print("INT"); return NULL;}
+void *visit(dint_type_name_c *symbol) {s4o.print("DINT"); return NULL;}
+void *visit(lint_type_name_c *symbol) {s4o.print("LINT"); return NULL;}
+void *visit(usint_type_name_c *symbol) {s4o.print("USINT"); return NULL;}
+void *visit(uint_type_name_c *symbol) {s4o.print("UINT"); return NULL;}
+void *visit(udint_type_name_c *symbol) {s4o.print("UDINT"); return NULL;}
+void *visit(ulint_type_name_c *symbol) {s4o.print("ULINT"); return NULL;}
+void *visit(real_type_name_c *symbol) {s4o.print("REAL"); return NULL;}
+void *visit(lreal_type_name_c *symbol) {s4o.print("LREAL"); return NULL;}
+void *visit(date_type_name_c *symbol) {s4o.print("DATE"); return NULL;}
+void *visit(tod_type_name_c *symbol) {s4o.print("TOD"); return NULL;}
+void *visit(dt_type_name_c *symbol) {s4o.print("DT"); return NULL;}
+void *visit(byte_type_name_c *symbol) {s4o.print("BYTE"); return NULL;}
+void *visit(word_type_name_c *symbol) {s4o.print("WORD"); return NULL;}
+void *visit(lword_type_name_c *symbol) {s4o.print("LWORD"); return NULL;}
+void *visit(dword_type_name_c *symbol) {s4o.print("DWORD"); return NULL;}
+void *visit(string_type_name_c *symbol) {s4o.print("STRING"); return NULL;}
+void *visit(wstring_type_name_c *symbol) {s4o.print("WSTRING"); return NULL;}
+
+
+
+/********************************/
+/* B 1.3.3 - Derived data types */
+/********************************/
+/*  TYPE type_declaration_list END_TYPE */
+void *visit(data_type_declaration_c *symbol) {
+  s4o.print("TYPE\n");
+  s4o.indent_right();
+  symbol->type_declaration_list->accept(*this);
+  s4o.indent_left();
+  s4o.print("END_TYPE\n\n\n");
+  return NULL;
+}
+
+
+/* helper symbol for data_type_declaration */
+/*| type_declaration_list type_declaration ';' */
+void *visit(type_declaration_list_c *symbol) {
+  return print_list(symbol, s4o.indent_spaces, ";\n" + s4o.indent_spaces, ";\n");
+}
+
+
+/*  simple_type_name ':' simple_spec_init */
+void *visit(simple_type_declaration_c *symbol) {
+  symbol->simple_type_name->accept(*this);
+  s4o.print(" : ");
+  symbol->simple_spec_init->accept(*this);
+  return NULL;
+}
+
+/* simple_specification ASSIGN constant */
+void *visit(simple_spec_init_c *symbol) {
+  symbol->simple_specification->accept(*this);
+  if (symbol->constant != NULL) {
+    s4o.print(" := ");
+    symbol->constant->accept(*this);
+  }
+  return NULL;
+}
+
+/*  subrange_type_name ':' subrange_spec_init */
+void *visit(subrange_type_declaration_c *symbol) {
+  symbol->subrange_type_name->accept(*this);
+  s4o.print(" : ");
+  symbol->subrange_spec_init->accept(*this);
+  return NULL;
+}
+
+/* subrange_specification ASSIGN signed_integer */
+void *visit(subrange_spec_init_c *symbol) {
+  symbol->subrange_specification->accept(*this);
+  if (symbol->signed_integer != NULL) {
+    s4o.print(" := ");
+    symbol->signed_integer->accept(*this);
+  }
+  return NULL;
+}
+
+/*  integer_type_name '(' subrange')' */
+void *visit(subrange_specification_c *symbol) {
+  symbol->integer_type_name->accept(*this);
+  s4o.print("(");
+  symbol->subrange->accept(*this);
+  s4o.print(")");
+  return NULL;
+}
+
+/*  signed_integer DOTDOT signed_integer */
+void *visit(subrange_c *symbol) {
+  symbol->lower_limit->accept(*this);
+  s4o.print(" .. ");
+  symbol->upper_limit->accept(*this);
+  return NULL;
+}
+
+/*  enumerated_type_name ':' enumerated_spec_init */
+void *visit(enumerated_type_declaration_c *symbol) {
+  symbol->enumerated_type_name->accept(*this);
+  s4o.print(" : ");
+  symbol->enumerated_spec_init->accept(*this);
+  return NULL;
+}
+
+/* enumerated_specification ASSIGN enumerated_value */
+void *visit(enumerated_spec_init_c *symbol) {
+  symbol->enumerated_specification->accept(*this);
+  if (symbol->enumerated_value != NULL) {
+    s4o.print(" := ");
+    symbol->enumerated_value->accept(*this);
+  }
+  return NULL;
+}
+
+/* helper symbol for enumerated_specification->enumerated_spec_init */
+/* enumerated_value_list ',' enumerated_value */
+void *visit(enumerated_value_list_c *symbol) {print_list(symbol, "(", ", ", ")"); return NULL;}
+
+/* enumerated_type_name '#' identifier */
+void *visit(enumerated_value_c *symbol) {
+  symbol->type->accept(*this);
+  s4o.print("#");
+  symbol->value->accept(*this);
+  return NULL;
+}
+
+/*  identifier ':' array_spec_init */
+void *visit(array_type_declaration_c *symbol) {
+  symbol->identifier->accept(*this);
+  s4o.print(" : ");
+  symbol->array_spec_init->accept(*this);
+  return NULL;
+}
+
+/* array_specification [ASSIGN array_initialization} */
+/* array_initialization may be NULL ! */
+void *visit(array_spec_init_c *symbol) {
+  symbol->array_specification->accept(*this);
+  if (symbol->array_initialization != NULL) {
+    s4o.print(" := ");
+    symbol->array_initialization->accept(*this);
+  }
+  return NULL;
+}
+
+/* ARRAY '[' array_subrange_list ']' OF non_generic_type_name */
+void *visit(array_specification_c *symbol) {
+  s4o.print("ARRAY [");
+  symbol->array_subrange_list->accept(*this);
+  s4o.print("] OF ");
+  symbol->non_generic_type_name->accept(*this);
+  return NULL;
+}
+
+/* helper symbol for array_specification */
+/* array_subrange_list ',' subrange */
+void *visit(array_subrange_list_c *symbol) {print_list(symbol, "", ", "); return NULL;}
+
+/* helper symbol for array_initialization */
+/* array_initial_elements_list ',' array_initial_elements */
+void *visit(array_initial_elements_list_c *symbol) {print_list(symbol, "[", ", ", "]"); return NULL;}
+
+/* integer '(' [array_initial_element] ')' */
+/* array_initial_element may be NULL ! */
+void *visit(array_initial_elements_c *symbol) {
+  symbol->integer->accept(*this);
+  s4o.print("(");
+  if (symbol->array_initial_element != NULL)
+    symbol->array_initial_element->accept(*this);
+  s4o.print(")");
+  return NULL;
+}
+
+/*  structure_type_name ':' structure_specification */
+void *visit(structure_type_declaration_c *symbol) {
+  symbol->structure_type_name->accept(*this);
+  s4o.print(" : ");
+  symbol->structure_specification->accept(*this);
+  return NULL;
+}
+
+/* structure_type_name ASSIGN structure_initialization */
+/* structure_initialization may be NULL ! */
+void *visit(initialized_structure_c *symbol) {
+  symbol->structure_type_name->accept(*this);
+  if (symbol->structure_initialization != NULL) {
+    s4o.print(" := ");
+    symbol->structure_initialization->accept(*this);
+  }
+  return NULL;
+}
+
+/* helper symbol for structure_declaration */
+/* structure_declaration:  STRUCT structure_element_declaration_list END_STRUCT */
+/* structure_element_declaration_list structure_element_declaration ';' */
+void *visit(structure_element_declaration_list_c *symbol) {
+  s4o.print("STRUCT\n");
+  s4o.indent_right();
+  print_list(symbol, s4o.indent_spaces, ";\n" + s4o.indent_spaces, ";\n" + s4o.indent_spaces);
+  s4o.print("END_STRUCT");
+  s4o.indent_left();
+  return NULL;
+}
+
+/*  structure_element_name ':' *_spec_init */
+void *visit(structure_element_declaration_c *symbol) {
+  symbol->structure_element_name->accept(*this);
+  s4o.print(" : ");
+  symbol->spec_init->accept(*this);
+  return NULL;
+}
+
+/* helper symbol for structure_initialization */
+/* structure_initialization: '(' structure_element_initialization_list ')' */
+/* structure_element_initialization_list ',' structure_element_initialization */
+void *visit(structure_element_initialization_list_c *symbol) {print_list(symbol, "(", ", ", ")"); return NULL;}
+
+/*  structure_element_name ASSIGN value */
+void *visit(structure_element_initialization_c *symbol) {
+  symbol->structure_element_name->accept(*this);
+  s4o.print(" := ");
+  symbol->value->accept(*this);
+  return NULL;
+}
+
+/*  string_type_name ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init */
+void *visit(string_type_declaration_c *symbol) {
+  symbol->string_type_name->accept(*this);
+  s4o.print(" : ");
+  symbol->elementary_string_type_name->accept(*this);
+  symbol->string_type_declaration_size->accept(*this);
+  if (symbol->string_type_declaration_init != NULL)
+    symbol->string_type_declaration_init->accept(*this);
+  return NULL;
+}
+
+
+
+
+
+/*********************/
+/* B 1.4 - Variables */
+/*********************/
+void *visit(symbolic_variable_c *symbol) {
+  symbol->var_name->accept(*this);
+  return NULL;
+}
+
+/********************************************/
+/* B.1.4.1   Directly Represented Variables */
+/********************************************/
+void *visit(direct_variable_c *symbol) {return print_token(symbol);}
+
+
+/*************************************/
+/* B.1.4.2   Multi-element Variables */
+/*************************************/
+/*  subscripted_variable '[' subscript_list ']' */
+void *visit(array_variable_c *symbol) {
+  symbol->subscripted_variable->accept(*this);
+  s4o.print("[");
+  symbol->subscript_list->accept(*this);
+  s4o.print("]");
+  return NULL;
+}
+
+
+/* subscript_list ',' subscript */
+void *visit(subscript_list_c *symbol) {return print_list(symbol, "", ", ");}
+
+/*  record_variable '.' field_selector */
+void *visit(structured_variable_c *symbol) {
+  symbol->record_variable->accept(*this);
+  s4o.print(".");
+  symbol->field_selector->accept(*this);
+  return NULL;
+}
+
+
+/******************************************/
+/* B 1.4.3 - Declaration & Initialisation */
+/******************************************/
+void *visit(constant_option_c *symbol) {s4o.print("CONSTANT"); return NULL;}
+void *visit(retain_option_c *symbol) {s4o.print("RETAIN"); return NULL;}
+void *visit(non_retain_option_c *symbol) {s4o.print("NON_RETAIN"); return NULL;}
+
+/* VAR_INPUT [RETAIN | NON_RETAIN] input_declaration_list END_VAR */
+/* option -> the RETAIN/NON_RETAIN/<NULL> directive... */
+void *visit(input_declarations_c *symbol) {
+  s4o.print(s4o.indent_spaces); s4o.print("VAR_INPUT ");
+  if (symbol->option != NULL)
+    symbol->option->accept(*this);
+  s4o.print("\n");
+  s4o.indent_right();
+  symbol->input_declaration_list->accept(*this);
+  s4o.indent_left();
+  s4o.print(s4o.indent_spaces); s4o.print("END_VAR\n");
+  return NULL;
+}
+
+/* helper symbol for input_declarations */
+/*| input_declaration_list input_declaration ';' */
+void *visit(input_declaration_list_c *symbol) {
+  return print_list(symbol, s4o.indent_spaces, ";\n" + s4o.indent_spaces, ";\n");
+}
+
+/* edge -> The F_EDGE or R_EDGE directive */
+void *visit(edge_declaration_c *symbol) {
+  symbol->var1_list->accept(*this);
+  s4o.print(" : BOOL ");
+  symbol->edge->accept(*this);
+  return NULL;
+}
+
+
+void *visit(raising_edge_option_c *symbol) {
+  s4o.print("R_EDGE");
+  return NULL;
+}
+
+void *visit(falling_edge_option_c *symbol) {
+  s4o.print("F_EDGE");
+  return NULL;
+}
+
+
+/* var1_list is one of the following...
+ *    simple_spec_init_c *
+ *    subrange_spec_init_c *
+ *    enumerated_spec_init_c *
+ */
+void *visit(var1_init_decl_c *symbol) {
+  symbol->var1_list->accept(*this);
+  s4o.print(" : ");
+  symbol->spec_init->accept(*this);
+  return NULL;
+}
+
+
+void *visit(var1_list_c *symbol) {return print_list(symbol, "", ", ");}
+
+
+/* var1_list ':' array_spec_init */
+void *visit(array_var_init_decl_c *symbol) {
+  symbol->var1_list->accept(*this);
+  s4o.print(" : ");
+  symbol->array_spec_init->accept(*this);
+  return NULL;
+}
+
+
+/*  var1_list ':' initialized_structure */
+void *visit(structured_var_init_decl_c *symbol) {
+  symbol->var1_list->accept(*this);
+  s4o.print(" : ");
+  symbol->initialized_structure->accept(*this);
+  return NULL;
+}
+
+/* name_list ':' function_block_type_name ASSIGN structure_initialization */
+/* structure_initialization -> may be NULL ! */
+void *visit(fb_name_decl_c *symbol) {
+  symbol->fb_name_list->accept(*this);
+  s4o.print(" : ");
+  symbol->function_block_type_name->accept(*this);
+  if (symbol->structure_initialization != NULL) {
+    s4o.print(" := ");
+    symbol->structure_initialization->accept(*this);
+  }
+  return NULL;
+}
+
+/* name_list ',' fb_name */
+void *visit(fb_name_list_c *symbol) {return print_list(symbol, "", ", ");}
+
+/* VAR_OUTPUT [RETAIN | NON_RETAIN] var_init_decl_list END_VAR */
+/* option -> may be NULL ! */
+void *visit(output_declarations_c *symbol) {
+  s4o.print(s4o.indent_spaces); s4o.print("VAR_OUTPUT ");
+  if (symbol->option != NULL)
+    symbol->option->accept(*this);
+  s4o.print("\n");
+  s4o.indent_right();
+  symbol->var_init_decl_list->accept(*this);
+  s4o.indent_left();
+  s4o.print(s4o.indent_spaces); s4o.print("END_VAR\n");
+  return NULL;
+}
+
+/*  VAR_IN_OUT  END_VAR */
+void *visit(input_output_declarations_c *symbol) {
+  s4o.print(s4o.indent_spaces); s4o.print("VAR_IN_OUT ");
+  s4o.print("\n");
+  s4o.indent_right();
+  symbol->var_declaration_list->accept(*this);
+  s4o.indent_left();
+  s4o.print(s4o.indent_spaces); s4o.print("END_VAR\n");
+  return NULL;
+}
+
+/* helper symbol for input_output_declarations */
+/* var_declaration_list var_declaration ';' */
+void *visit(var_declaration_list_c *symbol) {
+  return print_list(symbol, s4o.indent_spaces, ";\n" + s4o.indent_spaces, ";\n");
+}
+
+/*  var1_list ':' array_specification */
+void *visit(array_var_declaration_c *symbol) {
+  symbol->var1_list->accept(*this);
+  s4o.print(" : ");
+  symbol->array_specification->accept(*this);
+  return NULL;
+}
+
+/*  var1_list ':' structure_type_name */
+void *visit(structured_var_declaration_c *symbol) {
+  symbol->var1_list->accept(*this);
+  s4o.print(" : ");
+  symbol->structure_type_name->accept(*this);
+  return NULL;
+}
+
+/* VAR [CONSTANT] var_init_decl_list END_VAR */
+/* option -> may be NULL ! */
+void *visit(var_declarations_c *symbol) {
+  s4o.print(s4o.indent_spaces); s4o.print("VAR ");
+  if (symbol->option != NULL)
+    symbol->option->accept(*this);
+  s4o.print("\n");
+  s4o.indent_right();
+  symbol->var_init_decl_list->accept(*this);
+  s4o.indent_left();
+  s4o.print(s4o.indent_spaces); s4o.print("END_VAR\n");
+  return NULL;
+}
+
+/*  VAR RETAIN var_init_decl_list END_VAR */
+void *visit(retentive_var_declarations_c *symbol) {
+  s4o.print(s4o.indent_spaces); s4o.print("VAR RETAIN ");
+  s4o.print("\n");
+  s4o.indent_right();
+  symbol->var_init_decl_list->accept(*this);
+  s4o.indent_left();
+  s4o.print(s4o.indent_spaces); s4o.print("END_VAR\n");
+  return NULL;
+}
+
+/*  VAR [CONSTANT|RETAIN|NON_RETAIN] located_var_decl_list END_VAR */
+/* option -> may be NULL ! */
+void *visit(located_var_declarations_c *symbol) {
+  s4o.print(s4o.indent_spaces); s4o.print("VAR ");
+  if (symbol->option != NULL)
+    symbol->option->accept(*this);
+  s4o.print("\n");
+  s4o.indent_right();
+  symbol->located_var_decl_list->accept(*this);
+  s4o.indent_left();
+  s4o.print(s4o.indent_spaces); s4o.print("END_VAR\n");
+  return NULL;
+}
+
+/* helper symbol for located_var_declarations */
+/* located_var_decl_list located_var_decl ';' */
+void *visit(located_var_decl_list_c *symbol) {
+  return print_list(symbol, s4o.indent_spaces, ";\n" + s4o.indent_spaces, ";\n");
+}
+
+/*  [variable_name] location ':' located_var_spec_init */
+/* variable_name -> may be NULL ! */
+void *visit(located_var_decl_c *symbol) {
+  if (symbol->variable_name != NULL) {
+    symbol->variable_name->accept(*this);
+    s4o.print(" ");
+  }
+  symbol->location->accept(*this);
+  s4o.print(" : ");
+  symbol->located_var_spec_init->accept(*this);
+  return NULL;
+}
+
+
+/*| VAR_EXTERNAL [CONSTANT] external_declaration_list END_VAR */
+/* option -> may be NULL ! */
+void *visit(external_var_declarations_c *symbol) {
+  s4o.print(s4o.indent_spaces); s4o.print("VAR_EXTERNAL ");
+  if (symbol->option != NULL)
+    symbol->option->accept(*this);
+  s4o.print("\n");
+  s4o.indent_right();
+  symbol->external_declaration_list->accept(*this);
+  s4o.indent_left();
+  s4o.print(s4o.indent_spaces); s4o.print("END_VAR\n");
+  return NULL;
+}
+
+/* helper symbol for external_var_declarations */
+/*| external_declaration_list external_declaration';' */
+void *visit(external_declaration_list_c *symbol) {
+  return print_list(symbol, s4o.indent_spaces, ";\n" + s4o.indent_spaces, ";\n");
+}
+
+/*  global_var_name ':' (simple_specification|subrange_specification|enumerated_specification|array_specification|prev_declared_structure_type_name|function_block_type_name) */
+void *visit(external_declaration_c *symbol) {
+  symbol->global_var_name->accept(*this);
+  s4o.print(" : ");
+  symbol->specification->accept(*this);
+  return NULL;
+}
+
+/*| VAR_GLOBAL [CONSTANT|RETAIN] global_var_decl_list END_VAR */
+/* option -> may be NULL ! */
+void *visit(global_var_declarations_c *symbol) {
+  s4o.print(s4o.indent_spaces); s4o.print("VAR_GLOBAL ");
+  if (symbol->option != NULL)
+    symbol->option->accept(*this);
+  s4o.print("\n");
+  s4o.indent_right();
+  symbol->global_var_decl_list->accept(*this);
+  s4o.indent_left();
+  s4o.print(s4o.indent_spaces); s4o.print("END_VAR\n");
+  return NULL;
+}
+
+/* helper symbol for global_var_declarations */
+/*| global_var_decl_list global_var_decl ';' */
+void *visit(global_var_decl_list_c *symbol) {
+  return print_list(symbol, s4o.indent_spaces, ";\n" + s4o.indent_spaces, ";\n");
+}
+
+/*| global_var_spec ':' [located_var_spec_init|function_block_type_name] */
+/* type_specification ->may be NULL ! */
+void *visit(global_var_decl_c *symbol) {
+  symbol->global_var_spec->accept(*this);
+  s4o.print(" : ");
+  if (symbol->type_specification != NULL)
+    symbol->type_specification->accept(*this);
+  return NULL;
+}
+
+/*| global_var_name location */
+void *visit(global_var_spec_c *symbol) {
+  symbol->global_var_name->accept(*this);
+  s4o.print(" ");
+  symbol->location->accept(*this);
+  return NULL;
+}
+
+/*  AT direct_variable */
+void *visit(location_c *symbol) {
+  s4o.print("AT ");
+  symbol->direct_variable->accept(*this);
+  return NULL;
+}
+
+/*| global_var_list ',' global_var_name */
+void *visit(global_var_list_c *symbol) {return print_list(symbol, "", ", ");}
+
+/*  var1_list ':' single_byte_string_spec */
+void *visit(single_byte_string_var_declaration_c *symbol) {
+  symbol->var1_list->accept(*this);
+  s4o.print(" : ");
+  symbol->single_byte_string_spec->accept(*this);
+  return NULL;
+}
+
+/*  STRING ['[' integer ']'] [ASSIGN single_byte_character_string] */
+/* integer ->may be NULL ! */
+/* single_byte_character_string ->may be NULL ! */
+void *visit(single_byte_string_spec_c *symbol) {
+  s4o.print("STRING [");
+  if (symbol->integer != NULL)
+    symbol->integer->accept(*this);
+  s4o.print("]");
+  if (symbol->single_byte_character_string != NULL) {
+    s4o.print(" := ");
+    symbol->single_byte_character_string->accept(*this);
+  }
+  return NULL;
+}
+
+/*  var1_list ':' double_byte_string_spec */
+void *visit(double_byte_string_var_declaration_c *symbol) {
+  symbol->var1_list->accept(*this);
+  s4o.print(" : ");
+  symbol->double_byte_string_spec->accept(*this);
+  return NULL;
+}
+
+/*  WSTRING ['[' integer ']'] [ASSIGN double_byte_character_string] */
+/* integer ->may be NULL ! */
+/* double_byte_character_string ->may be NULL ! */
+void *visit(double_byte_string_spec_c *symbol) {
+  s4o.print("WSTRING [");
+  if (symbol->integer != NULL)
+    symbol->integer->accept(*this);
+  s4o.print("]");
+  if (symbol->double_byte_character_string != NULL) {
+    s4o.print(" := ");
+    symbol->double_byte_character_string->accept(*this);
+  }
+  return NULL;
+}
+
+/*| VAR [RETAIN|NON_RETAIN] incompl_located_var_decl_list END_VAR */
+/* option ->may be NULL ! */
+void *visit(incompl_located_var_declarations_c *symbol) {
+  s4o.print(s4o.indent_spaces); s4o.print("VAR ");
+  if (symbol->option != NULL)
+    symbol->option->accept(*this);
+  s4o.print("\n");
+  s4o.indent_right();
+  symbol->incompl_located_var_decl_list->accept(*this);
+  s4o.indent_left();
+  s4o.print(s4o.indent_spaces); s4o.print("END_VAR\n");
+  return NULL;
+}
+
+/* helper symbol for incompl_located_var_declarations */
+/*| incompl_located_var_decl_list incompl_located_var_decl ';' */
+void *visit(incompl_located_var_decl_list_c *symbol) {
+  return print_list(symbol, s4o.indent_spaces, ";\n" + s4o.indent_spaces, ";\n");
+}
+
+/*  variable_name incompl_location ':' var_spec */
+void *visit(incompl_located_var_decl_c *symbol) {
+  symbol->variable_name->accept(*this);
+  s4o.print(" ");
+  symbol->incompl_location->accept(*this);
+  s4o.print(" : ");
+  symbol->var_spec->accept(*this);
+  return NULL;
+}
+
+
+/*  AT incompl_location_token */
+void *visit(incompl_location_c *symbol) {
+  s4o.print(" AT ");
+  return print_token(symbol);;
+}
+
+
+/* intermediate helper symbol for:
+ *  - non_retentive_var_decls
+ *  - output_declarations
+ */
+/* | var_init_decl_list var_init_decl ';' */
+void *visit(var_init_decl_list_c *symbol) {
+  return print_list(symbol, s4o.indent_spaces, ";\n" + s4o.indent_spaces, ";\n");
+}
+
+
+/***********************/
+/* B 1.5.1 - Functions */
+/***********************/
+void *visit(function_declaration_c *symbol) {
+  s4o.print("FUNCTION ");
+  symbol->derived_function_name->accept(*this);
+  s4o.print(" : ");
+  symbol->type_name->accept(*this);
+  s4o.print("\n");
+  s4o.indent_right();
+  symbol->var_declarations_list->accept(*this);
+  s4o.print("\n");
+  symbol->function_body->accept(*this);
+  s4o.indent_left();
+  s4o.print(s4o.indent_spaces + "END_FUNCTION\n\n\n");
+  return NULL;
+}
+
+/* intermediate helper symbol for function_declaration */
+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 ");
+  if (symbol->option != NULL)
+    symbol->option->accept(*this);
+  s4o.print("\n");
+  s4o.indent_right();
+  symbol->decl_list->accept(*this);
+  s4o.indent_left();
+  s4o.print(s4o.indent_spaces); s4o.print("END_VAR\n");
+  return NULL;
+}
+
+/* intermediate helper symbol for function_var_decls */
+void *visit(var2_init_decl_list_c *symbol) {
+  print_list(symbol, s4o.indent_spaces, ";\n" + s4o.indent_spaces, ";\n");
+  return NULL;
+}
+
+/*****************************/
+/* B 1.5.2 - Function Blocks */
+/*****************************/
+/*  FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */
+void *visit(function_block_declaration_c *symbol) {
+  s4o.print("FUNCTION_BLOCK ");
+  symbol->fblock_name->accept(*this);
+  s4o.print("\n");
+  s4o.indent_right();
+  symbol->var_declarations->accept(*this);
+  s4o.print("\n");
+  symbol->fblock_body->accept(*this);
+  s4o.indent_left();
+  s4o.print(s4o.indent_spaces + "END_FUNCTION_BLOCK\n\n\n");
+  return NULL;
+}
+
+/*  VAR_TEMP temp_var_decl_list END_VAR */
+void *visit(temp_var_decls_c *symbol) {
+  s4o.print("VAR_TEMP\n");
+  s4o.indent_right();
+  symbol->var_decl_list->accept(*this);
+  s4o.indent_left();
+  s4o.print("END_VAR\n");
+  return NULL;
+}
+
+/* intermediate helper symbol for temp_var_decls */
+void *visit(temp_var_decls_list_c *symbol) {return print_list(symbol);}
+
+/*  VAR NON_RETAIN var_init_decl_list END_VAR */
+void *visit(non_retentive_var_decls_c *symbol) {
+  s4o.print("VAR NON_RETAIN\n");
+  s4o.indent_right();
+  symbol->var_decl_list->accept(*this);
+  s4o.indent_left();
+  s4o.print("END_VAR\n");
+  return NULL;
+}
+
+
+/**********************/
+/* B 1.5.3 - Programs */
+/**********************/
+/*  PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM */
+void *visit(program_declaration_c *symbol) {
+  s4o.print("PROGRAM ");
+  symbol->program_type_name->accept(*this);
+  s4o.print("\n");
+  s4o.indent_right();
+  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;
+}
+
+
+
+/********************************/
+/* B 1.7 Configuration elements */
+/********************************/
+/*
+CONFIGURATION configuration_name
+   optional_global_var_declarations
+   (resource_declaration_list | single_resource_declaration)
+   optional_access_declarations
+   optional_instance_specific_initializations
+END_CONFIGURATION
+*/
+void *visit(configuration_declaration_c *symbol) {
+  s4o.print("CONFIGURATION ");
+  symbol->configuration_name->accept(*this);
+  s4o.print("\n");
+  s4o.indent_right();
+  if (symbol->global_var_declarations != NULL)
+    symbol->global_var_declarations->accept(*this);
+  symbol->resource_declarations->accept(*this);
+  if (symbol->access_declarations != NULL)
+    symbol->access_declarations->accept(*this);
+  if (symbol->instance_specific_initializations != NULL)
+    symbol->instance_specific_initializations->accept(*this);
+  s4o.indent_left();
+  s4o.print(s4o.indent_spaces + "END_CONFIGURATION\n\n\n");
+  return NULL;
+}
+
+
+/* helper symbol for configuration_declaration */
+/*| resource_declaration_list resource_declaration */
+void *visit(resource_declaration_list_c *symbol) {return print_list(symbol);}
+
+
+/*
+RESOURCE resource_name ON resource_type_name
+   optional_global_var_declarations
+   single_resource_declaration
+END_RESOURCE
+*/
+void *visit(resource_declaration_c *symbol) {
+  s4o.print(s4o.indent_spaces + "RESOURCE ");
+  symbol->resource_name->accept(*this);
+  s4o.print(" ON ");
+  symbol->resource_type_name->accept(*this);
+  s4o.print("\n");
+  s4o.indent_right();
+  if (symbol->global_var_declarations != NULL)
+    symbol->global_var_declarations->accept(*this);
+  symbol->resource_declaration->accept(*this);
+  s4o.indent_left();
+  s4o.print(s4o.indent_spaces + "END_RESOURCE\n");
+  return NULL;
+}
+
+
+/* task_configuration_list program_configuration_list */
+void *visit(single_resource_declaration_c *symbol) {
+  symbol->task_configuration_list->accept(*this);
+  symbol->program_configuration_list->accept(*this);
+  return NULL;
+}
+
+/* helper symbol for single_resource_declaration */
+/*| task_configuration_list task_configuration ';'*/
+void *visit(task_configuration_list_c *symbol) {
+  return print_list(symbol, s4o.indent_spaces, ";\n" + s4o.indent_spaces, ";\n");
+}
+
+
+/* helper symbol for single_resource_declaration */
+/*| program_configuration_list program_configuration ';'*/
+void *visit(program_configuration_list_c *symbol) {
+  return print_list(symbol, s4o.indent_spaces, ";\n" + s4o.indent_spaces, ";\n");
+}
+
+
+/* helper symbol for
+ *  - access_path
+ *  - instance_specific_init
+ */
+/* | any_fb_name_list any_identifier '.'*/
+void *visit(any_fb_name_list_c *symbol) {return print_list(symbol, ".", ".");}
+
+
+/*  [resource_name '.'] global_var_name ['.' structure_element_name] */
+void *visit(global_var_reference_c *symbol) {
+  if (symbol->resource_name != NULL) {
+    symbol->resource_name->accept(*this);
+    s4o.print(".");
+  }
+  symbol->global_var_name->accept(*this);
+  if (symbol->structure_element_name != NULL) {
+    s4o.print(".");
+    symbol->structure_element_name->accept(*this);
+  }
+  return NULL;
+}
+
+/* program_name '.' symbolic_variable */
+void *visit(program_output_reference_c *symbol) {
+  symbol->program_name->accept(*this);
+  s4o.print(".");
+  symbol->symbolic_variable->accept(*this);
+  return NULL;
+}
+
+/*  TASK task_name task_initialization */
+void *visit(task_configuration_c *symbol) {
+  s4o.print("TASK ");
+  symbol->task_name->accept(*this);
+  s4o.print(" ");
+  symbol->task_initialization->accept(*this);
+  return NULL;
+}
+
+/*  '(' [SINGLE ASSIGN data_source ','] [INTERVAL ASSIGN data_source ','] PRIORITY ASSIGN integer ')' */
+void *visit(task_initialization_c *symbol) {
+  s4o.print("(");
+  if (symbol->single_data_source != NULL) {
+    s4o.print("SINGLE := ");
+    symbol->single_data_source->accept(*this);
+    s4o.print(", ");
+  }
+  if (symbol->interval_data_source != NULL) {
+    s4o.print("INTERVAL := ");
+    symbol->interval_data_source->accept(*this);
+    s4o.print(", ");
+  }
+  s4o.print("PRIORITY := ");
+  symbol->priority_data_source->accept(*this);
+  s4o.print(")");
+  return NULL;
+}
+
+/*  PROGRAM [RETAIN | NON_RETAIN] program_name [WITH task_name] ':' program_type_name ['(' prog_conf_elements ')'] */
+void *visit(program_configuration_c *symbol) {
+  s4o.print("PROGRAM ");
+  if (symbol->retain_option != NULL)
+    symbol->retain_option->accept(*this);
+  symbol->program_name->accept(*this);
+  if (symbol->task_name != NULL) {
+    s4o.print(" WITH ");
+    symbol->task_name->accept(*this);
+  }
+  s4o.print(" : ");
+  symbol->program_type_name->accept(*this);
+  if (symbol->prog_conf_elements != NULL) {
+    s4o.print("(");
+    symbol->prog_conf_elements->accept(*this);
+    s4o.print(")");
+  }
+  return NULL;
+}
+
+
+/* prog_conf_elements ',' prog_conf_element */
+void *visit(prog_conf_elements_c *symbol) {return print_list(symbol, "", ", ");}
+
+/*  fb_name WITH task_name */
+void *visit(fb_task_c *symbol) {
+  symbol->fb_name->accept(*this);
+  s4o.print(" WITH ");
+  symbol->task_name->accept(*this);
+  return NULL;
+}
+
+/*  any_symbolic_variable ASSIGN prog_data_source */
+void *visit(prog_cnxn_assign_c *symbol) {
+  symbol->symbolic_variable->accept(*this);
+  s4o.print(" := ");
+  symbol->prog_data_source->accept(*this);
+  return NULL;
+}
+
+/* any_symbolic_variable SENDTO data_sink */
+void *visit(prog_cnxn_sendto_c *symbol) {
+  symbol->symbolic_variable->accept(*this);
+  s4o.print(" => ");
+  symbol->prog_data_source->accept(*this);
+  return NULL;
+}
+
+/* VAR_CONFIG instance_specific_init_list END_VAR */
+void *visit(instance_specific_initializations_c *symbol) {
+  s4o.print(s4o.indent_spaces + "VAR_CONFIG\n");
+  s4o.indent_right();
+  symbol->instance_specific_init_list->accept(*this);
+  s4o.indent_left();
+  s4o.print(s4o.indent_spaces + "END_VAR\n");
+  return NULL;
+}
+
+/* helper symbol for instance_specific_initializations */
+/*| instance_specific_init_list instance_specific_init ';'*/
+void *visit(instance_specific_init_list_c *symbol) {
+  return print_list(symbol, s4o.indent_spaces, ";\n" + s4o.indent_spaces, ";\n");
+}
+
+/* resource_name '.' program_name '.' optional_fb_name_list '.'
+    ((variable_name [location] ':' located_var_spec_init) | (fb_name ':' fb_initialization))
+*/
+void *visit(instance_specific_init_c *symbol) {
+  symbol->resource_name->accept(*this);
+  s4o.print(".");
+  symbol->program_name->accept(*this);
+  symbol->any_fb_name_list->accept(*this);
+  if (symbol->variable_name != NULL) {
+    s4o.print(".");
+    symbol->variable_name->accept(*this);
+  }
+  if (symbol->location != NULL) {
+    s4o.print(" ");
+    symbol->location->accept(*this);
+  }
+  s4o.print(" : ");
+  symbol->initialization->accept(*this);
+  return NULL;
+}
+
+/* helper symbol for instance_specific_init */
+/* function_block_type_name ':=' structure_initialization */
+void *visit(fb_initialization_c *symbol) {
+  symbol->function_block_type_name->accept(*this);
+  s4o.print(" := ");
+  symbol->structure_initialization->accept(*this);
+  return NULL;
+}
+
+
+/***********************************/
+/* B 2.1 Instructions and Operands */
+/***********************************/
+/*| instruction_list il_instruction */
+void *visit(instruction_list_c *symbol) {
+  return print_list(symbol, s4o.indent_spaces, "\n" + s4o.indent_spaces, "\n");
+}
+
+/* | label ':' [il_incomplete_instruction] eol_list */
+void *visit(il_instruction_c *symbol) {
+  if (symbol->label != NULL) {
+    symbol->label->accept(*this);
+    s4o.print(": ");
+  }
+  symbol->il_instruction->accept(*this);
+  return NULL;
+}
+
+
+/* | il_simple_operator [il_operand] */
+void *visit(il_simple_operation_c *symbol) {
+  symbol->il_simple_operator->accept(*this);
+  if (symbol->il_operand != NULL)
+    symbol->il_operand->accept(*this);
+  return NULL;
+}
+
+/* | function_name [il_operand_list] */
+void *visit(il_function_call_c *symbol) {
+  symbol->function_name->accept(*this);
+  s4o.print(" ");
+  if (symbol->il_operand_list != NULL)
+    symbol->il_operand_list->accept(*this);
+  return NULL;
+}
+
+
+/* | il_expr_operator '(' [il_operand] eol_list [simple_instr_list] ')' */
+void *visit(il_expression_c *symbol) {
+  symbol->il_expr_operator->accept(*this);
+  s4o.print("(");
+  if (symbol->il_operand != NULL)
+    symbol->il_operand->accept(*this);
+  if (symbol->simple_instr_list != NULL) {
+    s4o.print("\n");
+    s4o.indent_right();
+    symbol->simple_instr_list->accept(*this);
+    s4o.indent_left();
+  }
+  s4o.print(")");
+  return NULL;
+}
+
+/*  il_jump_operator label */
+void *visit(il_jump_operation_c *symbol) {
+  symbol->il_jump_operator->accept(*this);
+  symbol->label->accept(*this);
+  return NULL;
+}
+
+/*   il_call_operator prev_declared_fb_name
+ * | il_call_operator prev_declared_fb_name '(' ')'
+ * | il_call_operator prev_declared_fb_name '(' eol_list ')'
+ * | il_call_operator prev_declared_fb_name '(' il_operand_list ')'
+ * | il_call_operator prev_declared_fb_name '(' eol_list il_param_list ')'
+ */
+void *visit(il_fb_call_c *symbol) {
+  symbol->il_call_operator->accept(*this);
+  symbol->fb_name->accept(*this);
+  s4o.print("(");
+  if (symbol->il_operand_list != NULL)
+    symbol->il_operand_list->accept(*this);
+  if (symbol->il_param_list != NULL) {
+    s4o.print("\n");
+    s4o.indent_right();
+    symbol->il_param_list->accept(*this);
+    s4o.indent_left();
+  }
+  s4o.print(")");
+  return NULL;
+}
+
+
+/* | function_name '(' eol_list [il_param_list] ')' */
+void *visit(il_formal_funct_call_c *symbol) {
+  symbol->function_name->accept(*this);
+  s4o.print("(");
+  if (symbol->il_param_list != NULL) {
+    s4o.print("\n");
+    s4o.indent_right();
+    symbol->il_param_list->accept(*this);
+    s4o.print(")");
+  }
+  return NULL;
+}
+
+
+/* | il_operand_list ',' il_operand */
+void *visit(il_operand_list_c *symbol) {return print_list(symbol, "", ", ");}
+
+/* | simple_instr_list il_simple_instruction */
+void *visit(simple_instr_list_c *symbol) {
+  return print_list(symbol,  s4o.indent_spaces, "\n" + s4o.indent_spaces, "\n" + s4o.indent_spaces);
+}
+
+/* | il_initial_param_list il_param_instruction */
+void *visit(il_param_list_c *symbol) {return print_list(symbol);}
+
+/*  il_assign_operator il_operand
+ * | il_assign_operator '(' eol_list simple_instr_list ')'
+ */
+void *visit(il_param_assignment_c *symbol) {
+  symbol->il_assign_operator->accept(*this);
+  s4o.print(" ");
+  if (symbol->il_operand != NULL)
+    symbol->il_operand->accept(*this);
+  if (symbol->simple_instr_list != NULL) {
+    s4o.print("(\n");
+    s4o.indent_right();
+    symbol->simple_instr_list->accept(*this);
+    s4o.indent_left();
+    s4o.print(")");
+  }
+  return NULL;
+}
+
+/*  il_assign_out_operator variable */
+void *visit(il_param_out_assignment_c *symbol) {
+  symbol->il_assign_out_operator->accept(*this);
+  symbol->variable->accept(*this);
+  return NULL;
+}
+
+
+/*******************/
+/* B 2.2 Operators */
+/*******************/
+void *visit(LD_operator_c *symbol) {s4o.print("LD "); return NULL;}
+void *visit(LDN_operator_c *symbol) {s4o.print("LDN "); return NULL;}
+void *visit(ST_operator_c *symbol) {s4o.print("ST "); return NULL;}
+void *visit(STN_operator_c *symbol) {s4o.print("STN "); return NULL;}
+void *visit(NOT_operator_c *symbol) {s4o.print("NOT "); return NULL;}
+void *visit(S_operator_c *symbol) {s4o.print("S "); return NULL;}
+void *visit(R_operator_c *symbol) {s4o.print("R "); return NULL;}
+void *visit(S1_operator_c *symbol) {s4o.print("S1 "); return NULL;}
+void *visit(R1_operator_c *symbol) {s4o.print("R1 "); return NULL;}
+void *visit(CLK_operator_c *symbol) {s4o.print("CLK "); return NULL;}
+void *visit(CU_operator_c *symbol) {s4o.print("CU "); return NULL;}
+void *visit(CD_operator_c *symbol) {s4o.print("CD "); return NULL;}
+void *visit(PV_operator_c *symbol) {s4o.print("PV "); return NULL;}
+void *visit(IN_operator_c *symbol) {s4o.print("IN "); return NULL;}
+void *visit(PT_operator_c *symbol) {s4o.print("PT "); return NULL;}
+void *visit(AND_operator_c *symbol) {s4o.print("AND "); return NULL;}
+void *visit(OR_operator_c *symbol) {s4o.print("OR "); return NULL;}
+void *visit(XOR_operator_c *symbol) {s4o.print("XOR "); return NULL;}
+void *visit(ANDN_operator_c *symbol) {s4o.print("ANDN "); return NULL;}
+void *visit(ORN_operator_c *symbol) {s4o.print("ORN "); return NULL;}
+void *visit(XORN_operator_c *symbol) {s4o.print("XORN "); return NULL;}
+void *visit(ADD_operator_c *symbol) {s4o.print("ADD "); return NULL;}
+void *visit(SUB_operator_c *symbol) {s4o.print("SUB "); return NULL;}
+void *visit(MUL_operator_c *symbol) {s4o.print("MUL "); return NULL;}
+void *visit(DIV_operator_c *symbol) {s4o.print("DIV "); return NULL;}
+void *visit(MOD_operator_c *symbol) {s4o.print("MOD "); return NULL;}
+void *visit(GT_operator_c *symbol) {s4o.print("GT "); return NULL;}
+void *visit(GE_operator_c *symbol) {s4o.print("GE "); return NULL;}
+void *visit(EQ_operator_c *symbol) {s4o.print("EQ "); return NULL;}
+void *visit(LT_operator_c *symbol) {s4o.print("LT "); return NULL;}
+void *visit(LE_operator_c *symbol) {s4o.print("LE "); return NULL;}
+void *visit(NE_operator_c *symbol) {s4o.print("NE "); return NULL;}
+void *visit(CAL_operator_c *symbol) {s4o.print("CAL "); return NULL;}
+void *visit(CALC_operator_c *symbol) {s4o.print("CALC "); return NULL;}
+void *visit(CALCN_operator_c *symbol) {s4o.print("CALCN "); return NULL;}
+void *visit(RET_operator_c *symbol) {s4o.print("RET "); return NULL;}
+void *visit(RETC_operator_c *symbol) {s4o.print("RETC "); return NULL;}
+void *visit(RETCN_operator_c *symbol) {s4o.print("RETCN "); return NULL;}
+void *visit(JMP_operator_c *symbol) {s4o.print("JMP "); return NULL;}
+void *visit(JMPC_operator_c *symbol) {s4o.print("JMPC "); return NULL;}
+void *visit(JMPCN_operator_c *symbol) {s4o.print("JMPCN "); return NULL;}
+
+/*| [NOT] any_identifier SENDTO */
+void *visit(il_assign_out_operator_c *symbol) {
+  if (symbol->option != NULL)
+    symbol->option->accept(*this);
+  symbol->variable_name->accept(*this);
+  s4o.print(" => ");
+  return NULL;
+}
+
+
+/***********************/
+/* B 3.1 - Expressions */
+/***********************/
+void *visit(or_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " OR ");}
+void *visit(xor_expression_c *symbol) {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, " AND ");}
+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(div_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " / ");}
+void *visit(mod_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " MOD ");}
+void *visit(power_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " ** ");}
+void *visit(neg_expression_c *symbol) {return print_unary_expression(symbol->exp, "-");}
+void *visit(not_expression_c *symbol) {return print_unary_expression(symbol->exp, "NOT ");}
+
+void *visit(function_invocation_c *symbol) {
+  symbol->function_name->accept(*this);
+  s4o.print("(");
+  symbol->parameter_assignment_list->accept(*this);
+  s4o.print(")");
+  return NULL;
+}
+
+/********************/
+/* B 3.2 Statements */
+/********************/
+void *visit(statement_list_c *symbol) {
+  return print_list(symbol, s4o.indent_spaces, ";\n" + s4o.indent_spaces, ";\n");
+}
+
+/*********************************/
+/* B 3.2.1 Assignment Statements */
+/*********************************/
+void *visit( assignment_statement_c *symbol) {
+  symbol->l_exp->accept(*this);
+  s4o.print(" := ");
+  symbol->r_exp->accept(*this);
+  return NULL;
+}
+
+/*****************************************/
+/* B 3.2.2 Subprogram Control Statements */
+/*****************************************/
+/*  RETURN */
+void *visit(return_statement_c *symbol) {
+  s4o.print("RETURN");
+  return NULL;
+}
+
+
+/* fb_name '(' [param_assignment_list] ')' */
+void *visit(fb_invocation_c *symbol) {
+  symbol->fb_name->accept(*this);
+  s4o.print("(");
+  if (symbol->param_assignment_list != NULL)
+    symbol->param_assignment_list->accept(*this);
+  s4o.print(")");
+  return NULL;
+}
+
+
+/* helper symbol for fb_invocation */
+/* param_assignment_list ',' param_assignment */
+void *visit(param_assignment_list_c *symbol) {return print_list(symbol, "", ", ");}
+
+
+void *visit(input_variable_param_assignment_c *symbol) {
+  symbol->variable_name->accept(*this);
+  s4o.print(" := ");
+  symbol->expression->accept(*this);
+  return NULL;
+}
+
+
+void *visit(output_variable_param_assignment_c *symbol) {
+  if (symbol->not_param != NULL)
+    symbol->not_param->accept(*this);
+  symbol->variable_name->accept(*this);
+  s4o.print(" => ");
+  symbol->variable->accept(*this);
+  return NULL;
+}
+
+
+void *visit(not_paramassign_c *symbol) {
+  s4o.print("NOT ");
+  return NULL;
+}
+
+
+/********************************/
+/* B 3.2.3 Selection Statements */
+/********************************/
+void *visit(if_statement_c *symbol) {
+  s4o.print("IF ");
+  symbol->expression->accept(*this);
+  s4o.print(" THEN\n");
+  s4o.indent_right();
+  symbol->statement_list->accept(*this);
+  s4o.indent_left();
+  symbol->elseif_statement_list->accept(*this);
+
+  if (symbol->else_statement_list != NULL) {
+    s4o.print(s4o.indent_spaces); s4o.print("ELSE\n");
+    s4o.indent_right();
+    symbol->else_statement_list->accept(*this);
+    s4o.indent_left();
+  }
+  s4o.print(s4o.indent_spaces); s4o.print("END_IF");
+  return NULL;
+}
+
+/* helper symbol for if_statement */
+void *visit(elseif_statement_list_c *symbol) {return print_list(symbol);}
+
+/* helper symbol for elseif_statement_list */
+void *visit(elseif_statement_c *symbol) {
+  s4o.print(s4o.indent_spaces); s4o.print("ELSIF ");
+  symbol->expression->accept(*this);
+  s4o.print(s4o.indent_spaces); s4o.print("THEN\n");
+  s4o.indent_right();
+  symbol->statement_list->accept(*this);
+  s4o.indent_left();
+  return NULL;
+}
+
+void *visit(case_statement_c *symbol) {
+  s4o.print("CASE ");
+  symbol->expression->accept(*this);
+  s4o.print(" OF\n");
+  s4o.indent_right();
+  symbol->case_element_list->accept(*this);
+  if (symbol->statement_list != NULL) {
+    s4o.print(s4o.indent_spaces + "ELSE\n");
+    s4o.indent_right();
+    symbol->statement_list->accept(*this);
+    s4o.indent_left();
+  }
+  s4o.indent_left();
+  s4o.print(s4o.indent_spaces + "END_CASE");
+  return NULL;
+}
+
+/* helper symbol for case_statement */
+void *visit(case_element_list_c *symbol) {
+  return print_list(symbol);
+}
+
+void *visit(case_element_c *symbol) {
+  s4o.print(s4o.indent_spaces);
+  symbol->case_list->accept(*this);
+  s4o.print(":\n");
+  s4o.indent_right();
+  symbol->statement_list->accept(*this);
+  s4o.indent_left();
+  return NULL;
+}
+
+void *visit(case_list_c *symbol) {return print_list(symbol, "", ", ");}
+
+/********************************/
+/* B 3.2.4 Iteration Statements */
+/********************************/
+void *visit(for_statement_c *symbol) {
+  s4o.print("FOR ");
+  symbol->control_variable->accept(*this);
+  s4o.print(" := ");
+  symbol->beg_expression->accept(*this);
+  s4o.print(" TO ");
+  symbol->end_expression->accept(*this);
+  if (symbol->by_expression != NULL) {
+    s4o.print(" BY ");
+    symbol->by_expression->accept(*this);
+  }
+  s4o.print(" DO\n");
+  s4o.indent_right();
+  symbol->statement_list->accept(*this);
+  s4o.indent_left();
+  s4o.print(s4o.indent_spaces); s4o.print("END_FOR");
+  return NULL;
+}
+
+void *visit(while_statement_c *symbol) {
+  s4o.print("WHILE ");
+  symbol->expression->accept(*this);
+  s4o.print(" DO\n");
+  s4o.indent_right();
+  symbol->statement_list->accept(*this);
+  s4o.indent_left();
+  s4o.print(s4o.indent_spaces); s4o.print("END_WHILE");
+  return NULL;
+}
+
+void *visit(repeat_statement_c *symbol) {
+  s4o.print("REPEAT\n");
+  s4o.indent_right();
+  symbol->statement_list->accept(*this);
+  s4o.indent_left();
+  s4o.print(s4o.indent_spaces); s4o.print("UNTIL ");
+  symbol->expression->accept(*this);
+  s4o.print("\n" + s4o.indent_spaces + "END_REPEAT");
+  return NULL;
+}
+
+void *visit(exit_statement_c *symbol) {
+  s4o.print("EXIT");
+  return NULL;
+}
+
+
+}; /* class generate_iec_c */
+
+
+
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
+
+
+
+
+visitor_c *new_code_generator(stage4out_c *s4o)  {return new generate_iec_c(s4o);}
+void delete_code_generator(visitor_c *code_generator) {delete code_generator;}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+