Logo Search packages:      
Sourcecode: fauhdlc version File versions

GenCode.cpp

/* $Id: GenCode.cpp 4338 2009-01-30 15:54:44Z potyra $ 
 *
 * Code generator, which transforms the abstract syntax tree into intermediate
 * code.
 *
 * 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/visitor/GenCode.hpp"
#include <cassert>
#include <cmath>
#include "frontend/misc/RangeSet.hpp"
#include "frontend/misc/Driver.hpp"
#include "frontend/ast/VarAssignStat.hpp"
#include "frontend/ast/ConstInteger.hpp"
#include "frontend/ast/ConstReal.hpp"
#include "frontend/ast/SimpleName.hpp"
#include "frontend/ast/AttributeName.hpp"
#include "frontend/ast/Subscript.hpp"
#include "frontend/ast/Slice.hpp"
#include "frontend/ast/SelectedName.hpp"
#include "frontend/ast/IfStat.hpp"
#include "frontend/ast/RecordType.hpp"
#include "frontend/ast/RangeConstraintType.hpp"
#include "frontend/ast/UnconstrainedArrayType.hpp"
#include "frontend/ast/PhysicalType.hpp"
#include "frontend/ast/EnumerationType.hpp"
#include "frontend/ast/FunctionCall.hpp"
#include "frontend/ast/Process.hpp"
#include "frontend/ast/SigAssignStat.hpp"
#include "frontend/ast/Aggregate.hpp"
#include "frontend/ast/ReturnStat.hpp"
#include "frontend/ast/SubtypeIndication.hpp"
#include "frontend/ast/ForLoopStat.hpp"
#include "frontend/ast/WhileLoopStat.hpp"
#include "frontend/ast/NextStat.hpp"
#include "frontend/ast/ExitStat.hpp"
#include "frontend/ast/ConstantDeclaration.hpp"
#include "frontend/ast/Architecture.hpp"
#include "frontend/ast/CompInstStat.hpp"
#include "frontend/ast/Package.hpp"
#include "frontend/ast/WaitStat.hpp"
#include "frontend/ast/AssertStat.hpp"
#include "frontend/ast/Entity.hpp"
#include "frontend/ast/ConstArray.hpp"
#include "frontend/ast/ProcCallStat.hpp"
#include "frontend/ast/AttributeSpecification.hpp"
#include "frontend/ast/CaseStat.hpp"
#include "frontend/ast/Others.hpp"
#include "frontend/reporting/ErrorRegistry.hpp"
#include "frontend/reporting/CompileError.hpp"
#include "frontend/visitor/GCArrays.hpp"
#include "frontend/visitor/GCTypes.hpp"
#include "frontend/visitor/GCLoops.hpp"
#include "frontend/visitor/ResolveAggregates.hpp"
#include "frontend/visitor/GCBuiltins.hpp"
#include "frontend/visitor/ResolveTypes.hpp"
#include "frontend/visitor/LookupTypes.hpp"
#include "intermediate/operands/ImmediateOperand.hpp"
#include "intermediate/operands/IndirectOperand.hpp"
#include "intermediate/operands/Reference.hpp"
#include "intermediate/operands/RegisterFactory.hpp"
#include "intermediate/opcodes/Abort.hpp"
#include "intermediate/opcodes/Mov.hpp"
#include "intermediate/opcodes/Je.hpp"
#include "intermediate/opcodes/Jne.hpp"
#include "intermediate/opcodes/Jb.hpp"
#include "intermediate/opcodes/Jbe.hpp"
#include "intermediate/opcodes/Jmp.hpp"
#include "intermediate/opcodes/IMul.hpp"
#include "intermediate/opcodes/Add.hpp"
#include "intermediate/opcodes/Sub.hpp"
#include "intermediate/opcodes/Connect.hpp"
#include "intermediate/opcodes/SetParam.hpp"
#include "intermediate/opcodes/GetParam.hpp"
#include "intermediate/opcodes/BeginTransfer.hpp"
#include "intermediate/opcodes/EndTransfer.hpp"
#include "intermediate/opcodes/Call.hpp"
#include "intermediate/opcodes/Proc.hpp"
#include "intermediate/opcodes/Return.hpp"
#include "intermediate/opcodes/Update.hpp"
#include "intermediate/opcodes/GetSig.hpp"
#include "intermediate/opcodes/ROffset.hpp"
#include "intermediate/opcodes/Suspend.hpp"
#include "intermediate/opcodes/WakeAt.hpp"
#include "intermediate/opcodes/WakeOn.hpp"
#include "intermediate/opcodes/Log.hpp"
#include "intermediate/container/Label.hpp"
#include "intermediate/container/LabelFactory.hpp"
#include "intermediate/container/Data.hpp"
#include "intermediate/container/TypeFactory.hpp"
#include "intermediate/container/Type.hpp"
#include "intermediate/container/TypeElement.hpp"

namespace ast {

/* import some names into current namespace, just to avoid lengthy types */
using namespace intermediate;

00103 GenCode::GenCode() :    container(new intermediate::CodeContainer("top")),
                  assignExpression(false),
                  isTarget(false),
                  sourceRegs(RegisterSet(*container)),
                  destRegs(RegisterSet(*container)),
                  dataOp(NULL),
                  currentProcess(NULL),
                  currentSubprog(NULL),
                  assignOperation(ASSIGN_OPERATION_COPY)
{
}

// FIXME eventually separate expression handling from rest.
00116 GenCode::GenCode(CodeContainer *cc) :     container(cc),
                              assignExpression(false),
                              isTarget(false),
                              sourceRegs(RegisterSet(*cc)),
                              destRegs(RegisterSet(*cc)),
                              dataOp(NULL),
                              currentProcess(NULL),
                              currentSubprog(NULL),
                              assignOperation(ASSIGN_OPERATION_COPY)
{
}

void
00129 GenCode::visit(Package &node)
{
      if (node.declarations != NULL) {
            this->listTraverse(*node.declarations);
      }

      if (node.body != NULL) {
            node.body->accept(*this);
      }
}

void
00141 GenCode::visit(Architecture &node)
{
      assert(node.entity != NULL);
      assert(this->archComponents.empty());
      CodeContainer *current = this->container;
      this->container = new CodeContainer(node.entity->getICName());

      // handle entity specific parts.
      // FIXME: in case more than one architecture per entity is present,
      //        this won't work! (however that should actually be filtered
      //        out with configurations)
      this->container->dataMode = CodeContainer::DATA_TRANSFER;
      if (node.entity->generics != NULL) {
            this->listTraverse(*node.entity->generics);
      }
      if (node.entity->ports != NULL) {
            this->listTraverse(*node.entity->ports);
      }

      this->container->dataMode = CodeContainer::DATA_STACK;
      if (node.entity->declarations != NULL) {
            this->listTraverse(*node.entity->declarations);
      }

      // FIXME what creation/deletion functions must be present
      //       for a corresponding component instantiation statement?
      // there should be at least an architecture_name_init function
      // that runs the subhierarchy
      // eventually an architecture_name_create function would be
      // suitable as well.
      if (node.declarations != NULL) {
            this->listTraverse(*node.declarations);
      }

      if (node.concurrentStats != NULL) {
            this->listTraverse(*node.concurrentStats);
      }

      this->createInitFunction(node);

      current->addChild(this->container);
      this->container = current;
      this->archComponents.clear();
}

void
00187 GenCode::visit(Entity &node)
{
      // do nothing, handled by Architecture already
}

void
00193 GenCode::createInitFunction(const Architecture &node)
{
      assert(node.entity != NULL);

      this->instantiateComponents(node);
      Return *ret = new Return();
      this->container->addCode(ret);
}

void
00203 GenCode::instantiateComponents(const Architecture &node)
{
      for (std::list<CompInstStat*>::const_iterator i = 
            this->archComponents.begin();
            i != this->archComponents.end(); i++) {

            this->instantiateComponent(**i);
      }
}

void
00214 GenCode::instantiateComponent(CompInstStat &node)
{     
      assert(node.entity != NULL);
      Reference *ref;

      AttributeSpecification *foreign = node.entity->hasAttr("foreign");

      if (foreign != NULL) {
            assert(foreign->init != NULL);
            ConstArray *fVal = dynamic_cast<ConstArray *>(foreign->init);
            assert(fVal != NULL);
            ref = new Reference(fVal->unsafeMakeString());
      } else {
            ref = new Reference(node.entity->getICName());
      }

      assert(node.name != NULL);
      BeginTransfer *bg = new BeginTransfer(ref, new Reference(*node.name));
      this->container->addCode(bg);

      if (node.genericMap != NULL) {
            this->setGenericMap(ref, *node.genericMap, foreign != NULL);
      }     
      if (node.portMap != NULL) {
            this->setPortList(ref, *node.portMap, foreign != NULL);
      }

      Call *call = new Call(ref);
      this->container->addCode(call);
      EndTransfer *et = new EndTransfer(ref, ImmediateOperand::getZero());
      this->container->addCode(et);

      if (foreign != NULL) {
            bg->annotate("foreign", "entity");
            assert(node.name != NULL);
            call->annotate("foreign", "entity");
            et->annotate("foreign", "entity");
      }

}

void
00256 GenCode::setGenericMap(
      Reference *cont,
      std::list<AssociationElement*> &genericMap,
      bool isForeign
)
{
      assert(cont != NULL);
      const char *foreign = NULL;
      if (isForeign) {
            foreign = "generic";
      }

      for (std::list<AssociationElement*>::const_iterator i = 
            genericMap.begin();
            i != genericMap.end(); i++) {

            this->sourceRegs = RegisterSet(*this->container);

            switch ((*i)->actual->baseType) {
            case BASE_TYPE_REAL:
            case BASE_TYPE_INTEGER:
            case BASE_TYPE_ENUM:
                  this->setArgByValue(cont, NULL, **i, foreign, false);
                  break;

            case BASE_TYPE_ARRAY:
            case BASE_TYPE_RECORD:
                  /* need hidden formal for this */
                  std::cerr << __func__ << " not implemented yet FIXME!"
                        << std::endl;
                  break;

            default:
                  assert(0);
            }
      }
}

