absyntax_utils/function_param_iterator.cc
changeset 350 2c3c4dc34979
parent 279 c0453b7f99df
child 424 43d73e28eca8
--- a/absyntax_utils/function_param_iterator.cc	Mon Jul 11 09:47:27 2011 +0100
+++ b/absyntax_utils/function_param_iterator.cc	Fri Jul 29 16:03:28 2011 +0100
@@ -48,8 +48,11 @@
 
 
 
-#include "function_param_iterator.hh"
-#include "spec_init_separator.hh"
+#include "absyntax_utils.hh"  /* required for extract_integer() */
+// #include "function_param_iterator.hh"  /* no longer required, aready included by absyntax_utils.hh */
+// #include "spec_init_separator.hh"  /* no longer required, aready included by absyntax_utils.hh */
+#include <stdlib.h>  /* required for strtol() */
+#include <string.h>
 #include <strings.h>
 
 
@@ -67,6 +70,49 @@
 
 
 
+/* compare the name of two __extensible__ function parameters.
+ * The usual use case is to have one of the parameters as used
+ * in the function declaration, and another as used in a formal function call.
+ *
+ * Will return:
+ *         < 0 : if two parameters are not compatible, or one is invalid
+ *        >= 0 : if both parameters ..........
+ */
+/*
+ *   ("in", "i0")      -> returns error (<0)
+ *   ("in1", "in")     -> returns error (<0)
+ *   ("in", "in")      -> returns error (<0)
+ *   ("in", "inw")     -> returns error (<0)
+ *   ("in", "in10.4")  -> returns error (<0)
+ *   ("in", "in10e")   -> returns error (<0)
+ *   ("in", "")        -> returns error (<0)
+ *   ("", "in10e")     -> returns error (<0)
+ *   ("in", "in0")     -> returns 0
+ *   ("in", "in9")     -> returns 9
+ *   ("in", "in42")    -> returns 42
+ *   ("in", "in-42")   -> returns -42 (error!)
+ */
+int function_param_iterator_c::cmp_extparam_names(const char* s1, const char* s2) {
+  int res;
+  char *endptr;
+  int len;
+
+  if ((s1 == NULL) || (s2 == NULL) || (*s1 == '\0') || (*s2 == '\0')) return -1;
+
+  len = strlen(s1);
+  if (strncasecmp(s1, s2, len)) return -2;
+
+  s1 = &s2[len];
+  if (*s1 == '\0') return -3;
+
+  res = strtol(s1, &endptr, 10);
+  if (*endptr != '\0') return -4;
+
+  return res;
+}
+
+
+
 void* function_param_iterator_c::handle_param_list(list_c *list) {
   switch (current_operation) {
     case iterate_op:
@@ -79,12 +125,27 @@
 
     case search_op:
       for(int i = 0; i < list->n; i++) {
-        identifier_c *variable_name = dynamic_cast<identifier_c *>(list->elements[i]);
+        symbol_c *sym = list->elements[i];
+        extensible_input_parameter_c *extensible_parameter = dynamic_cast<extensible_input_parameter_c *>(sym);
+        if (extensible_parameter != NULL) {
+          sym = extensible_parameter->var_name;
+          current_param_is_extensible = true;
+          _first_extensible_param_index = extract_integer(extensible_parameter->first_index);
+        }
+        identifier_c *variable_name = dynamic_cast<identifier_c *>(sym);
         if (variable_name == NULL) ERROR;
-
-        if (strcasecmp(search_param_name->value, variable_name->value) == 0)
-          /* FOUND! This is the same parameter!! */
-          return (void *)variable_name;
+        
+        if (!current_param_is_extensible)
+          if (strcasecmp(search_param_name->value, variable_name->value) == 0)
+            /* FOUND! This is the same parameter!! */
+            return (void *)variable_name;
+  
+        if (current_param_is_extensible) {
+          current_extensible_param_index = cmp_extparam_names(variable_name->value, search_param_name->value);
+          if (current_extensible_param_index >= 0)
+            /* FOUND! This is a compatible extensible parameter!! */
+            return (void *)variable_name;
+        }  
       }
       break;
   } /* switch */
@@ -102,12 +163,26 @@
       break;
 
     case search_op:
+      extensible_input_parameter_c *extensible_parameter = dynamic_cast<extensible_input_parameter_c *>(var_name);
+      if (extensible_parameter != NULL) {
+        var_name = extensible_parameter->var_name;
+        current_param_is_extensible = true;
+        _first_extensible_param_index = extract_integer(extensible_parameter->first_index);
+      }
       identifier_c *variable_name = dynamic_cast<identifier_c *>(var_name);
       if (variable_name == NULL) ERROR;
-
-      if (strcasecmp(search_param_name->value, variable_name->value) == 0)
-        /* FOUND! This is the same parameter!! */
-        return (void *)variable_name;
+      
+      if (!current_param_is_extensible)
+        if (strcasecmp(search_param_name->value, variable_name->value) == 0)
+          /* FOUND! This is the same parameter!! */
+          return (void *)variable_name;
+
+      if (current_param_is_extensible) {
+        current_extensible_param_index = cmp_extparam_names(variable_name->value, search_param_name->value);
+        if (current_extensible_param_index >= 0)
+          /* FOUND! This is a compatible extensible parameter!! */
+          return (void *)variable_name;
+      }  
       break;
   } /* switch */
 
