-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparse_program.cpp
More file actions
124 lines (111 loc) · 3.96 KB
/
parse_program.cpp
File metadata and controls
124 lines (111 loc) · 3.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include "parse_program.hpp"
#include <sstream>
#include <stdexcept>
#include <algorithm>
std::array<std::optional<Instruction>, std::numeric_limits<uint8_t>::max()> parse_program(const std::string& program_text) {
std::array<std::optional<Instruction>, std::numeric_limits<uint8_t>::max()> instructions{};
std::istringstream input(program_text);
std::string line;
uint8_t index = 0;
while (std::getline(input, line)) {
// strip whitespace
line.erase(0, line.find_first_not_of(" \t"));
line.erase(line.find_last_not_of(" \t") + 1);
// ignore empty lines or commented lines
if (line.empty() || line[0] == '#') continue;
if (index >= instructions.size()) {
throw std::runtime_error("program too large for instruction memory");
}
instructions.at(index++) = parse_line(line);
}
return instructions;
}
Instruction parse_line(const std::string& line) {
std::istringstream ss(line);
std::string opcode;
ss >> opcode;
if (opcode == "ADD") {
std::string register_1, register_2, output_register;
ss >> register_1 >> register_2 >> output_register;
return Instruction::add(
parse_register(clean_token(register_1)),
parse_register(clean_token(register_2)),
parse_register(clean_token(output_register))
);
}
else if (opcode == "SUB") {
std::string register_1, register_2, output_register;
ss >> register_1 >> register_2 >> output_register;
return Instruction::sub(
parse_register(clean_token(register_1)),
parse_register(clean_token(register_2)),
parse_register(clean_token(output_register))
);
}
else if (opcode == "CMP") {
std::string register_1, register_2;
ss >> register_1 >> register_2;
return Instruction::compare(
parse_register(clean_token(register_1)),
parse_register(clean_token(register_2))
);
}
else if (opcode == "LOAD") {
std::string address, output_register;
ss >> address >> output_register;
return Instruction::load(
parse_u8(clean_token(address)),
parse_register(clean_token(output_register))
);
}
else if (opcode == "STORE") {
std::string input_register, address;
ss >> input_register >> address;
return Instruction::store(
parse_register(clean_token(input_register)),
parse_u8(clean_token(address))
);
}
else if (opcode == "JMP") {
std::string address;
ss >> address;
return Instruction::jump(parse_u8(clean_token(address)));
}
else if (opcode == "JMP_EQ") {
std::string address;
ss >> address;
return Instruction::jump_equal(parse_u8(clean_token(address)));
}
else if (opcode == "HALT") {
return Instruction::halt();
}
else if (opcode == "PRINT") {
std::string address;
ss >> address;
return Instruction::print(parse_u8(clean_token(address)));
}
else {
throw std::runtime_error("unknown instruction: " + opcode);
}
}
Register parse_register(const std::string& token) {
if (token.empty() || token[0] != 'R') {
throw std::runtime_error("expected register, got: " + token );
}
int register_index = std::stoi(token.substr(1));
if (register_index < 0 || register_index > 7) {
throw std::runtime_error("register out of bounds: " + token );
}
return static_cast<Register>(register_index);
}
uint8_t parse_u8(const std::string& token) {
int value = std::stoi(token);
if (value < 0 || value > static_cast<int>(std::numeric_limits<uint8_t>::max())) {
throw std::runtime_error("u8 value out of bounds: " + token);
}
return static_cast<uint8_t>(value);
}
std::string clean_token(std::string token) {
token.erase(std::remove(token.begin(), token.end(), ','), token.end());
return token;
}