aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-13 03:23:52 +0000
committer_ov4 <ov4@ov4.org>2026-10-13 03:23:52 +0000
commitf9a0c7e9687bc3e113f4c8f44861533c9ca48b3a (patch)
tree5d51c5a403dd096b0c3748118409be20eb3e1900 /tools
parent3818460a473bd3ffcd35f09eb6429e1b0f00bc07 (diff)
feat: compile source files with configurable IR output
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/driver/main.cc84
1 files changed, 80 insertions, 4 deletions
diff --git a/tools/driver/main.cc b/tools/driver/main.cc
index ca978b5..22c448c 100644
--- a/tools/driver/main.cc
+++ b/tools/driver/main.cc
@@ -1,17 +1,93 @@
#include "cps/Lexer.h"
#include "cps/Parser.h"
#include "cps/CodeGen.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include <fstream>
+#include <string>
-int main() {
- cps::Lexer Lex;
+int main(int argc, char **argv) {
+ if (argc == 1) {
+ // TODO: Print help here when help text is available.
+ return 0;
+ }
+
+ std::string InputPath;
+ std::string OutputPath;
+ for (int I = 1; I < argc; ++I) {
+ std::string Arg = argv[I];
+ if (Arg == "-o") {
+ if (!OutputPath.empty()) {
+ llvm::errs() << "Error: -o may only be specified once\n";
+ return 1;
+ }
+ if (I + 1 == argc || argv[I + 1][0] == '-' || argv[I + 1][0] == '\0') {
+ llvm::errs() << "Error: -o requires an output path\n";
+ return 1;
+ }
+ OutputPath = argv[++I];
+ } else if (Arg.empty() || Arg[0] == '-') {
+ llvm::errs() << "Error: unknown argument '" << Arg << "'\n";
+ return 1;
+ } else if (!InputPath.empty()) {
+ llvm::errs() << "Error: only one source file is supported\n";
+ return 1;
+ } else {
+ InputPath = Arg;
+ }
+ }
+
+ if (InputPath.empty()) {
+ llvm::errs() << "Error: no source file specified\n";
+ return 1;
+ }
+ if (OutputPath.empty()) {
+ 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() << "Error: cannot open source file '" << InputPath << "'\n";
+ return 1;
+ }
+ if (llvm::sys::fs::equivalent(InputPath, OutputPath)) {
+ llvm::errs() << "Error: output file must not be the source file\n";
+ return 1;
+ }
+
+ cps::Lexer Lex(Input);
cps::Parser Parser(Lex);
auto Statements = Parser.Parse();
+ if (Input.bad()) {
+ llvm::errs() << "Error: cannot read source file '" << InputPath << "'\n";
+ return 1;
+ }
+ if (Lex.hadError() || Parser.hadError()) return 1;
cps::CodeGen CG;
CG.compile(Statements);
- CG.print();
+ if (CG.hadError()) return 1;
- return (Lex.hadError() || Parser.hadError() || CG.hadError()) ? 1 : 0;
+ std::error_code EC;
+ llvm::raw_fd_ostream Output(OutputPath, EC);
+ if (EC) {
+ llvm::errs() << "Error: cannot open output file '" << OutputPath
+ << "': " << EC.message() << "\n";
+ return 1;
+ }
+ CG.print(Output);
+ Output.close();
+ if (Output.has_error()) {
+ llvm::errs() << "Error: cannot write output file '" << OutputPath
+ << "': " << Output.error().message() << "\n";
+ Output.clear_error();
+ return 1;
+ }
+ return 0;
}