Fix C code generation when forward references (-p command line option) is on.
authormjsousa
Sat, 06 Dec 2014 19:14:23 +0000
changeset 959 8bfcc8e62bd6
parent 958 7474d2cd1d6e
child 961 b05f63d9d0fa
Fix C code generation when forward references (-p command line option) is on.
main.cc
stage3/Makefile.am
stage3/remove_forward_dependencies.cc
stage3/remove_forward_dependencies.hh
stage3/stage3.cc
stage3/stage3.hh
--- a/main.cc	Sat Dec 06 19:11:32 2014 +0000
+++ b/main.cc	Sat Dec 06 19:14:23 2014 +0000
@@ -134,7 +134,7 @@
 
 
 int main(int argc, char **argv) {
-  symbol_c *tree_root;
+  symbol_c *tree_root, *ordered_tree_root;
   char * builddir = NULL;
   int optres, errflg = 0;
   int path_len;
@@ -252,11 +252,11 @@
   //add_en_eno_param_decl_c::add_to(tree_root);
 
   /* Do semantic verification of code */
-  if (stage3(tree_root) < 0)
+  if (stage3(tree_root, &ordered_tree_root) < 0)
     return EXIT_FAILURE;
   
   /* 3rd Pass */
-  if (stage4(tree_root, builddir) < 0)
+  if (stage4(ordered_tree_root, builddir) < 0)
     return EXIT_FAILURE;
 
   /* 4th Pass */
--- a/stage3/Makefile.am	Sat Dec 06 19:11:32 2014 +0000
+++ b/stage3/Makefile.am	Sat Dec 06 19:14:23 2014 +0000
@@ -14,5 +14,6 @@
 	array_range_check.cc \
         constant_folding.cc \
         declaration_check.cc \
-        enum_declaration_check.cc
+        enum_declaration_check.cc \
+        remove_forward_dependencies.cc
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stage3/remove_forward_dependencies.cc	Sat Dec 06 19:14:23 2014 +0000
@@ -0,0 +1,303 @@
+/*
+ *  matiec - a compiler for the programming languages defined in IEC 61131-3
+ *
+ *  Copyright (C) 2014  Mario de Sousa (msousa@fe.up.pt)
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * 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 compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ */
+
+/*
+ * Re-oder the POUs in te library so that no forward references occur.
+ * 
+ * Since stage1_2 now suppport POUs that contain references to POUS that are only declared later,
+ * (e.g. a variable of FB1_t is declared, before the FB1_T function block is itself declared!)
+ * we may need to re-order all the POUs in the library so that these forward references do not occur.
+ * 
+ * This utility function will do just that. However, it does not destroy the original abstract syntax 
+ * tree (AST). It instead creates a new re-ordered AST, by instantiating a new library_c object.
+ * This new library_c object will however point to the *same* objects of the original AST, just in 
+ * a new order. 
+ * This means that the new and original AST share all the object instances, and only use a distinct
+ * library_c object!
+ */
+
+#include "remove_forward_dependencies.hh"
+#include "../main.hh" // required for ERROR() and ERROR_MSG() macros.
+#include "../absyntax_utils/absyntax_utils.hh"
+
+
+
+
+
+#define FIRST_(symbol1, symbol2) (((symbol1)->first_order < (symbol2)->first_order)   ? (symbol1) : (symbol2))
+#define  LAST_(symbol1, symbol2) (((symbol1)->last_order  > (symbol2)->last_order)    ? (symbol1) : (symbol2))
+
+#define FIRST_(symbol1, symbol2) (((symbol1)->first_order < (symbol2)->first_order)   ? (symbol1) : (symbol2))
+#define  LAST_(symbol1, symbol2) (((symbol1)->last_order  > (symbol2)->last_order)    ? (symbol1) : (symbol2))
+
+#define STAGE3_ERROR(error_level, symbol1, symbol2, ...) {                                                                  \
+  if (current_display_error_level >= error_level) {                                                                         \
+    fprintf(stderr, "%s:%d-%d..%d-%d: error: ",                                                                             \
+            FIRST_(symbol1,symbol2)->first_file, FIRST_(symbol1,symbol2)->first_line, FIRST_(symbol1,symbol2)->first_column,\
+                                                 LAST_(symbol1,symbol2) ->last_line,  LAST_(symbol1,symbol2) ->last_column);\
+    fprintf(stderr, __VA_ARGS__);                                                                                           \
+    fprintf(stderr, "\n");                                                                                                  \
+    error_count++;                                                                                                     \
+  }                                                                                                                         \
+}
+
+
+#define STAGE3_WARNING(symbol1, symbol2, ...) {                                                                             \
+    fprintf(stderr, "%s:%d-%d..%d-%d: warning: ",                                                                           \
+            FIRST_(symbol1,symbol2)->first_file, FIRST_(symbol1,symbol2)->first_line, FIRST_(symbol1,symbol2)->first_column,\
+                                                 LAST_(symbol1,symbol2) ->last_line,  LAST_(symbol1,symbol2) ->last_column);\
+    fprintf(stderr, __VA_ARGS__);                                                                                           \
+    fprintf(stderr, "\n");                                                                                                  \
+    warning_found = true;                                                                                                   \
+}
+
+
+
+/* NOTE: We create an independent visitor for this task instead of having this done by the remove_forward_dependencies_c
+ *       because we do not want to handle the ***_pragma_c classes while doing this search.
+ *      (remove_forward_dependencies_c needs to visit those classes when handling all the possible entries in
+ *       library_c, and must have those visitors)
+ * 
+ * NOTE:
+ *      This class could have been written by visiting all the AST objects that could _reference_ a
+ *          - FB type
+ *          - Program type
+ *          - Function type
+ *      and by checking whether those references are in the declared_identifiers list.
+ *      However, one of those objects, the ref_spec_c, may reference an FB type, or any other datatype, so we must have a way
+ *      of knowing what is being referenced in this case. I have opted to introduce a new object type in the AST, the
+ *      poutype_identifier_c, that will be used anywhere in the AST that references either a PROGRAM name or a FB type name
+ *      or a FUNCTION name (previously a simple identifier_c was used!).
+ *      This means that we merely need to visit the new poutype_identifier_c object in this visitor.
+ */
+class find_forward_dependencies_c: public search_visitor_c {
+  private:
+    identifiers_symbtable_t *declared_identifiers; // list of identifiers already declared by the symbols in the new tree
+  public:
+    find_forward_dependencies_c(identifiers_symbtable_t *declared_identifiers_) {declared_identifiers = declared_identifiers_;}
+  /*******************************************/
+  /* B 1.1 - Letters, digits and identifiers */
+  /*******************************************/
+  // return NULL if the symbol is already in the declared_identifiers symbol table, otherwise return the missing symbol!
+  void *visit(            poutype_identifier_c *symbol)
+    {if (declared_identifiers->find_value(symbol) != declared_identifiers->end_value()) return NULL; else return symbol;}
+};   /* class find_forward_dependencies_c */
+
+
+
+
+/* A class to count the number of POUs (Function, FBs Programs and Configurations) in a library.
+ * This will be used to make sure whether we have copied all the POUs from the original AST (abstract
+ * syntax tree) to the new AST.
+ * Note that we can't simply use the number of 'elements' in the AST, as it may contain unknown/unsupported pragmas.
+ */
+class pou_count_c: public search_visitor_c {
+  private:
+    static pou_count_c *singleton;
+    long long int count;
+
+  public:
+    static long long int get_count(library_c *library) {
+      if (NULL == singleton) singleton = new pou_count_c;
+      if (NULL == singleton) ERROR;
+      singleton->count = 0;
+      library->accept(*singleton);
+      return singleton->count;
+    }
+    
+    /**************************************/
+    /* B.1.5 - Program organization units */
+    /**************************************/
+    void *visit(      function_declaration_c *symbol) {count++; return NULL;}
+    void *visit(function_block_declaration_c *symbol) {count++; return NULL;} 
+    void *visit(       program_declaration_c *symbol) {count++; return NULL;} 
+    void *visit( configuration_declaration_c *symbol) {count++; return NULL;} 
+};   /* class pou_count_c */
+
+pou_count_c *pou_count_c::singleton = NULL;
+symbol_c remove_forward_dependencies_c_null_symbol;
+
+
+
+
+
+
+
+
+/************************************************************/
+/************************************************************/
+/******   The main class: Remove Forward Depencies    *******/
+/************************************************************/
+/************************************************************/
+
+// constructor & destructor
+remove_forward_dependencies_c:: remove_forward_dependencies_c(void) {
+  find_forward_dependencies      = new find_forward_dependencies_c(&declared_identifiers);
+  current_display_error_level = error_level_default;
+  error_count = 0;
+}
+
+remove_forward_dependencies_c::~remove_forward_dependencies_c(void) {
+  delete find_forward_dependencies;
+}
+
+
+int remove_forward_dependencies_c::get_error_count(void) {
+  return error_count;
+}
+
+
+
+library_c *remove_forward_dependencies_c::create_new_tree(symbol_c *tree) {
+  library_c *old_tree = dynamic_cast<library_c *>(tree);
+  if (NULL == old_tree) ERROR;
+  new_tree = new library_c;
+  *((symbol_c *)new_tree) = *((symbol_c *)tree); // copy any annotations from tree to new_tree;
+  new_tree->clear(); // remove all elements from list.
+  tree->accept(*this);
+  return new_tree;
+}
+
+
+
+void *remove_forward_dependencies_c::handle_library_symbol(symbol_c *symbol, symbol_c *name, symbol_c *search1, symbol_c *search2, symbol_c *search3) {
+  if (inserted_symbols.find(symbol) != inserted_symbols.end())                 return NULL; // already previously inserted into new_tree and declared_identifiers. Do not handle again!
+  if ((search1 != NULL) && (search1->accept(*find_forward_dependencies) != NULL)) return NULL; // A forward depency has not yet been satisfied. Wait for a later iteration to try again! 
+  if ((search2 != NULL) && (search2->accept(*find_forward_dependencies) != NULL)) return NULL; // A forward depency has not yet been satisfied. Wait for a later iteration to try again!
+  if ((search3 != NULL) && (search3->accept(*find_forward_dependencies) != NULL)) return NULL; // A forward depency has not yet been satisfied. Wait for a later iteration to try again!
+  /* no forward dependencies found => insert into new AST, and add to the 'defined identifiers' and 'inserted symbol' lists */
+  if (declared_identifiers.find_value(name) == declared_identifiers.end_value())
+      declared_identifiers.insert(name, NULL);  // only add if not yet in the symbol table (an overloaded version of this same POU could have been inderted previously!)
+  inserted_symbols.insert(symbol);
+  new_tree->add_element(current_code_generation_pragma);  
+  new_tree->add_element(symbol);  
+  return NULL;
+}
+
+
+/* Tell the user that the source code contains a circular dependency */
+void remove_forward_dependencies_c::print_circ_error(library_c *symbol) {
+  /* Note that we only print Functions and FBs, as Programs and Configurations cannot contain circular references due to syntax rules */
+  /* Note too that circular references in derived datatypes is also not possible due to sytax!                                        */
+  int initial_error_count = error_count;
+  for (int i = 0; i < symbol->n; i++) 
+    if (   (inserted_symbols.find(symbol->elements[i]) == inserted_symbols.end())            // if not copied to new AST
+        &&(  (NULL != dynamic_cast <function_block_declaration_c *>(symbol->elements[i]))    // and (is a FB  
+           ||(NULL != dynamic_cast <      function_declaration_c *>(symbol->elements[i]))))  //      or a Function)
+      STAGE3_ERROR(0, symbol->elements[i], symbol->elements[i], "POU (%s) contains a self-reference and/or belongs in a circular referencing loop", get_datatype_info_c::get_id_str(symbol->elements[i]));
+  if (error_count == initial_error_count) ERROR; // We were unable to determine which POUs contain the circular references!!
+}
+
+
+/***************************/
+/* B 0 - Programming Model */
+/***************************/
+/* enumvalue_symtable is filled in by enum_declaration_check_c, during stage3 semantic verification, with a list of all enumerated constants declared inside this POU */
+// SYM_LIST(library_c, enumvalue_symtable_t enumvalue_symtable;)
+void *remove_forward_dependencies_c::visit(library_c *symbol) {
+  /* this method is the expected entry point for this visitor, and implements the main algorithm of the visitor */
+  
+  /* first insert all the derived datatype declarations, in the same order by which they are delcared in the original AST */
+  /* Since IEC 61131-3 does not allow FBs in arrays or structures, it is actually safe to place all the datatypes before all the POUs! */
+  for (int i = 0; i < symbol->n; i++) 
+    if (NULL != dynamic_cast <data_type_declaration_c *>(symbol->elements[i]))
+      new_tree->add_element(symbol->elements[i]);  
+
+  /* now do the POUs, in whatever order is necessary to guarantee no forward references. */    
+  long long int old_tree_pou_count = pou_count_c::get_count(symbol);
+    // if no code generation pragma exists before the first entry in the library, the default is to enable code generation.
+  enable_code_generation_pragma_c *default_code_generation_pragma = new enable_code_generation_pragma_c; 
+  int prev_n;
+  cycle_count = 0;
+  do {
+    cycle_count++;
+    prev_n = new_tree->n;
+    current_code_generation_pragma = default_code_generation_pragma;
+    for (int i = 0; i < symbol->n; i++)  symbol->elements[i]->accept(*this);
+  } while (prev_n != new_tree->n); // repeat while new elementns are still being added to the new AST
+  
+  if (old_tree_pou_count != pou_count_c::get_count(new_tree)) 
+    print_circ_error(symbol);
+
+  return NULL;
+}
+
+
+/**************************************/
+/* B.1.5 - Program organization units */
+/**************************************/
+/***********************/
+/* B 1.5.1 - Functions */
+/***********************/
+// SYM_REF4(function_declaration_c, derived_function_name, type_name, var_declarations_list, function_body, enumvalue_symtable_t enumvalue_symtable;)
+void *remove_forward_dependencies_c::visit(function_declaration_c *symbol) 
+  {return handle_library_symbol(symbol, symbol->derived_function_name, symbol->type_name, symbol->var_declarations_list, symbol->function_body);}
+/*****************************/
+/* B 1.5.2 - Function Blocks */
+/*****************************/
+/*  FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */
+// SYM_REF3(function_block_declaration_c, fblock_name, var_declarations, fblock_body, enumvalue_symtable_t enumvalue_symtable;)
+void *remove_forward_dependencies_c::visit(function_block_declaration_c *symbol) 
+  {return handle_library_symbol(symbol, symbol->fblock_name, symbol->var_declarations, symbol->fblock_body);}
+/**********************/
+/* B 1.5.3 - Programs */
+/**********************/
+/*  PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM */
+// SYM_REF3(program_declaration_c, program_type_name, var_declarations, function_block_body, enumvalue_symtable_t enumvalue_symtable;)
+void *remove_forward_dependencies_c::visit(program_declaration_c *symbol) 
+  {return handle_library_symbol(symbol, symbol->program_type_name, symbol->var_declarations, symbol->function_block_body);}
+/********************************/
+/* B 1.7 Configuration elements */
+/********************************/
+/* CONFIGURATION configuration_name (...) END_CONFIGURATION */
+// SYM_REF5(configuration_declaration_c, configuration_name, global_var_declarations, resource_declarations, access_declarations, instance_specific_initializations, enumvalue_symtable_t enumvalue_symtable;)
+void *remove_forward_dependencies_c::visit(configuration_declaration_c *symbol) 
+  {return handle_library_symbol(symbol, symbol->configuration_name, symbol->global_var_declarations, symbol->resource_declarations, symbol->access_declarations);}
+/********************/
+/* 2.1.6 - Pragmas  */
+/********************/
+void *remove_forward_dependencies_c::visit(disable_code_generation_pragma_c *symbol) {current_code_generation_pragma = symbol; return NULL;}
+void *remove_forward_dependencies_c::visit( enable_code_generation_pragma_c *symbol) {current_code_generation_pragma = symbol; return NULL;}
+/* I have no ideia what this pragma is. Where should we place it in the re-ordered tree? 
+ * Without knowing the semantics of the pragma, it is not possible to hande it correctly.
+ * We therefore print out an error message, and abort!
+ */
+// TODO: print error message!
+void *remove_forward_dependencies_c::visit(pragma_c *symbol) {
+  if (1 != cycle_count) return NULL; // only handle unknown pragmas in the first cycle!
+  STAGE3_WARNING(symbol, symbol, "Unrecognized pragma. Including the pragma when using the '-p' command line option for 'allow use of forward references' may result in unwanted behaviour.");
+  new_tree->add_element(symbol);
+  return NULL;
+}
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stage3/remove_forward_dependencies.hh	Sat Dec 06 19:14:23 2014 +0000
@@ -0,0 +1,115 @@
+/*
+ *  matiec - a compiler for the programming languages defined in IEC 61131-3
+ *
+ *  Copyright (C) 2014  Mario de Sousa (msousa@fe.up.pt)
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * 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 compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ */
+
+
+/*
+ * Re-oder the POUs in te library so that no forward references occur.
+ * 
+ * Since stage1_2 now suppport POUs that contain references to POUS that are only declared later,
+ * (e.g. a variable of FB1_t is declared, before the FB1_T function block is itself declared!)
+ * we may need to re-order all the POUs in the library so that these forward references do not occur.
+ * 
+ * This utility class will do just that. However, it does not destroy the original abstract syntax 
+ * tree (AST). It instead creates a new re-ordered AST, by instantiating a new library_c object.
+ * This new library_c object will however point to the *same* objects of the original AST, just in 
+ * a new order. 
+ * This means that the new and original AST share all the object instances, and only use a distinct
+ * library_c object!
+ */
+
+#include "../absyntax/absyntax.hh"
+#include "../absyntax/visitor.hh"
+#include "../util/symtable.hh"
+#include <set>
+
+
+class   find_forward_dependencies_c;
+extern  symbol_c remove_forward_dependencies_c_null_symbol;
+typedef symtable_c<symbol_c *, &remove_forward_dependencies_c_null_symbol> identifiers_symbtable_t;
+
+
+
+
+
+
+
+class remove_forward_dependencies_c: public search_visitor_c {
+
+  private:
+    /* The level of detail that the user wants us to display error messages. */
+    #define error_level_default (1)
+    #define error_level_nagging (4)
+    unsigned int    current_display_error_level;
+    int             error_count;
+    bool            warning_found;
+    library_c      *new_tree;
+    int             cycle_count; // main algorithm runs in a loop. The nuber of the current cycle...
+    // NOTE: we need two lists in order to correctly handle overloaded functions
+    identifiers_symbtable_t      declared_identifiers; // list of identifiers already declared by the symbols in the new tree
+    std::set <symbol_c *>        inserted_symbols;     // list of symbols already inserted in the new tree 
+    symbol_c       *current_code_generation_pragma;    // points to any currently 'active' enable_code_generation_pragma_c
+    find_forward_dependencies_c    *find_forward_dependencies;  
+
+  public:
+     remove_forward_dependencies_c(void);
+    ~remove_forward_dependencies_c(void);
+    library_c *create_new_tree(symbol_c *old_tree);  // create a new tree with POUs ordered so it does not contain forward dependencies...
+    int        get_error_count(void);
+
+  private:
+    void *handle_library_symbol(symbol_c *symbol, symbol_c *name, symbol_c *search1, symbol_c *search2 = NULL, symbol_c *search3 = NULL);
+    void  print_circ_error(library_c *symbol);
+
+    /***************************/
+    /* B 0 - Programming Model */
+    /***************************/
+    void *visit(library_c *symbol);
+    /**************************************/
+    /* B.1.5 - Program organization units */
+    /**************************************/
+    void *visit(function_declaration_c *symbol);
+    void *visit(function_block_declaration_c *symbol);
+    void *visit(program_declaration_c *symbol);
+    /********************************/
+    /* B 1.7 Configuration elements */
+    /********************************/
+    void *visit(configuration_declaration_c *symbol);
+    /********************/
+    /* 2.1.6 - Pragmas  */
+    /********************/
+    void *visit(disable_code_generation_pragma_c *symbol);
+    void *visit(enable_code_generation_pragma_c *symbol);
+    void *visit(pragma_c *symbol);
+
+};   /* class remove_forward_dependencies_c */
+
+
+
--- a/stage3/stage3.cc	Sat Dec 06 19:11:32 2014 +0000
+++ b/stage3/stage3.cc	Sat Dec 06 19:14:23 2014 +0000
@@ -44,6 +44,8 @@
 #include "constant_folding.hh"
 #include "declaration_check.hh"
 #include "enum_declaration_check.hh"
