Logo Search packages:      
Sourcecode: fauhdlc version File versions

NodeFactory.cpp

/* $Id: NodeFactory.cpp 4323 2009-01-27 13:48:12Z potyra $ 
 *
 * NodeFactory: helper scripts for the Parser to create AST nodes, mainly
 *              useful to keep lots of c++ code out of the parser.
 *
 * Copyright (C) 2007-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 <cassert>
#include <iostream>
#include "frontend/ast/NodeFactory.hpp"
#include "frontend/ast/SignalDeclaration.hpp"
#include "frontend/ast/ConstantDeclaration.hpp"
#include "frontend/ast/VarDeclaration.hpp"
#include "frontend/ast/ConstInteger.hpp"
#include "frontend/ast/WhileLoopStat.hpp"
#include "frontend/ast/SigAssignStat.hpp"
#include "frontend/ast/FunctionCall.hpp"
#include "frontend/reporting/ErrorRegistry.hpp"
#include "frontend/reporting/CompileError.hpp"
#include "frontend/reporting/UndefinedSymbol.hpp"
#include "frontend/misc/SymbolTable.hpp"
#include "frontend/misc/NameLookup.hpp"
#include "frontend/misc/BuiltinFunction.hpp"
#include "frontend/ast/EnumerationType.hpp"
#include "frontend/ast/FunctionDeclaration.hpp"
#include "frontend/visitor/ResolveTypes.hpp"
#include "frontend/ast/UnconstrainedArrayType.hpp"

namespace ast {

struct NodeFactory::IfHelperS& 
00036 NodeFactory::createNestedElseIfs(
      struct NodeFactory::IfHelperS* remainder,
      Expression* condition,
      std::list<SeqStat*>* thenStats,
      Location loc
) 
{
      struct NodeFactory::IfHelperS* ret = NULL;

      /* no parent elsif statements... create one */
      if (remainder == NULL) {
            ret = new NodeFactory::IfHelperS();
            ret->topstat = new IfStat(condition, thenStats, NULL, loc);
            ret->bottomElse = &(ret->topstat->elseStats);
            return *ret;
      }
      
      /* parent present. attach to bottom else */
      IfStat *bottomIf = new IfStat(condition, thenStats, NULL, loc);
      std::list<SeqStat*>* l = new std::list<SeqStat*>();
      l->push_back(bottomIf);
      
      *(remainder->bottomElse) = l;

      /* set old bottom else to new one */
      remainder->bottomElse = &(bottomIf->elseStats);
      
      return *remainder;
}

00066 IfStat& NodeFactory::createIfStat(
      Expression* condition,
      std::list<SeqStat*>* thenStats,
      struct NodeFactory::IfHelperS* elsIfs,
      std::list<SeqStat*>* elseStats,
      ast::Location loc
)
{
      IfStat* ret = NULL;

      /* trivial case: no eslIfs */
      if (elsIfs == NULL) {
            ret = new IfStat(condition, thenStats, elseStats, loc);
            return *ret;
      }

      /* remap elsIfs to nested if-else (part already done via elseIfs */
      /* sanity checks for parser */
      assert(elsIfs->topstat != NULL);
      assert(*(elsIfs->bottomElse) == NULL);

      /* elseif stats... should go to else part */
      std::list<SeqStat*>* ep = new std::list<SeqStat*>();
      ep->push_back(elsIfs->topstat);

      /* create real ifstat */
      ret = new IfStat(condition, thenStats, ep, loc);

      /* attach else-part to bottom most else-list */
      *(elsIfs->bottomElse) = elseStats;

      /* cleanup */
      delete elsIfs;

      return *ret;
}


