diff -r aad38592bdde -r c0bda77b37a0 absyntax_utils/search_varfb_instance_type.cc --- a/absyntax_utils/search_varfb_instance_type.cc Tue Aug 14 19:40:01 2012 +0200 +++ b/absyntax_utils/search_varfb_instance_type.cc Wed Aug 22 16:46:17 2012 +0200 @@ -1,7 +1,7 @@ /* * matiec - a compiler for the programming languages defined in IEC 61131-3 * - * Copyright (C) 2003-2011 Mario de Sousa (msousa@fe.up.pt) + * Copyright (C) 2003-2012 Mario de Sousa (msousa@fe.up.pt) * Copyright (C) 2007-2011 Laurent Bessard and Edouard Tisserant * * This program is free software: you can redistribute it and/or modify @@ -75,225 +75,143 @@ * * Member functions: * ================ + * get_basetype_id() ---> returns 2A (implemented, although currently it is not needed! ) * get_basetype_decl() ---> returns 2B * get_type_id() ---> returns 1A * - * Since we haven't yet needed them, we don't yet implement - * get_basetype_id() ----> would return 2A - * get_type_decl() ----> would return 1B + * Since we haven't yet needed it, we don't yet implement + * get_type_decl() ---> returns 1B */ -/* - * TODO: this code has a memory leak... - * We call 'new' in several locations, but bever get to 'delete' the object instances... - */ + #include "absyntax_utils.hh" +void search_varfb_instance_type_c::init(void) { + this->current_type_id = NULL; + this->current_basetype_id = NULL; + this->current_basetype_decl = NULL; + this->current_field_selector = NULL; +} + + search_varfb_instance_type_c::search_varfb_instance_type_c(symbol_c *search_scope): search_var_instance_decl(search_scope) { - this->decompose_var_instance_name = NULL; - this->current_structelement_name = NULL; - this->current_typeid = NULL; - this->current_basetypeid = NULL; -} - -symbol_c *search_varfb_instance_type_c::get_type_decl(symbol_c *variable_name) { - this->current_structelement_name = NULL; - this->current_typeid = NULL; - this->current_basetypeid = NULL; - this->decompose_var_instance_name = new decompose_var_instance_name_c(variable_name); - if (NULL == decompose_var_instance_name) ERROR; - - /* find the part of the variable name that will appear in the - * variable declaration, for e.g., in window.point.x, this would be - * window! + this->init(); +} + + +/* We expect to be passed a symbolic_variable_c */ +symbol_c *search_varfb_instance_type_c::get_type_id(symbol_c *variable_name) { + this->init(); + variable_name->accept(*this); + return current_type_id; +} + + +symbol_c *search_varfb_instance_type_c::get_basetype_id(symbol_c *variable_name) { + this->init(); + variable_name->accept(*this); + return current_basetype_id; +} + + +symbol_c *search_varfb_instance_type_c::get_basetype_decl(symbol_c *variable_name) { + this->init(); + variable_name->accept(*this); + return current_basetype_decl; +} + + + + +/*************************/ +/* B.1 - Common elements */ +/*************************/ +/*******************************************/ +/* B 1.1 - Letters, digits and identifiers */ +/*******************************************/ +// SYM_TOKEN(identifier_c) +void *search_varfb_instance_type_c::visit(identifier_c *variable_name) { + /* symbol should be a variable name!! */ + /* Note: although the method is called get_decl(), it is getting the declaration of the variable, which for us is the type_id of that variable! */ + current_type_id = search_var_instance_decl.get_decl (variable_name); + current_basetype_decl = search_base_type.get_basetype_decl(current_type_id); + current_basetype_id = search_base_type.get_basetype_id (current_type_id); + + /* What if the variable has not been declared? Then this should not be a compiler error! + * However, currently stage 2 of the compiler already detects when variables have not been delcared, + * so if the variable's declaration is not found, then that means that we have an internal compiler error! + * + * Actually, the above is not true anymore. See the use of the any_symbolic_variable in iec_bison.yy + * - when defining the delay of a delayed action association in SFC + * - in program connections inside configurations (will this search_varfb_instance_type_c class be called to handle this??) */ - symbol_c *var_name_part = decompose_var_instance_name->next_part(); - if (NULL == var_name_part) ERROR; - - /* Now we try to find the variable instance declaration, to determine its type... */ - symbol_c *var_decl = search_var_instance_decl.get_decl(var_name_part); - if (NULL == var_decl) ERROR; - - /* if it is a struct or function block, we must search the type - * of the struct or function block member. - * This is done by this class visiting the var_decl. - * This class, while visiting, will recursively call - * decompose_var_instance_name->get_next() when and if required... - */ - symbol_c *res = (symbol_c *)var_decl->accept(*this); - /* NOTE: A Null result is not really an internal compiler error, but rather an error in - * the IEC 61131-3 source code being compiled. This means we cannot just abort the compiler with ERROR. - * // if (NULL == res) ERROR; - */ - if (NULL == res) return NULL; - - /* make sure that we have decomposed all structure elements of the variable name */ - symbol_c *var_name = decompose_var_instance_name->next_part(); - /* NOTE: A non-NULL result is not really an internal compiler error, but rather an error in - * the IEC 61131-3 source code being compiled. - * (for example, 'int_var.struct_elem' in the source code, when 'int_var' is a simple integer, - * and not a structure, will result in this result being non-NULL!) - * This means we cannot just abort the compiler with ERROR. - * // if (NULL != var_name) ERROR; - */ - if (NULL != var_name) return NULL; - - return res; -} - - -symbol_c *search_varfb_instance_type_c::get_basetype_decl(symbol_c *variable_name) { - symbol_c *res = get_type_decl(variable_name); - if (NULL == res) return NULL; - return (symbol_c *)base_type(res); -} - - -unsigned int search_varfb_instance_type_c::get_vartype(symbol_c *variable_name) { - this->current_structelement_name = NULL; - this->current_typeid = NULL; - this->current_basetypeid = NULL; - this->is_complex = false; - this->decompose_var_instance_name = new decompose_var_instance_name_c(variable_name); - if (NULL == decompose_var_instance_name) ERROR; - - /* find the part of the variable name that will appear in the - * variable declaration, for e.g., in window.point.x, this would be - * window! - */ - symbol_c *var_name_part = decompose_var_instance_name->next_part(); - if (NULL == var_name_part) ERROR; - - /* Now we try to find the variable instance declaration, to determine its type... */ - symbol_c *var_decl = search_var_instance_decl.get_decl(var_name_part); - if (NULL == var_decl) { - /* variable instance declaration not found! */ - return 0; - } - - /* if it is a struct or function block, we must search the type - * of the struct or function block member. - * This is done by this class visiting the var_decl. - * This class, while visiting, will recursively call - * decompose_var_instance_name->get_next() when and if required... - */ - var_decl->accept(*this); - unsigned int res = search_var_instance_decl.get_vartype(); - - /* make sure that we have decomposed all structure elements of the variable name */ - symbol_c *var_name = decompose_var_instance_name->next_part(); - if (NULL != var_name) ERROR; - - return res; -} - -symbol_c *search_varfb_instance_type_c::get_type_id(symbol_c *variable_name) { - this->current_typeid = NULL; - symbol_c *vartype = this->get_type_decl(variable_name); - if (this->current_typeid != NULL) - return this->current_typeid; - else - return vartype; -} - -bool search_varfb_instance_type_c::type_is_complex(void) { - return this->is_complex; -} - -/* a helper function... */ -void *search_varfb_instance_type_c::visit_list(list_c *list) { - if (NULL == current_structelement_name) ERROR; - - for(int i = 0; i < list->n; i++) { - void *res = list->elements[i]->accept(*this); - if (res != NULL) - return res; - } - /* not found! */ - return NULL; -} - -/* a helper function... */ -void *search_varfb_instance_type_c::base_type(symbol_c *symbol) { - search_base_type_c search_base_type; - return symbol->accept(search_base_type); -} - -/* We override the base class' visitor to identifier_c. - * This is so because the base class does not consider a function block - * to be a type, unlike this class that allows a variable instance - * of a function block type... - */ -void *search_varfb_instance_type_c::visit(identifier_c *type_name) { - /* we only store the new type id if none had been found yet. - * Since we will recursively carry on looking at the base type - * to determine the base type declaration and id, we must only set this variable - * the first time. - * e.g. TYPE myint1_t : int := 1; - * myint2_t : int1_t := 2; - * myint3_t : int2_t := 3; - * END_TYPE; - * VAR - * myint1 : myint1_t; - * myint2 : myint2_t; - * myint3 : myint3_t; - * END_VAR - * - * If we ask for typeid of myint3, it must return myint3_t - * If we ask for basetypeid of myint3, it must return int - * - * When determining the data type of myint3, we will recursively go all the way - * down to int, but we must still only store myint3_t as the base type id. - */ - if (NULL == this->current_typeid) - this->current_typeid = type_name; - this->current_basetypeid = type_name; - - /* look up the type declaration... */ - symbol_c *fb_decl = function_block_type_symtable.find_value(type_name); - if (fb_decl != function_block_type_symtable.end_value()) - /* Type declaration found!! */ - return fb_decl->accept(*this); - - /* No. It is not a function block, so we let - * the base class take care of it... - */ - return search_base_type_c::visit(type_name); -} + // if (NULL == current_type_id) ERROR; + + return NULL; +} + + + + /********************************/ /* B 1.3.3 - Derived data types */ /********************************/ - /* identifier ':' array_spec_init */ +/* NOTE: I don't think this will ever get called, since in the visit method for array_variable_c + * we use the basetype_decl for recursively calling this class, and the base type should never be a + * array_type_declaration_c, but for now, let's leave it in... + */ void *search_varfb_instance_type_c::visit(array_type_declaration_c *symbol) { - return symbol->array_spec_init->accept(*this); + ERROR; + return NULL; } /* array_specification [ASSIGN array_initialization] */ /* array_initialization may be NULL ! */ +/* NOTE: I don't think this will ever get called, since in the visit method for array_variable_c + * we use the basetype_decl for recursively calling this class, and the base type should never be a + * array_spec_init_c, but for now, let's leave it in... + */ void *search_varfb_instance_type_c::visit(array_spec_init_c *symbol) { - return symbol->array_specification->accept(*this); + /* Note that the 'array_specification' may be either an identifier of a previsously defined array type, + * or an array_specification_c, so we can not stop here and simply return a array_spec_init_c, + * especially if we are looking for the base class! + */ + ERROR; + return NULL; } /* ARRAY '[' array_subrange_list ']' OF non_generic_type_name */ +/* NOTE: This method will be reached after being called from the + * search_varfb_instance_type_c::visit(array_variable_c *symbol) + * method, so we must return the data type of the data stored in the array, + * and not the data type of the array itself! + */ void *search_varfb_instance_type_c::visit(array_specification_c *symbol) { - this->is_complex = true; - this->current_typeid = symbol; - return symbol->non_generic_type_name->accept(*this); -} + /* found the type of the element we were looking for! */ + current_type_id = symbol->non_generic_type_name; + current_basetype_decl = search_base_type.get_basetype_decl(current_type_id); + current_basetype_id = search_base_type.get_basetype_id (current_type_id); + + return NULL; +} + /* structure_type_name ':' structure_specification */ /* NOTE: this is only used inside a TYPE ... END_TYPE declaration. * It is never used directly when declaring a new variable! */ +/* NOTE: I don't think this will ever get called, since in the visit method for structured_variable_c + * we use the basetype_decl for recursively calling this class, and the base type should never be a + * structure_type_declaration_c, but for now, let's leave it in... + */ void *search_varfb_instance_type_c::visit(structure_type_declaration_c *symbol) { - this->is_complex = true; - - if (NULL == current_structelement_name) ERROR; - return symbol->structure_specification->accept(*this); + if (NULL == current_field_selector) ERROR; + symbol->structure_specification->accept(*this); + return NULL; /* NOTE: structure_specification will point to either a * initialized_structure_c * OR A @@ -301,82 +219,45 @@ */ } -/* var1_list ':' structure_type_name */ -void *search_varfb_instance_type_c::visit(structured_var_declaration_c *symbol) { - this->is_complex = true; - if (NULL != current_structelement_name) ERROR; - - /* make sure that we have decomposed all structure elements of the variable name */ - symbol_c *var_name = decompose_var_instance_name->next_part(); - if (NULL == var_name) { - /* this is it... ! - * No need to look any further... - * Note also that, unlike for the struct types, a function block may - * not be defined based on another (i.e. no inheritance is allowed), - * so this function block is already the most base type. - * We simply return it. - */ - return (void *)symbol; - } - - /* reset current_type_id because of new structure element part */ - this->current_typeid = NULL; - - /* look for the var_name in the structure declaration */ - current_structelement_name = var_name; - - /* recursively find out the data type of current_structelement_name... */ - return symbol->structure_type_name->accept(*this); -} - /* structure_type_name ASSIGN structure_initialization */ /* structure_initialization may be NULL ! */ // SYM_REF2(initialized_structure_c, structure_type_name, structure_initialization) -/* NOTE: only the initialized structure is ever used when declaring a new variable instance */ +/* NOTE: only the initialized structure is never used when declaring a new variable instance */ +/* NOTE: I don't think this will ever get called, since in the visit method for structured_variable_c + * we use the basetype_decl for recursively calling this class, and the base type should never be a + * initialized_structure_c, but for now, let's leave it in... + */ void *search_varfb_instance_type_c::visit(initialized_structure_c *symbol) { - this->is_complex = true; - if (NULL != current_structelement_name) ERROR; - - /* make sure that we have decomposed all structure elements of the variable name */ - symbol_c *var_name = decompose_var_instance_name->next_part(); - if (NULL == var_name) { - /* this is it... ! - * No need to look any further... - * Note also that, unlike for the struct types, a function block may - * not be defined based on another (i.e. no inheritance is allowed), - * so this function block is already the most base type. - * We simply return it. - */ - return (void *)symbol; - } - - /* reset current_type_id because of new structure element part */ - this->current_typeid = NULL; - - /* look for the var_name in the structure declaration */ - current_structelement_name = var_name; - - /* recursively find out the data type of current_structelement_name... */ - return symbol->structure_type_name->accept(*this); + if (NULL != current_field_selector) ERROR; + + /* recursively find out the data type of current_field_selector... */ + symbol->structure_type_name->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 *search_varfb_instance_type_c::visit(structure_element_declaration_list_c *symbol) { - if (NULL == current_structelement_name) ERROR; + if (NULL == current_field_selector) ERROR; + /* now search the structure declaration */ - return visit_list(symbol); + for(int i = 0; i < symbol->n; i++) { + symbol->elements[i]->accept(*this); + } + + return NULL; } /* structure_element_name ':' spec_init */ void *search_varfb_instance_type_c::visit(structure_element_declaration_c *symbol) { - if (NULL == current_structelement_name) ERROR; - - if (compare_identifiers(symbol->structure_element_name, current_structelement_name) == 0) { - current_structelement_name = NULL; + if (NULL == current_field_selector) ERROR; + + if (compare_identifiers(symbol->structure_element_name, current_field_selector) == 0) { /* found the type of the element we were looking for! */ - return symbol->spec_init->accept(*this); + current_type_id = symbol->spec_init; + current_basetype_decl = search_base_type.get_basetype_decl(current_type_id); + current_basetype_id = search_base_type.get_basetype_id (current_type_id); } /* Did not find the type of the element we were looking for! */ @@ -392,6 +273,79 @@ void *search_varfb_instance_type_c::visit(structure_element_initialization_c *symbol) {ERROR; return NULL;} /* should never get called... */ +/*********************/ +/* B 1.4 - Variables */ +/*********************/ +// SYM_REF1(symbolic_variable_c, var_name) +void *search_varfb_instance_type_c::visit(symbolic_variable_c *symbol) { + symbol->var_name->accept(*this); + return NULL; +} + +/********************************************/ +/* B.1.4.1 Directly Represented Variables */ +/********************************************/ +// SYM_TOKEN(direct_variable_c) +/* We do not yet handle this. Will we ever need to handle it, as the data type of the direct variable is + * directly obtainable from the syntax of the direct variable itself? + */ + +/*************************************/ +/* B 1.4.2 - Multi-element variables */ +/*************************************/ +/* subscripted_variable '[' subscript_list ']' */ +// SYM_REF2(array_variable_c, subscripted_variable, subscript_list) +/* NOTE: when passed a array_variable_c, which represents some IEC61131-3 code similar to X[42] + * we must return the data type of the value _stored_ in the array. + * If you want to get the data type of the array itself (i.e. just the X variable, without the [42]) + * then this class must be called with the identifier_c 'X'. + */ +void *search_varfb_instance_type_c::visit(array_variable_c *symbol) { + /* determine the data type of the subscripted_variable... + * This should be an array_specification_c + * ARRAY [xx..yy] OF Stored_Data_Type + */ + symbol->subscripted_variable->accept(*this); + symbol_c *basetype_decl = current_basetype_decl; + this->init(); /* set all current_*** pointers to NULL ! */ + + /* Now we determine the 'Stored_Data_Type', i.e. the data type of the variable stored in the array. */ + if (NULL != basetype_decl) { + basetype_decl->accept(*this); + } + + return NULL; +} + + +/* record_variable '.' field_selector */ +/* WARNING: input and/or output variables of function blocks + * may be accessed as fields of a structured variable! + * Code handling a structured_variable_c must take this into account! + * (i.e. that a FB instance may be accessed as a structured variable)! + * + * WARNING: Status bit (.X) and activation time (.T) of STEPS in SFC diagrams + * may be accessed as fields of a structured variable! + * Code handling a structured_variable_c must take this into account + * (i.e. that an SFC STEP may be accessed as a structured variable)! + */ +// SYM_REF2(structured_variable_c, record_variable, field_selector) +void *search_varfb_instance_type_c::visit(structured_variable_c *symbol) { + symbol->record_variable->accept(*this); + symbol_c *basetype_decl = current_basetype_decl; + this->init(); /* set all current_*** pointers to NULL ! */ + + /* Now we search for the data type of the field... But only if we were able to determine the data type of the variable */ + if (NULL != basetype_decl) { + current_field_selector = symbol->field_selector; + basetype_decl->accept(*this); + current_field_selector = NULL; + } + + return NULL; +} + + /**************************************/ /* B.1.5 - Program organization units */ @@ -399,46 +353,53 @@ /*****************************/ /* B 1.5.2 - Function Blocks */ /*****************************/ + /* FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */ // SYM_REF4(function_block_declaration_c, fblock_name, var_declarations, fblock_body, unused) void *search_varfb_instance_type_c::visit(function_block_declaration_c *symbol) { - /* make sure that we have decomposed all structure elements of the variable name */ - symbol_c *var_name = decompose_var_instance_name->next_part(); - if (NULL == var_name) { - /* this is it... ! - * No need to look any further... - * Note also that, unlike for the struct types, a function block may - * not be defined based on another (i.e. no inheritance is allowed), - * so this function block is already the most base type. - * We simply return it. - */ - return (void *)symbol; - } - - /* reset current_type_id because of new structure element part */ - this->current_typeid = NULL; - - /* now search the function block declaration for the variable... */ - search_var_instance_decl_c search_decl(symbol); - symbol_c *var_decl = search_decl.get_decl(var_name); - if (NULL == var_decl) { - /* variable instance declaration not found! */ - return NULL; - } -#if 0 - /* We have found the declaration. - * Should we look any further? - */ - var_name = decompose_var_instance_name->next_part(); - if (NULL == var_name) { - /* this is it... ! */ - return base_type(var_decl); - } - - current_structelement_name = var_name; - /* recursively find out the data type of var_name... */ - return symbol->var_declarations->accept(*this); -#endif - /* carry on recursively, in case the variable has more elements to be decomposed... */ - return var_decl->accept(*this); -} + if (NULL == current_field_selector) ERROR; + + /* now search the function block declaration for the variable... */ + /* If not found, these pointers will all be set to NULL!! */ + search_var_instance_decl_c search_decl(symbol); + current_type_id = search_decl.get_decl(current_field_selector); + current_basetype_decl = search_base_type.get_basetype_decl(current_type_id); + current_basetype_id = search_base_type.get_basetype_id (current_type_id); + + return NULL; +} + + + +/*********************************************/ +/* B.1.6 Sequential function chart elements */ +/*********************************************/ +/* INITIAL_STEP step_name ':' action_association_list END_STEP */ +// SYM_REF2(initial_step_c, step_name, action_association_list) +/* NOTE: this method may be called from visit(structured_variable_c *symbol) method| */ +void *search_varfb_instance_type_c::visit(initial_step_c *symbol) { + if (NULL == current_field_selector) ERROR; + + identifier_c T("T"); + identifier_c X("X"); + + if (compare_identifiers(&T, current_field_selector) == 0) + current_type_id = &search_constant_type_c::time_type_name; + if (compare_identifiers(&X, current_field_selector) == 0) + current_type_id = &search_constant_type_c::bool_type_name; + + current_basetype_decl = search_base_type.get_basetype_decl(current_type_id); + current_basetype_id = search_base_type.get_basetype_id (current_type_id); + + return NULL; +} + + +/* STEP step_name ':' action_association_list END_STEP */ +// SYM_REF2(step_c, step_name, action_association_list) +/* NOTE: this method may be called from visit(structured_variable_c *symbol) method| */ +void *search_varfb_instance_type_c::visit(step_c *symbol) { + /* The code here should be identicial to the code in the visit(initial_step_c *) visitor! So we simply call the other visitor! */ + initial_step_c initial_step(NULL, NULL); + return initial_step.accept(*this); +}