00001
00008 #ifndef CPROGRAM_H
00009 #define CPROGRAM_H 1
00010
00011 #include <vector>
00012 #include <set>
00013 #include <map>
00014 #include <stdexcept>
00015 #include <boost/algorithm/string.hpp>
00016 #include <boost/algorithm/string/split.hpp>
00017 #ifdef DEBUG
00018 # include <iostream>
00019 # include <iomanip>
00020 #endif
00021
00027 class CProgramError
00028 : public std::invalid_argument
00029 {
00030 public:
00041 CProgramError(const std::string& what)
00042 : std::invalid_argument(what)
00043 {}
00044 };
00045
00046 #include "cinstruction.h"
00047 #include "instructions.h"
00048
00049
00050 template <class T>
00051 class CInstruction;
00052
00059 template <class T>
00060 class CProgram
00061 : public std::vector<CInstruction<T> *>
00062 {
00063 typedef typename std::set<CInstruction<T> *>::iterator setiterator;
00064 typedef std::vector<CInstruction<T> *> super;
00065 typedef typename super::iterator iterator;
00066 using super::begin;
00067 using super::end;
00068 using super::size;
00069
00070 public:
00081 CProgram();
00082
00093 ~CProgram();
00094
00105 const std::map<std::string, unsigned>& getLabels() const
00106 {
00107 return m_labels;
00108 }
00109
00120 unsigned findLabel(const std::string& label) const;
00121
00132 void compile(std::istream& in);
00133
00134 #if DEBUG
00135
00145 void dump(std::ostream& out);
00146 #endif
00147
00148 private:
00149
00151 std::set<CInstruction<T> *> m_instrset;
00152 std::map<std::string, unsigned> m_labels;
00153 };
00154
00155
00156
00157 template <class T>
00158 CProgram<T>::CProgram()
00159 {
00160 m_instrset.insert(new CInstructionInc<T>);
00161 m_instrset.insert(new CInstructionDec<T>);
00162 m_instrset.insert(new CInstructionAdd<T>);
00163 m_instrset.insert(new CInstructionSub<T>);
00164 m_instrset.insert(new CInstructionMul<T>);
00165 m_instrset.insert(new CInstructionDiv<T>);
00166 m_instrset.insert(new CInstructionLoad<T>);
00167 m_instrset.insert(new CInstructionStore<T>);
00168 m_instrset.insert(new CInstructionTest<T>);
00169 m_instrset.insert(new CInstructionLabel<T>);
00170 m_instrset.insert(new CInstructionJumpA<T>);
00171 m_instrset.insert(new CInstructionJumpZ<T>);
00172 m_instrset.insert(new CInstructionJumpS<T>);
00173 m_instrset.insert(new CInstructionWrite<T>);
00174 }
00175
00176
00177
00178 template <class T>
00179 CProgram<T>::~CProgram()
00180 {
00181
00182 for (setiterator it = m_instrset.begin(); it != m_instrset.end(); ++it)
00183 delete *it;
00184
00185
00186 for (iterator it2 = begin(); it2 != end(); ++it2)
00187 delete *it2;
00188 }
00189
00190
00191
00192 template <class T>
00193 void CProgram<T>::compile(std::istream& in)
00194 {
00195 if (!in.good())
00196 return;
00197
00198 std::string line;
00199 unsigned i = 0;
00200 while (!in.eof() && in.good())
00201 {
00202 ++i;
00203
00204
00205 std::getline(in, line);
00206 if (line.empty())
00207 continue;
00208
00209 boost::trim(line);
00210 boost::to_lower(line);
00211
00212
00213 if (line.find_first_of('#') == 0)
00214 continue;
00215
00216
00217 size_t pos = line.find_first_of(' ');
00218 std::string instrname(line.substr(0, pos));
00219
00220
00221 CInstruction<T> *instrptr = NULL;
00222 setiterator it;
00223 for (it = m_instrset.begin(); it != m_instrset.end(); ++it)
00224 {
00225 if (*(*it) == instrname)
00226 {
00227 instrptr = *it;
00228 break;
00229 }
00230 }
00231 if (instrptr == NULL)
00232 {
00233 std::stringstream sstr;
00234 sstr << "Unknown instruction '" << instrname << "' on line " << i << ".";
00235 throw CProgramError(sstr.str());
00236 }
00237
00238
00239 CInstruction<T> *instr = instrptr->factory();
00240
00241
00242 std::string params = (pos == std::string::npos) ? "" : line.substr(pos + 1);
00243 boost::trim(params);
00244 std::list<std::string> instrparams;
00245 boost::split(instrparams, params, boost::is_any_of(", \t"), boost::token_compress_on);
00246
00247
00248 try
00249 {
00250
00251 if (instrname == "label")
00252 {
00253 if (instrparams.size() != 1)
00254 throw CInstructionError("Invalid paramater count - must be 1");
00255 std::string label(instrparams.front());
00256 if (label.length() < 2 || label[ label.length() - 1] != ':')
00257 throw CInstructionError("Label has invalid syntax");
00258 m_labels[ label.substr(0, label.length() - 1) ] = size();
00259 }
00260 instr->compile(instrparams);
00261 }
00262 catch(CInstructionError& ex)
00263 {
00264 std::stringstream sstr;
00265 sstr << "Unable to compile instruction '" << instrname
00266 << "' (line " << i << "): " << ex.what();
00267 throw CProgramError(sstr.str());
00268 }
00269
00270 push_back(instr);
00271 }
00272 }
00273
00274
00275
00276 template <class T>
00277 unsigned CProgram<T>::findLabel(const std::string& label) const
00278 {
00279 std::map<std::string, unsigned>::const_iterator it;
00280 it = m_labels.find(label);
00281 if (it == m_labels.end())
00282 throw CProgramError("Unknown label '" + label + "'");
00283 return it->second;
00284 }
00285
00286
00287
00288 #if DEBUG
00289 template <class T>
00290 void CProgram<T>::dump(std::ostream& out)
00291 {
00292 out << "[PROGRAM DUMP]" << std::endl;
00293 unsigned i = 0;
00294 for(iterator it = begin(); it != end(); ++it)
00295 {
00296 out << "[" << std::setw(4) << std::setfill('0') << i << "] "
00297 << *(*it) << std::endl;
00298 ++i;
00299 }
00300 }
00301 #endif
00302
00303 #endif
00304
00305