From 26a97259f5a7b066cff2927e88c867fac2aaad87 Mon Sep 17 00:00:00 2001 From: manuel Date: Tue, 26 May 2009 23:10:13 +0200 Subject: template FTW!!!!!11 --- ue4/mycpu/cprogram.h | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 3 deletions(-) (limited to 'ue4/mycpu/cprogram.h') diff --git a/ue4/mycpu/cprogram.h b/ue4/mycpu/cprogram.h index 27e7647..43193ac 100644 --- a/ue4/mycpu/cprogram.h +++ b/ue4/mycpu/cprogram.h @@ -2,7 +2,7 @@ * @module cprogram * @author Guenther Neuwirth (0626638), Manuel Mausz (0728348) * @brief CProgram extends std::vector and adds a method for parsing programfile - * @date 10.05.2009 + * @date 26.05.2009 */ #ifndef CPROGRAM_H @@ -11,7 +11,18 @@ #include #include #include +#include +#include +#ifdef DEBUG +# include +# include +#endif #include "cinstruction.h" +#include "instructions.h" + +/* forward declare CInstruction */ +template +class CInstruction; /** * @class CProgram @@ -19,9 +30,17 @@ * CProgram extends std::vector and adds a method for parsing * programfile. This adds instances of CInstruction to CProgram itself. */ +template class CProgram - : public std::vector + : public std::vector *> { + typedef typename std::set *>::iterator setiterator; + typedef std::vector *> super; + typedef typename super::iterator iterator; + using super::begin; + using super::end; + using super::size; + public: /** * @method CProgram @@ -97,10 +116,158 @@ class CProgram private: /* members */ /** set of known instructions */ - std::set m_instrset; + std::set *> m_instrset; std::map m_labels; }; +/*----------------------------------------------------------------------------*/ + +template +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); +} + +/*----------------------------------------------------------------------------*/ + +template +CProgram::~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 +void CProgram::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 *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 std::runtime_error(sstr.str()); + } + + /* create instruction */ + CInstruction *instr = instrptr->factory(); + + /* parse instruction parameters */ + std::string params = (pos == std::string::npos) ? "" : line.substr(pos + 1); + boost::trim(params); + std::list 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 std::runtime_error("Invalid paramater count - must be 1"); + std::string label(instrparams.front()); + if (label.length() < 2 || label[ label.length() - 1] != ':') + throw std::runtime_error("Label has invalid syntax"); + m_labels[ label.substr(0, label.length() - 1) ] = size(); + } + instr->compile(instrparams); + } + catch(std::runtime_error& ex) + { + std::stringstream sstr; + sstr << "Unable to compile instruction '" << instrname + << "' (line " << i << "): " << ex.what(); + throw std::runtime_error(sstr.str()); + } + + push_back(instr); + } +} + +/*----------------------------------------------------------------------------*/ + +template +unsigned CProgram::findLabel(const std::string& label) const +{ + std::map::const_iterator it; + it = m_labels.find(label); + if (it == m_labels.end()) + throw std::runtime_error("Unknown label '" + label + "'"); + return it->second; +} + +/*----------------------------------------------------------------------------*/ + +#if DEBUG +template +void CProgram::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: */ -- cgit v1.2.3