mycpu/cprogram.h

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 /* forward declare CInstruction */
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     /* members */
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   /* free instruction set */
00182   for (setiterator it = m_instrset.begin(); it != m_instrset.end(); ++it)
00183     delete *it;
00184 
00185   /* free instruction */
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     /* read stream per line */
00205     std::getline(in, line);
00206     if (line.empty())
00207       continue;
00208 
00209     boost::trim(line);
00210     boost::to_lower(line);
00211 
00212     /* ignore comments */
00213     if (line.find_first_of('#') == 0)
00214       continue;
00215 
00216     /* get instruction name */
00217     size_t pos = line.find_first_of(' ');
00218     std::string instrname(line.substr(0, pos));
00219 
00220     /* search and create instruction */
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     /* create instruction */
00239     CInstruction<T> *instr = instrptr->factory();
00240 
00241     /* parse instruction parameters */
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     /* let instruction parse the parameters. catch+throw exception */
00248     try
00249     {
00250       /* handle label instruction ourself, but still add a dummy instruction */
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 /* vim: set et sw=2 ts=2: */

Generated on Sat May 30 16:32:35 2009 for mycpu by  doxygen 1.5.3