std::list<SignalDeclaration*>& 
00105 NodeFactory::makeSignalDecls(
      std::list<std::string*>& ids,
      enum ValDeclaration::Mode mode, 
      bool isBus, 
      Expression* varInit,
      SubtypeIndication* subtypeIndic,
      Location loc
)
{
      std::list<SignalDeclaration*> *v = 
                  new std::list<SignalDeclaration*>();

      for (std::list<std::string*>::iterator i = ids.begin();
           i != ids.end(); i++) {

            SignalDeclaration *s = 
                  new SignalDeclaration(*i, mode, isBus, varInit,
                              subtypeIndic, loc);
            v->push_back(s);
            assert(subtypeIndic);
      }
      util::MiscUtil::terminate(varInit);
      util::MiscUtil::terminate(subtypeIndic);

      return *v;
}

std::list<ConstantDeclaration*>& 
00133 NodeFactory::makeConstantDecls(
      std::list<std::string*>& ids,
      Expression* varInit,
      SubtypeIndication* subtypeIndic,
      Location loc
)
{
      std::list<ConstantDeclaration*> *v = 
                  new std::list<ConstantDeclaration*>();

      for (std::list<std::string*>::iterator i = ids.begin();
           i != ids.end(); i++) {

            ConstantDeclaration *s = 
                  new ConstantDeclaration(*i, varInit, subtypeIndic, 
                                    true, loc);
            v->push_back(s);
            assert(subtypeIndic);
      }

      util::MiscUtil::terminate(varInit);
      util::MiscUtil::terminate(subtypeIndic);

      return *v;
}

std::list<SymbolDeclaration*>& 
00160 NodeFactory::makeVarDecls(
      std::list<std::string*>& ids,
      Expression* varInit,
      SubtypeIndication* subtypeIndic,
      Location loc
)
{
      std::list<SymbolDeclaration*> *v = 
            new std::list<SymbolDeclaration*>();

      for (std::list<std::string*>::iterator i = ids.begin();
           i != ids.end(); i++) {

            VarDeclaration *s = new VarDeclaration(
                              ValDeclaration::MODE_INOUT,
                              *i,
                              varInit,
                              subtypeIndic,
                              loc
                              );

            v->push_back(s);
            assert(subtypeIndic);
      }

      util::MiscUtil::terminate(varInit);
      util::MiscUtil::terminate(subtypeIndic);

      return *v;
}

std::list<ValDeclaration*>&
00192 NodeFactory::makeFuncInterfaceDecls(
      std::list<std::string*>& ids,
      Expression* varInit,
      enum ValDeclaration::Mode mode,
      enum ValDeclaration::ObjClass cls,
      SubtypeIndication* subtypeIndic,
      Location loc
)
{
      std::list<ValDeclaration*> *v = new std::list<ValDeclaration*>();
      if (mode != ValDeclaration::MODE_IN) {
            assert(! ids.empty());
            // only in is allowed for functions.
            CompileError *ce = new CompileError(loc, 
                        "Wrong parameter mode for argument <"
                        + *ids.front() + ">, setting to IN.");
            ErrorRegistry::addError(ce);
      }

      for (std::list<std::string*>::iterator i = ids.begin();
           i != ids.end(); i++) {
            ValDeclaration *s = NULL;
            /* no class -> constant
                 mode always in
            */
            switch (cls) {
            case ValDeclaration::OBJ_CLASS_VARIABLE: {
                  CompileError* ce = new CompileError(loc,
                              "Object class VARIABLE not allowed "
                              "for Function argument <"
                              + **i + ">, using CONSTANT.");
                  ErrorRegistry::addError(ce);
                  /* fall through */
                }
            case ValDeclaration::OBJ_CLASS_UNSPECIFIED:
            case ValDeclaration::OBJ_CLASS_CONSTANT:
                  s = new ConstantDeclaration(*i, varInit, 
                                    subtypeIndic, 
                                    false, loc);
                  break;

            case ValDeclaration::OBJ_CLASS_SIGNAL:
                  s = new SignalDeclaration(*i, 
                                    ValDeclaration::MODE_IN,
                                    false, 
                                    varInit,
                                    subtypeIndic,
                                    loc
                                    );
                  break;

            }

            v->push_back(s);
            assert(subtypeIndic);
      }
      util::MiscUtil::terminate(varInit);
      util::MiscUtil::terminate(subtypeIndic);

      return *v;
}

