/** * @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 #include #ifdef DEBUG # include # include #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::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::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 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::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: */