void
00295 GenCode::setPortList(
      Reference *cont,
      std::list<AssociationElement*> &portList,
      bool isForeign
)
{
      assert(cont != NULL);
      // this method assumes that the port list has already been 
      // normalized, so that it just contains single port elements.
      // FIXME this won't work with conversion functions.
      this->isTarget = false;

      const char *foreign;
      if (isForeign) {
            foreign = "port";
      } else {
            foreign = NULL;
      }

      for (std::list<AssociationElement*>::const_reverse_iterator i = 
            portList.rbegin(); i != portList.rend(); i++) {
            
            this->sourceRegs = RegisterSet(*this->container);

            assert((*i)->formal != NULL);
            assert((*i)->actual != NULL);
            switch ((*i)->formal->baseType) {
            case BASE_TYPE_REAL:
            case BASE_TYPE_INTEGER:
            case BASE_TYPE_ENUM:
                  this->setArgByPointer(cont, NULL, **i, foreign);
                  break;

            case BASE_TYPE_ARRAY:
            case BASE_TYPE_RECORD:
                  this->setArgByBasePointer(cont, NULL, **i, foreign);
                  break;

            default:
                  // must not happen
                  assert(0);
            }
      }
}

void
00341 GenCode::createInitFunction(const Process &node)
{
      for (std::list<Driver*>::const_iterator i = node.drivers.begin();
            i != node.drivers.end(); i++) {

            this->sourceRegs = RegisterSet(*this->container);
            // even though the signal and the driver are known,
            // the way how to access these is not (pointer, or
            // base-pointer?). (ok, driver of a Process should
            // always be directly via the reference, as it
            // cannot be a parameter!)
            // reuse the SimpleName stored in the driver to
            // find out.

            // first pick up destination driver (the 
            // SimpleName is used to obtain the signal
            // *and* the driver depending on isTarget)
            this->assignOperation = ASSIGN_OPERATION_CONNECT;
            this->isTarget = true;
            this->assignExpression = false;
            assert((*i)->n != NULL);
            (*i)->n->accept(*this);

            // then pick up the source signal.
            this->destRegs = this->sourceRegs;
            this->sourceRegs = RegisterSet(*this->container);
            this->isTarget = false;
            this->assignExpression = true;
            (*i)->n->accept(*this);
      }

      this->assignExpression = false;
      this->assignOperation = ASSIGN_OPERATION_COPY;
      this->sourceRegs = RegisterSet(*this->container);
      this->destRegs = RegisterSet(*this->container);
      
      Reference *ref = new Reference(node.getICName());
      BeginTransfer *bg = new BeginTransfer(ref, new Reference(""));
      this->container->addCode(bg);

      Proc *proc = new Proc(ref);
      this->container->addCode(proc);

      EndTransfer *et = new EndTransfer(ref, ImmediateOperand::getZero());
      this->container->addCode(et);
}

void
00389 GenCode::visit(CompInstStat &node)
{
      assert(node.entity != NULL);
      assert(node.name != NULL);

      this->archComponents.push_back(&node);
      // the real instantiation is done via the init-function so no need for
      // anything else here.
}

void
00400 GenCode::visit(VarAssignStat &node)
{
      this->sourceRegs = RegisterSet(*this->container);
      this->destRegs = RegisterSet(*this->container);

      // traverse to target, storing result in reg
      this->assignExpression = false;
      this->isTarget = true;
      node.target->accept(*this);

      this->destRegs = this->sourceRegs;

      // traverse to source, storing result in reg
      this->assignExpression = true;
      this->isTarget = false;
      node.source->accept(*this);

      // FIXME aggregate assignments (i.e. with an aggregate as target)
      //       are currently not supported.
}

void
00422 GenCode::visit(SigAssignStat &node)
{
      this->sourceRegs = RegisterSet(*this->container);
      this->destRegs = RegisterSet(*this->container);

      assert(node.target);
      assert(node.waveForm);

      this->isTarget = true;
      this->assignExpression = false;
      node.target->accept(*this);
      this->destRegs = this->sourceRegs;

      this->isTarget = false;

      //traverse to waveform elements
      for (std::list<WaveFormElem*>::const_iterator i = 
            node.waveForm->begin(); i != node.waveForm->end(); i++) {
      
            this->sourceRegs = RegisterSet(*this->container);
            if ((*i)->delay != NULL) {
                  (*i)->accept(*this);
                  this->dataOp = 
                        this->sourceRegs.getValue(
                                    (*i)->delay->baseType);
                  this->sourceRegs = RegisterSet(*this->container);
            } else {
                  this->dataOp = ImmediateOperand::getZero();
            }
            this->assignExpression = true;
            assert((*i)->value != NULL);
            (*i)->value->accept(*this);   
      }

      this->dataOp = NULL;
}

void
00460 GenCode::visit(SimpleName &node)
{
      assert(node.candidates.size() == 1);
      Symbol *sym = node.candidates.front();

      bool refPointer = false;

      // sanity check only
      switch(sym->type) {
      case SYMBOL_VARIABLE:
            break;
      case SYMBOL_SIGNAL:
            break;

      case SYMBOL_PARAMETER:
      switch (node.baseType) {
            case BASE_TYPE_ARRAY:
            case BASE_TYPE_RECORD:
                  refPointer = true;
                  break;

            default:
                  break;
            }
            break;

      case SYMBOL_PORT:
            switch (node.baseType) {
            case BASE_TYPE_ARRAY:
            case BASE_TYPE_RECORD:
                  if (! this->isTarget) {
                        // the ports means that the 
                        // driver is *always* locally stored.
                        refPointer = true;
                  }
                  break;

            default:
                  break;
            }
            break;

      default:
            std::cerr << "unexpected symbol found: " << *sym << std::endl;
            assert(false);
      }

      ProcessStackedExpression pse = ProcessStackedExpression(*this, node);

      this->sourceRegs = RegisterSet(*this->container);

      Reference *ref;
      if (this->isTarget && node.isSignal()) {
            assert(node.driver != NULL);
            ref = new Reference(node.driver->getICName());
      } else {
            ref = new Reference(node.getName());
      }

      Operand *op = ref;

      if (refPointer) {
            Register *ptr = RegisterFactory::getRegister(OP_TYPE_POINTER);
            Mov *m = new Mov(ref, ptr);
            this->container->addCode(m);
            op = new IndirectOperand(ptr, OP_TYPE_POINTER);

            // check for unconstraint arrays.
            const ValDeclaration *decl = 
                  dynamic_cast<const ValDeclaration*>(
                                    node.getDeclaration());
            assert(decl != NULL);
            if (decl->isUnconstraint()) {
                  this->getConstraints(*decl);
            }

      }

      this->sourceRegs.setPointer(op);
      this->sourceRegs.isSignal = node.isSignal();
}

void
00543 GenCode::visit(ConstInteger &node)
{
      ProcessStackedExpression pse = ProcessStackedExpression(*this, node);
      this->processConst(node);
}

void
00550 GenCode::visit(ConstReal &node)
{
      ProcessStackedExpression pse = ProcessStackedExpression(*this, node);
      this->processConst(node);
}

void
00557 GenCode::visit(IfStat &node)
{
      this->assignExpression = false;
      // generate code for condition
      node.condition->accept(*this);

      ImmediateOperand *trueOp = new ImmediateOperand(
                        static_cast<universal_integer>(VHDL_TRUE));

      Label *thenLabel = LabelFactory::getLabel("then");

      Operand *condOp = 
            this->sourceRegs.getValue(node.condition->baseType);

      Je *condJmp = new Je(condOp, trueOp, thenLabel);
      this->container->addCode(condJmp);

      Label *endIf = LabelFactory::getLabel("endif");
      Label *elseLbl = NULL;
      if (node.elseStats != NULL) {
            elseLbl = LabelFactory::getLabel("else");
            Jmp *ej = new Jmp(elseLbl);
            this->container->addCode(ej);
      } else {
            Jmp *out = new Jmp(endIf);
            this->container->addCode(out);
      }

      assert(node.thenStats != NULL);
      this->container->addCode(thenLabel);
      this->listTraverse(*node.thenStats);
      
      if (node.elseStats != NULL) {
            Jmp *out = new Jmp(endIf);
            this->container->addCode(out);
            this->container->addCode(elseLbl);
            this->listTraverse(*node.elseStats);
      }

      this->container->addCode(endIf);
}

void
00600 GenCode::visit(Process &node)
{
      CodeContainer *current = this->container;
      this->container = new CodeContainer(node.getICName());

      if (node.declarations != NULL) {
            this->listTraverse(*node.declarations);
      }

      this->currentProcess = &node;

      std::string runS = node.getICName() + "_run";
      Label *runL = LabelFactory::getFixedLabel(runS);

      // FIXME how to handle implicit variables?

      this->container->addCode(runL);
      if (node.seqStats != NULL) {
            this->listTraverse(*node.seqStats);
      }

      Jmp *loop = new Jmp(runL);
      this->container->addCode(loop);

      this->currentProcess = NULL;

      current->addChild(this->container);
      this->container = current;
      // register drivers in *architecture*
      this->registerDrivers(node);
      // also add init function code to *architecture*
      this->createInitFunction(node);
}

void
00635 GenCode::registerDrivers(const Process &node)
{
      for (std::list<Driver*>::const_iterator i = node.drivers.begin(); 
            i != node.drivers.end(); i++) {

            this->registerDriver(**i);
      }
}

void
00645 GenCode::registerDriver(Driver &drv)
{
      std::string name = drv.getICName();
      GCTypes::GenTypeElements gte = 
            GCTypes::GenTypeElements(true, "FIXME", drv.signal, NULL);

      assert(drv.signal.subtypeIndic != NULL);
      drv.signal.subtypeIndic->accept(gte);
      assert(gte.composite.size() == 1);
      TypeElement *te = gte.composite.front();

      Data *d = new Data(name, STORAGE_TYPE_DRIVER, te);
      this->container->addData(d);
}