std::list<ValDeclaration*>&
00255 NodeFactory::makeProcInterfaceDecls(
      std::list<std::string*>& ids,
      Expression* varInit,
      enum ValDeclaration::Mode mode,
      enum ValDeclaration::ObjClass cls,
      SubtypeIndication* subtypeIndic,
      Location loc
)
{
      std::list<ValDeclaration*> *v = new std::list<ValDeclaration*>();

      for (std::list<std::string*>::iterator i = ids.begin();
           i != ids.end(); i++) {
            ValDeclaration *s = NULL;
            /* no class -> in -> constant 
                               others -> variable 
               NOTE: it's unclear what the default mode of an interface
                         element of a procedure is, in case no class is given.
                         FAUhdlc will choose MODE_IN here.
                   cf. IEEE Standard VHDL Language Reference Manual 
                         (ISBN 1-55397-376-8), p. 20
            */
            switch (cls) {
            case ValDeclaration::OBJ_CLASS_UNSPECIFIED:
                  if (mode == ValDeclaration::MODE_IN) {
                        s = new ConstantDeclaration(*i, varInit, 
                                    subtypeIndic, false, loc);
                        /* TODO issue warning if mode != MODE_IN */
                  } else {
                        s = new VarDeclaration(mode, *i, varInit,
                                          subtypeIndic, loc);
                  }
                  break;

            case ValDeclaration::OBJ_CLASS_VARIABLE:
                  s = new VarDeclaration(mode, *i, varInit, 
                                    subtypeIndic, loc);
                  break;

            case ValDeclaration::OBJ_CLASS_SIGNAL:
                  s = new SignalDeclaration(*i, mode, false, varInit, 
                                    subtypeIndic, loc);
                  break;

            case ValDeclaration::OBJ_CLASS_CONSTANT:
                  s = new ConstantDeclaration(*i, varInit, 
                                    subtypeIndic, false, loc);
                  switch (mode) {
                  case ValDeclaration::MODE_IN:
                        break;

                  default: {
                        CompileError *ce = new CompileError(loc, 
                                    "Object class constant for <"
                                    + **i + "> must "
                                    "be of mode IN.");
                        ErrorRegistry::addError(ce);
                      }
                  }
                  break;

            }

            assert(subtypeIndic);
            v->push_back(s);
      }

      util::MiscUtil::terminate(varInit);
      util::MiscUtil::terminate(subtypeIndic);
      
      return *v;
}


struct NodeFactory::ContextItemS&
00330 NodeFactory::mergeContextItems(
      struct NodeFactory::ContextItemS& first, 
      struct NodeFactory::ContextItemS& second
)
{
      if (first.libClauses && second.libClauses) {
            listCombine(first.libClauses, second.libClauses);
            delete second.libClauses;
      }

      if (first.libClauses == NULL) {
            first.libClauses = second.libClauses;
      }

      if (first.useClauses && second.useClauses) {
            listCombine(first.useClauses, second.useClauses);
            delete second.useClauses;
      }
      
      if (first.useClauses == NULL) {
            first.useClauses = second.useClauses;
      }

      delete &second;

      return first;
}

CondalSigAssign&
00359 NodeFactory::makeCondalSigAssign(Name& trg, SeqStat& conds, Location loc)
{
      CondalSigAssign& ret = *(new CondalSigAssign(&trg, &conds, loc));
      NodeFactory::CondalSigAssignSetter setter = 
            NodeFactory::CondalSigAssignSetter(trg);
      ret.accept(setter);
      return ret;
}


void
00370 NodeFactory::CondalSigAssignSetter::visit(SigAssignStat &node)
{
      assert(node.target == NULL); // parser is wrong otherwise.
      node.target = &(this->target);
      /* _don't_ traverse here. (as it's not of our concern below.) */
}

