-
Notifications
You must be signed in to change notification settings - Fork 0
/
assembler.cpp
169 lines (133 loc) · 4.8 KB
/
assembler.cpp
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#include <iostream>
#include <fstream>
#include "vm/value.h"
#include "assembler/file.h"
#include "assembler/attribute.h"
#include "assembler/value.h"
secd::assembler::value::attribute_list attributes;
void read_operands(std::istream& is, secd::value::operands_list& ops) {
ops.clear();
char paren;
is >> paren;
if (paren != '(') {
throw std::runtime_error("Operands list expected to start with '('");
}
std::string rand;
is >> rand;
while (!rand.ends_with(')')) {
ops.push_back(attributes.index<secd::assembler::value::attribute::Id>(rand));
is >> rand;
}
if (rand != ")") {
auto sub = rand.substr(0, rand.length() - 1);
ops.push_back(attributes.index<secd::assembler::value::attribute::Id>(sub));
}
}
std::istream& secd::assembler::value::operator>>(std::istream& is, secd::assembler::value::instruction& ins) {
using namespace secd::assembler::value;
std::string name;
is >> name;
ins.opcode = secd::opcodes::opcode_code(name);
ins.operands = {};
switch (ins.opcode) {
case secd::opcodes::SEL: {
std::string then_b, else_b;
is >> then_b >> else_b;
auto then_index = attributes.index<attribute::Code>(then_b);
auto else_index = attributes.index<attribute::Code>(else_b);
ins.operands = {then_index, else_index};
break;
}
case secd::opcodes::LDC: {
int constant;
is >> constant;
auto const_index = attributes.index<attribute::Int>(std::to_string(constant));
attributes[const_index].set<attribute::Int>(constant);
ins.operands = {const_index};
break;
}
case secd::opcodes::ST:
case secd::opcodes::LDE: {
std::string name;
is >> name;
auto name_index = attributes.index<attribute::Id>(name);
attributes[name_index].set<attribute::Id>(name);
ins.operands = {name_index};
break;
}
case secd::opcodes::LDF: {
std::string body;
std::vector<uint16_t> ops;
is >> body;
read_operands(is, ops);
auto body_index = attributes.index<attribute::Code>(body);
// TODO: remove "ops", it is impossible to have several functions now
auto operands_index = attributes.index<attribute::Operands>("ops");
attributes[operands_index].set<attribute::Operands>(ops);
ins.operands = {body_index, operands_index};
break;
}
default:
break;
}
return is;
}
std::istream& secd::assembler::value::operator>>(std::istream& is, secd::assembler::value::block& block) {
using namespace secd::assembler::value;
std::string label;
is >> label;
if (!label.ends_with(':')) {
throw std::runtime_error("Label expected, got " + label);
}
label = label.substr(0, label.length() - 1); // Label without colon at the end
std::cout << "Pure Label: " << label << "\n";
block.label = label;
block.instructions = {};
for (auto iter = std::istream_iterator<instruction>(is); iter->opcode != secd::opcodes::STP; iter++) {
block.instructions.push_back(*iter);
}
block.instructions.emplace_back(secd::opcodes::STP, secd::value::operands_list{});
auto block_index = attributes.index<attribute::Code>(label);
std::cout << "index: " << block_index << "\n";
attributes[block_index].set<attribute::Code>(block);
std::cout << "length: " << attributes[block_index].length << "\n\n";
for (const auto& ins : block.instructions) {
std::cout << "OPCODE: " << secd::opcodes::opcode_name(ins.opcode) << " "
<< ins.operands.size() << "\n";
}
std::cout << "\n";
return is;
}
void write_magic(std::ofstream& ofs) {
uint32_t magic = 0x1CEDC0DE;
ofs.write(reinterpret_cast<const char*>(&magic), sizeof(uint32_t));
}
void write_attribute(std::ofstream& ofs, const secd::assembler::value::attribute& a) {
ofs.write(reinterpret_cast<const char*>(&a.length), sizeof(uint16_t));
ofs.write(reinterpret_cast<const char*>(&a.tag), sizeof(uint8_t));
ofs.write(a.payload.get(), a.length - 1);
}
void write_attributes(std::ofstream& ofs) {
uint16_t length = attributes.size();
ofs.write(reinterpret_cast<const char *>(&length), sizeof(uint16_t));
for (const auto& a : attributes) {
write_attribute(ofs, a);
}
}
int main(int argc, char *argv[]) {
if (argc != 3) {
std::cerr << "usage: " << argv[0] << " <input-file> <output-file>\n";
return 1;
}
std::ifstream ifs{argv[1]};
// Main should always be the last code block
for (
auto iter = std::istream_iterator<secd::assembler::value::block>(ifs);
iter->label != "main";
iter++
);
std::ofstream ofs{argv[2]};
write_magic(ofs);
write_attributes(ofs);
return 0;
}