-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmain.cc
149 lines (111 loc) · 3.58 KB
/
main.cc
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
#include <cassert>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <ostream>
#include "tokenizer.hpp"
#include "parser.hpp"
#include "codegen.hpp"
/*
# means not equal.
! prints a value.
? gets a value from inputs.
program = block "." ;
block = [ "const" ident "=" number {"," ident "=" number} ";"]
[ "var" ident {"," ident} ";"]
{ "procedure" ident ";" block ";" } statement ;
statement = [ ident ":=" expression
| "call" ident
| "?" ident | "!" expression
| "begin" statement {";" statement } "end"
| "if" condition "then" statement
| "while" condition "do" statement ];
condition = "odd" expression |
expression ("="|"#"|"<"|"<="|">"|">=") expression ;
expression = [ "+"|"-"] term { ("+"|"-") term};
term = factor {("*"|"/") factor};
factor = ident | number | "(" expression ")";
*/
using pl0::tokenizer::Tokenizer;
using pl0::parser::Parser;
using pl0::ast::AstPrinter;
using pl0::codegen::CodeGenerator;
static auto readFile(const char* path) -> std::string {
std::ifstream stream(path);
const std::size_t size = stream.seekg(0, std::ios::end).tellg();
stream.seekg(0, std::ios::beg);
std::string buffer(size, '\0');
stream.read(buffer.data(), size);
return buffer;
}
auto main(int argc, char** argv) -> int {
if(argc < 2){
std::cerr << "Usage: " << argv[0] << " [-llvm] [-ast] [-object] <file>\n"
<< " -llvm\tDump LLVM IR\n"
<< " -object\tProduce only the object file\n"
<< " -ast\tDump AST\n"
<< std::endl;
std::exit(EXIT_FAILURE);
}
bool dumpIR = false;
bool dumpAST = false;
bool produceOnlyObject = false;
char** args;
for(args = argv + 1; *args != argv[argc]; args++){
if(**args != '-') break;
if(std::strncmp(*args, "-llvm", 5) == 0) {
dumpIR = true;
} else if(std::strncmp(*args, "-ast", 4) == 0){
dumpAST = true;
} else if(std::strncmp(*args, "-object", 7) == 0) {
produceOnlyObject = true;
} else {
std::cerr << "Unknow option '" << *args << "'.\n";
std::exit(EXIT_FAILURE);
}
}
std::string_view filename = *args;
if(!filename.ends_with(".pl0")) {
std::cerr << "Invalid file. This file doesn't have '.pl0' file extension.\n";
std::exit(EXIT_FAILURE);
}
auto source = readFile(filename.data());
Tokenizer tokenizer = Tokenizer(source);
auto tokens = tokenizer.tokenize();
Parser parser(tokens);
auto ast = parser.parseProgram();
if(parser.hadError()) {
for(const auto& error : parser.errors()){
std::cout << error << '\n';
}
std::exit(EXIT_FAILURE);
}
if(dumpAST) {
AstPrinter printer;
printer.print(ast);
if(!dumpIR) return EXIT_SUCCESS;
}
filename.remove_suffix(4); // remove .pl0
CodeGenerator codegen(filename);
if(!codegen.generate(ast)) {
std::exit(EXIT_FAILURE);
}
if(codegen.hadError()) {
for(const auto& error : codegen.errors()){
std::cout << error << '\n';
}
std::exit(EXIT_FAILURE);
}
if(dumpIR) {
codegen.dumpLLVM();
} else {
codegen.produceObjectFile();
if(!produceOnlyObject) {
if(!codegen.produceExecutable()) {
std::cerr << "An error occurred while generating the executable." << std::endl;
std::exit(EXIT_FAILURE);
}
}
}
return EXIT_SUCCESS;
}