std::list<RecordTypeElement*>&
00378 NodeFactory::makeRecordTypeElements(
      std::list<std::string*> &idlist,
      SubtypeIndication &subtype,
      Location loc
)
{
      std::list<RecordTypeElement*> *result = 
                  new std::list<RecordTypeElement*>();

      for (std::list<std::string*>::iterator i = idlist.begin();
            i != idlist.end(); i++) {

            result->push_back(
                  new RecordTypeElement(*i, &subtype, loc));
      }

      SubtypeIndication* si = &subtype;
      util::MiscUtil::terminate(si);

      return *result;
}

Aggregate*
00401 NodeFactory::makeAggregateFromString(
      const std::string &stringLit,
      Location loc,
      const NameLookup &nl
)
{
      std::list<ElementAssociation*> *elements = 
                  new std::list<ElementAssociation*>();
      
      for (std::string::const_iterator i = stringLit.begin(); 
            i != stringLit.end(); i++) {

            std::string *s = new std::string("'");
            s->append(std::string(1, *i));
            s->append("'");

            std::list<Symbol*> cands = nl.lookup(*s);
            if (cands.empty()) {
                  UndefinedSymbol *us = new UndefinedSymbol(*s, loc);
                  ErrorRegistry::addError(us);
            }

            FunctionCall *fc = 
                  new FunctionCall(
                        new SimpleName(
                              s,
                              cands,
                              loc),
                        new std::list<AssociationElement*>(),
                        loc);

            ElementAssociation* assoc = 
                  new ElementAssociation(NULL, fc, loc);
            elements->push_back(assoc);
      }

      return new Aggregate(elements, loc);
}


void
00442 NodeFactory::registerEnumElems(
      const EnumerationType *e,
      SymbolTable &symbolTable,
      Symbol *typeSym
)
{
      assert(e);
      assert(e->elements);

      for (std::list<EnumerationElement*>::const_iterator i = 
            e->elements->begin(); i != e->elements->end(); i++) {

            //register the corresponding function for enumeration
            //elements.
            SimpleName *sn = new SimpleName(new std::string(*e->name),
                                    e->location);
            sn->candidates.push_back(typeSym);
            SubtypeIndication *si = new SubtypeIndication(sn,
                                          (*i)->location);
            FunctionDeclaration *f = new FunctionDeclaration(
                                    new std::string(*(*i)->name),
                                    NULL,
                                    si,
                                    true,
                                    (*i)->location);
            f->isBuiltin = true;
            f->builtin = new ReturnValue((*i)->value, e);

            symbolTable.registerSymbol(SYMBOL_FUNCTION, *f);
      }
}

00474 NodeFactory::TypeDeclHelper::TypeDeclHelper(
      std::list<DiscreteRange*> *indexConstraint,
      SubtypeIndication *elementType,
      Location loc,
      SymbolTable &s
) :         enumType(NULL),
            typeDecl(NULL),
            conArrayBase(NULL),
            wasRecordType(false)
{

      std::list<TypeDeclaration*> *l = 
                        new std::list<TypeDeclaration*>();

      for (std::list<DiscreteRange*>::const_iterator i = 
            indexConstraint->begin(); i != indexConstraint->end(); i++) {
            // FIXME this is not 100% correct:
            // in case the result is a universal type, it should get
            // converted to integer.
            // For now, just assume that it's a universal type,
            // and require integer as a result.
            //
            // One problem is, that the type resolution is non-const in
            // itself. Maybe it should be rewritten in a const part,
            // and in a non-const part.
            ResolveTypes r = ResolveTypes(s);
            TypeDeclaration *stdInt = s.getStdStandardType("integer");
            assert(stdInt != NULL);
            r.typeCandidates.insert(stdInt);
            (*i)->accept(r);

            if ((*i)->type == NULL) {
                  // type error occured, bail out early
                  util::MiscUtil::lterminate(l);
                  return;
            }

            l->push_back((*i)->type);
      }
      
      // create base type: anonymous unconstrained array.
      std::string n = s.getMangledPathName() + "__constraint_base__";
      this->conArrayBase = new UnconstrainedArrayType(
                                    new std::string(n),
                                    l,
                                    elementType,
                                    loc);
      
      SubtypeIndication *t = new SubtypeIndication(this->conArrayBase, loc);
      t->indexConstraint = indexConstraint;
      this->typeDecl = t;
}

