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
|
#include "cps/Lexer.h"
#include "cps/Parser.h"
#include "cps/CodeGen.h"
#ifdef CPSC_RUN_EMBEDDED
#include "EmbeddedRunner.h"
#endif
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/raw_ostream.h"
#include <fstream>
#include <string>
namespace {
int compilationTerminated() {
llvm::errs() << "compilation terminated.\n";
return 1;
}
} // namespace
int main(int argc, char **argv) {
for (int I = 1; I < argc; ++I) {
if (std::string(argv[I]) == "-h") {
#ifdef _WIN32
llvm::outs() << "See Start Menu > cpsc > cpsc Help for HTML help.\n";
#else
llvm::outs() << "See man 1 cpsc for help.\n";
#endif
return 0;
}
}
std::string InputPath;
std::string OutputPath;
bool Run = false;
for (int I = 1; I < argc; ++I) {
std::string Arg = argv[I];
if (Arg == "-r") {
Run = true;
} else if (Arg == "-o") {
if (!OutputPath.empty()) {
llvm::errs() << "cpsc: error: -o may only be specified once\n";
return compilationTerminated();
}
if (I + 1 == argc || argv[I + 1][0] == '-' || argv[I + 1][0] == '\0') {
llvm::errs() << "cpsc: error: -o requires an output path\n";
return compilationTerminated();
}
OutputPath = argv[++I];
} else if (Arg.empty() || Arg[0] == '-') {
llvm::errs() << "cpsc: error: unknown argument '" << Arg << "'\n";
return compilationTerminated();
} else if (!InputPath.empty()) {
llvm::errs() << "cpsc: error: only one source file is supported\n";
return compilationTerminated();
} else {
InputPath = Arg;
}
}
if (InputPath.empty()) {
llvm::errs() << "cpsc: fatal error: no input files\n";
return compilationTerminated();
}
#ifdef CPSC_RUN_PATH
std::string LliPath;
#endif
if (Run) {
#ifdef CPSC_RUN_PATH
auto Lli = llvm::sys::findProgramByName("lli");
if (!Lli) {
llvm::errs() << "cpsc: fatal error: -r requires lli in PATH: " << Lli.getError().message() << "\n";
return compilationTerminated();
}
LliPath = *Lli;
#elif defined(CPSC_RUN_NONE)
llvm::errs() << "cpsc: fatal error: -r is disabled in this build (CPSC_RUN_MODE=NONE)\n";
return compilationTerminated();
#endif
}
if (OutputPath.empty() && !Run) {
llvm::SmallString<256> DefaultPath(InputPath);
llvm::sys::path::replace_extension(DefaultPath, ".ir");
OutputPath = std::string(DefaultPath);
}
std::ifstream Input(InputPath, std::ios::binary);
if (!Input) {
llvm::errs() << "cpsc: fatal error: cannot open source file '" << InputPath << "'\n";
return compilationTerminated();
}
if (llvm::sys::fs::equivalent(InputPath, OutputPath)) {
llvm::errs() << "cpsc: error: output file must not be the source file\n";
return compilationTerminated();
}
cps::Lexer Lex(Input);
cps::Parser Parser(Lex);
auto Statements = Parser.Parse();
if (Input.bad()) {
llvm::errs() << "cpsc: fatal error: cannot read source file '" << InputPath << "'\n";
return compilationTerminated();
}
if (Lex.hadError() || Parser.hadError()) return compilationTerminated();
cps::CodeGen CG;
CG.compile(Statements);
if (CG.hadError()) return compilationTerminated();
#ifdef CPSC_RUN_EMBEDDED
if (Run && OutputPath.empty()) return runEmbedded(CG);
#endif
std::error_code EC;
int OutputFD;
llvm::FileRemover TemporaryOutput;
if (OutputPath.empty()) {
llvm::SmallString<256> TemporaryPath;
EC = llvm::sys::fs::createTemporaryFile("cpsc", "ir", OutputFD, TemporaryPath);
if (!EC) {
OutputPath = std::string(TemporaryPath);
TemporaryOutput.setFile(OutputPath);
}
} else {
EC = llvm::sys::fs::openFileForWrite(OutputPath, OutputFD);
}
if (EC) {
llvm::errs() << "cpsc: fatal error: cannot open output file '" << OutputPath
<< "': " << EC.message() << "\n";
return compilationTerminated();
}
llvm::raw_fd_ostream Output(OutputFD, true);
CG.print(Output);
Output.close();
if (Output.has_error()) {
llvm::errs() << "cpsc: fatal error: cannot write output file '" << OutputPath
<< "': " << Output.error().message() << "\n";
Output.clear_error();
return compilationTerminated();
}
if (!Run) return 0;
#ifdef CPSC_RUN_PATH
llvm::SmallString<256> RunPath(OutputPath);
if (auto PathError = llvm::sys::fs::make_absolute(RunPath)) {
llvm::errs() << "cpsc: error: cannot resolve IR path: " << PathError.message() << "\n";
return 1;
}
std::string ExecutionError;
int Result = llvm::sys::ExecuteAndWait(LliPath, {LliPath, RunPath},
std::nullopt, {}, 0, 0, &ExecutionError);
if (Result < 0) {
llvm::errs() << "cpsc: error: lli execution failed (status " << Result << "): "
<< ExecutionError << "\n";
return 1;
}
return Result;
#elif defined(CPSC_RUN_EMBEDDED)
return runEmbedded(CG);
#else
return 0;
#endif
}
|