diff options
Diffstat (limited to 'ue3/mycpu/cprogram.cpp')
| -rw-r--r-- | ue3/mycpu/cprogram.cpp | 186 |
1 files changed, 119 insertions, 67 deletions
diff --git a/ue3/mycpu/cprogram.cpp b/ue3/mycpu/cprogram.cpp index 9297b6e..3fcf734 100644 --- a/ue3/mycpu/cprogram.cpp +++ b/ue3/mycpu/cprogram.cpp | |||
| @@ -1,109 +1,161 @@ | |||
| 1 | /** | 1 | /** |
| 2 | * @module cprogram | 2 | * @module cprogram |
| 3 | * @author Guenther Neuwirth (0626638), Manuel Mausz (0728348) | 3 | * @author Guenther Neuwirth (0626638), Manuel Mausz (0728348) |
| 4 | * @brief class for parsing and saving a program | 4 | * @brief CProgram extends std::vector and adds a method for parsing programfile |
| 5 | * @date 11.05.2009 | 5 | * @date 12.05.2009 |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include <fstream> | ||
| 9 | #include <vector> | ||
| 10 | #include <string> | ||
| 11 | #include <boost/tokenizer.hpp> | ||
| 12 | #include <boost/algorithm/string.hpp> | 8 | #include <boost/algorithm/string.hpp> |
| 13 | #include <boost/algorithm/string/split.hpp> | 9 | #include <boost/algorithm/string/split.hpp> |
| 10 | #ifdef DEBUG | ||
| 11 | # include <iostream> | ||
| 12 | # include <iomanip> | ||
| 13 | #endif | ||
| 14 | #include "cprogram.h" | 14 | #include "cprogram.h" |
| 15 | 15 | #include "instructions.h" | |
| 16 | |||
| 17 | 16 | ||
| 18 | using namespace std; | 17 | using namespace std; |
| 19 | using namespace boost; | ||
| 20 | 18 | ||
| 21 | CProgram::CProgram(const std::string& progfile) : | 19 | CProgram::CProgram() |
| 22 | m_programfile(progfile) | ||
| 23 | { | 20 | { |
| 24 | parse(); | 21 | m_instrset.insert(new CInstructionInc); |
| 25 | dump(std::cout); | 22 | m_instrset.insert(new CInstructionDec); |
| 26 | 23 | m_instrset.insert(new CInstructionAdd); | |
| 24 | m_instrset.insert(new CInstructionSub); | ||
| 25 | m_instrset.insert(new CInstructionMul); | ||
| 26 | m_instrset.insert(new CInstructionDiv); | ||
| 27 | m_instrset.insert(new CInstructionLoad); | ||
| 28 | m_instrset.insert(new CInstructionStore); | ||
| 29 | m_instrset.insert(new CInstructionTest); | ||
| 30 | m_instrset.insert(new CInstructionLabel); | ||
| 31 | m_instrset.insert(new CInstructionJumpA); | ||
| 32 | m_instrset.insert(new CInstructionJumpZ); | ||
| 33 | m_instrset.insert(new CInstructionJumpS); | ||
| 34 | m_instrset.insert(new CInstructionWrite); | ||
| 27 | } | 35 | } |
| 28 | 36 | ||
| 29 | /*----------------------------------------------------------------------------*/ | 37 | /*----------------------------------------------------------------------------*/ |
| 30 | 38 | ||
| 31 | CProgram::~CProgram() | 39 | CProgram::~CProgram() |
| 32 | { | 40 | { |
| 33 | 41 | /* free instruction set */ | |
| 42 | set<CInstruction *>::iterator it; | ||
| 43 | for (it = m_instrset.begin(); it != m_instrset.end(); ++it) | ||
| 44 | delete *it; | ||
| 45 | |||
| 46 | /* free instruction */ | ||
| 47 | for (iterator it = begin(); it != end(); ++it) | ||
| 48 | delete *it; | ||
| 34 | } | 49 | } |
| 35 | 50 | ||
| 36 | |||
| 37 | |||
| 38 | /*----------------------------------------------------------------------------*/ | 51 | /*----------------------------------------------------------------------------*/ |
| 39 | 52 | ||
| 40 | void CProgram::parse() | 53 | void CProgram::compile(std::istream& in) |
| 41 | { | 54 | { |
| 42 | /* open and read file */ | 55 | if (!in.good()) |
| 43 | ifstream file(m_programfile.c_str(), ios::in); | 56 | return; |
| 44 | // if (!file) | 57 | |
| 45 | // throw ParserError("Unable to open scriptfile '" + m_scriptfile + "'."); | 58 | string line; |
| 46 | 59 | unsigned i = 0; | |
| 47 | int cur_line_nr = 0; | 60 | while (!in.eof() && in.good()) |
| 48 | |||
| 49 | while (!file.eof() && file.good()) | ||
| 50 | { | 61 | { |
| 51 | string cur_line; | 62 | ++i; |
| 52 | 63 | ||
| 53 | /* read file per line */ | 64 | /* read stream per line */ |
| 54 | getline(file, cur_line); | 65 | getline(in, line); |
| 55 | if (cur_line.empty()) | 66 | if (line.empty()) |
| 56 | continue; | 67 | continue; |
| 57 | 68 | ||
| 58 | trim(cur_line); | 69 | boost::trim(line); |
| 70 | boost::to_lower(line); | ||
| 59 | 71 | ||
| 60 | /* ignore comments */ | 72 | /* ignore comments */ |
| 61 | if (cur_line.find_first_of('#') == 0) | 73 | if (line.find_first_of('#') == 0) |
| 62 | continue; | 74 | continue; |
| 63 | 75 | ||
| 64 | /*remove commas from current line */ | 76 | /* get instruction name */ |
| 65 | unsigned int pos; | 77 | size_t pos = line.find_first_of(' '); |
| 66 | while (( pos = cur_line.find_first_of(",") ) != string::npos) | 78 | string instrname(line.substr(0, pos)); |
| 67 | cur_line.erase(pos, 1); | 79 | |
| 68 | 80 | /* search and create instruction */ | |
| 69 | /* add source line*/ | 81 | CInstruction *instrptr = NULL; |
| 70 | m_progsource.push_back(vector<string>()); | 82 | set<CInstruction *>::iterator it; |
| 71 | algorithm::split( m_progsource.back(), cur_line, is_any_of(" \t")); | 83 | for (it = m_instrset.begin(); it != m_instrset.end(); ++it) |
| 72 | 84 | { | |
| 73 | /* jump addr as line number */ | 85 | if (*(*it) == instrname) |
| 74 | if(m_progsource[cur_line_nr][0] == "label") | 86 | { |
| 75 | { | 87 | instrptr = *it; |
| 76 | int size = m_progsource[cur_line_nr][01].size() - 1; | 88 | break; |
| 77 | string label(m_progsource[cur_line_nr][01].substr(0, size)); | 89 | } |
| 78 | m_jumpaddr[label] = cur_line_nr; | 90 | } |
| 79 | } | 91 | if (instrptr == NULL) |
| 80 | 92 | { | |
| 81 | cur_line_nr++; | 93 | stringstream sstr; |
| 94 | sstr << "Unknown instruction '" << instrname << "' on line " << i << "."; | ||
| 95 | throw runtime_error(sstr.str()); | ||
| 96 | } | ||
| 97 | |||
| 98 | /* create instruction */ | ||
| 99 | CInstruction *instr = instrptr->factory(); | ||
| 100 | |||
| 101 | /* parse instruction parameters */ | ||
| 102 | string params = (pos == string::npos) ? "" : line.substr(pos + 1); | ||
| 103 | boost::trim(params); | ||
| 104 | list<string> instrparams; | ||
| 105 | boost::split(instrparams, params, boost::is_any_of(", \t"), boost::token_compress_on); | ||
| 106 | |||
| 107 | /* let instruction parse the parameters. catch+throw exception */ | ||
| 108 | try | ||
| 109 | { | ||
| 110 | /* handle label instruction ourself, but still add a dummy instruction */ | ||
| 111 | if (instrname == "label") | ||
| 112 | { | ||
| 113 | if (instrparams.size() != 1) | ||
| 114 | throw runtime_error("Invalid paramater count - must be 1"); | ||
| 115 | string label(instrparams.front()); | ||
| 116 | if (label.length() < 2 || label[ label.length() - 1] != ':') | ||
| 117 | throw runtime_error("Label has invalid syntax"); | ||
| 118 | m_labels[ label.substr(0, label.length() - 1) ] = size(); | ||
| 119 | } | ||
| 120 | instr->compile(instrparams); | ||
| 121 | } | ||
| 122 | catch(runtime_error& ex) | ||
| 123 | { | ||
| 124 | stringstream sstr; | ||
| 125 | sstr << "Unable to compile instruction '" << instrname | ||
| 126 | << "' (line " << i << "): " << ex.what(); | ||
| 127 | throw runtime_error(sstr.str()); | ||
| 128 | } | ||
| 129 | |||
| 130 | push_back(instr); | ||
| 82 | } | 131 | } |
| 83 | file.close(); | 132 | } |
| 133 | |||
| 134 | /*----------------------------------------------------------------------------*/ | ||
| 84 | 135 | ||
| 136 | unsigned CProgram::findLabel(const std::string& label) const | ||
| 137 | { | ||
| 138 | map<string, unsigned>::const_iterator it; | ||
| 139 | it = m_labels.find(label); | ||
| 140 | if (it == m_labels.end()) | ||
| 141 | throw runtime_error("Unknown label '" + label + "'"); | ||
| 142 | return it->second; | ||
| 85 | } | 143 | } |
| 86 | 144 | ||
| 87 | /*----------------------------------------------------------------------------*/ | 145 | /*----------------------------------------------------------------------------*/ |
| 88 | 146 | ||
| 89 | #ifdef DEBUG | 147 | #if DEBUG |
| 90 | void CProgram::dump(std::ostream& out) | 148 | void CProgram::dump(std::ostream& out) |
| 91 | { | 149 | { |
| 92 | 150 | out << "[PROGRAM DUMP]" << endl; | |
| 93 | out << endl << "Program file:" << endl << m_programfile << endl; | 151 | unsigned i = 0; |
| 94 | 152 | for(iterator it = begin(); it < end(); ++it) | |
| 95 | out << endl << "Program source:" << endl; | ||
| 96 | for (int i = 0; i < (int) m_progsource.size();i++) | ||
| 97 | { | 153 | { |
| 98 | for(int x = 0; x < (int) m_progsource[i].size();x++) | 154 | out << "[" << std::setw(4) << std::setfill('0') << i << "] " |
| 99 | out << m_progsource[i][x] << " "; | 155 | << *(*it) << endl; |
| 100 | out << std::endl; | 156 | ++i; |
| 101 | } | 157 | } |
| 102 | |||
| 103 | out << endl << "Jump addresses:" << endl; | ||
| 104 | map<string, unsigned int>::iterator it; | ||
| 105 | for (it = m_jumpaddr.begin(); it != m_jumpaddr.end(); it++) | ||
| 106 | out << (*it).first << " " << (*it).second << endl; | ||
| 107 | |||
| 108 | } | 158 | } |
| 109 | #endif | 159 | #endif |
| 160 | |||
| 161 | /* vim: set et sw=2 ts=2: */ | ||