+#include "remove_forward_dependencies.hh"
+
 
 
 static int enum_declaration_check(symbol_c *tree_root){
@@ -114,7 +116,26 @@
 }
 
 
-int stage3(symbol_c *tree_root){
+
+/* Removing forward dependencies only makes sense when stage1_2 is run with the pre-parsing option.
+ * This algorithm has no dependencies on other stage 3 algorithms.
+ * Typically this is run last, just to show that the remaining algorithms also do not depend on the fact that 
+ * the library_c (i.e. the source code) does not contain forward dependencies.
+ */
+static int remove_forward_dependencies(symbol_c *tree_root, symbol_c **ordered_tree_root) {
+	if (NULL != ordered_tree_root)    *ordered_tree_root = tree_root; // by default, consider tree_root already ordered
+	if (!runtime_options.pre_parsing)  return 0;                      // No re-ordering necessary, just return
+	  
+	/* We need to re-order the elements in the library, to fix any forward references! */
+	remove_forward_dependencies_c remove_forward_dependencies;
+	symbol_c *new_tree_root = remove_forward_dependencies.create_new_tree(tree_root);
+	if (NULL ==     new_tree_root)   ERROR;
+	if (NULL != ordered_tree_root)   *ordered_tree_root = new_tree_root;
+	return remove_forward_dependencies.get_error_count();
+}
+
+
+int stage3(symbol_c *tree_root, symbol_c **ordered_tree_root) {
 	int error_count = 0;
 	error_count += enum_declaration_check(tree_root);
 	error_count += declaration_safety(tree_root);
@@ -123,6 +144,7 @@
 	error_count += type_safety(tree_root);
 	error_count += lvalue_check(tree_root);
 	error_count += array_range_check(tree_root);
+	error_count += remove_forward_dependencies(tree_root, ordered_tree_root);
 	
 	if (error_count > 0) {
 		fprintf(stderr, "%d error(s) found. Bailing out!\n", error_count); 
--- a/stage3/stage3.hh	Sat Dec 06 19:11:32 2014 +0000
+++ b/stage3/stage3.hh	Sat Dec 06 19:14:23 2014 +0000
@@ -36,6 +36,6 @@
 #include "../util/symtable.hh"
 
 
-int stage3(symbol_c *tree_root);
+int stage3(symbol_c *tree_root, symbol_c **ordered_tree_root);
 
 #endif /* _STAGE3_HH */