Skip to content

Commit b614f35

Browse files
committed
Harden frontend for v0.2.0 release
* Fixed segfault issue with arena allocator, beefed up test harness to tell if the rror cases errored correctly * Fixed holes in analyzer type checking system, Added special error type for analyzing program with no main * Reformatted LOC summary to split test harness code from compiler code * Fixed bug with string escape truncation in the tokenizer, made struct decls consistent with semi colons * Fix lexer error recovery and add struct-typed global parsing Lexer: consume entire malformed number literal before returning an error so diagnostics aren't repeated per digit. Add ERANGE check for strtol overflow. Parser: accept struct-typed globals at file scope (identifier lookahead, same pattern as local declarations). Allow optional trailing semicolon after struct closing brace. Add NULL check after malloc in GENERATE_ERROR macro. AST printer: loop ptr_depth for correct star count (u16** not u16*), add depth guard in print_ast_labeled. * Add error kinds for analyzer hardening New error types: ERR_MISSING_MAIN, ERR_LITERAL_OUT_OF_RANGE, ERR_NOT_LVALUE, ERR_VOID_VARIABLE, ERR_NOT_A_STRUCT, ERR_MISSING_RETURN. Add lvalue union member to error_t. Fix type_to_string to loop ptr_depth with a local stars buffer instead of printing a single star. * Close silent-accept gaps in semantic analyzer Validate declared types everywhere (locals, params, globals, regs, fields, return types) - unknown structs and non-pointer void rejected at the declaration site. Bad symbols poisoned with TYPE_INVALID to prevent cascading diagnostics. New checks: lvalue validation for assignment/&/++/--, integer literal range checking, negative literal typing (-5 as i8 not u8), global initializer type checking, bare return in non-void rejection, shallow missing-return detection, struct pointer auto-deref for field access. * Update README and CHANGELOG for v0.2.0
1 parent b00e811 commit b614f35

54 files changed

Lines changed: 1023 additions & 145 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,35 @@ releases are reserved for bug fixes only.
3636
- Compiler test cases covering analyzer error paths (undeclared
3737
identifiers, type mismatches, call errors, struct errors) and
3838
success paths (scoping, widening, pointers, basic analysis).
39+
- **Analyzer hardening** — additional validation closing gaps where invalid
40+
programs were previously accepted silently:
41+
- Named struct types are checked for existence in *every* declaration form
42+
(locals, parameters, globals, registers, struct fields, function return
43+
types), not just struct initializers and field access. A symbol whose
44+
declared type is invalid is poisoned, so later uses don't cascade
45+
duplicate diagnostics.
46+
- A non-pointer `void` is rejected as a variable/parameter/field/global
47+
type (`void*` remains valid as a null pointer).
48+
- Integer literals that don't fit any supported type are now an error
49+
(previously swallowed); the lexer rejects literals that overflow `long`.
50+
Negative literals are typed from their value (`-5` is `i8`, `-300` is
51+
`i16`).
52+
- Assignment targets and the operands of `&`, `++`, and `--` must be
53+
lvalues.
54+
- Global variable initializers are type-checked (resolved in the global
55+
scope), just like local declarations - previously they were ignored.
56+
- A bare `return;` in a non-void function is rejected, and a non-void
57+
function that can fall off its end without returning a value is flagged.
58+
(This last check is shallow: a function ending in a control-flow statement
59+
— e.g. a one-armed `if` that falls through, or an `if`/`else` where only
60+
some branches return — is assumed to return and is not flagged. Full
61+
path-coverage analysis is future work.)
62+
- Struct-typed globals (`Point p;` at file scope) now parse, matching the
63+
form used for locals.
64+
- Field access auto-dereferences a single-level struct pointer (`c.field` on
65+
a `Struct*`), since there is no `->` operator.
66+
- A negative-test corpus exercising each new check, plus positive tests for
67+
pointer field auto-deref and negative-literal typing.
3968

4069
### Changed
4170

@@ -54,6 +83,18 @@ releases are reserved for bug fixes only.
5483
- Generalized the arena allocator out of `parser.c` into shared
5584
infrastructure, so semantic analysis can reuse it for its own
5685
allocations.
86+
- Diagnostics now print the full pointer depth (`u16**`, not `u16*`) and name
87+
the actual type in field-access-on-non-struct errors; a malformed number
88+
literal and a repeated unknown-type are each reported once rather than per
89+
character / per use.
90+
91+
### Fixed
92+
93+
- Fixed a segfault when a parse error's offending token was a numeric literal.
94+
- Fixed a memory leak in the arena allocator when a standard chunk allocation
95+
followed an oversized one.
96+
- String literals with escape sequences no longer drop a trailing character
97+
per escape, and common escapes (`\n`, `\t`, `\\`, `\"`, ...) are decoded.
5798

5899
## [0.1.1] - 2026-06-20
59100

@@ -96,7 +137,6 @@ implemented.
96137

97138
### Known Limitations
98139

99-
- No semantic analysis: types, struct fields, and symbol references are not validated.
100140
- No code generation: `cc02` does not yet produce a working 65C02 binary.
101141
- No array type or subscript syntax.
102142
- `->` is not implemented; field access through a pointer is intended to auto-dereference via semantic analysis once that exists.

README.md

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919

