aboutsummaryrefslogtreecommitdiff
path: root/AGENTS
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 /AGENTS
parent3818460a473bd3ffcd35f09eb6429e1b0f00bc07 (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.md25
-rw-r--r--AGENTS/CONVENTIONS.md6
-rw-r--r--AGENTS/PITFALLS.md4
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