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 26.05.2009
*/
#ifndef CPROGRAM_H
#define CPROGRAM_H 1
#include <vector>
#include <set>
#include <map>
#include <stdexcept>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/split.hpp>
#ifdef DEBUG
# include <iostream>
# include <iomanip>
#endif
/**
* @class CProgramError
*
* Exception thrown by implemententations of CProgram
*/
class CProgramError
: public std::invalid_argument
{
public:
/**
* @method CProgramError
* @brief Default exception ctor
* @param what message to pass along
* @return -
* @globalvars none
* @exception none
* @pre none
* @post none
*/
CProgramError(const std::string& what)
: std::invalid_argument(what)
{}
};
#include "cinstruction.h"
#include "instructions.h"
/* forward declare CInstruction */
template <class T>
class CInstruction;
/**
* @class CProgram
*
* CProgram extends std::vector and adds a method for parsing
* programfile. This adds instances of CInstruction to CProgram itself.
*/
template <class T>
class CProgram
: public std::vector<CInstruction<T> *>
{
typedef typename std::set<CInstruction<T> *>::iterator setiterator;
typedef std::vector<CInstruction<T> *> super;
typedef typename super::iterator iterator;
using super::begin;
using super::end;
using super::size;
public:
/**
* @method CProgram
* @brief Default ctor
* @param -
* @return -
* @globalvars none
* @exception none
* @pre none
* @post none
*/
CProgram();
/**
* @method ~CProgram
* @brief Default dtor
* @param -
* @return -
* @globalvars none
* @exception none
* @pre none
* @post none
*/
~CProgram();
/**
* @method getLabels
* @brief get reference to labels map
* @param -
* @return reference to labels map
* @globalvars none
* @exception none
* @pre none
* @post none
*/
const std::map<std::string, unsigned>& getLabels() const
{
return m_labels;
}
/**
* @method findLabel
* @brief search for label
* @param label name of label to search for
* @return index of found label in program
* @globalvars none
* @exception CProgramError
* @pre none
* @post none
*/
unsigned findLabel(const std::string& label) const;
/**
* @method compile
* @brief create instructions from parsing stream
* @param in inputstream to read from
* @return void
* @globalvars none
* @exception CProgramError
* @pre none
* @post none
*/
void compile(std::istream& in);
#if DEBUG
/**
* @method dump
* @brief dumps contents to outputstream
* @param out outputstream to write to
* @return void
* @globalvars none
* @exception none
* @pre none
* @post none
*/
void dump(std::ostream& out);
#endif
private:
/* members */
/** set of known instructions */
std::set<CInstruction<T> *> m_instrset;
std::map<std::string, unsigned> m_labels;
};
/*----------------------------------------------------------------------------*/
template <class T>
CProgram<T>::CProgram()
{
m_instrset.insert(new CInstructionInc<T>);
m_instrset.insert(new CInstructionDec<T>);
m_instrset.insert(new CInstructionAdd<T>);
m_instrset.insert(new CInstructionSub<T>);
m_instrset.insert(new CInstructionMul<T>);
m_instrset.insert(new CInstructionDiv<T>);
m_instrset.insert(new CInstructionLoad<T>);
m_instrset.insert(new CInstructionStore<T>);
m_instrset.insert(new CInstructionTest<T>);
m_instrset.insert(new CInstructionLabel<T>);
m_instrset.insert(new CInstructionJumpA<T>);
m_instrset.insert(new CInstructionJumpZ<T>);
m_instrset.insert(new CInstructionJumpS<T>);
m_instrset.insert(new CInstructionWrite<T>);
}
/*----------------------------------------------------------------------------*/
template <class T>
CProgram<T>::~CProgram()
{
/* free instruction set */
for (setiterator it = m_instrset.begin(); it != m_instrset.end(); ++it)
delete *it;
/* free instruction */
for (iterator it2 = begin(); it2 != end(); ++it2)
delete *it2;
}
/*----------------------------------------------------------------------------*/
template <class T>
void CProgram<T>::compile(std::istream& in)
{
if (!in.good())
return;
std::string line;
unsigned i = 0;
while (!in.eof() && in.good())
{
++i;
/* read stream per line */
std::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(' ');
std::string instrname(line.substr(0, pos));
/* search and create instruction */
CInstruction<T> *instrptr = NULL;
setiterator it;
for (it = m_instrset.begin(); it != m_instrset.end(); ++it)
{
if (*(*it) == instrname)
{
instrptr = *it;
break;
}
}
if (instrptr == NULL)
{
std::stringstream sstr;
sstr << "Unknown instruction '" << instrname << "' on line " << i << ".";
throw CProgramError(sstr.str());
}
/* create instruction */
CInstruction<T> *instr = instrptr->factory();
/* parse instruction parameters */
std::string params = (pos == std::string::npos) ? "" : line.substr(pos + 1);
boost::trim(params);
std::list<std::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 CInstructionError("Invalid paramater count - must be 1");
std::string label(instrparams.front());
if (label.length() < 2 || label[ label.length() - 1] != ':')
throw CInstructionError("Label has invalid syntax");
m_labels[ label.substr(0, label.length() - 1) ] = size();
}
instr->compile(instrparams);
}
catch(CInstructionError& ex)
{
std::stringstream sstr;
sstr << "Unable to compile instruction '" << instrname
<< "' (line " << i << "): " << ex.what();
throw CProgramError(sstr.str());
}
push_back(instr);
}
}
/*----------------------------------------------------------------------------*/
template <class T>
unsigned CProgram<T>::findLabel(const std::string& label) const
{
std::map<std::string, unsigned>::const_iterator it;
it = m_labels.find(label);
if (it == m_labels.end())
throw CProgramError("Unknown label '" + label + "'");
return it->second;
}
/*----------------------------------------------------------------------------*/
#if DEBUG
template <class T>
void CProgram<T>::dump(std::ostream& out)
{
out << "[PROGRAM DUMP]" << std::endl;
unsigned i = 0;
for(iterator it = begin(); it != end(); ++it)
{
out << "[" << std::setw(4) << std::setfill('0') << i << "] "
<< *(*it) << std::endl;
++i;
}
}
#endif
#endif
/* vim: set et sw=2 ts=2: */