void
00661 GenCode::visit(ForLoopStat &node)
{
      class LoopImpl : public ForLoopIterate {
      public:
            LoopImpl(
                  intermediate::CodeContainer &container,
                  intermediate::Operand &counter,
                  intermediate::Operand &initializer,
                  intermediate::Operand &rightBound,
                  bool isAscending,
                  GenCode &genCode,
                  ForLoopStat &nd
                  ) :   ForLoopIterate(
                              container,
                              counter,
                              initializer,
                              rightBound,
                              isAscending),
                        gc(genCode),
                        loopNode(nd) {}
      private:
            virtual void loopBody(void) {
                  gc.listTraverse(*this->loopNode.loopStats);
            }


            GenCode &gc;
            ForLoopStat &loopNode;
      };

      assert(node.loopStats != NULL);
      assert(node.range != NULL);
      assert(node.loopVariable != NULL);
      assert(node.loopVariable->subtypeIndic != NULL);
      assert(node.loopVariable->subtypeIndic->baseType 
             == BASE_TYPE_INTEGER);

      // add declaration for loop variable
      node.loopVariable->accept(*this);

      bool asc = node.range->direction == DiscreteRange::DIRECTION_UP;
      this->assignExpression = false;
      
      this->sourceRegs = RegisterSet(*this->container);
      node.range->accept(*this);
      assert(this->sourceRegs.sliceBegin != NULL);
      assert(this->sourceRegs.sliceEnd != NULL);

      Reference *ref = new Reference(node.loopVariable->getICName());
      Register *loopVarP = RegisterFactory::getRegister(OP_TYPE_POINTER);
      Mov *mov = new Mov(ref, loopVarP);
      this->container->addCode(mov);

      Operand *cnt = new IndirectOperand(loopVarP, OP_TYPE_INTEGER);

      Operand *left = this->sourceRegs.sliceBegin;
      Operand *right = this->sourceRegs.sliceEnd;
      this->sourceRegs = RegisterSet(*this->container);
      
      LoopImpl li = LoopImpl(
                  *this->container,
                  *cnt,
                  *left,
                  *right,
                  asc,
                  *this,
                  node);
      this->loopRegistry.rememberLoop(&node, &li);

      li.addIteration();

      this->loopRegistry.forgetLoop(&node);
}

void
00736 GenCode::visit(WhileLoopStat &node)
{
      class WLImpl : public WhileIterate {
      public:
            WLImpl(
                  CodeContainer &container,
                  GenCode &genCode,
                  WhileLoopStat &n
                  ) :   WhileIterate(container),
                        gc(genCode),
                        nd(n) {}

      private:
            virtual void initializeCounter(void) {
                  // do nothing.
            }

            virtual void checkCondition(void) {
                  this->gc.sourceRegs = 
                        RegisterSet(*this->gc.container);
                  this->gc.destRegs = 
                        RegisterSet(*this->gc.container);
                  this->gc.assignExpression = false;
                  assert(this->nd.condition != NULL);

                  this->nd.condition->accept(this->gc);
                  Operand *condOp = this->gc.sourceRegs.getValue(
                                    this->nd.condition->baseType);

                  ImmediateOperand *trueOp = 
                        new ImmediateOperand(
                              static_cast<universal_integer>(
                                                VHDL_TRUE));
                  Jne *jne = new Jne(
                              trueOp, 
                              condOp,
                              this->loopDone);
                  this->cc.addCode(jne);
                  this->gc.sourceRegs = RegisterSet(*this->gc.container);
            }

            virtual void incCounter(void) {
                  // nothing to do
            }

            virtual void loopBody(void) {
                  if (this->nd.loopStats == NULL) {
                        return;
                  }

                  this->gc.listTraverse(*nd.loopStats);
            }

            GenCode &gc;
            WhileLoopStat &nd;
      };

      WLImpl loop = WLImpl(*this->container, *this, node);

      this->loopRegistry.rememberLoop(&node, &loop);
      loop.addIteration();
      this->loopRegistry.forgetLoop(&node);
}

void
00801 GenCode::visit(NextStat &node)
{
      assert(node.referredLoop != NULL);
      WhileIterate *wl = this->loopRegistry.lookup(node.referredLoop);
      assert(wl->loopInc != NULL);

      this->processCFLoopStat(node.condition, wl->loopInc);
}

void
00811 GenCode::visit(ExitStat &node)
{
      assert(node.referredLoop != NULL);
      WhileIterate *wl = this->loopRegistry.lookup(node.referredLoop);
      assert(wl->loopDone != NULL);

      this->processCFLoopStat(node.condition, wl->loopDone);
}

void
00821 GenCode::visit(WaitStat &node)
{
      this->sourceRegs = RegisterSet(*this->container);
      this->assignExpression = false;
      this->isTarget = false;

      Label *loopLbl = NULL;
      Label *exitWait = NULL;
      Register *resumeAt = NULL;

      // semantics of a wait:
      // time := now() + timeout
      // loop
      //      trigger(self, time)
      //      trigger_sig(self, signal_list)
      //      suspend()
      //      time1 := now()
      //      exit if time1 >= time -- timeout
      //      if !condition goto loop -- condition met
      // end loop


      // time := now() + timeout
      if (node.timeout != NULL) {
            node.timeout->accept(*this);
            Operand *timeout = 
                  this->sourceRegs.getValue(node.timeout->baseType);

            assert(timeout != NULL);
            // TODO
            // now := now();
            Register *now = RegisterFactory::getSimTime();
            resumeAt = RegisterFactory::getRegister(OP_TYPE_INTEGER);
            Add *cra = new Add(now, timeout, resumeAt);
            this->container->addCode(cra);
      }

      // loop ...
      if (node.condition != NULL) {
            loopLbl = LabelFactory::getLabel("wait_until_loop");
            this->container->addCode(loopLbl);
            exitWait = LabelFactory::getLabel("wait_done");
      }

      // trigger(self, time)
      if (node.timeout != NULL) {
            WakeAt *wa = new WakeAt(resumeAt);
            this->container->addCode(wa);
      }

      // trigger_sig(self, signal_list)
      // sensitivities must have been set by WaitConditions visitor.
      assert(node.sensitivities != NULL);
      for (std::list<Name*>::iterator i = node.sensitivities->begin();
            i != node.sensitivities->end(); i++) {

            // FIXME use WakeOn as assign operation for 
            //       composite signals!
            this->sourceRegs = RegisterSet(*this->container);
            (*i)->accept(*this);
            Operand *sigPtr = 
                  this->sourceRegs.getDestination((*i)->baseType);
            WakeOn *wo = new WakeOn(sigPtr);
            this->container->addCode(wo);
      }

      //suspend
      Suspend *suspend = new Suspend();
      this->container->addCode(suspend);

      // exit if now() >= time -- timeout
      if ((node.timeout != NULL) && (node.condition != NULL)) {
            Register *now = RegisterFactory::getSimTime();
            Jbe *exitTimout = new Jbe(resumeAt, now, exitWait);
            this->container->addCode(exitTimout);
      }

      // if !condition goto loop
      if (node.condition != NULL) {
            this->sourceRegs = RegisterSet(*this->container);
            node.condition->accept(*this);
            Operand *cond = this->sourceRegs.getValue(BASE_TYPE_INTEGER);
            Jne *goLoop = 
                  new Jne(cond, ImmediateOperand::getOne(), loopLbl);
            this->container->addCode(goLoop);
            this->sourceRegs = RegisterSet(*this->container);

            this->container->addCode(exitWait);
      }
}

void
00913 GenCode::visit(AssertStat &node)
{
      assert(node.condition != NULL);

      this->assignExpression = false;
      this->sourceRegs = RegisterSet(*this->container);
      this->destRegs = RegisterSet(*this->container);

      node.condition->accept(*this);

      //evaluate condition 
      Label *assertSuccL = LabelFactory::getLabel("assert_succ");
      Operand *cond = 
            this->sourceRegs.getValue(node.condition->baseType);
      Je *je = new Je(cond, 
                  new ImmediateOperand(
                        static_cast<universal_integer>(VHDL_TRUE)),
                  assertSuccL);
      this->container->addCode(je);

      // severity present? 
      if (node.severity != NULL) {
            this->sourceRegs = RegisterSet(*this->container);
            node.severity->accept(*this);
            this->dataOp = this->sourceRegs.getValue(BASE_TYPE_INTEGER);
      } else {
            // no severity -> error (lrm 8.2)
            this->dataOp = new ImmediateOperand(
                              static_cast<universal_integer>(2));
      }
      Operand *severityOp = this->dataOp;

      // log VHDL position
      std::string loc = util::MiscUtil::toString(node.location);
      loc += ": ";
      for (std::string::const_iterator i = loc.begin(); i != loc.end(); 
            i++) {

            ImmediateOperand *charVal = 
                  new ImmediateOperand(
                        static_cast<universal_integer>(*i));

            Log *l = new Log(this->dataOp, charVal);

            this->dataOp = 
                  new ImmediateOperand(
                        static_cast<universal_integer>(-1));
            this->container->addCode(l);
      }

      if (node.report != NULL) {
            this->assignExpression = true;
            this->assignOperation = ASSIGN_OPERATION_LOG;
            node.report->accept(*this);
            this->assignOperation = ASSIGN_OPERATION_COPY;
            this->assignExpression = false;

            // add a newline
            universal_integer newline = '\n';
            universal_integer mo = -1;
            Log *l = new Log(new ImmediateOperand(mo),
                        new ImmediateOperand(newline));
            this->container->addCode(l);

            // EXTENSION: abort if severity is ERROR or FAILURE
            universal_integer sevError = 2;
            Jb *jb = new Jb(severityOp, new ImmediateOperand(sevError), 
                        assertSuccL);
            Abort *a = new Abort();
            this->container->addCode(jb);
            this->container->addCode(a);

      } else {
            // TODO Log "Assertion violation." 
      }

      this->container->addCode(assertSuccL);
      this->dataOp = NULL;
}

void
00994 GenCode::visit(ProcCallStat &node)
{
      this->sourceRegs = RegisterSet(*this->container);
      this->destRegs = RegisterSet(*this->container);

      assert(node.definition != NULL);
      AttributeSpecification *foreign = node.definition->hasAttr("foreign");
      const char *fattr = NULL;
      if (foreign != NULL) {
            fattr = "procedure";
      }

      this->callSubprog(node, fattr);
}

void
01010 GenCode::visit(ConstArray &node)
{
      assert(this->assignExpression);

      switch (this->assignOperation) {
      case ASSIGN_OPERATION_COPY:
            if (this->destRegs.isSignal) {
                  this->processArrayUpdate(node);
            } else {
                  this->processArrayCopy(node);
            }
            break;

      case ASSIGN_OPERATION_LOG:
            // only the first character should get logged with
            // level in dataOp, the rest with -1 (so that
            // level will only be printed for the first
            // character)
            for (std::vector<ConstInteger *>::iterator i = 
                  node.elements->begin();
                  i != node.elements->end(); i++) {

                  (*i)->accept(*this);
                  if (i == node.elements->begin()) {
                        universal_integer mo = -1;
                        this->dataOp = new ImmediateOperand(mo);
                  }
            }
            break;

      case ASSIGN_OPERATION_CONNECT:
            // mustn't happen
            assert(false);
            break;
      };
}

