Download | Plain Text | Line Numbers


/**
 * @module cprogram
 * @author Guenther Neuwirth (0626638), Manuel Mausz (0728348)
 * @brief  CProgram extends std::vector and adds a method for parsing programfile
 * @date   12.05.2009
 */
 
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/split.hpp>
#ifdef DEBUG
# include <iostream>
# include <iomanip>
#endif
#include "cprogram.h"
#include "instructions.h"
 
using namespace std;
 
CProgram::CProgram()
{
  m_instrset.insert(new CInstructionInc);
  m_instrset.insert(new CInstructionDec);
  m_instrset.insert(new CInstructionAdd);
  m_instrset.insert(new CInstructionSub);
  m_instrset.insert(new CInstructionMul);
  m_instrset.insert(new CInstructionDiv);
  m_instrset.insert(new CInstructionLoad);
  m_instrset.insert(new CInstructionStore);
  m_instrset.insert(new CInstructionTest);
  m_instrset.insert(new CInstructionLabel);
  m_instrset.insert(new CInstructionJumpA);
  m_instrset.insert(new CInstructionJumpZ);
  m_instrset.insert(new CInstructionJumpS);
  m_instrset.insert(new CInstructionWrite);
}
 
/*----------------------------------------------------------------------------*/
 
CProgram::~CProgram()
{
  /* free instruction set */
  set<CInstruction *>::iterator it;
  for (it = m_instrset.begin(); it != m_instrset.end(); ++it)
    delete *it;
 
  /* free instruction */
  for (iterator it = begin(); it != end(); ++it)
    delete *it;
}
 
/*----------------------------------------------------------------------------*/
 
void CProgram::compile(std::istream& in)
{
  if (!in.good())
    return;
 
  string line;
  unsigned i = 0;
  while (!in.eof() && in.good())
  {
    ++i;
 
    /* read stream per line */
    getline(in, line);
    if (line.empty())
      continue;
 
    boost::trim(line);
    boost::to_lower(line);
 
    /* ignore comments */
    if (line.find_first_of('#') == 0)
      continue;
 
    /* get instruction name */
    size_t pos = line.find_first_of(' ');
    string instrname(line.substr(0, pos));
 
    /* search and create instruction */
    CInstruction *instrptr = NULL;
    set<CInstruction *>::iterator it;
    for (it = m_instrset.begin(); it != m_instrset.end(); ++it)
    {
      if (*(*it) == instrname)
      {
        instrptr = *it;
        break;
      }
    }
    if (instrptr == NULL)
    {
      stringstream sstr;
      sstr << "Unknown instruction '" << instrname << "' on line " << i << ".";
      throw runtime_error(sstr.str());
    }
 
    /* create instruction */
    CInstruction *instr = instrptr->factory();
 
    /* parse instruction parameters */
    string params = (pos == string::npos) ? "" : line.substr(pos + 1);
    boost::trim(params);
    list<string> instrparams;
    boost::split(instrparams, params, boost::is_any_of(", \t"), boost::token_compress_on);
 
    /* let instruction parse the parameters. catch+throw exception */
    try
    {
      /* handle label instruction ourself, but still add a dummy instruction */
      if (instrname == "label")
      {
        if (instrparams.size() != 1)
          throw runtime_error("Invalid paramater count - must be 1");
        string label(instrparams.front());
        if (label.length() < 2 || label[ label.length() - 1] != ':')
          throw runtime_error("Label has invalid syntax");
        m_labels[ label.substr(0, label.length() - 1) ] = size();
      }
      instr->compile(instrparams);
    }
    catch(runtime_error& ex)
    {
      stringstream sstr;
      sstr << "Unable to compile instruction '" << instrname
           << "' (line " << i << "): " << ex.what();
      throw runtime_error(sstr.str());
    }
 
    push_back(instr);
  }
}
 
/*----------------------------------------------------------------------------*/
 
unsigned CProgram::findLabel(const std::string& label) const
{
  map<string, unsigned>::const_iterator it;
  it = m_labels.find(label);
  if (it == m_labels.end())
    throw runtime_error("Unknown label '" + label + "'");
  return it->second;
}
 
/*----------------------------------------------------------------------------*/
 
#if DEBUG
void CProgram::dump(std::ostream& out)
{
  out << "[PROGRAM DUMP]" << endl;
  unsigned i = 0;
  for(iterator it = begin(); it < end(); ++it)
  {
    out << "[" << std::setw(4) << std::setfill('0') << i << "]  "
        << *(*it) << endl;
    ++i;
  }
}
#endif
 
/* vim: set et sw=2 ts=2: */