Logo Search packages:      
Sourcecode: fauhdlc version File versions

CheckAccessMode.cpp

/* $Id: CheckAccessMode.cpp 4323 2009-01-27 13:48:12Z potyra $ 
 * CheckAccessMode: visitor to check if reading/writing data is permitted
 * via in,inout,out access modes.
 *
 * 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/CheckAccessMode.hpp"
#include "frontend/ast/SimpleName.hpp"
#include "frontend/ast/VarAssignStat.hpp"
#include "frontend/ast/SigAssignStat.hpp"
#include "frontend/ast/Subscript.hpp"
#include "frontend/ast/Slice.hpp"
#include "frontend/ast/Aggregate.hpp"
#include "frontend/ast/CompInstStat.hpp"
#include "frontend/ast/ConstInteger.hpp"
#include "frontend/ast/ConstReal.hpp"
#include "frontend/ast/ConstArray.hpp"
#include "frontend/ast/FunctionCall.hpp"
#include "frontend/ast/ProcCallStat.hpp"
#include "frontend/reporting/ErrorRegistry.hpp"

namespace ast {

void
00029 CheckAccessMode::visit(SimpleName &node)
{
      assert(node.candidates.size() >= 1);
      const Symbol *sym = node.candidates.front();

      switch (sym->type) {
      case SYMBOL_SIGNAL:
      case SYMBOL_PARAMETER:
      case SYMBOL_VARIABLE:
      case SYMBOL_PORT:
            break;

      default:
            // skip non variables/signals/parameters
            return;
      }

      ValDeclaration *decl = 
            dynamic_cast<ValDeclaration*>(
                              node.getDeclaration());

      std::string *action = NULL;
      std::string *mode_s = NULL;

      if (this->isForeign) {
            decl->usage |= ValDeclaration::USAGE_FOREIGN;
      }

      switch (this->accessMode) {
      case ValDeclaration::MODE_IN:
            if (! this->isForeign) {
                  decl->usage |= ValDeclaration::USAGE_READ;
            }

            switch (decl->mode) {
            case ValDeclaration::MODE_IN:
            case ValDeclaration::MODE_INOUT:
                  // ok
                  break;

            case ValDeclaration::MODE_OUT:
                  // error
                  action = new std::string("read from");
                  mode_s = new std::string("OUT");
                  break;
            }
            break;

      case ValDeclaration::MODE_OUT:
            if (! this->isForeign) {
                  decl->usage |= ValDeclaration::USAGE_WRITE;
            }

            switch (decl->mode) {
            case ValDeclaration::MODE_OUT:
            case ValDeclaration::MODE_INOUT:
                  // ok
                  break;

            case ValDeclaration::MODE_IN:
                  action = new std::string("write to");
                  mode_s = new std::string("IN");
                  break;

            }
            break;

      case ValDeclaration::MODE_INOUT:
            if (! this->isForeign) {
                  decl->usage |= ValDeclaration::USAGE_READ 
                              |  ValDeclaration::USAGE_WRITE;
            } 

            switch (decl->mode) {
            case ValDeclaration::MODE_INOUT:
                  // ok
                  break;

            case ValDeclaration::MODE_IN:
                  // error
                  action = new std::string("use as INOUT");
                  mode_s = new std::string("IN");
                  break;

            case ValDeclaration::MODE_OUT:
                  // error
                  action = new std::string("use as INOUT");
                  mode_s = new std::string("OUT");
                  break;
            }
            break;
      }

      if (action == NULL) {
            return;
      }

      std::string msg = std::string("Trying to ");
      msg += *action;
      msg += " '";
      msg += util::MiscUtil::toString(node);
      msg += "' which is of mode ";
      msg += *mode_s;
      msg += ".";

      delete action;
      delete mode_s;

      CompileError *ce = new CompileError(node, msg);
      ErrorRegistry::addError(ce);
}

void
00142 CheckAccessMode::visit(VarAssignStat &node)
{
      assert(node.source != NULL);
      assert(node.target != NULL);

      this->accessMode = ValDeclaration::MODE_OUT;
      node.target->accept(*this);
      this->accessMode = ValDeclaration::MODE_IN;
      node.source->accept(*this);
}

void
00154 CheckAccessMode::visit(SigAssignStat &node)
{
      assert(node.target != NULL);
      assert(node.waveForm != NULL);

      this->accessMode = ValDeclaration::MODE_OUT;
      node.target->accept(*this);
      this->accessMode = ValDeclaration::MODE_IN;
      this->listTraverse(*node.waveForm);
}

void
00166 CheckAccessMode::visit(Subscript &node)
{
      assert(node.indices != NULL);
      assert(node.source != NULL);

      enum ValDeclaration::Mode backup = this->accessMode;
      bool ifc = this->isForeign;
      this->isForeign = false;
      this->accessMode = ValDeclaration::MODE_IN;

      this->listTraverse(*node.indices);

      this->accessMode = backup;
      this->isForeign = ifc;
      node.source->accept(*this);
}

void
00184 CheckAccessMode::visit(Slice &node)
{
      assert(node.source != NULL);
      assert(node.range != NULL);

      bool ifc = this->isForeign;
      this->isForeign = false;
      enum ValDeclaration::Mode backup = this->accessMode;
      this->accessMode = ValDeclaration::MODE_IN;

      node.range->accept(*this);

      this->isForeign = ifc;
      this->accessMode = backup;
      node.source->accept(*this);
}

void
00202 CheckAccessMode::visit(Aggregate &node)
{
      enum ValDeclaration::Mode backup = this->accessMode;
      bool ifc = this->isForeign;

      assert(node.associations != NULL);

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

            if ((*i)->choices != NULL) {
                  this->isForeign = false;
                  this->accessMode = ValDeclaration::MODE_IN;

                  this->listTraverse(*(*i)->choices);

                  this->accessMode = backup;
                  this->isForeign = ifc;
            }

            if ((*i)->actual != NULL) {
                  (*i)->actual->accept(*this);
            }
      }
}


void
00231 CheckAccessMode::visit(ConstInteger &node)
{
      this->processConst(node);
}

void
00237 CheckAccessMode::visit(ConstReal &node)
{
      this->processConst(node);
}

void
00243 CheckAccessMode::visit(ConstArray &node)
{
      this->processConst(node);
}

void 
00249 CheckAccessMode::processConst(const Expression &node) const
{
      switch (this->accessMode) {
      case ValDeclaration::MODE_IN:
            // ok
            return;

      case ValDeclaration::MODE_INOUT:
      case ValDeclaration::MODE_OUT:
            // error
            break;
      }

      // error case.
      CompileError *ce = 
            new CompileError(node, "Trying to access constant expression "
                              "with OUT/INOUT mode.");
      ErrorRegistry::addError(ce);
}

void
00270 CheckAccessMode::visit(FunctionCall &node)
{
      assert(node.definition != NULL);
      if (node.arguments != NULL) {
            this->processCall(*node.arguments, *node.definition);
      }

      switch (this->accessMode) {
      case ValDeclaration::MODE_IN:
            /* ok */
            return;

      case ValDeclaration::MODE_INOUT:
      case ValDeclaration::MODE_OUT:
            // error (return is a value, and must not be written to
            break;
      }

      CompileError *ce =
            new CompileError(node, "Trying to access the return value of "
                              " a function call via OUT/INOUT.");
      ErrorRegistry::addError(ce);
}