void
01048 GenCode::processArrayCopy(ConstArray &node)
{
      class ConstArrayAssign : public StaticArrayIterate {
      public:
            ConstArrayAssign(
                  TypeDeclaration *at,
                  Operand *b,
                  CodeContainer &container,
                  ConstArray &nod
                  ) :   StaticArrayIterate(at, b, container),
                        ca(nod) {}
      private:
            ConstArray &ca;

            virtual void 
            iterateBody(
                  Register *element,
                  std::list<universal_integer> indics) {

                  universal_integer i = indics.front();
                  unsigned int ri = static_cast<unsigned int>(i);
                  assert(static_cast<universal_integer>(ri) == i);
                  ConstInteger *ci = (*this->ca.elements)[ri];
                  universal_integer value = ci->value;
                  IndirectOperand *valOp = 
                        new IndirectOperand(element, OP_TYPE_INTEGER);
                  Mov *m = new Mov(new ImmediateOperand(value), valOp);
                  this->cc.addCode(m);
            }

      };

      ConstArrayAssign caa = 
            ConstArrayAssign(node.type, 
                        this->destRegs.getPointer(),
                        *this->container,
                        node);
      caa.iterate();
}

void
01089 GenCode::processArrayUpdate(ConstArray &node)
{
      class ConstArrayAssign : public StaticArrayIterate {
      public:
            ConstArrayAssign(
                  TypeDeclaration *at,
                  Operand *b,
                  CodeContainer &container,
                  ConstArray &nod,
                  Operand *delay
                  ) :   StaticArrayIterate(at, b, container),
                        ca(nod),
                        delayOp(delay) {}
      private:
            ConstArray &ca;
            Operand *delayOp;

            virtual void 
            iterateBody(
                  Register *element,
                  std::list<universal_integer> indics) {

                  universal_integer i = indics.front();
                  unsigned int ri = static_cast<unsigned int>(i);
                  assert(static_cast<universal_integer>(ri) == i);
                  ConstInteger *ci = (*this->ca.elements)[ri];
                  universal_integer value = ci->value;

                  IndirectOperand *drvPtr = 
                        new IndirectOperand(element, OP_TYPE_POINTER);

                  Update *up = new Update(new ImmediateOperand(value), 
                                    this->delayOp,
                                    drvPtr);
                  this->cc.addCode(up);
            }

      };

      ConstArrayAssign caa = 
            ConstArrayAssign(node.type, 
                        this->destRegs.getPointer(),
                        *this->container,
                        node,
                        this->dataOp);
      caa.iterate();
}

void
01138 GenCode::processCFLoopStat(Expression *optCond, Label *target)
{
      assert(target != NULL);

      if (optCond == NULL) {
            Jmp *jmp = new Jmp(target);
            this->container->addCode(jmp);
            return;
      }

      // optCond != NULL
      this->sourceRegs = RegisterSet(*this->container);
      this->assignExpression = false;
      optCond->accept(*this);

      Operand *cond = this->sourceRegs.getValue(optCond->baseType);

      ImmediateOperand *trueOp = 
            new ImmediateOperand(
                  static_cast<universal_integer>(VHDL_TRUE));

      Je *jcond = new Je(cond, trueOp, target);
      this->container->addCode(jcond);
      this->sourceRegs = RegisterSet(*this->container);
}

template <typename T>
void
01166 GenCode::processConst(T &node)
{
      this->sourceRegs = RegisterSet(*this->container);
      this->sourceRegs.setValue(new ImmediateOperand(node.value));
}

void
01173 GenCode::visit(Subscript &node)
{
      ProcessStackedExpression pse = ProcessStackedExpression(*this, node);

      assert(node.indices != NULL);
      assert(node.source != NULL);
      node.source->accept(*this);
      assert(! node.indices->empty());

      this->processSubscription(node, *node.indices);
}

void
01186 GenCode::processSubscription(Subscript &node, std::list<Expression*> &indices)
{
      std::list<Operand*> idcs = std::list<Operand*>();

      for (std::list<Expression*>::iterator i = indices.begin(); 
            i != indices.end(); i++) {
            Operand *value = this->getSubscriptIndex(*i);
            idcs.push_back(value);
      }

      this->sourceRegs.subscribe(node.source->type, idcs);
}

intermediate::Operand *
01200 GenCode::getSubscriptIndex(Expression *index)
{
      bool backupIsTarget = this->isTarget;
      RegisterSet backupRegs = this->sourceRegs;
      this->sourceRegs = RegisterSet(*this->container);

      this->isTarget = false;
      index->accept(*this);
      this->isTarget = backupIsTarget;
      RegisterSet ret = this->sourceRegs;
      this->sourceRegs = backupRegs;

      return ret.getValue(index->baseType);
}

void
01216 GenCode::visit(Slice &node)
{
      ProcessStackedExpression pse = ProcessStackedExpression(*this, node);

      assert(node.source != NULL);
      // traverse to source
      node.source->accept(*this);

      // backup transfer registers
      RegisterSet backupRegs = this->sourceRegs;
      this->sourceRegs = RegisterSet(*this->container);

      bool backupIsTarget = this->isTarget;
      this->isTarget = false;
      // traverse to range
      assert(node.range != NULL);
      node.range->accept(*this);

      // FIXME did the slice narrow/boundary check.
      backupRegs.sliceBegin = this->sourceRegs.sliceBegin;
      backupRegs.sliceEnd = this->sourceRegs.sliceEnd;
      this->sourceRegs = backupRegs;
      this->isTarget = backupIsTarget;
}

void
01242 GenCode::visit(DiscreteRange &node)
{
      if (node.from != NULL) {
            assert(node.to != NULL);
            this->processDRByBounds(node);
            return;
      }

      if (node.rangeName != NULL) {
            node.rangeName->accept(*this);
            return;
      }

      assert(false);
}

void
01259 GenCode::processDRByBounds(DiscreteRange &node)
{
      assert(node.from != NULL);
      assert(node.to != NULL);

      node.from->accept(*this);
      Operand *sliceFrom = 
            this->sourceRegs.getValue(node.from->baseType);
      this->sourceRegs = RegisterSet(*this->container);

      node.to->accept(*this);
      Operand *sliceTo = 
            this->sourceRegs.getValue(node.to->baseType);
      this->sourceRegs = RegisterSet(*this->container);

      switch (node.direction) {
      case DiscreteRange::DIRECTION_UP:
            this->sourceRegs.sliceBegin = sliceFrom;
            this->sourceRegs.sliceEnd = sliceTo;
            break;

      case DiscreteRange::DIRECTION_DOWN:
            this->sourceRegs.sliceBegin = sliceTo;
            this->sourceRegs.sliceEnd = sliceFrom;
            break;

      default:
            // must not happen
            assert(false);
      }
}

void
01292 GenCode::visit(AttributeName &node)
{
      if ((*node.name) == std::string("range")) {
            this->processRangeAttr(node);
            return;
      }
      // TODO
}

void
01302 GenCode::processRangeAttr(AttributeName &node)
{
      // FIXME maybe the static part should go to constant propagation?
      std::list<DiscreteRange *> staticResolution;

      ResolveTypes::pickupIndexConstraint(node.type, staticResolution);
      if (! staticResolution.empty()) {
            DiscreteRange *dr = staticResolution.front();
            dr->accept(*this);
            return;
      }

      // need to resolve at run time (unconstraint arrays)
      assert(this->assignExpression == false);
      assert(! this->isTarget);

      node.prefix->accept(*this);
      
      std::list<Operand *> lbs;
      std::list<Operand *> ubs;
      this->sourceRegs.getConstraints(lbs, ubs);
      assert(! lbs.empty());
      assert(! ubs.empty());

      // TODO direction
      this->sourceRegs.sliceBegin = lbs.front();
      this->sourceRegs.sliceEnd = ubs.front();

      lbs.clear();
      ubs.clear();
      // clear unconstraint state
      this->sourceRegs.setUnconstraintBounds(lbs, ubs);
}

void
01337 GenCode::visit(SelectedName &node)
{
      ProcessStackedExpression pse = ProcessStackedExpression(*this, node);

      assert(node.prefix);
      //traverse to prefix
      node.prefix->accept(*this);

      assert(this->sourceRegs.sliceBegin == NULL);
      assert(this->sourceRegs.sliceEnd == NULL);
      assert(node.candidates.size() == 1);
      Symbol *sym = node.candidates.front();

      // symbol must be a RecordTypeElement
      RecordTypeElement *elem = 
            dynamic_cast<RecordTypeElement*>(&sym->declaration);
      assert(elem != NULL);

      ImmediateOperand *off = new ImmediateOperand(elem->offset);
      Type *rt = TypeFactory::lookupType(elem->parent->getICName());
      assert(rt != NULL);

      Register *r = RegisterFactory::getRegister(OP_TYPE_POINTER);
      ROffset *selection = 
            new ROffset(this->sourceRegs.getPointer(),
                              off,
                              rt,
                              r);

      this->sourceRegs.setPointer(r);
      this->container->addCode(selection);
}

void
01371 GenCode::visit(FunctionCall &node)
{
      ProcessStackedExpression pse = ProcessStackedExpression(*this, node);
      assert(! this->isTarget);

      if (node.definition->isBuiltin) {
            if (node.definition->gcBuiltin == NULL) {
                  std::cerr << "WARNING: builtin, but then again not a "
                        << "builtin: "
                        << *node.definition->name
                        << std::endl;
            }
            assert(node.definition->gcBuiltin != NULL);
            assert(node.arguments != NULL);
            this->sourceRegs = 
                  node.definition->gcBuiltin->emitCode(
                                          *this, 
                                          *node.arguments);
            return;
      }

      // not a builtin.
      AttributeSpecification *foreign = node.definition->hasAttr("foreign");
      const char *fattr = NULL;
      if (foreign != NULL) {
            fattr = "function";
      }

      this->callSubprog(node, fattr);

      // return type is always a *value*
      // simple type: move to register.
      // composite type: return value on stack, mov to temporary (from
      // process/fc)
      
      enum BaseType bt = node.definition->returnType->baseType;

      switch(bt) {
      case BASE_TYPE_INTEGER: 
      case BASE_TYPE_REAL:
      case BASE_TYPE_ENUM: {
            Register *retVal = RegisterFactory::getRegister(toOpType(bt));
            this->sourceRegs.setValue(retVal);
            Register *result = 
                  RegisterFactory::getReturnRegister(toOpType(bt));
            Mov *mov = new Mov(result, retVal);
            this->container->addCode(mov);

            break;
          }
      case BASE_TYPE_RECORD:
      case BASE_TYPE_ARRAY:
            this->handleCompositeReturn(node);
            break;

      default:
            assert(false);
      }
}

