diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-13 03:23:52 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-13 03:23:52 +0000 |
| commit | f9a0c7e9687bc3e113f4c8f44861533c9ca48b3a (patch) | |
| tree | 5d51c5a403dd096b0c3748118409be20eb3e1900 /tools/driver | |
| parent | 3818460a473bd3ffcd35f09eb6429e1b0f00bc07 (diff) | |
feat: compile source files with configurable IR output
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat (limited to 'tools/driver')
| -rw-r--r-- | tools/driver/main.cc | 84 |
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; } |