@@ -128,6 +203,8 @@
 /* start off at the first parameter once again... */
 void function_param_iterator_c::reset(void) {
   next_param = param_count = 0;
+  _first_extensible_param_index = -1;
+  current_param_is_extensible = false;
   current_param_name = NULL;
   current_param_type = current_param_default_value = NULL;
 }
@@ -166,6 +243,11 @@
   void *res;
   identifier_c *identifier;
  
+  if (current_param_is_extensible) {
+    current_extensible_param_index++;
+    return current_param_name;
+  }
+  
   param_count = 0;
   en_eno_param_implicit = false;
   next_param++;
@@ -175,6 +257,13 @@
     return NULL;
 
   symbol_c *sym = (symbol_c *)res;
+  extensible_input_parameter_c *extensible_parameter = dynamic_cast<extensible_input_parameter_c *>(sym);
+  if (extensible_parameter != NULL) {
+    sym = extensible_parameter->var_name;
+    current_param_is_extensible = true;
+    _first_extensible_param_index = extract_integer(extensible_parameter->first_index);
+    current_extensible_param_index = _first_extensible_param_index;
+  }
   identifier = dynamic_cast<identifier_c *>(sym);
   if (identifier == NULL)
     ERROR;
@@ -187,6 +276,8 @@
   if (NULL == param_name) ERROR;
   search_param_name = dynamic_cast<identifier_c *>(param_name);
   if (NULL == search_param_name) ERROR;
+  en_eno_param_implicit = false;
+  current_param_is_extensible = false;
   current_operation = function_param_iterator_c::search_op;
   void *res = f_decl->accept(*this);
   identifier_c *res_param_name = dynamic_cast<identifier_c *>((symbol_c *)res);
@@ -210,6 +301,24 @@
   return en_eno_param_implicit;
 }
 
+/* Returns if currently referenced parameter is an extensible parameter. */
+/* extensible paramters only occur in some standard functions, e.g. AND(word#34, word#44, word#65); */
+bool function_param_iterator_c::is_extensible_param(void) {
+  return current_param_is_extensible;
+}
+
+/* Returns the index of the current extensible parameter. */             
+/* If the current parameter is not an extensible paramter, returns -1 */
+int function_param_iterator_c::extensible_param_index(void) {
+  return (current_param_is_extensible? current_extensible_param_index : -1);
+}
+
+/* Returns the index of the first extensible parameter, or -1 if no extensible parameter found. */             
+/* WARNING: Will only return the correct value _after_ an extensible parameter has been found! */
+int function_param_iterator_c::first_extensible_param_index(void) {
+  return _first_extensible_param_index;
+}
+
 /* Returns the currently referenced parameter's data passing direction.
  * i.e. VAR_INPUT, VAR_OUTPUT or VAR_INOUT
  */
@@ -218,7 +327,7 @@
 }
 
 void *function_param_iterator_c::visit(implicit_definition_c *symbol) {
-	en_eno_param_implicit = current_operation == function_param_iterator_c::iterate_op;
+	en_eno_param_implicit = true;
 	return NULL;
 }
 
@@ -243,12 +352,15 @@
    * variables will get overwritten when we visit the next
    * var1_init_decl_c list!
    */
-  symbol->method->accept(*this);
-
   current_param_default_value = symbol->value;
   current_param_type = symbol->type;
 
-  return handle_single_param(symbol->name);
+  void *res = handle_single_param(symbol->name);
+  
+    /* If we have found the parameter we will be returning, we set the en_eno_param_implicit to TRUE if implicitly defined */
+  if (res != NULL) symbol->method->accept(*this);
+  
+  return res;
 }
 
 /* var1_list ':' array_spec_init */
@@ -278,6 +390,7 @@
   current_param_direction = direction_out;
   return symbol->var_init_decl_list->accept(*this);
 }
+
 void *function_param_iterator_c::visit(eno_param_declaration_c *symbol) {
   TRACE("eno_param_declaration_c");
   /* It is OK to store these values in the current_param_XXX
@@ -286,18 +399,23 @@
    * variables will get overwritten when we visit the next
    * var1_init_decl_c list!
    */
-  symbol->method->accept(*this);
-
   current_param_default_value = NULL;
   current_param_type = symbol->type;
 
-  return handle_single_param(symbol->name);
-}
+  void *res = handle_single_param(symbol->name);
+  
+    /* If we have found the parameter we will be returning, we set the en_eno_param_implicit to TRUE if implicitly defined */
+  if (res != NULL) symbol->method->accept(*this);
+  
+  return res;
+}
+
 void *function_param_iterator_c::visit(input_output_declarations_c *symbol) {
   TRACE("input_output_declarations_c");
   current_param_direction = direction_inout;
   return symbol->var_declaration_list->accept(*this);
 }
+
 void *function_param_iterator_c::visit(var_declaration_list_c *symbol) {TRACE("var_declaration_list_c"); return iterate_list(symbol);}
 
 /*  var1_list ':' array_specification */
@@ -425,12 +543,12 @@
 }
 
 
-
 void *function_param_iterator_c::visit(var1_list_c *symbol) {
   TRACE("var1_list_c");
   return handle_param_list(symbol);
 }
 
+
 void *function_param_iterator_c::visit(var_init_decl_list_c *symbol) {TRACE("var_init_decl_list_c"); return iterate_list(symbol);}