void
01432 GenCode::visit(Aggregate &node)
{
      switch(node.baseType) {
      case BASE_TYPE_ARRAY:
            this->processArrayAggregate(node);
            break;

      case BASE_TYPE_RECORD:
            this->processRecordAggregate(node);
            break;

      default:
            std::cerr << "strange Aggregate at " << node.location
                  << ": " << node << std::endl;
            // not valid for an Aggregate
            assert(false);
      }
}

void
01452 GenCode::processArrayAggregate(Aggregate &node)
{
      // hints from lrm, p.109:
      // if a choice is present, it must be locally static
      // the only exception is, if there is
      // - just one associaton *and*
      // - this one has only one choice

      assert(this->assignExpression);
      // FIXME
      assert(node.associations != NULL);

      // determine index constraint.
      std::list<DiscreteRange*> idcs = std::list<DiscreteRange*>();
      // TODO? return value is the base type.
      ResolveTypes::pickupIndexConstraint(node.type, idcs);

      assert(idcs.size() > 0);
      DiscreteRange *neededIndex = idcs.front();

      // resolve arrray ranges
      ResolveAggregates ra = 
            ResolveAggregates(*neededIndex);
      node.accept(ra);

      assert(node.associations != NULL);
      for (std::list<ElementAssociation*>::iterator i = 
            node.associations->begin(); 
            i != node.associations->end(); i++) {

            this->processArrayAssoc(**i, node.type);
      }
}

void
01487 GenCode::processArrayAssoc(ElementAssociation &node, TypeDeclaration *aType)
{
      if (node.range == NULL) {
            // error occured beforehand, reported already.
            return;
      }

      // lrm 7.3.2: reinterpeted:
      // a <= (1 to 3 | 5 => '1', others => '0')
      // means that each array element of a, that falls in the choices
      // 1 to 3 | 5 gets '1' assigned, and each element that falls in 
      // the choices others gets '0' assigned.
      //
      // In particular, this means to do a subscript for each element of a,
      // and put the result of the actual in there.
      //
      // One possible approach is to iterate over each element of the ranges
      // and assign the first result to the first element of a and reuse 
      // that space as a cache for the remaining elements of a choice.

      // empty Range? -> do nothing. (might happen in case of "Others" 
      // referring to an empty Range).
      RangeSet rs = *node.range;
      if (rs.empty()) {
            return;
      }

      // subscribe to first element of choices, and let the actual do the
      // assignment in the first place.
      RegisterSet dRegs = this->destRegs;
      // FIXME think about slices?
      this->destRegs = RegisterSet(this->destRegs);

      assert(node.actual != NULL);
      std::list<Operand *> indices = std::list<Operand *>();
      universal_integer i = rs.getLowerBound();
      ImmediateOperand *idx = new ImmediateOperand(i);
      indices.push_back(idx);

      this->destRegs.subscribe(aType, indices);

      // determine value of actual (and also assign it to the first 
      // destination offset)
      node.actual->accept(*this);
      bool ret = rs.minus(i, i);
      assert(ret);
      // prepare to handle remaining elements. use the evaluated element
      // that was just assigned as source.
      // FIXME this only works for variables, not for signals!
      this->sourceRegs = this->destRegs;
      assert(! this->sourceRegs.isSignal);

      while (! rs.empty()) {
            // determine new destination index for the next element
            indices.clear();
            i = rs.getLowerBound();
            indices.push_back(new ImmediateOperand(i));

            this->destRegs = RegisterSet(dRegs);
            this->destRegs.subscribe(aType, indices);
            // assign it
            this->doAssignment(*node.actual->type);

            // remove the next index from the set.
            ret = rs.minus(i, i);
            assert(ret);
      }

      this->destRegs = dRegs;
}

void
01559 GenCode::processRecordAggregate(Aggregate &node)
{
      // TODO
      assert(false);
}

void
01566 GenCode::visit(ReturnStat &node)
{
      if (node.result != NULL) {
            /* FIXME composite results... there needs to be
             *       an assignment! */
            this->destRegs = RegisterSet(*this->container);
            this->sourceRegs = RegisterSet(*this->container);
            this->assignExpression = false;
            node.result->accept(*this);

            switch(node.result->baseType) {
            case BASE_TYPE_ENUM:
            case BASE_TYPE_INTEGER:
            case BASE_TYPE_REAL: {
                  Register *r = 
                        RegisterFactory::getReturnRegister(
                              toOpType(node.result->baseType));
                  Operand *src = 
                        this->sourceRegs.getValue(
                              node.result->baseType);
                  Mov *m = new Mov(src, r);
                  this->container->addCode(m);
                  break;
                }
            case BASE_TYPE_ARRAY:
            case BASE_TYPE_RECORD:
                  /* TODO allocate space on stack, and have a pointer
                   * return register point to it */
                  assert(false);
                  break;

            default:
                  /* must not happen */
                  assert(false);
            }

      }

      Return *ret = new Return();
      this->container->addCode(ret);
}

void
01609 GenCode::visit(SignalDeclaration &node)
{
      // FIXME for procedures, skip OUT signals (only driver needed)
      Data *d = this->processValDecl(node, STORAGE_TYPE_SIGNAL);

      if (d == NULL) {
            return;
      }

      // annotate foreign signals
      if ((node.usage & ValDeclaration::USAGE_FOREIGN) == 0) {
            // not foreign
            return;
      }

      // lookup base type
      // FIXME this doesn't work well for composite types and needs further
      //       thoughts.
      //
      //       array -> element type?
      //       or
      //       array -> array type? (might also be a mapping?)
      //
      //       record -> ???

      assert(node.subtypeIndic != NULL);
      LookupTypes lat = LookupTypes(true, true);
      node.subtypeIndic->accept(lat);
      assert(lat.declaration != NULL);
      assert(lat.declaration->name != NULL);

      d->annotate("foreign", *lat.declaration->name);

      if ((node.usage & ValDeclaration::USAGE_READ) != 0) {
            d->annotate("read", 1);
      }
      // don't care about writes, Driver must handle this.
}

Data *
01649 GenCode::processValDecl(ValDeclaration &node, enum StorageType st)
{
      // skip unused declarations (but *not* signals, as these might be
      // ports.
      // FIXME this shouldn't be done in GenCode, but rather beforehand.
      // Ports are a little bit problematic though. If unused, 
      // NormalizeAssocs will add unassociated ports as association
      // elements.
      // If used in a port map statement, the port is signal is 
      // "kind of" used, i.e. it shouldn't get optimized out --
      // unless the association is *also* removed.

#if 0 /* FIXME deficiency in WarnUnused */
      if (   (node.usage == ValDeclaration::USAGE_NONE)
          && (st != STORAGE_TYPE_SIGNAL)) {
            return NULL;
      }
#endif

      bool usePointer = false;

      // for transfer segments:
      // * signals/drivers will always be passed as pointers
      // * records/arrays will always be passed as pointers
      switch (this->container->dataMode) {
      case CodeContainer::DATA_TRANSFER:
            switch (st) {
            case STORAGE_TYPE_SIGNAL:
            case STORAGE_TYPE_DRIVER:
                  usePointer = true;
                  break;

            default:
                  switch (node.subtypeIndic->baseType) {
                  case BASE_TYPE_RECORD:
                  case BASE_TYPE_ARRAY:
                        usePointer = true;
                        break;

                  default:
                        break;
                  }
            }
      default:
            break;
      }

            
      if (usePointer) {
            TypeElement *typeE = 
                  new TypeElement("__pointer__", 
                              ImmediateOperand::getZero(),
                              1);
            Data *d = new Data(node.getICName(), 
                              STORAGE_TYPE_VARIABLE,
                              typeE);
            this->container->addData(d);
            if (node.isUnconstraint()) {
                  this->addUnconstraintParams(node);
            }
            return d;
      }

      GCTypes::GenTypeElements gte = 
            GCTypes::GenTypeElements(true, 
                              "Cannot instantiate a data type "
                              "of an unconstraint array.",
                              node,
                              node.init);
      assert(node.subtypeIndic != NULL);
      node.subtypeIndic->accept(gte);
      if (gte.composite.size() != 1) {
            //error (already reported, hopefully), e.g.
            //instantiating an unconstraint array.
            return NULL;
      }

      TypeElement *te = gte.composite.front();

      Data *d = new Data(node.getICName(), st, te);
      this->container->addData(d);
      GenCode::annotateDataSize(*d, node.subtypeIndic);

      return d;
}

void
01736 GenCode::visit(VarDeclaration &node)
{
      this->processValDecl(node, STORAGE_TYPE_VARIABLE);
}

void
01742 GenCode::visit(ConstantDeclaration &node)
{
      this->processValDecl(node, STORAGE_TYPE_VARIABLE);
}

void
01748 GenCode::visit(SubtypeIndication &node)
{
      this->process(node);
}

void
01754 GenCode::process(Callable &node)
{
      if (node.hasAttr("foreign") != NULL) {
            // foreign subprogram
            if (node.definition != NULL) {
                  CompileError *ce = 
                        new CompileError(node,
                              "Implementation of foreign "
                              "subprogram found.");
                  ErrorRegistry::addError(ce);
            }
            return;
      }

      if (node.definition == NULL) {
            CompileError *ce = 
                  new CompileError(node, 
                        "Subprogram declaration w.o. specification.");
                  ErrorRegistry::addError(ce);
            return;
      }

      CodeContainer *current = this->container;
      this->container = new CodeContainer(node.getICName());
      
      this->container->dataMode = CodeContainer::DATA_TRANSFER;
      if (node.arguments != NULL) {
            this->listTraverse(*node.arguments);
      }

      for (std::list<Driver*>::const_iterator i = node.drivers.begin(); 
            i != node.drivers.end(); i++) {
            // only the pointer to the driver is transferred, so 
            // it's a variable of type pointer.
            TypeElement *te = 
                  new TypeElement("__pointer__", 
                              ImmediateOperand::getZero());
            Data *d = new Data((*i)->getICName(), 
                              STORAGE_TYPE_VARIABLE,
                              te);
            this->container->addData(d);
      }
      this->container->dataMode = CodeContainer::DATA_STACK;

      this->currentSubprog = &node;
      node.definition->accept(*this);
      this->currentSubprog = NULL;
      Return *ret = new Return();
      this->container->addCode(ret);

      current->addChild(this->container);
      this->container = current;
}