void
00528 NodeFactory::TypeDeclHelper::registerType(
      SymbolTable &symTab,
      NodeFactory::Identifier *id
) const
{
      assert(id);
      assert(id->identifier);

      if (this->enumType) {
            assert(this->typeDecl == NULL);
            this->enumType->name = id->identifier;
            Symbol *sym = symTab.registerSymbol(SYMBOL_TYPE, 
                                          *this->enumType);
            NodeFactory::registerEnumElems(this->enumType, symTab, sym);
            delete id;
            return;
      }

      // no enumeration type
      assert(this->enumType == NULL);
      if (this->typeDecl == NULL) {
            // type error must have been registered
            assert(false); // FIXME for debugging.
            return;
      }

      this->typeDecl->name = id->identifier;
      delete id;

      if (this->wasRecordType) {
            symTab.lateRegisterAttach(SYMBOL_TYPE, *this->typeDecl);
            // leave scope of record type
            symTab.popRegion();
            return;
      }

      // base type for constrained array present?
      if (this->conArrayBase != NULL) {
            symTab.registerSymbol(SYMBOL_TYPE, *this->conArrayBase);
      }

      // fall through: neither a record type, nor an enumeration type
      symTab.registerSymbol(SYMBOL_TYPE, *this->typeDecl);
}

std::list<SymbolDeclaration*>*
00574 NodeFactory::TypeDeclHelper::flatten(void) const
{
      std::list<SymbolDeclaration*> *ret = 
            new std::list<SymbolDeclaration*>();

      if (this->enumType) {
            ret->push_back(this->enumType);
            return ret;
      }

      if (this->conArrayBase != NULL) {
            ret->push_back(this->conArrayBase);
      }

      if (this->typeDecl == NULL) {
            // type error must have been registered.
            return ret;
      }
      ret->push_back(this->typeDecl);
      return ret;
}

AttributeSpecification *
00597 NodeFactory::handleAttributeSpecs(
      SimpleName *designator,
      std::list<SimpleName *> entityList,
      enum entityClassE classFilter,
      Expression *init,
      const SymbolTable &symTab
)
{
      // find out attribute by designator.
      for (std::list<Symbol *>::iterator i = designator->candidates.begin();
            i != designator->candidates.end(); /* nothing */) {

            switch ((*i)->type) {
            case SYMBOL_ATTRIBUTE:
                  i++;
                  break;

            default:
                  i = designator->candidates.erase(i);
            }
      }

      if (designator->candidates.size() != 1) {
            std::string s = "<" + *designator->name + "> does not refer"
                  " to an Attribute.";
            CompileError *ce = new CompileError(*designator, s);
            ErrorRegistry::addError(ce);
            return NULL;
      }

      AttributeDeclaration *decl = 
            dynamic_cast<AttributeDeclaration *>(
                  &designator->candidates.front()->declaration);
      assert(decl != NULL);

      AttributeSpecification *spec = 
            new AttributeSpecification(init, decl, designator->location);

      // attribute every referred to symbol that matches classFilter
      for (std::list<SimpleName*>::const_iterator i = entityList.begin(); 
            i != entityList.end(); i++) {

            assert((*i)->candidates.empty());
            assert((*i)->name != NULL);
            std::list<Symbol*> syms = symTab.lookup(*(*i)->name);

            if (syms.empty()) {
                  UndefinedSymbol *us = 
                        new UndefinedSymbol(*(*i)->name,
                                          (*i)->location);
                  ErrorRegistry::addError(us);
                  continue;
            }
            
            for (std::list<Symbol *>::const_iterator j = syms.begin(); 
                  j != syms.end(); j++) {

                  if (NodeFactory::isOfEntityClass(**j, classFilter)) {
                        AttributableDeclaration *ad =
                              dynamic_cast<AttributableDeclaration*>(
                                          &(*j)->declaration);
                        assert(ad != NULL);
                        // FIXME check if attribute already present
                        // and report error if so.
                        ad->attributes[*decl->name] = spec;
                  } else {
                        // FIXME if no "others"/"all" is present,
                        // report an error (LRM 5.1)
                  }
            }
      }

      return spec;
}