void
00295 CheckAccessMode::visit(ProcCallStat &node)
{
      assert(node.definition != NULL);
      if (node.arguments != NULL) {
            this->processCall(*node.arguments, *node.definition);
      }
}

void
00304 CheckAccessMode::processCall(
      std::list<AssociationElement *> &args,
      const Callable &node
)
{
      bool ifc = this->isForeign;
      AttributeSpecification *spec = node.hasAttr("foreign");
      if (spec != NULL) {
            this->isForeign = true;
      } else {
            this->isForeign = false;
      }

      assert(node.arguments != NULL);

      enum ValDeclaration::Mode backup = this->accessMode;

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

            assert(a != node.arguments->end());
            // FIXME handle formals
            assert((*i)->formal == NULL);
            assert((*i)->actual != NULL); // FIXME open assocs!

            this->accessMode = (*a)->mode;
            (*i)->actual->accept(*this);
      }

      this->accessMode = backup;
      this->isForeign = ifc;
}

void
00340 CheckAccessMode::visit(CompInstStat &node)
{
      assert(node.entity != NULL);

      // FIXME generic map

      if (node.portMap != NULL) {
            for (std::list<AssociationElement*>::iterator i = 
                  node.portMap->begin(); i != node.portMap->end(); 
                  i++) {

                  assert((*i)->formal != NULL);
                  ValDeclaration *port = 
                        dynamic_cast<SignalDeclaration*>(
                              (*i)->formal->getDeclaration());

                  // also propagate info from inside to outside.
                  // it's not necessary to propagate this info *back* 
                  // to the inside of other entities on the same nesting
                  // level, since it doesn't affect these.
                  if ((port->usage & ValDeclaration::USAGE_FOREIGN) 
                        != 0) {
                        this->isForeign = true;
                  }
      
                  this->accessMode = port->mode;
                  (*i)->actual->accept(*this);
                  this->isForeign = false;
            }
      }

      this->accessMode = ValDeclaration::MODE_IN;
      this->isForeign = false;
}

void
00376 CheckAccessMode::visit(Entity &node)
{
      AttributeSpecification *spec = node.hasAttr("foreign");
      if (spec != NULL) {
            assert(node.ports != NULL);

            for (std::list<SignalDeclaration*>::iterator i = 
                  node.ports->begin();
                  i != node.ports->end();
                  i++) {

                  (*i)->usage |= ValDeclaration::USAGE_FOREIGN;
            }
      }
      TopDownVisitor::visit(node);
}

void
00394 CheckAccessMode::process(Callable &node)
{
      AttributeSpecification *spec = node.hasAttr("foreign");

      // arguments of foreign subprograms always have foreign usage
      if (spec != NULL) {
            if (node.arguments != NULL) {
                  for (std::list<ValDeclaration *>::const_iterator i = 
                        node.arguments->begin();
                        i != node.arguments->end(); i++) {

                        (*i)->usage = ValDeclaration::USAGE_FOREIGN;
                  }
            }
      }
      TopDownVisitor::process(node);
}

}; /* namespace ast */

Generated by  Doxygen 1.6.0   Back to index