void
01809 GenCode::process(TypeDeclaration &node)
{
      if (node.name == NULL) {
            return;
      }

      GCTypes::GenTypes gt = GCTypes::GenTypes();
      node.accept(gt);
      if (gt.type != NULL) {
            this->container->addData(gt.type);
      }
}

void
01823 GenCode::processExpression(Expression &node)
{
      if (! this->assignExpression) {
            return;
      }

      assert(node.type != NULL);
      this->doAssignment(*node.type);
}

void
01834 GenCode::doAssignment(TypeDeclaration &type)
{
      RegisterSet *dest = NULL;

      switch (this->assignOperation) {
      case ASSIGN_OPERATION_CONNECT:
      case ASSIGN_OPERATION_COPY:
            dest = &this->destRegs;
            break;

      case ASSIGN_OPERATION_LOG:
            // only needs one RegisterSet
            break;
      }
      AssignVisitor av = AssignVisitor(
                              &this->sourceRegs,
                              dest,
                              *this->container,
                              this->dataOp,
                              this->assignOperation);
      type.accept(av);
}

template <typename T>
void
01859 GenCode::callSubprog(T &node, const char *foreign)
{
      assert(node.definition != NULL);
      std::list<OpCode *> copyBackFormals = std::list<OpCode *>();
      
      // FIXME make use of foreign.
      Reference *subprog;
      if (foreign != NULL) {
            subprog = new Reference(*node.definition->name);
      } else {
            subprog = new Reference(node.definition->getICName());
      }
      BeginTransfer *bg = new BeginTransfer(subprog, new Reference(""));
      this->container->addCode(bg);

      if (foreign != NULL) {
            bg->annotate("foreign", foreign);
      }
      
      if (node.arguments != NULL) {
            RegisterSet backup = this->destRegs;
            bool assignExp = this->assignExpression;
            this->assignExpression = false;

            copyBackFormals = this->setArgList(node, foreign);
            this->destRegs = backup;
            this->assignExpression = assignExp;
      }

      Call *c = new Call(subprog);
      this->container->addCode(c);
      if (foreign != NULL) {
            c->annotate("foreign", foreign);
      }

      // copy back formals...
      for (std::list<OpCode *>::const_iterator i = copyBackFormals.begin();
            i != copyBackFormals.end(); i++) {
            
            this->container->addCode(*i);
      }

      ImmediateOperand *trueOp = ImmediateOperand::getOne();
      EndTransfer *et = new EndTransfer(subprog, trueOp);
      if (foreign != NULL) {
            et->annotate("foreign", foreign);
      }
      this->container->addCode(et);
}

template <typename T>
std::list<OpCode *>
01911 GenCode::setArgList(T &node, const char *foreign)
{
      std::list<OpCode *> ret = std::list<OpCode *>();
      OpCode *op;

      assert(node.arguments != NULL);
      assert(node.definition != NULL);
      assert(node.definition->arguments != NULL);

      std::list<ValDeclaration*>::iterator j =
                  node.definition->arguments->begin();

      for (std::list<AssociationElement*>::iterator i = 
            node.arguments->begin(); i != node.arguments->end(); 
            i++, j++) {

            // FIXME individual association

            op = this->setArg(*node.definition, **j, **i, foreign);
            if (op) {
                  ret.push_back(op);
            }
      }

      return ret;
}

intermediate::OpCode *
01939 GenCode::setArg(
      Callable &c,
      ValDeclaration &vd, 
      AssociationElement &element,
      const char *foreign
)
{
      //FIXME individiual association?
      // imo this *should* have been cleared somewhere else. (but is not)
      
      assert(element.formal == NULL);
      assert(element.actual != NULL);
      assert(! this->isTarget);
      assert(! this->assignExpression);
      
      Reference *callee = NULL;
      if (foreign != NULL) {
            callee = new Reference(*c.name);
      } else {
            callee = new Reference(c.getICName());
      }
      OpCode *op = NULL;

      this->sourceRegs = RegisterSet(*this->container);
      this->destRegs = RegisterSet(*this->container);

      switch (vd.storageClass) {
      case ValDeclaration::OBJ_CLASS_CONSTANT:
            switch (element.actual->baseType) {
            case BASE_TYPE_INTEGER:
            case BASE_TYPE_ENUM:
            case BASE_TYPE_REAL:
                  this->setArgByValue(callee, &vd, element, foreign, 
                              false);
                  break;

            case BASE_TYPE_RECORD:
            case BASE_TYPE_ARRAY:
                  this->setArgByBasePointerToTemporary(
                                          callee, 
                                          vd, 
                                          element,
                                          foreign);
                  break;

            default:
                  // must not happen
                  assert(false);
            }
            break;

      case ValDeclaration::OBJ_CLASS_VARIABLE:
            switch (element.actual->baseType) {
            case BASE_TYPE_INTEGER:
            case BASE_TYPE_ENUM:
            case BASE_TYPE_REAL:
                  switch (vd.mode) {
                  case ValDeclaration::MODE_IN:
                        op = this->setArgByValue(
                                          callee, 
                                          &vd, 
                                          element, 
                                          foreign,
                                          false); 
                        assert(op == NULL);
                        break;

                  case ValDeclaration::MODE_INOUT:
                  case ValDeclaration::MODE_OUT:
                        // need to copy back to op.
                        op = this->setArgByValue(
                                          callee,
                                          &vd, 
                                          element,
                                          foreign,
                                          true);
                        assert(op != NULL);
                        break;
                  }

                  break;

            case BASE_TYPE_RECORD:
            case BASE_TYPE_ARRAY:
                  this->setArgByBasePointer(
                                    callee,
                                    &vd,
                                    element,
                                    foreign);
                  break;

            default:
                  // must not happen
                  assert(false);
            }
            break;

      case ValDeclaration::OBJ_CLASS_SIGNAL:
            switch (element.actual->baseType) {
            case BASE_TYPE_ARRAY:
            case BASE_TYPE_RECORD:
                  switch (vd.mode) {
                  case ValDeclaration::MODE_IN:
                        this->setArgByBasePointer(
                                    callee,
                                    &vd,
                                    element,
                                    foreign);
                        break;

                  case ValDeclaration::MODE_INOUT:
                        this->setArgByBasePointer(
                                    callee,
                                    &vd,
                                    element,
                                    foreign);
                        /* fall through */

                  case ValDeclaration::MODE_OUT:
                        this->setArgByDriver(
                                    callee,
                                    c.drivers,
                                    vd,
                                    element,
                                    foreign,
                                    true);
                        break;
                  }
                  break;

            case BASE_TYPE_INTEGER:
            case BASE_TYPE_ENUM:
            case BASE_TYPE_REAL:
                  switch (vd.mode) {
                  case ValDeclaration::MODE_IN:
                        this->setArgByPointer(
                                    callee,
                                    &vd,
                                    element,
                                    foreign);
                        break;

                  case ValDeclaration::MODE_INOUT:
                        this->setArgByPointer(
                                    callee,
                                    &vd,
                                    element,
                                    foreign);
                        /* fall through */

                  case ValDeclaration::MODE_OUT:
                        this->setArgByDriver(
                                    callee,
                                    c.drivers,
                                    vd,
                                    element,
                                    foreign,
                                    false);
                        break;
                  }
                  break;

            default:
                  assert(0);
            }
            break;

      default:
            // must not happen
            assert(false);
      }

      this->sourceRegs = RegisterSet(*this->container);
      this->destRegs = RegisterSet(*this->container);
      return op;
}


OpCode *
02118 GenCode::setArgByValue(
      Reference *callee,
      ValDeclaration *vd,
      AssociationElement &element,
      const char *foreign,
      bool copyBack
)
{
      // sanity check
      switch (element.actual->baseType) {
      case BASE_TYPE_INTEGER:
      case BASE_TYPE_REAL:
      case BASE_TYPE_ENUM:
            break;

      default:
            // composites must be called by reference!
            assert(false);
      }

      if (vd != NULL) {
            assert(element.formal == NULL); // FIXME
      } else {
            // FIXME individual association
            SimpleName *sn = dynamic_cast<SimpleName*>(element.formal);
            assert(sn != NULL);
            vd = dynamic_cast<ValDeclaration*>(sn->getDeclaration());
            assert(vd != NULL);
      }

      element.actual->accept(*this);

      Reference *formal;
      if (foreign != NULL) {
            formal = new Reference(*vd->name);
      } else {
            formal = new Reference(vd->getICName());
      }

      Operand *value = this->sourceRegs.getValue(element.actual->baseType);
      SetParam *sp = new SetParam(value, callee, formal);
      this->container->addCode(sp);
      if (foreign != NULL) {
            sp->annotate("foreign", foreign);
      }

      if (copyBack) {
            Operand *dest = this->sourceRegs.getDestination(
                                    element.actual->baseType);
            GetParam *gp = new GetParam(formal, callee, dest);
            return gp;
      }
      return NULL;
}

void
GenCode::setArgByBasePointer(
      Reference *callee,
      ValDeclaration *vd,
      AssociationElement &element,
      const char *foreign
)
{
      if (vd == NULL) {
            assert(element.formal != NULL);
            // FIXME
            SimpleName *sn = dynamic_cast<SimpleName*>(element.formal);
            assert(sn != NULL);
            vd = dynamic_cast<ValDeclaration*>(sn->getDeclaration());
            assert(vd != NULL);
      }

      element.actual->accept(*this);

      std::string formal_name;
      if (foreign != NULL) {
            formal_name = *vd->name;
      } else {
            formal_name = vd->getICName();
      }
      Reference *formal = new Reference(formal_name);

      Operand *pointer = this->sourceRegs.getPointer();
      SetParam *sp = new SetParam(pointer, callee, formal);
      this->container->addCode(sp);

      if (foreign != NULL) {
            sp->annotate("foreign", foreign);
      }

      if (vd->isUnconstraint()) {
            assert(foreign == NULL);
            if (this->sourceRegs.isUnconstraint()) {
                  // either constraints are paremeters already
                  this->setConstraintsByRS(callee, formal_name, foreign);
            } else {
                  // or the array is constraint
                  this->setConstraintsByType(callee,
                              formal_name, 
                              element.actual->type,
                              foreign);
            }
      }
}

