Do not allow constant_propagation algorithm go into infinite loop when analysing code with circular references.
authormjsousa
Fri, 16 Jan 2015 12:20:14 +0000
changeset 990 4c235d65afdd
parent 989 d4f8931d80cd
child 993 bb30d84711ee
Do not allow constant_propagation algorithm go into infinite loop when analysing code with circular references.
stage3/constant_folding.cc
stage3/constant_folding.hh
--- a/stage3/constant_folding.cc	Fri Jan 16 11:17:33 2015 +0000
+++ b/stage3/constant_folding.cc	Fri Jan 16 12:20:14 2015 +0000
@@ -1416,6 +1416,8 @@
   return NULL;
 }
 
+
+#include <algorithm>    // std::find
 void *constant_propagation_c::handle_var_list_decl(symbol_c *var_list, symbol_c *type_decl, bool is_global_var) {
   type_decl->accept(*this);  // Do constant folding of the initial value, and literals in subranges! (we will probably be doing this multiple times for the same init value, but this is safe as the cvalue is idem-potent)
   symbol_c *init_value = type_initial_value_c::get(type_decl);  
@@ -1441,8 +1443,17 @@
     //  Remmeber that in this case we will recursively visit the FB type declaration!!
     function_block_declaration_c *fb_type = itr->second;
     if (NULL == fb_type) ERROR; // syntax parsing should not allow this!
-    // TODO: detect whether we are already currently visiting this exact same FB declaration (possible with -p option), so we do not get into an infinite loop!!
-    fb_type->accept(*this);
+    // WARNING: Before calling fb_type->accept(*this), we must first determine whether we are already currently visiting this exact 
+    //          same FB declaration (possible with -p option), so we do not get into an infinite loop!!
+    // NOTE: We use the std::find() standard algorithm, since the std::stack and std::deque do not have the find() member function.
+    //       We could alternatively use a std::set instead of std::deque, but then it would not be evident that insertion and deletion
+    //       of fb_types follows a push() and pop() algorithm typical of stacks.
+    if (std::find(fbs_currently_being_visited.begin(), fbs_currently_being_visited.end(), fb_type) == fbs_currently_being_visited.end()) {
+      // The fb_type is not in the fbs_currently_being_visited stack, so we push it onto the stack, and then visit it!!
+      fbs_currently_being_visited.push_back(fb_type);
+      fb_type->accept(*this);
+      fbs_currently_being_visited.pop_back();
+    }
     return NULL;
   }
   
--- a/stage3/constant_folding.hh	Fri Jan 16 11:17:33 2015 +0000
+++ b/stage3/constant_folding.hh	Fri Jan 16 12:20:14 2015 +0000
@@ -201,6 +201,7 @@
 
 
 
+#include <deque>
 
 class constant_propagation_c : public constant_folding_c {
   public:
@@ -212,6 +213,9 @@
     symbol_c *current_configuration;
     map_values_t *values;
     map_values_t var_global_values;
+    /* A stack of all the FB declarations currently being recursively constant propagated */
+    std::deque<function_block_declaration_c *> fbs_currently_being_visited; // We use a deque instead of stack, so we can search in the stack using direct access to its elements!
+
     void *handle_var_list_decl(symbol_c *var_list, symbol_c *type_decl, bool is_global_var = false);
     void *handle_var_decl     (symbol_c *var_list, bool fixed_init_value);
     // Flag to indicate whether the variables in the variable declaration list will always have a fixed value when the POU is executed!