Logo Search packages:      
Sourcecode: fauhdlc version File versions

NameLookup.cpp

/* $Id: NameLookup.cpp 4323 2009-01-27 13:48:12Z potyra $ 
 * NameLookup: Knows about VHDL names and how/where to look these up in the
 * symboltable (i.e. it can e.g. switch the scope for prefixed names etc.)
 *
 * Copyright (C) 2008-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */


#include "frontend/misc/NameLookup.hpp"
#include "frontend/misc/Symbol.hpp"
#include "frontend/ast/SimpleName.hpp"
#include "frontend/ast/SelectedName.hpp"
#include "frontend/ast/FunctionCall.hpp"
#include "frontend/ast/UnconstrainedArrayType.hpp"
#include "util/MiscUtil.hpp"
#include "frontend/ast/FunctionDeclaration.hpp"
#include "frontend/reporting/CompileError.hpp"
#include "frontend/reporting/ErrorRegistry.hpp"
#include "frontend/reporting/UndefinedSymbol.hpp"
#include "frontend/visitor/ResolveTypes.hpp"
#include "frontend/visitor/LookupTypes.hpp"
#include <set>
#include <sstream>

namespace ast {

00030 NameLookup::NameLookup(
      SymbolTable &symtab
) :         symbolTable(symtab),
            shiftedLookups(false)
{
}

void
00038 NameLookup::openRegion(Name *name) throw(CompileError)
{
      const SimpleName *sname = dynamic_cast<const SimpleName*>(name);

      assert(sname != NULL); /* logic error in parser */

      if (sname->candidates.size() > 1) {
            std::string msg = "Multiple definitions for Name '";
            msg += util::MiscUtil::toString(*name);
            msg += "'.";

            throw CompileError(*name, msg);
      }

      if (sname->candidates.empty()) {
            std::string msg = "Cannot find definition for Name '";
            msg += util::MiscUtil::toString(*name);
            msg += "'.";
            
            throw CompileError(*name, msg);
      }

      const Symbol *sym = sname->candidates.front();
      assert(sym->region != NULL); // logic error in parser

      this->symbolTable.pushRegion(*sym->region);
}

void
00067 NameLookup::shiftScope(Name &prefix, bool isFunction)
{
      this->shiftedLookups = true;
      //LRM: 6.3

      // hit by preference? symbol is an enclosing named entity
      // -> expanded name, nothing else considered.
      for(std::list<Symbol*>::const_iterator i = prefix.candidates.begin();
            i != prefix.candidates.end(); i++) {
            
            const DeclarativeRegion *current = 
                        this->symbolTable.getCurrentRegion();

            assert(current != NULL);
            if (current->isEnclosingSymbol(**i)) {
                  //immediate hit.
                  this->shiftExpanded(**i);
                  return;
            }
      }

      // is the prefix a function call? -> only selected name possible
      if (isFunction) {
            this->shiftSelectedScope(prefix);
            return;
      }

      // does the prefix denote a library/package?
      if (prefix.candidates.size() == 1) {
            switch(prefix.candidates.front()->type) {
            case SYMBOL_PACKAGE:
            case SYMBOL_LIBRARY:
                  this->shiftExpanded(*prefix.candidates.front());
                  return;
            default:
                  break;
            }
      }

      //remaining symbols must be selected names
      this->shiftSelectedScope(prefix);
}

ast::Callable*
00111 NameLookup::findOrRegisterSubprog(Callable* spec)
{
      enum symType t = SYMBOL_PROCEDURE;

      switch(spec->kind) {
      case SubprogBody::PROG_KIND_PROCEDURE:
            t = SYMBOL_PROCEDURE;
            break;

      case SubprogBody::PROG_KIND_FUNCTION:
            t = SYMBOL_FUNCTION;
            break;

      default:
            assert(false);
      }

      /* lookup if specification registered already. */
      assert(spec->name);
      bool found = false;
      Callable *c = NULL;

      std::list<Symbol*> ret = this->symbolTable.lookup(*spec->name);
      for (std::list<Symbol*>::const_iterator i = ret.begin(); 
            i != ret.end(); i++) {

            if ((*i)->type != t) {
                  continue;
            }

            switch(spec->kind) {
            case SubprogBody::PROG_KIND_PROCEDURE:
                  c = dynamic_cast<Callable*>(&(*i)->declaration);
                  found = this->conformProcSig(spec, c);
                  break;

            case SubprogBody::PROG_KIND_FUNCTION: {
                  FunctionDeclaration *f;
                  FunctionDeclaration *g;

                  f = dynamic_cast<FunctionDeclaration*>(
                                    &(*i)->declaration);
                  assert(f);
                  g = dynamic_cast<FunctionDeclaration*>(spec);
                  assert(g);

                  found = this->conformFuncSig(g, f);
                  c = f;
                  break;
                }
            default:
                  assert(false);
            }

            if (found) {
                  break;
            }
      }

      if (! found) {
            this->symbolTable.registerSymbolWithRegion(t, *spec);
            if (spec->arguments == NULL) {
                  return spec;
            }

            //register formals
            for (std::list<ValDeclaration*>::const_iterator i = 
                  spec->arguments->begin(); i != spec->arguments->end();
                  i++) {

                  this->symbolTable.registerSymbol(SYMBOL_PARAMETER, 
                                          **i);
            }
            return spec;
      }

      assert(c != NULL);
      assert(c->region != NULL);
      this->symbolTable.pushRegion(*c->region);
      c->seen = true;
      return c;
}

std::list<Symbol*>
00195 NameLookup::lookup(std::string &id) const
{
      if (! this->shiftedLookups) {
            assert(this->lookupScopes.empty());
            return this->symbolTable.lookup(id);
      }

      std::set<Symbol*> unionSet = std::set<Symbol*>();

      for (std::list<DeclarativeRegion*>::const_iterator i = 
            this->lookupScopes.begin(); i != this->lookupScopes.end();
            i++) {

            std::list<Symbol*> lu = (*i)->lookupLocal(id);
            if (! lu.empty()) {
                  unionSet.insert(lu.begin(), lu.end());
            }
      }

      std::list<Symbol*> ret;
      ret.insert(ret.end(), unionSet.begin(), unionSet.end());
      return ret;
}

void
00220 NameLookup::unshiftScope(void)
{
      this->lookupScopes.clear();
      this->shiftedLookups = false;
}

Name* 
00227 NameLookup::makeSelectedName(
      Expression *prefix,
      std::string *suffix,
      std::list<Symbol*> candidates,
      Location loc) const
{
      if (this->isExpanded) {
            SimpleName *s = dynamic_cast<SimpleName*>(prefix);
            assert(s); // otherwise isExpanded is wrong

            SimpleName *ret = new SimpleName(suffix, candidates, loc);
            if (*suffix == "all") {
                  //store candidates of prefix, to be used for use
                  //clauses
                  ret->candidates = s->candidates;
            }

            ret->prefixStrings = s->prefixStrings;
            ret->prefixStrings.push_back(s->name);
            s->name = NULL;
            s->prefixStrings.clear();

            util::MiscUtil::terminate(s);
            return ret;
      }

      //selected name
      return new SelectedName(suffix, prefix, candidates, loc);
}

void
00258 NameLookup::registerLibClauses(const std::list<SimpleName*> &libs)
{
      for (std::list<SimpleName*>::const_iterator i = libs.begin();
            i != libs.end(); i++) {

            if (! this->symbolTable.addlibrary(*(*i)->name)) {
                  std::string msg = "Library '" + *(*i)->name 
                              + "' not found.";
                  CompileError *err = new CompileError(*(*i), msg);
                  ErrorRegistry::addError(err);
            }
      }
}

void
00273 NameLookup::registerUseClauses(const std::list<Name*> &usecs)
{
      for (std::list<Name*>::const_iterator i = usecs.begin();
            i != usecs.end(); i++) {

            SimpleName *s = dynamic_cast<SimpleName*>(*i);
            if (s == NULL) {
                  // not an expanded name, report an error.
                  CompileError *ce = new CompileError(
                                    **i,
                                    "Wrong name in use-clause.");
                  ErrorRegistry::addError(ce);
                  return;
            }

            //need to resolve to exactly one symbol.
            if (s->candidates.empty()) {
                  // error was already reported.
                  continue;
            }

            // FIXME could be more than one symbols
            assert(s->candidates.size() == 1);
            Symbol *sym = s->candidates.front();

            // suffix "all"
            if (*s->name == "all") {
                  assert(sym->region);
                  this->symbolTable.importSymbols(*sym->region);

                  continue;
            }

            // FIXME potyra (this goes through to the parser): s.th. l.ike
            //       import x.'y' is also possible, which would be 
            //       a character enumeration literal.
            this->symbolTable.importSymbol(*sym);
      }

}

void
00315 NameLookup::shiftExpanded(const Symbol &sym)
{
      assert(sym.region != NULL);
      assert(this->lookupScopes.empty());

      this->lookupScopes.push_back(sym.region);
      this->isExpanded = true;
      assert(this->shiftedLookups);
}

std::list<Symbol*>
00326 NameLookup::shiftSubscriptCands(std::list<Symbol*> &cands, Location loc)
{
      std::list<Symbol*> result;

      for (std::list<Symbol*>::iterator i = cands.begin(); 
            i != cands.end(); /* nothing */) {
            
            Symbol *s = NameLookup::shiftSubscriptCand(*i);
            if (s == NULL) {
                  // not an array, remove candidate
                  i = cands.erase(i);
                  continue;
            }

            result.push_back(s);
            i++;
      }

      if (result.empty()) {
            CompileError *ce = new CompileError(
                              loc,
                              "Subscript to non-array");
            ErrorRegistry::addError(ce);
      }

      return result;
}

Symbol *
00355 NameLookup::shiftSubscriptCand(Symbol *candidate)
{
      LookupTypes lt = LookupTypes(true, false);
      candidate->declaration.accept(lt);

      const UnconstrainedArrayType *array = 
            dynamic_cast<const UnconstrainedArrayType*>(lt.declaration);

      if (array == NULL) {
            return NULL;
      }

      TypeDeclaration *container = array->containerType;
      assert(container != NULL);

      // FIXME: memory leak (noone will free this symbol)
      // the return value is a temporary symbol, which points only to the
      // TypeDeclaration in question and has it's region set.
      std::string *tn;

      if (container->name != NULL) {
            tn = new std::string(*container->name);
      } else {
            tn = new std::string("__temporary__");
      }
      Symbol *ret = new Symbol(tn,
                        SYMBOL_TYPE, 
                        container->region, // region unneeded
                        *container);

      return ret;
}

void
00389 NameLookup::shiftSelectedScope(Name &prefix)
{
      /* open scope of type of prefix */
      this->isExpanded = false;
      this->shiftedLookups = true;

      if (prefix.candidates.empty()) {
            /* unresolved symbol already reported. */
            return;
      }

      for (std::list<Symbol*>::const_iterator i = prefix.candidates.begin();
            i != prefix.candidates.end(); i++) {

            this->shiftSelectedSym(*i);
      }
}

void
00408 NameLookup::shiftSelectedSym(Symbol *prefixSym)
{
      LookupTypes lt = LookupTypes(true, false);
      prefixSym->declaration.accept(lt);

      if (lt.declaration == NULL) {
            return;
      }

      if (lt.declaration->region == NULL) {
            return;
      }

      this->lookupScopes.push_back(lt.declaration->region);
      assert(this->shiftedLookups);
}

/* FIXME for conform*: 
 *       according to LRM, 2.7 this check is not enough: 
 *       instead, lexical elements (!) have to get compared.
 */
bool
00430 NameLookup::conformProcSig(const Callable* a, const Callable* b)
{
      if ((a == NULL) || (b == NULL)) {
            return false;
      }

      return util::MiscUtil::listMatch(*a->arguments, *b->arguments, 
                              NameLookup::conformParameter);

}

bool
00442 NameLookup::conformFuncSig(
      const FunctionDeclaration* a,
      const FunctionDeclaration* b
)
{
      if (! NameLookup::conformProcSig(a, b)) {
            return false;
      }
      
      assert(a->returnType);
      assert(b->returnType);

      assert(a->returnType->typeName);
      assert(a->returnType->typeName->candidates.size() == 1);
      assert(b->returnType->typeName);
      assert(b->returnType->typeName->candidates.size() == 1);

      if (   a->returnType->typeName->candidates.front() 
          != b->returnType->typeName->candidates.front()) {

            return false;
      }

      return true;
}

bool
00469 NameLookup::conformParameter(
      const ValDeclaration* a, 
      const ValDeclaration* b
)
{
      assert(a);
      assert(b);

      if ((*a->name) != (*b->name)) {
            return false;
      }

      if (a->mode != b->mode) {
            return false;
      }

      if (a->storageClass != b->storageClass) {
            return false;
      }

      //compare pointers!
      assert(a->subtypeIndic);
      assert(b->subtypeIndic);
      assert(a->subtypeIndic->typeName);
      assert(b->subtypeIndic->typeName);
      assert(a->subtypeIndic->typeName->candidates.size() == 1);
      assert(b->subtypeIndic->typeName->candidates.size() == 1);
      
      if (   a->subtypeIndic->typeName->candidates.front() 
          != b->subtypeIndic->typeName->candidates.front()) {

            return false;
      }

      return true;
}

}; /* namespace ast */

Generated by  Doxygen 1.6.0   Back to index