void
GenCode::setArgByBasePointerToTemporary(
      Reference *callee,
      ValDeclaration &vd,
      AssociationElement &element,
      const char *foreign
)
{
      assert(element.hiddenFormal != NULL);
      assert(element.formal == NULL); // FIXME

      // assign the constant to the hidden formal
      this->assignExpression = false;
      this->isTarget = true;
      element.hiddenFormal->accept(*this);
      this->destRegs = this->sourceRegs;
      this->sourceRegs = RegisterSet(*this->container);

      this->isTarget = false;
      this->assignExpression = true;
      element.actual->accept(*this);
      this->assignExpression = false;
      
      // get a grip on the hidden formal
      this->sourceRegs = RegisterSet(*this->container);
      element.hiddenFormal->accept(*this);

      std::string formal_name;
      if (foreign != NULL) {
            formal_name = *vd.name;
      } else {
            formal_name = vd.getICName();
      }
      Reference *formal = new Reference(formal_name);

      SetParam *sp = 
            new SetParam(this->sourceRegs.getPointer(), callee, formal);
      this->container->addCode(sp);
      if (foreign != NULL) {
            sp->annotate("foreign", foreign);
      }

      if (vd.isUnconstraint()) {
            if (this->sourceRegs.isUnconstraint()) {
                  // either constraints are paremeters already
                  this->setConstraintsByRS(callee, formal_name, 
                                    foreign);
            } else {
                  // or the array is constraint
                  this->setConstraintsByType(callee,
                              formal_name, 
                              element.actual->type,
                              foreign);
            }
      }
}

void
02281 GenCode::setArgByPointer(
      Reference *callee,
      ValDeclaration *vd,
      AssociationElement &element,
      const char *foreign
)
{
      if (vd == NULL) {
            assert(element.formal != NULL);
            // FIXME
            SimpleName *sn = dynamic_cast<SimpleName*>(element.formal);
            assert(sn != NULL);
            vd = dynamic_cast<ValDeclaration*>(sn->getDeclaration());
            assert(vd != NULL);
      }

      element.actual->accept(*this);

      Reference *formal;
      if (foreign != NULL) {
            formal = new Reference(*vd->name);
      } else {
            formal = new Reference(vd->getICName());
      }

      Operand *pointer = 
            this->sourceRegs.getDestination(element.actual->baseType);
      SetParam *sp = new SetParam(pointer, callee, formal);
      this->container->addCode(sp);

      if (foreign != NULL) {
            sp->annotate("foreign", foreign);
      }
}


void
02318 GenCode::setArgByDriver(
      Reference *callee,
      const std::list<Driver *> &drivers,
      ValDeclaration &vd,
      AssociationElement &element,
      const char *foreign,
      bool usePointer
)
{
      assert(element.formal == NULL);
      // need a driver
      this->isTarget = true;
      element.actual->accept(*this);
      this->isTarget = false;

      std::string name;
      bool found = false;

      for (std::list<Driver *>::const_iterator i = drivers.begin();
            i != drivers.end(); i++) {
            
            if (&(*i)->signal == &vd) {
                  if (foreign != NULL) {
                        name = (*i)->getForeignName();
                  } else {
                        name = (*i)->getICName();
                  }
                  found = true;
                  break;
            }
      }

      assert(found);

      Reference *formal = new Reference(name);
      Operand *drv;
      if (usePointer) {
            drv = this->sourceRegs.getPointer();
      } else {
            drv = this->sourceRegs.getDestination(
                              element.actual->baseType);
      }
      SetParam *sp = new SetParam(drv, callee, formal);
      this->container->addCode(sp);
      if (foreign != NULL) {
            sp->annotate("foreign", foreign);
      }
}


void
02369 GenCode::setConstraintsByType(
      Reference *cRef,
      const std::string &icPrefix, 
      const TypeDeclaration *t,
      const char *foreign
)
{
      std::list<DiscreteRange *> ic = std::list<DiscreteRange *>();

      ResolveTypes::pickupIndexConstraint(t, ic);
      assert(! ic.empty());

      size_t dim = 0;
      for (std::list<DiscreteRange *>::const_iterator i = ic.begin();
            i != ic.end(); i++, dim++) {

            ImmediateOperand *lb = 
                  new ImmediateOperand((*i)->getLowerBound());
            ImmediateOperand *ub = 
                  new ImmediateOperand((*i)->getUpperBound());
            Reference *lname = new Reference(icPrefix + "_lb_" 
                              + util::MiscUtil::toString(dim));
            Reference *uname = new Reference(icPrefix + "_ub_" 
                              + util::MiscUtil::toString(dim));
            SetParam *sp1 = new SetParam(lb, cRef, lname);
            SetParam *sp2 = new SetParam(ub, cRef, uname);
            this->container->addCode(sp1);
            this->container->addCode(sp2);
            if (foreign != NULL) {
                  sp1->annotate("foreign", foreign);
                  sp2->annotate("foreign", foreign);
            }
      }
}

void
02405 GenCode::setConstraintsByRS(
      Reference *cRef, 
      const std::string &icPrefix,
      const char *foreign
)
{
      std::list<Operand *> lb;
      std::list<Operand *> ub;

      this->sourceRegs.getConstraints(lb, ub);
      std::list<Operand *>::const_iterator li = lb.begin();
      std::list<Operand *>::const_iterator ui = ub.begin();

      for (size_t dim = 0; li != lb.end(); li++, ui++, dim++) {
            Reference *lname = new Reference(icPrefix + "_lb_" 
                              + util::MiscUtil::toString(dim));
            Reference *uname = new Reference(icPrefix + "_ub_" 
                              + util::MiscUtil::toString(dim));

            SetParam *sp1 = new SetParam(*li, cRef, lname);
            SetParam *sp2 = new SetParam(*ui, cRef, uname);

            this->container->addCode(sp1);
            this->container->addCode(sp2);
            if (foreign != NULL) {
                  sp1->annotate("foreign", foreign);
                  sp2->annotate("foreign", foreign);
            }
      }
}

void
02437 GenCode::addUnconstraintParams(const ValDeclaration &node)
{
      const UnconstrainedArrayType *ua = 
            dynamic_cast<const UnconstrainedArrayType *>(
                  ResolveTypes::findBaseType(node.subtypeIndic));
      assert(ua != NULL);

      std::string prefix = node.getICName();

      for (size_t dim = 0; dim < ua->numIndices; dim++) {
            // make a NULL range the default
            TypeElement *ltypeE = new TypeElement("universal_integer",
                                    ImmediateOperand::getOne());
            TypeElement *utypeE = new TypeElement("universal_integer",
                                    ImmediateOperand::getZero());
            std::string lname = prefix + "_lb_" 
                          + util::MiscUtil::toString(dim);
            std::string uname = prefix + "_ub_" 
                          + util::MiscUtil::toString(dim);

            Data *ld = new Data(lname, STORAGE_TYPE_VARIABLE, ltypeE);
            Data *ud = new Data(uname, STORAGE_TYPE_VARIABLE, utypeE);
            this->container->addData(ld);
            this->container->addData(ud);
      }
}

void
02465 GenCode::getConstraints(const ValDeclaration &node)
{
      const UnconstrainedArrayType *ua = 
            dynamic_cast<const UnconstrainedArrayType *>(
                  ResolveTypes::findBaseType(node.subtypeIndic));
      assert(ua != NULL);

      std::string prefix = node.getICName();

      std::list<Operand *> lbs;
      std::list<Operand *> ubs;

      for (size_t dim = 0; dim < ua->numIndices; dim++) {
            std::string lname = prefix + "_lb_" 
                          + util::MiscUtil::toString(dim);
            std::string uname = prefix + "_ub_" 
                          + util::MiscUtil::toString(dim);

            Register *lb = RegisterFactory::getRegister(OP_TYPE_POINTER);
            Register *ub = RegisterFactory::getRegister(OP_TYPE_POINTER);

            Mov *lm = new Mov(new Reference(lname), lb);
            Mov *um = new Mov(new Reference(uname), ub);
            this->container->addCode(lm);
            this->container->addCode(um);

            IndirectOperand *lbv = 
                  new IndirectOperand(lb, OP_TYPE_INTEGER);
            IndirectOperand *ubv = 
                  new IndirectOperand(ub, OP_TYPE_INTEGER);

            lbs.push_back(lbv);
            ubs.push_back(ubv);
      }

      this->sourceRegs.setUnconstraintBounds(lbs, ubs);
}

void
02504 GenCode::handleCompositeReturn(FunctionCall &node)
{
      assert(false);
      /* TODO */
}

void
02511 GenCode::annotateDataSize(Data &data, const SubtypeIndication *type)
{
      const TypeDeclaration *t = ResolveTypes::findBaseType(type);
      const EnumerationType *et = dynamic_cast<const EnumerationType*>(t);
      // consider only enumeration types
      if (et == NULL) {
            return;
      }

      assert(et->elements != NULL);
      size_t sz = et->elements->size();
      double bit_count = log(static_cast<double>(sz));
      int cnt = static_cast<int>(ceil(bit_count));

      data.annotate("display_size", cnt);
}

void
02529 GenCode::visit(AttributeSpecification &node)
{
      //TODO
}

void
02535 GenCode::processAlternative(
      CaseAlternative &node,
      Operand *cmpVal,
      Label *caseNext, 
      Label *caseOut
)
{
      assert(node.isVals != NULL);
      assert(node.thenStats != NULL);

      Label *altFound = LabelFactory::getLabel("alternative_execute");

      for (std::list<Expression *>::const_iterator i = 
            node.isVals->begin(); i != node.isVals->end(); i++) {

            const Others *others = dynamic_cast<const Others*>(*i);
            if (others != NULL) {
                  Jmp *jmp = new Jmp(altFound);
                  this->container->addCode(jmp);
                  break;
            }

            this->assignExpression = false;
            this->isTarget = false;
            this->sourceRegs = RegisterSet(*this->container);
            (*i)->accept(*this);

            Operand *choice = this->sourceRegs.getValue((*i)->baseType);
            Je *je = new Je(cmpVal, choice, altFound);
            this->container->addCode(je);
      }

      Jmp *jmp = new Jmp(caseNext);
      this->container->addCode(jmp);
      this->container->addCode(altFound);

      this->sourceRegs = RegisterSet(*this->container);
      this->listTraverse(*node.thenStats);
      Jmp *jmp2 = new Jmp(caseOut);
      this->container->addCode(jmp2);
}

