/** * @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 #include #include #include #include #include #ifdef DEBUG # include # include #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 CInstruction; /** * @class CProgram * * 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 *> { 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 * @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& 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 *> 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 CProgramError(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 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 unsigned CProgram::findLabel(const std::string& label) const { std::map::const_iterator it; it = m_labels.find(label); if (it == m_labels.end()) throw CProgramError("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: */