Logo Search packages:      
Sourcecode: fauhdlc version File versions

ParserDriver.cpp

/* $Id: ParserDriver.cpp 4323 2009-01-27 13:48:12Z potyra $ 
 *
 * ParserDriver: glue class to driver between scanner and parser.
 *
 * Copyright (C) 2007-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */


#include "frontend/newparser/ParserDriver.hpp"
#include "frontend/newparser/FAUhdlScanner.hpp"
#include <iostream>
#include <fstream>
#include <cctype>
#include <algorithm>
#include <stdexcept>
#include <cassert>
#include <sstream>
#include "frontend/reporting/SyntaxError.hpp"
#include "frontend/ast/NodeFactory.hpp"
#include "util/MiscUtil.hpp"
#include "frontend/ast/Callable.hpp"
#include "frontend/misc/NameLookup.hpp"
#include "frontend/reporting/UndefinedSymbol.hpp"
#include "frontend/reporting/ErrorRegistry.hpp"

namespace yy {

00031 ParserDriver::ParserDriver(
      ast::SymbolTable& symTab
      ) :   scanner(NULL),
            topNode(new ast::LibraryList()), 
            currentLibrary(NULL),
            symbolTable(symTab),
            nameLookup(*new ast::NameLookup(symTab)),
            lookupIdentifiers(true),
            label(NULL),
            currentFile(NULL), 
            currentLoc(NULL)
{
}

00045 ParserDriver::~ParserDriver() 
{
      if (this->scanner) {
            delete this->scanner;
      }

      if (this->topNode) {
            util::MiscUtil::terminate(this->topNode);
      }

      delete &this->nameLookup;
}

int 
ParserDriver::yylex(FAUhdlParser::semantic_type* yylval,
                FAUhdlParser::location_type* yylloc)
{
      this->currentLoc = yylloc;

      FAUhdlParser::token_type token =
            this->scanner->yylex(yylval, yylloc, *this);

      /* forward to lexer */
      return token;
}

void 
ParserDriver::error(const FAUhdlParser::location_type& l,
                const std::string& msg) throw(SyntaxError)
{

      std::stringstream stream;

      stream << "ERROR> ";
      if (this->currentFile) {
            stream << *this->currentFile << ":";
      }

      stream << l.begin.line << ": Parse error: "
             << msg << std::endl;

      std::string *emsg = new std::string();
      *emsg = stream.str();

      SyntaxError err = SyntaxError(*emsg);
      throw err;
}


void
00095 ParserDriver::parse(const std::string& filename, const char* libName) 
      throw(std::runtime_error, SyntaxError, ast::CompileError)
{
      std::ifstream inStream;
      // open file
      inStream.open(filename.c_str(), std::ifstream::in);

      if (! inStream.good()) {
            inStream.close();
            throw std::runtime_error("Failed to open file <" 
                               + filename + ">");
      }

      // set up scanner 
      this->scanner = new FAUhdlScanner(&inStream, &std::cout);
      FAUhdlParser parser = FAUhdlParser(*this);

      this->currentFile = new std::string(filename);
      this->currentLibrary = this->topNode->enterLibrary(libName);

      // enter library region
      this->symbolTable.pushLibrary(*(this->currentLibrary));

      // push new region that will be the region of the first
      // design unit (and will get pop'd from within the parser)
      this->symbolTable.pushNewRegion();

      // parse stuff
      parser.parse();
      // close stream again
      inStream.close();

      this->currentFile = NULL;

      // leave anonymous region that would contain the next design_unit
      // again
      this->symbolTable.popRegion();
      // leave library region again
      this->symbolTable.popRegion();
}

void
00137 ParserDriver::toLower(std::string& mixed)
{
      std::transform(mixed.begin(), mixed.end(), mixed.begin(),
                  static_cast<int(*)(int)>(std::tolower));
}

long
00144 ParserDriver::makeLong(const std::string& intval, unsigned char base)
      throw(std::invalid_argument, std::out_of_range)
{
      long result = 0;
      unsigned char basemul = 1;
      unsigned int i=0;
      char c;
      char digitValue;
      bool negative = false;

      if (intval[i] == '-' || intval[i] == '+') {
            if (intval[i] == '-') {
                  negative = true;
            }
            i++;
      }

      
      for (; i < intval.length(); i++) {
            c = intval[i];
            digitValue = ParserDriver::getDigitValue(c);
            if (digitValue == -1) {
                  throw std::invalid_argument(
                        "not a correct parameter <intval>"
                          " number: " + intval);
            }

            if (base < digitValue) {
                  throw std::out_of_range(
                        "digit in <intval> greater than base " 
                        " number: " + intval);
            }

            result *= basemul;
            result += digitValue;
            basemul = base;
      }
      
      if (negative) {
            return -result;
      }

      return result;
}

std::string*
00190 ParserDriver::removeQuotes(std::string s)
{
      unsigned long i;
      /* surrounding quotes */
      s.erase(0, 1);
      s.erase(s.length() - 1, 1);
      
      /* replace all "" with " */
      i = s.find("\"\"", 0);
      while (i != std::string::npos) {
            s.erase(i, 1);
            i = s.find("\"\"", 0);
      }

      return new std::string(s);
}

std::string*
00208 ParserDriver::makeBitString(std::string s) throw(std::out_of_range)
{
      char spec = s[0];

      if (spec == 'X' || spec == 'x') {
            return ParserDriver::makeHexBitString(s);
      } else if (spec == 'o' || spec == 'O') {
            return ParserDriver::makeOctBitString(s);
      }

      assert(spec == 'b' || spec == 'B');

      unsigned long i;
      i = s.find('_');
      while (i != std::string::npos) {
            s.erase(i, 1);
            i = s.find('_');
      }

      // spec && first "
      s.erase(0, 2);
      // last "
      s.erase(s.length() - 1, 1);
      
      return new std::string(s);
}

void
00236 ParserDriver::registerLibUnit(ast::LibUnit *unit)
{
      assert(this->currentLibrary);
      this->currentLibrary->units.push_back(unit);
}

FAUhdlParser::token_type
00243 ParserDriver::getTokenForId(
      const char *id,
      ast::NodeFactory::Identifier *&semanticValue,
      const FAUhdlParser::location_type &loc
) const
{
      std::string* s = new std::string(id); 
      ParserDriver::toLower(*s);

      std::list<ast::Symbol*> syms = std::list<ast::Symbol*>(); 

      if (this->lookupIdentifiers) {
            syms = this->nameLookup.lookup(*s);

            // eventually register an error
            if (syms.empty()) {
                  this->reportNameError(id, loc);
            }
      }

      semanticValue = new ast::NodeFactory::Identifier(s, syms);

      return ParserDriver::reduceSymbolToToken(semanticValue->candidates);

}

ast::SimpleName*
00270 ParserDriver::buildOperatorName(
      const char *op,
      const FAUhdlParser::location_type &loc
) const
{
      ast::SimpleName* s = new ast::SimpleName(op, this->bl(loc));

      // FIXME currently, this bypasses any selected scope by a 
      // direct lookup in the SymbolTable. The current grammar 
      // doesn't support expanded name as an operator, so it 
      // doesn't matter. If the grammar is fixed, this should use
      // NameLookup instead.
      s->candidates = this->symbolTable.lookup(std::string(op));
      if (s->candidates.empty()) {
            this->reportNameError(op, loc);
      }

      return s;
}

std::string*
00291 ParserDriver::makeHexBitString(std::string& s)
{
      const char lookupHex[16][5] = {
            "0000",
            "0001",
            "0010",
            "0011",
            "0100",
            "0101",
            "0110",
            "0111",
            "1000",
            "1001",
            "1010",
            "1011",
            "1100",
            "1101",
            "1110",
            "1111"
      };

      std::string *result = new std::string();

      for (unsigned int i=2; i < s.length() - 1; i++) {
            char v = ParserDriver::getDigitValue(s[i]);
            if (v < 0) {
                  continue;
            }
            /* should not happen. scanner's fault otherwise */
            assert(v <= 0xF);
            result->append(lookupHex[static_cast<short>(v)]);
      }

      return result;
}

std::string*
00328 ParserDriver::makeOctBitString(std::string& s) throw(std::out_of_range)
{
      const char lookupOctal[8][4] = {
            "000",
            "001",
            "010",
            "011",
            "100",
            "101",
            "110",
            "111"
      };


      std::string *result = new std::string();

      /* x"3314_F_124_4" */
      for (unsigned int i=2; i < s.length() - 1; i++) {
            char v = ParserDriver::getDigitValue(s[i]);
            if (v < 0) {
                  continue;
            }
            if (v > 7) {
                  delete result;
                  throw std::out_of_range("digit out of range: "
                              + s);
            }
            result->append(lookupOctal[static_cast<short>(v)]);
      }
      
      return result;
}

char
00362 ParserDriver::getDigitValue(char c)
{
      if (('0' <= c) && (c <= '9')) {
            return static_cast<char>(c - '0');
      } else if (('A' <= c) && (c <= 'Z')) {
            return static_cast<char>(c - 'A' + 10);
      } else if (('a' <= c) && (c <= 'z')) {
            return static_cast<char>(c - 'a' + 10);
      }

      return -1;
}

FAUhdlParser::token_type
00376 ParserDriver::reduceSymbolToToken(std::list<ast::Symbol*> candidates)
{
      bool overloadPossible = false;

      // no candidates -> symbol was not found. unclassified identifier.
      if (candidates.empty()) {
            return FAUhdlParser::token::t_Identifier;
      }

      FAUhdlParser::token_type ret = FAUhdlParser::token::t_Identifier;

      switch(candidates.front()->type) {
      case ast::SYMBOL_PROCEDURE:
            ret = FAUhdlParser::token::ID_procedure;
            overloadPossible = true;
            break;

      case ast::SYMBOL_TYPE:
            ret = FAUhdlParser::token::ID_type;
            overloadPossible = true;
            break;

      case ast::SYMBOL_FUNCTION:
            ret = FAUhdlParser::token::ID_function;
            overloadPossible = true;
            break;

      case ast::SYMBOL_ALL:
            assert(false);

      default:
            ret = FAUhdlParser::token::t_Identifier;
            break;
      }

      if (candidates.size() == 1) {
            return ret;
      }

      /* more than one candidate: all should be of same type, otherwise
       * s.th. is wrong, at least if not of an overloadable type.
       * (FIXME: enum literal == function,
       *         procedure vs. function (necessary?)
       */
      for (std::list<ast::Symbol*>::const_iterator i = candidates.begin();
            i != candidates.end(); i++) {

            switch((*i)->type) {
            case ast::SYMBOL_PROCEDURE:
                  assert(overloadPossible);
                  break;

            case ast::SYMBOL_FUNCTION:
                  assert(ret == FAUhdlParser::token::ID_function);
                  break;

            default:
                  assert(ret == FAUhdlParser::token::t_Identifier);
                  break;
            }
      }

      return ret;

}

void
00443 ParserDriver::reportNameError(
      const char *id,
      const FAUhdlParser::location_type &loc
) const
{
      assert(this->lookupIdentifiers);
      ast::UndefinedSymbol *e = new ast::UndefinedSymbol(
                              std::string(id),
                              this->bl(loc));

      ast::ErrorRegistry::addError(e);
}

}; /* namespace yy */


Generated by  Doxygen 1.6.0   Back to index