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 /AGENTS | |
| parent | 3818460a473bd3ffcd35f09eb6429e1b0f00bc07 (diff) | |
feat: compile source files with configurable IR output
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat (limited to 'AGENTS')
| -rw-r--r-- | AGENTS/ARCH.md | 25 | ||||
| -rw-r--r-- | AGENTS/CONVENTIONS.md | 6 | ||||
| -rw-r--r-- | AGENTS/PITFALLS.md | 4 |
3 files changed, 18 insertions, 17 deletions
diff --git a/AGENTS/ARCH.md b/AGENTS/ARCH.md index 4ed2404..0161286 100644 --- a/AGENTS/ARCH.md +++ b/AGENTS/ARCH.md @@ -4,8 +4,8 @@ Kaleidoscope-style design, C++17, no external deps beyond LLVM 18 and libc. ``` -stdin ──> Lexer ──> Parser ──> vector<unique_ptr<StmtAST>> ──> CodeGen ──> textual LLVM IR on stderr - (getchar) (recursive (flat program list; (one llvm::Module "cps_module", +file ──> Lexer ──> Parser ──> vector<unique_ptr<StmtAST>> ──> CodeGen ──> textual LLVM IR in a file + (istream) (recursive (flat program list; (one llvm::Module "cps_module", descent) FunctionDefAST mixed in) everything else inside i32 main()) ``` @@ -24,20 +24,21 @@ The compiler stops at textual IR. Making a runnable binary is manual: ```bash mkdir -p build && cd build && cmake -DLLVM_DIR=/usr/lib/llvm-18/cmake .. && make # build cpsc -./cpsc < prog.cps 2> prog.ll # stdin is the ONLY input; IR goes to STDERR +./cpsc prog.cps -o prog.ll # default without -o: prog.ir beside the source clang-18 prog.ll -o prog && ./prog ``` -Facts about the driver (`tools/driver/main.cc`) that break naive automation: +Driver behavior (`tools/driver/main.cc`): -- **No argv.** `./cpsc file.cps` blocks forever on stdin; you must redirect `<`. -- **IR and error messages share stderr.** A failed compile still dumps (partial) IR, - mixed with `Error:` lines that make clang reject the file. -- **Exit code is non-zero iff a diagnostic was emitted.** Lexer, Parser and CodeGen each - track an error flag (`hadError()`); every failure path prints an `Error:` line, and - `main` returns 1 when any flag is set. The emitted module is also checked with - `verifyModule`, so invalid IR flips the exit code too. Check the exit code — do not - grep stderr. +- One source file, with optional `-o path`; options may precede or follow the source. + No stdin source input. No arguments exits silently with status 0 (help TODO). +- IR is written only after successful parsing, code generation and module + verification. Diagnostics stay on stderr; failures do not overwrite existing IR. +- Lexer, Parser and CodeGen track error flags (`hadError()`); any error, including + invalid IR from `verifyModule`, makes the driver return 1. File/argument errors + also return 1. Check the exit code rather than grepping stderr. +- Successful compilation overwrites the output, but paths aliasing the source + (including symlinks/hard links) are rejected. Build pin: developed and tested against **LLVM 18**. (The historical LLVM 19 breakage — `ArithmeticHandler.cc` touching `llvm::Module` through a transitive include — is gone diff --git a/AGENTS/CONVENTIONS.md b/AGENTS/CONVENTIONS.md index 7c6956d..6681d1a 100644 --- a/AGENTS/CONVENTIONS.md +++ b/AGENTS/CONVENTIONS.md @@ -15,9 +15,9 @@ identifier. Assignment is `<-` (ASCII only), equality is single `=`, inequality concatenation `&` (reaches the parser as raw ASCII 38 — no token). No escape sequences in string/char literals. Comments are `//` to end of line. -**The lexer can run once per process, from stdin only.** `gettok()` keeps its lookahead -in a function-local `static int LastChar` and calls `getchar()` directly. No re-lexing, -no file paths, and unit tests can't lex two programs in one process. +**The lexer reads a caller-owned stream.** Construct it with `Lexer(std::istream &)`; +the stream must outlive the lexer. Lookahead, line number and error state belong to +each instance. The driver opens the source file; stdin is not used for compilation. **Types travel as uppercase `std::string`** (`"INTEGER"`, `"REAL"`, ..., plus user-defined names) — never an enum. `TypeSystem` resolves the string to diff --git a/AGENTS/PITFALLS.md b/AGENTS/PITFALLS.md index 7fddfff..acf21d2 100644 --- a/AGENTS/PITFALLS.md +++ b/AGENTS/PITFALLS.md @@ -38,8 +38,8 @@ test programs. unknown-function calls; OUTPUT reports an error for a nullptr result. - The lexer emits no newline tokens; the grammar is purely keyword-delimited. Bare `RETURN` is only recognized right before ENDIF/ELSE/ENDFUNCTION/ENDPROCEDURE. -- Invalid modules still print their IR, but `verifyModule` runs at the end of - `compile()` and makes the driver exit non-zero. +- `verifyModule` runs at the end of `compile()`; invalid modules make the driver + exit non-zero without writing IR. - The FOR loop variable must be pre-DECLAREd as INTEGER; FOR reuses that alloca. The loop direction is decided at run time from the STEP value's sign; STEP is evaluated exactly once, before the loop. (The TO expression is still re-evaluated every |