2020
1. **Source Tracking Tokenizer:** Maps characters to discrete tokens while maintaining source locations (file, line, column) for robust compilation errors.
2121
2. **Recursive Descent Parser:** Transforms the token stream into a structured AST, treating hardware registers and standard controls as first-class grammatical constructs.
22-
3. **Lexically Scoped Semantic Analyzer:** Implements a type synthesizer and validation engine. It enforces a hierarchical symbol table structure to handle block scoping (`if/else`, `while`, `for`), tracking variable lifetimes, validating function signatures, and trapping type mismatches before code generation.
23-
5. **Optimized Code Generator:** Generates valid 65C02 binaries. It avoids slow stack execution by mapping parameters and expression scratchpads directly onto a high-performance zero-page register design.
22+
3. **Lexically Scoped Semantic Analyzer:** Two-pass validation engine over the AST. Pass 1 registers all top-level declarations (functions, structs, registers, globals) into the global symbol table. Pass 2 walks function bodies with a scoped symbol table, checking undeclared identifiers, type mismatches, argument counts/types, struct field access, lvalue validity, and return-type consistency. Invalid declarations are poisoned to prevent cascading diagnostics.
23+
4. **Optimized Code Generator:** Generates valid 65C02 binaries. It avoids slow stack execution by mapping parameters and expression scratchpads directly onto a high-performance zero-page register design.
2424
> To be implemented!!
2525
2626
#### c02-objdump Disassembler
@@ -29,13 +29,14 @@
2929

3030
## Current Status & Limitations
3131

32-
C02 is under active, early development. This is a **frontend-only** release — the tokenizer, parser, and analyzer are functional and tested, but nothing downstream of analysis exists yet:
32+
C02 is under active, early development. The **complete frontend** - tokenizer, parser, and semantic analyzer - is functional and tested, but nothing downstream of analysis exists yet:
3333

3434
- **Code generation is not implemented.** `cc02` will not currently produce a working 65C02 binary. The zero-page register layout below is a design target for the code generator, not yet a reality.
3535
- **No arrays.** There's no array type or subscript syntax (`a[i]`) yet. Strings work as `u8*` and pointer arithmetic covers some of the same ground in the meantime, but fixed-size arrays with bounds/length tracking are unimplemented.
36-
- **No `struct` field access through a pointer is auto-dereferenced**, but there's no `->` operator — `.` is used uniformly and indirection is intended to be resolved during semantic analysis, which doesn't exist yet, so this is currently unverified in practice.
36+
- **Struct field access through a pointer is auto-dereferenced** - there's no `->` operator; `.` is used uniformly and the analyzer resolves single-level pointer indirection automatically (e.g. `ptr.field` where `ptr` is a `Struct*`).
37+
- **Missing-return detection is shallow.** A non-void function with no `return` at the end is flagged, but the analyzer does not perform full path-coverage analysis - a one-armed `if` that falls through, or an `if`/`else` where only some branches return, is not caught.
3738

38-
If you're exploring the codebase: the parser, [parser.c](cc02/src/parser.c) and its design notes in the header comment are the most complete and representative part of the project right now. Issues and PRs around parser bugs, grammar gaps, or AST design are welcome; IR / codegen is actively being worked on next.
39+
If you're exploring the codebase: the parser ([parser.c](cc02/src/parser/parser.c)) and the analyzer ([analyzer.c](cc02/src/analysis/analyzer.c)) are the most complete parts of the project. Issues and PRs around parser bugs, grammar gaps, or analyzer edge cases are welcome; IR / codegen is actively being worked on next.
3940

4041
## Toolchain Usage
4142

@@ -63,7 +64,8 @@ cc02 [OPTIONS] <FILE>
6364
- `<FILE>`: The input source file (.c02).
6465
- `-h, --help`: Show help message
6566
- `--token-dump`: Dump the token list after tokenization
66-
- `--ast-dump`: Dump the AST using print_ast after parsing
67+
- `--ast-dump`: Dump the AST after parsing
68+
- `--symbol-dump`: Dump the global symbol table after analysis
6769
- `--syntax-check-only`: Stop after syntax and semantic checks
6870
- `--time-report`: Prints a report showing how long each stage of compilation took
6971
- `-o, --output`: Specify output file
@@ -86,7 +88,7 @@ All generated error messages are presented in a clang like format with concise s
8688

8789
## Language Specifications
8890

89-
> The grammar below reflects what the tokenizer and parser currently accept. Semantic analysis and code generation are not implemented yet, so none of this is type-checked or compiled to 65C02 yet — see [Getting Started](#getting-started-key-features--architecture) above.
91+
> The grammar below reflects what the tokenizer and parser currently accept. Semantic analysis validates the full AST after parsing - see [Getting Started](#getting-started-key-features--architecture) above. Code generation is not implemented yet.
9092
9193
### Basic Types
9294

@@ -136,19 +138,22 @@ reg u8 PORTB @ 0x6000;
136138
struct Point {
137139
u8 x;
138140
u8 y;
139-
};
141+
}
140142
```
141143

142144
- Body is a sequence of `type name;` fields, no nested initialisers.
145+
- A trailing `;` after the closing `}` is optional.
143146

144147
#### Global Variables
145148

146149
```c
147150
u8 *msg = "Hello C02!";
148151
u16 counter;
152+
Point origin;
149153
```
150154

151155
- Same form as a local variable declaration: `type name;` or `type name = expr;`.
156+
- Struct-typed globals are supported (`Point p;`).
152157

153158
### Statements
154159

@@ -203,7 +208,7 @@ Precedence, lowest to highest:
203208
```
204209
205210
- **Unary (prefix):** `!` (logical not), `-` (negate), `&` (address-of), `~` (bitwise not), `++` / `--`, `*` and `@` (dereference).
206-
- **Postfix:** `.field` field access, chainable (`a.b.c`).
211+
- **Postfix:** `.field` field access, chainable (`a.b.c`). Auto-dereferences struct pointers (`ptr.field` where `ptr` is a `Struct*`).
207212
- **Calls:** `name(arg1, arg2, ...)`.
208213
- **Casts:** `(type)expr`, e.g. `(u16)x`.
209214
- **Grouping:** `(expr)`.

0 commit comments

Comments
 (0)