-
Notifications
You must be signed in to change notification settings - Fork 0
/
Parser.cpp
143 lines (125 loc) · 5.09 KB
/
Parser.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
#include <fstream>
#include <bitset>
#include <iostream>
#include "Parser.h"
Parser::Parser(const string &source_name) : lexer(source_name) {
result.reserve(60);
}
void Parser::parse_top_level() {
Lexer::Token token = Lexer::tok_undefined;
while (true) {
token = lexer.get_token();
if (token == Lexer::tok_eof) break;
if (token == Lexer::tok_undefined) { //error
lexer.release_error({"알 수 없는 토큰: \"", lexer.get_word(), "\""});
} else if (token == Lexer::tok_comma || token == Lexer::tok_identifier || token == Lexer::tok_int) {
lexer.release_error({"잘못된 토큰 \"", lexer.get_word(), "\" : 해당 토큰은 여기에 올 수 없습니다."});
} else if (token == Lexer::tok_dollar) { //label
parse_label();
} else if (token == Lexer::tok_nop) { //nop
result.push_back(0);
} else if (token & (1 << 2)) { //ja, jb, je, jmp (피연산자 한 개)
parse_jmp(token);
} else { //나머지 모든 명령어 (피연산자 두 개)
parse_command(token);
}
}
set_unregistered_label(); //라벨들 처리
}
bool Parser::is_proper_regi(const string ®i_name) {
if (regi_name.size() == 1 && 'a' <= regi_name[0] && regi_name[0] <= 'c') {
return true;
}
lexer.release_error({"\"", regi_name, "\"는 잘못된 레지스터명입니다. 레지스터는 A,B,C 중 하나여야 합니다."});
return false;
}
void Parser::parse_label() {
auto token = lexer.get_token();
if (token != Lexer::tok_identifier) {
lexer.release_error({"잘못된 토큰 \"", lexer.get_word(),
"\" : 라벨명은 다른 명령어 이름이 아니어야 하고, 숫자로 시작하지 않아야 합니다."});
return;
}
if (label_map.contains(lexer.get_word())) {
lexer.release_error({"이미 선언된 라벨입니다."});
return;
}
label_map.emplace(lexer.get_word(), result.size());
}
void Parser::parse_jmp(Lexer::Token token) {
result.push_back((token << 4) + 3); //jmp들은 항상 src가 imm이어야해서 + 3을 하는 것
token = lexer.get_token(); //라벨 파싱
if (token != lexer.tok_identifier) {
lexer.release_error({"잘못된 토큰 \"", lexer.get_word(), "\" : 라벨이 필요합니다."});
return;
}
if (label_map.contains(lexer.get_word())) { //등록된 라벨이면 바로 값 대입
result.push_back(label_map[lexer.get_word()]);
} else {
//등록되지 않은 라벨 기록
unregistered_label_map.emplace(result.size(), Logger::LogInfo(lexer.get_token_loc(), lexer.get_word().size(),
lexer.get_word()));
result.push_back(-1);
}
}
void Parser::parse_command(Lexer::Token token) {
auto command = token;
token = lexer.get_token();
if (token == Lexer::tok_int) {
lexer.release_error({"dest에는 즉시값이 들어갈 수 없습니다."});
return;
}
if (!is_proper_regi(lexer.get_word())) return;
char dest = lexer.get_word()[0];
token = lexer.get_token();
if (token != Lexer::tok_comma) {
lexer.release_error({"잘못된 토큰 \"", lexer.get_word(), "\" : 이곳엔 콤마가 와야 합니다."});
return;
}
token = lexer.get_token();
if (token == Lexer::tok_identifier) {
if (!is_proper_regi(lexer.get_word())) return;
result.push_back((command << 4) + ((dest - 'a') << 2) + (lexer.get_word()[0] - 'a'));
} else if (token == Lexer::tok_int) {
int val = std::stoi(lexer.get_word());
if (val > 255) {
lexer.release_error({"즉시값은 255이하여야 합니다."});
return;
}
result.push_back((command << 4) + ((dest - 'a') << 2) + 3);
result.push_back(val);
} else {
lexer.release_error({"잘못된 토큰 \"", lexer.get_word(), "\" : src에는 값 또는 레지스터가 와야 합니다."});
}
}
void Parser::set_unregistered_label() {
for (int i = 0; i < result.size(); ++i) {
if (result[i] == -1) {
if (!label_map.contains(unregistered_label_map[i].msg)) {
auto info = unregistered_label_map[i];
info.msg = "라벨 \"" + info.msg + "\"는 존재하지 않는 라벨입니다.";
System::logger.log_error(info);
} else {
result[i] = label_map[unregistered_label_map[i].msg];
}
}
}
}
void Parser::show_code() {
if (System::logger.has_error()) return;
for (int op: result) {
string res = std::bitset<8>(op).to_string();
std::cout << res.substr(0, 4) << ' ' << res.substr(4, 4) << '\n';
}
}
void Parser::write_output() {
if (System::logger.has_error()) return;
std::ofstream output(System::output_name);
output << "v3.0 hex words plain\n";
for (int i = 0; i < result.size(); ++i) {
output.width(2);
output.fill('0');
output << std::hex << result[i] << ' ';
if (i % 10 == 9) output << '\n';
}
}