void
02578 GenCode::visit(CaseStat &node)
{
      // TODO: there are a number of restrictions on 
      //       select and alternatives, which aren't checked yet
      //       see lrm 8.8 for details.
      //       However these restrictions should be checked elsewhere.
      //
      // TODO 2: This is a pretty poor implementation, as all
      //       expression choices should be locally static.
      //       A good implementation would choose the best algorithm
      //       for the alternatives, including
      //       - a jump lookup table
      //       - if/then/else constructs (that's done here)
      //       - a combination thereof
      //       - ...

      assert(node.select != NULL);
      assert(node.alternatives != NULL);

      this->assignExpression = false;
      this->isTarget = false;
      this->sourceRegs = RegisterSet(*this->container);
      this->destRegs = RegisterSet(*this->container);

      switch (node.select->baseType) {
      case BASE_TYPE_RECORD:
      case BASE_TYPE_ARRAY:
            // FIXME not handled yet: this needs to 
            // 1) assign the result of the expression to a temporary
            // 2) compare the temporary with the choices
            assert(false);
            break;

      case BASE_TYPE_UNSET:
            assert(false);
            break;

      default:
            break;
      }

      node.select->accept(*this);
      Operand *cmpVal = this->sourceRegs.getValue(node.select->baseType);
      this->sourceRegs = RegisterSet(*this->container);
      
      Label *caseOut = LabelFactory::getLabel("case_out");

      // handle each alternative
      for (std::list<CaseAlternative *>::const_iterator i = 
            node.alternatives->begin();
            i != node.alternatives->end(); /* nothing */) {

            CaseAlternative *current = *i;
            Label *caseNext = caseOut;
            i++;

            // use caseOut as last next label.
            if (i != node.alternatives->end()) {
                  caseNext = LabelFactory::getLabel("case_next");
            }

            this->processAlternative(*current, cmpVal, caseNext, caseOut);

            if (i != node.alternatives->end()) {
                  this->container->addCode(caseNext);
            }
      }


      this->container->addCode(caseOut);
}

/*
 * ================== ASSIGN VISITOR ====================
 */

void
02655 GenCode::AssignVisitor::visit(SubtypeIndication &node)
{
      // traverse to the defining type.
      assert(node.declaration != NULL);

      switch (node.baseType) {
      case BASE_TYPE_ENUM:
      case BASE_TYPE_INTEGER:
      case BASE_TYPE_REAL: {
            /* traverse to declaration */
            TypeDeclaration *parent = 
                  const_cast<TypeDeclaration*>(node.declaration);
                  parent->accept(*this);
            return;
         }
      case BASE_TYPE_RECORD:
            /* subtype of a record cannot happen */
            assert(false);
            break;

      case BASE_TYPE_ARRAY:
            this->processArraySubtype(node);
            break;

      default:
            /* must not happen */
            assert(false);
            break;
      }
}

void
02687 GenCode::AssignVisitor::processArraySubtype(SubtypeIndication &node)
{
      // FIXME slices
      // FIXME unconstraint lbounds/ubounds
      class ArrayAssign : public ArrayIterate {
      public:
            ArrayAssign(
                  TypeDeclaration *at,
                  intermediate::CodeContainer &container,
                  AssignVisitor &instance,
                  std::list<Operand *> unclbounds,
                  std::list<Operand *> uncubounds
                  ) :   ArrayIterate(at, 
                                    instance.src->getPointer(),
                                    container,
                                    unclbounds,
                                    uncubounds),
                        av(instance) {}

      private:
            virtual void 
            iterateBody(
                  Register *element, 
                  std::list<Register *> idcs
            ) 
            {
                  RegisterSet *old_src = this->av.src;
                  RegisterSet *old_dst = this->av.dst;
                  this->av.src = new RegisterSet(this->cc);

                  if (this->av.dst != NULL) {   
                        this->av.dst = new RegisterSet(*this->av.dst);
                        this->setDest(idcs);
                  }
                  this->av.src->isSignal = old_src->isSignal;
                  this->av.src->setPointer(element);

                  switch (this->elementType->baseType) {
                  case BASE_TYPE_RECORD:
                        this->elementType->accept(this->av);
                        break;

                  case BASE_TYPE_INTEGER:
                  case BASE_TYPE_REAL:
                  case BASE_TYPE_ENUM:
                        this->av.performOperation(
                              this->elementType->baseType);
                        break;

                  default:
                        /* must not happen */
                        assert(false);
                        break;
                  }

                  delete this->av.src;

                  if (this->av.dst != NULL) {
                        delete this->av.dst;
                  }
                  this->av.src = old_src;
                  this->av.dst = old_dst;
            }

            void setDest(std::list<Register *> idcs) {
                  assert(this->av.dst != NULL);

                  std::list<Operand*> idx = std::list<Operand*>();
                  for (std::list<Register *>::const_iterator i =
                        idcs.begin(); i != idcs.end(); i++) {
                        
                        idx.push_back(*i);
                  }

                  this->av.dst->subscribe(this->arrayType, idx);
            }

            AssignVisitor &av;
      };

      std::list<Operand *> lb;
      std::list<Operand *> ub;

      this->src->getConstraints(lb, ub);
      if (this->dst != NULL) {
            // perform subtype conversion on the fly for unconstraint
            // arrays.
            // FIXME where bounds are statically known, subtype conversion
            // must have taken place beforehand!
            //
            // FIXME this still leaves the problem of unconstraint <->
            // constraint
            //
            // FIXME actually src should take over the constraints of
            //       dest, but that doesn't matter that much imho
            if (this->dst->isUnconstraint()) {
                  if (this->src->isUnconstraint()) {
                        this->dst->setUnconstraintBounds(lb, ub);
                  } else {
                        assert(false);
                  }
            }
      }
      ArrayAssign aa = ArrayAssign(&node, 
                              this->container, 
                              *this,
                              lb,
                              ub);
      aa.iterate();
}

void
02799 GenCode::AssignVisitor::visit(UnconstrainedArrayType &node)
{
      // mustn't traverse to UnconstrainedArrayType, should be handled from
      // elsewhere already
      // FIXME: eventually unconstrained arrays as parameters of subprograms
      //        might bring us here.
      assert(false);
}

void
02809 GenCode::AssignVisitor::visit(RecordType &node)
{
      universal_integer relement = 0;

      for (std::list<RecordTypeElement *>::const_iterator i = 
            node.elements->begin(); i != node.elements->end(); i++) {
            (*i)->accept(*this);

            Operand *src_composite = this->src->getPointer();
            Operand *dst_composite = NULL;
            if (this->dst != NULL) {
                  dst_composite = this->dst->getPointer();
            }

            // calculate new record offset of source
            relement++;
            Register *nb1 = RegisterFactory::getRegister(OP_TYPE_POINTER);
            ImmediateOperand *off1 = new ImmediateOperand(relement);
            Type *rt1 = TypeFactory::lookupType(node.getICName());
            assert(rt1 != NULL);
            ROffset *roffOp1 = 
                  new ROffset(this->src->getPointer(), off1, rt1, nb1);
            this->container.addCode(roffOp1);

            this->src->setPointer(nb1);

            // and for destination
            if (this->dst != NULL) {
                  Register *nb2 = 
                        RegisterFactory::getRegister(OP_TYPE_POINTER);
                  ImmediateOperand *off2 = 
                        new ImmediateOperand(relement);
                  Type *rt2 = TypeFactory::lookupType(node.getICName());
                  assert(rt2 != NULL);
                  ROffset *roffOp2 = 
                        new ROffset(
                              this->dst->getPointer(), 
                              off2, 
                              rt2, 
                              nb2);
                  this->container.addCode(roffOp2);

                  this->dst->setPointer(nb2);
            }

            // traverse to element
            (*i)->accept(*this);
            // restore old base pointers
            this->src->setPointer(src_composite);
            if (this->dst != NULL) {
                  this->dst->setPointer(dst_composite);
            }
      }
}

void
02865 GenCode::AssignVisitor::visit(RecordTypeElement &node)
{
      node.subtype->accept(*this);
}

void
02871 GenCode::AssignVisitor::visit(RangeConstraintType &node)
{
      this->performOperation(node.baseType);
}

void
02877 GenCode::AssignVisitor::visit(PhysicalType &node)
{
      this->performOperation(BASE_TYPE_INTEGER);
}

void
02883 GenCode::AssignVisitor::visit(EnumerationType &node)
{
      this->performOperation(BASE_TYPE_INTEGER);
}

void
02889 GenCode::AssignVisitor::performOperation(enum BaseType t)
{
      switch (this->operation) {
      case ASSIGN_OPERATION_COPY:
            this->makeAssignment(t);
            break;

      case ASSIGN_OPERATION_LOG:
            this->logValue();
            break;

      case ASSIGN_OPERATION_CONNECT:
            this->connect();
            break;
      }
}

void
02907 GenCode::AssignVisitor::makeAssignment(enum BaseType t)
{
      Operand *so = this->src->getValue(t);
      assert(this->dst != NULL);
      Operand *dsto = this->dst->getDestination(t);

      OpCode *assign;

      if (this->dst->isSignal) {
            assert(this->dataOp != NULL);
            assign = new Update(so, this->dataOp, dsto);
      } else {
            assign = new Mov(so, dsto);
      }
      this->container.addCode(assign);
}

void
02925 GenCode::AssignVisitor::logValue(void)
{
      assert(this->dataOp != NULL);

      Operand *c = this->src->getValue(BASE_TYPE_INTEGER);
      Log *l = new Log(this->dataOp, c);

      this->container.addCode(l);
}

void
02936 GenCode::AssignVisitor::connect(void)
{
      assert(this->dataOp == NULL);
      assert(this->dst->isSignal);
      // hm... getDestination ignores the base type if is a signal.
      Connect *c = new Connect(this->dst->getDestination(BASE_TYPE_REAL),
                        this->src->getDestination(BASE_TYPE_REAL));

      this->container.addCode(c);
}

/*
 * ================== PROCESS STACKED EXPRESSION ===============
 */

02951 GenCode::ProcessStackedExpression::ProcessStackedExpression(
      GenCode &gc,
      Expression &n
):          genCode(gc),
            node(n),
            stackedAssignExpression(gc.assignExpression)
{
      gc.assignExpression = false;
}

02961 GenCode::ProcessStackedExpression::~ProcessStackedExpression()
{
      this->genCode.assignExpression = this->stackedAssignExpression;

      if (this->stackedAssignExpression) {
            this->genCode.processExpression(node);
      }
}

}; /* namespace ast */

Generated by  Doxygen 1.6.0   Back to index