bool
00673 NodeFactory::isOfEntityClass(const Symbol &sym, enum entityClassE ec)
{
      switch (ec) {
      case EC_ENTITY:
            switch (sym.type) {
            case SYMBOL_ENTITY:
                  return true;

            default:
                  return false;
            }
            /* not reached */

      case EC_ARCHITECTURE:
            switch (sym.type) {
            case SYMBOL_ARCHITECTURE:
                  return true;

            default:
                  return false;
            }
            /* not reached */

      case EC_CONFIGURATION:
            assert(false);
            /* not reached */
      
      case EC_PROCEDURE:
            switch (sym.type) {
            case SYMBOL_PROCEDURE:
                  return true;

            default:
                  return false;
            }
            /* not reached */

      case EC_FUNCTION:
            switch (sym.type) {
            case SYMBOL_FUNCTION:
                  return true;

            default:
                  return false;
            }
            /* not reached */

      case EC_PACKAGE:
            switch (sym.type) {
            case SYMBOL_PACKAGE:
                  return true;

            default:
                  return false;
            }
            /* not reached */

      case EC_TYPE:
            switch (sym.type) {
            case SYMBOL_TYPE: {
                  /* must not be a subtype */
                  SubtypeIndication *si = 
                        dynamic_cast<SubtypeIndication*>(
                                          &sym.declaration);
                  return si == NULL;
                }
            default:
                  return false;
            }
            /* not reached */

      case EC_SUBTYPE:
            switch (sym.type) {
            case SYMBOL_TYPE: {
                  /* must be a subtype */
                  SubtypeIndication *si = 
                        dynamic_cast<SubtypeIndication*>(
                                          &sym.declaration);
                  return si != NULL;
                }
            default:
                  return false;
            }
            /* not reached */

      case EC_CONSTANT:
            switch (sym.type) {
            case SYMBOL_PARAMETER:
            case SYMBOL_VARIABLE: {
                  ValDeclaration *vd = 
                        dynamic_cast<ValDeclaration*>(
                                          &sym.declaration);
                  assert(vd != NULL);
                  switch (vd->storageClass) {
                  case ValDeclaration::OBJ_CLASS_CONSTANT:
                        return true;

                  default:
                        return false;
                  }
                  /* not reached */
                }
            default:
                  return false;
            }
            /* not reached */

      case EC_SIGNAL:
            switch (sym.type) {
            case SYMBOL_PORT:
            case SYMBOL_PARAMETER:
            case SYMBOL_SIGNAL: {
                  ValDeclaration *vd = 
                        dynamic_cast<ValDeclaration*>(
                                          &sym.declaration);
                  assert(vd != NULL);
                  switch (vd->storageClass) {
                  case ValDeclaration::OBJ_CLASS_SIGNAL:
                        return true;

                  default:
                        return false;
                  }
                  /* not reached */
                }
            default:
                  return false;
            }
            /* not reached */

      case EC_VARIABLE:
            switch (sym.type) {
            case SYMBOL_PARAMETER:
            case SYMBOL_VARIABLE: {
                  ValDeclaration *vd = 
                        dynamic_cast<ValDeclaration*>(
                                          &sym.declaration);
                  assert(vd != NULL);
                  switch (vd->storageClass) {
                  case ValDeclaration::OBJ_CLASS_VARIABLE:
                        return true;

                  default:
                        return false;
                  }
                  /* not reached */
                }
            default:
                  return false;
            }
            /* not reached */

      case EC_COMPONENT:
      case EC_LABEL:
      case EC_LITERAL:
      case EC_UNITS:
      case EC_GROUP:
      case EC_FILE:
            assert(false);
            /* not reached */ 
      }

      /* not reached */
      return false;
}

}; /* namespace ast */

Generated by  Doxygen 1.6.0   Back to index