etisserant@0: /*
Edouard@279:  *  matiec - a compiler for the programming languages defined in IEC 61131-3
etisserant@0:  *
Edouard@279:  *  Copyright (C) 2003-2011  Mario de Sousa (msousa@fe.up.pt)
Edouard@279:  *  Copyright (C) 2007-2011  Laurent Bessard and Edouard Tisserant
etisserant@0:  *
Edouard@279:  *  This program is free software: you can redistribute it and/or modify
Edouard@279:  *  it under the terms of the GNU General Public License as published by
Edouard@279:  *  the Free Software Foundation, either version 3 of the License, or
Edouard@279:  *  (at your option) any later version.
Edouard@279:  *
Edouard@279:  *  This program is distributed in the hope that it will be useful,
Edouard@279:  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
Edouard@279:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Edouard@279:  *  GNU General Public License for more details.
Edouard@279:  *
Edouard@279:  *  You should have received a copy of the GNU General Public License
Edouard@279:  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
Edouard@279:  *
etisserant@0:  *
etisserant@0:  * This code is made available on the understanding that it will not be
etisserant@0:  * used in safety-critical situations without a full and competent review.
etisserant@0:  */
etisserant@0: 
etisserant@0: /*
etisserant@0:  * A generic symbol table.
etisserant@0:  *
etisserant@0:  * This is used to create symbol tables such as a list of
etisserant@0:  * variables currently in scope, etc...
etisserant@0:  * Note that the list of previously defined funstions uses the
etisserant@0:  * dsymtable_c instead, as it requires the table to store duplicate values.
etisserant@0:  */
etisserant@0: 
etisserant@0: 
etisserant@0: #include <iostream>
etisserant@0: #include "symtable.hh"
etisserant@0: 
etisserant@0: 
etisserant@0: 
etisserant@0: /* A macro for printing out internal parser errors... */
etisserant@0: #define ERROR error_exit(__FILE__,__LINE__)
etisserant@0: /* function defined in main.cc */
etisserant@0: extern void error_exit(const char *file_name, int line_no);
etisserant@0: 
etisserant@0: 
etisserant@0: 
etisserant@0: 
etisserant@0: template<typename value_type, value_type null_value>
etisserant@0: symtable_c<value_type, null_value>::symtable_c(void) {inner_scope = NULL;}
etisserant@0: 
etisserant@0: 
etisserant@0:  /* clear all entries... */
etisserant@0: template<typename value_type, value_type null_value>
etisserant@0: void symtable_c<value_type, null_value>::reset(void) {
etisserant@0:   _base.clear();
etisserant@0: }
etisserant@0: 
etisserant@0:  /* create new inner scope */
etisserant@0: template<typename value_type, value_type null_value>
etisserant@0: void symtable_c<value_type, null_value>::push(void) {
etisserant@0:   if (inner_scope != NULL) {
etisserant@0:     inner_scope->push();
etisserant@0:   } else {
etisserant@0:     inner_scope = new symtable_c();
etisserant@0:   }
etisserant@0: }
etisserant@0: 
etisserant@0:   /* clear most inner scope */
etisserant@0:   /* returns 1 if this is the inner most scope	*/
etisserant@0:   /*         0 otherwise			*/
etisserant@0: template<typename value_type, value_type null_value>
etisserant@0: int symtable_c<value_type, null_value>::pop(void) {
etisserant@0:   if (inner_scope != NULL) {
etisserant@0:     if (inner_scope->pop() == 1) {
etisserant@0:       delete inner_scope;
etisserant@0:       inner_scope = NULL;
etisserant@0:     }
etisserant@0:     return 0;
etisserant@0:   } else {
etisserant@0:     _base.clear();
etisserant@0:     return 1;
etisserant@0:   }
etisserant@0: }
etisserant@0: 
etisserant@0: template<typename value_type, value_type null_value>
etisserant@0: void symtable_c<value_type, null_value>::set(const symbol_c *symbol, value_t new_value) {
etisserant@0:   if (inner_scope != NULL) {
etisserant@0:     inner_scope->set(symbol, new_value);
etisserant@0:     return;
etisserant@0:   }
etisserant@0: 
etisserant@0:   const token_c *name = dynamic_cast<const token_c *>(symbol);
etisserant@0:   if (name == NULL)
etisserant@0:     ERROR;
etisserant@0:   set(name->value, new_value);
etisserant@0: }
etisserant@0: 
etisserant@0: 
etisserant@0: template<typename value_type, value_type null_value>
etisserant@0: void symtable_c<value_type, null_value>::set(const char *identifier_str, value_t new_value) {
etisserant@0:   if (inner_scope != NULL) {
etisserant@0:     inner_scope->set(identifier_str, new_value);
etisserant@0:     return;
etisserant@0:   }
etisserant@0: 
etisserant@0:   // std::cout << "set_identifier(" << identifier_str << "): \n";
etisserant@0:   iterator i = _base.find(identifier_str);
etisserant@0:   if (i == _base.end())
etisserant@0:     /* identifier not already in map! */
etisserant@0:     ERROR;
etisserant@0: 
etisserant@0:   _base[identifier_str] = new_value;
etisserant@0: }
etisserant@0: 
etisserant@0: template<typename value_type, value_type null_value>
etisserant@0: void symtable_c<value_type, null_value>::insert(const char *identifier_str, value_t new_value) {
etisserant@0:   if (inner_scope != NULL) {
etisserant@0:     inner_scope->insert(identifier_str, new_value);
etisserant@0:     return;
etisserant@0:   }
etisserant@0: 
etisserant@0:   // std::cout << "store_identifier(" << identifier_str << "): \n";
etisserant@0:   std::pair<const char *, value_t> new_element(identifier_str, new_value);
etisserant@0:   std::pair<iterator, bool> res = _base.insert(new_element);
etisserant@0:   if (!res.second)
etisserant@0:     /* error inserting new identifier... */
etisserant@0:     /* identifier already in map?        */
etisserant@0:     ERROR;
etisserant@0: }
etisserant@0: 
etisserant@0: template<typename value_type, value_type null_value>
etisserant@0: void symtable_c<value_type, null_value>::insert(const symbol_c *symbol, value_t new_value) {
etisserant@0: /*
etisserant@0: // not required...
etisserant@0:   if (inner_scope != NULL) {
etisserant@0:     inner_scope->insert(symbol, new_value);
etisserant@0:     return;
etisserant@0:   }
etisserant@0: */
etisserant@0:   const token_c *name = dynamic_cast<const token_c *>(symbol);
etisserant@0:   if (name == NULL)
etisserant@0:     ERROR;
etisserant@0:   insert(name->value, new_value);
etisserant@0: }
etisserant@0: 
etisserant@0: 
etisserant@0: 
etisserant@0: /* returns null_value if not found! */
etisserant@0: template<typename value_type, value_type null_value>
etisserant@0: value_type symtable_c<value_type, null_value>::find_value(const char *identifier_str) {
etisserant@0:   if (inner_scope != NULL) {
etisserant@0:     value_t token = inner_scope->find_value(identifier_str);
etisserant@0:     if (token != null_value)
etisserant@0:       /* found in the lower level */
etisserant@0:       return token;
etisserant@0:   }
etisserant@0: 
etisserant@0:   /* if no lower level, or not found in lower level... */
etisserant@0:   iterator i = _base.find(identifier_str);
etisserant@0: 
etisserant@0:   if (i == _base.end())
etisserant@0:     return null_value;
etisserant@0:   else
etisserant@0:     return i->second;
etisserant@0: }
etisserant@0: 
etisserant@0: 
etisserant@0: template<typename value_type, value_type null_value>
etisserant@0: value_type symtable_c<value_type, null_value>::find_value(const symbol_c *symbol) {
etisserant@0:   const token_c *name = dynamic_cast<const token_c *>(symbol);
etisserant@0:   if (name == NULL)
etisserant@0:     ERROR;
etisserant@0:   return find_value(name->value);
etisserant@0: }
etisserant@0: 
etisserant@0: 
etisserant@0: /* debuging function... */
etisserant@0: template<typename value_type, value_type null_value>
etisserant@0: void symtable_c<value_type, null_value>::print(void) {
etisserant@0:   for(iterator i = _base.begin();
etisserant@0:       i != _base.end();
etisserant@0:       i++)
etisserant@0:     std::cout << i->second << ":" << i->first << "\n";
etisserant@0:   std::cout << "=====================\n";
etisserant@0: 
etisserant@0:   if (inner_scope != NULL) {
etisserant@0:     inner_scope->print();
etisserant@0:   }
etisserant@0: }
etisserant@0: 
etisserant@0: 
etisserant@0: 
etisserant@0: 
etisserant@0: 
etisserant@0: 
etisserant@0: 
etisserant@0: 
etisserant@0: