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: */