c-next 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +726 -0
  2. package/bin/cnext.js +5 -0
  3. package/grammar/C.g4 +1112 -0
  4. package/grammar/CNext.g4 +817 -0
  5. package/grammar/CPP14Lexer.g4 +282 -0
  6. package/grammar/CPP14Parser.g4 +1072 -0
  7. package/package.json +85 -0
  8. package/src/analysis/DivisionByZeroAnalyzer.ts +378 -0
  9. package/src/analysis/FunctionCallAnalyzer.ts +526 -0
  10. package/src/analysis/InitializationAnalyzer.ts +725 -0
  11. package/src/analysis/NullCheckAnalyzer.ts +427 -0
  12. package/src/analysis/types/IDivisionByZeroError.ts +25 -0
  13. package/src/analysis/types/IFunctionCallError.ts +17 -0
  14. package/src/analysis/types/IInitializationError.ts +55 -0
  15. package/src/analysis/types/INullCheckError.ts +25 -0
  16. package/src/codegen/CodeGenerator.ts +7945 -0
  17. package/src/codegen/CommentExtractor.ts +240 -0
  18. package/src/codegen/CommentFormatter.ts +155 -0
  19. package/src/codegen/HeaderGenerator.ts +265 -0
  20. package/src/codegen/TypeResolver.ts +365 -0
  21. package/src/codegen/types/ECommentType.ts +10 -0
  22. package/src/codegen/types/IComment.ts +21 -0
  23. package/src/codegen/types/ICommentError.ts +15 -0
  24. package/src/codegen/types/TOverflowBehavior.ts +6 -0
  25. package/src/codegen/types/TParameterInfo.ts +13 -0
  26. package/src/codegen/types/TTypeConstants.ts +94 -0
  27. package/src/codegen/types/TTypeInfo.ts +22 -0
  28. package/src/index.ts +518 -0
  29. package/src/lib/IncludeDiscovery.ts +131 -0
  30. package/src/lib/InputExpansion.ts +121 -0
  31. package/src/lib/PlatformIODetector.ts +162 -0
  32. package/src/lib/transpiler.ts +439 -0
  33. package/src/lib/types/ITranspileResult.ts +80 -0
  34. package/src/parser/c/grammar/C.interp +338 -0
  35. package/src/parser/c/grammar/C.tokens +229 -0
  36. package/src/parser/c/grammar/CLexer.interp +415 -0
  37. package/src/parser/c/grammar/CLexer.tokens +229 -0
  38. package/src/parser/c/grammar/CLexer.ts +750 -0
  39. package/src/parser/c/grammar/CListener.ts +976 -0
  40. package/src/parser/c/grammar/CParser.ts +9663 -0
  41. package/src/parser/c/grammar/CVisitor.ts +626 -0
  42. package/src/parser/cpp/grammar/CPP14Lexer.interp +478 -0
  43. package/src/parser/cpp/grammar/CPP14Lexer.tokens +264 -0
  44. package/src/parser/cpp/grammar/CPP14Lexer.ts +848 -0
  45. package/src/parser/cpp/grammar/CPP14Parser.interp +492 -0
  46. package/src/parser/cpp/grammar/CPP14Parser.tokens +264 -0
  47. package/src/parser/cpp/grammar/CPP14Parser.ts +19961 -0
  48. package/src/parser/cpp/grammar/CPP14ParserListener.ts +2120 -0
  49. package/src/parser/cpp/grammar/CPP14ParserVisitor.ts +1354 -0
  50. package/src/parser/grammar/CNext.interp +340 -0
  51. package/src/parser/grammar/CNext.tokens +214 -0
  52. package/src/parser/grammar/CNextLexer.interp +374 -0
  53. package/src/parser/grammar/CNextLexer.tokens +214 -0
  54. package/src/parser/grammar/CNextLexer.ts +668 -0
  55. package/src/parser/grammar/CNextListener.ts +1020 -0
  56. package/src/parser/grammar/CNextParser.ts +9239 -0
  57. package/src/parser/grammar/CNextVisitor.ts +654 -0
  58. package/src/preprocessor/Preprocessor.ts +301 -0
  59. package/src/preprocessor/ToolchainDetector.ts +225 -0
  60. package/src/preprocessor/types/IPreprocessResult.ts +39 -0
  61. package/src/preprocessor/types/IToolchain.ts +27 -0
  62. package/src/project/FileDiscovery.ts +236 -0
  63. package/src/project/Project.ts +425 -0
  64. package/src/project/types/IProjectConfig.ts +64 -0
  65. package/src/symbols/CNextSymbolCollector.ts +326 -0
  66. package/src/symbols/CSymbolCollector.ts +457 -0
  67. package/src/symbols/CppSymbolCollector.ts +362 -0
  68. package/src/symbols/SymbolTable.ts +312 -0
  69. package/src/symbols/types/IConflict.ts +20 -0
  70. package/src/types/ESourceLanguage.ts +10 -0
  71. package/src/types/ESymbolKind.ts +20 -0
  72. package/src/types/ISymbol.ts +45 -0
package/README.md ADDED
@@ -0,0 +1,726 @@
1
+ # C-Next
2
+
3
+ A safer C for embedded systems development. Transpiles to clean, readable C.
4
+
5
+ **Status: Working Transpiler** — Verified on Teensy MicroMod hardware.
6
+
7
+ ## Quick Example
8
+
9
+ ```cnx
10
+ // Register binding with type-safe access
11
+ register GPIO7 @ 0x42004000 {
12
+ DR: u32 rw @ 0x00,
13
+ DR_SET: u32 wo @ 0x84,
14
+ DR_TOGGLE: u32 wo @ 0x8C,
15
+ }
16
+
17
+ u32 LED_BIT <- 3;
18
+
19
+ scope LED {
20
+ void toggle() {
21
+ // Type-aware bit indexing on write-only register
22
+ GPIO7.DR_TOGGLE[LED_BIT] <- true;
23
+ }
24
+ }
25
+ ```
26
+
27
+ Generates clean C:
28
+
29
+ ```c
30
+ #define GPIO7_DR_TOGGLE (*(volatile uint32_t*)(0x42004000 + 0x8C))
31
+
32
+ uint32_t LED_BIT = 3;
33
+
34
+ void LED_toggle(void) {
35
+ GPIO7_DR_TOGGLE = (1 << LED_BIT);
36
+ }
37
+ ```
38
+
39
+ ## Installation
40
+
41
+ ### From npm (Recommended)
42
+
43
+ ```bash
44
+ npm install -g c-next
45
+ ```
46
+
47
+ Verify the installation:
48
+
49
+ ```bash
50
+ cnext --version
51
+ ```
52
+
53
+ ### From Source (Development)
54
+
55
+ ```bash
56
+ git clone https://github.com/jlaustill/c-next.git
57
+ cd c-next
58
+ npm install
59
+ npm link
60
+ ```
61
+
62
+ ## Usage
63
+
64
+ ```bash
65
+ # Transpile to C (output alongside input file)
66
+ cnext examples/blink.cnx
67
+
68
+ # Explicit output path
69
+ cnext examples/blink.cnx -o blink.c
70
+
71
+ # Parse only (syntax check)
72
+ cnext examples/blink.cnx --parse
73
+
74
+ # Output as C++ (.cpp)
75
+ cnext examples/blink.cnx --cpp
76
+
77
+ # Target platform for atomic code generation (ADR-049)
78
+ cnext examples/blink.cnx --target teensy41
79
+
80
+ # Show all options
81
+ cnext --help
82
+ ```
83
+
84
+ ## Getting Started with PlatformIO
85
+
86
+ C-Next integrates seamlessly with PlatformIO embedded projects. The transpiler automatically converts `.cnx` files to `.c` before each build.
87
+
88
+ ### Quick Setup
89
+
90
+ From your PlatformIO project root:
91
+
92
+ ```bash
93
+ cnext --pio-install
94
+ ```
95
+
96
+ This command:
97
+
98
+ - Creates `cnext_build.py` (pre-build transpilation script)
99
+ - Modifies `platformio.ini` to add `extra_scripts = pre:cnext_build.py`
100
+
101
+ ### Usage
102
+
103
+ 1. **Create `.cnx` files in your `src/` directory** (alongside existing `.c`/`.cpp` files)
104
+
105
+ ```bash
106
+ src/
107
+ ├── main.cpp # Existing C++ code
108
+ ├── ConfigStorage.cnx # New c-next code
109
+ └── SensorProcessor.cnx # New c-next code
110
+ ```
111
+
112
+ 2. **Build as usual** — transpilation happens automatically:
113
+
114
+ ```bash
115
+ pio run
116
+ ```
117
+
118
+ Output:
119
+
120
+ ```
121
+ Transpiling 2 c-next files...
122
+ ✓ ConfigStorage.cnx
123
+ ✓ SensorProcessor.cnx
124
+ Building...
125
+ ```
126
+
127
+ 3. **Commit both `.cnx` and generated `.c` files** to version control
128
+
129
+ ### Why Commit Generated Files?
130
+
131
+ Generated `.c` files are **reviewable artifacts** in pull requests:
132
+
133
+ ```diff
134
+ + // ConfigStorage.cnx
135
+ + u8 validate_config() {
136
+ + counter +<- 1;
137
+ + }
138
+
139
+ + // ConfigStorage.c (generated)
140
+ + uint8_t validate_config(void) {
141
+ + counter = cnx_clamp_add_u8(counter, 1);
142
+ + }
143
+ ```
144
+
145
+ **Benefits**:
146
+
147
+ - See exactly what C code the transpiler generates
148
+ - Review safety features (overflow protection, atomic operations)
149
+ - Verify transpiler behavior
150
+ - Build succeeds even if transpiler isn't available
151
+
152
+ This follows the same pattern as TypeScript committing `.js` files or Bison committing generated parsers.
153
+
154
+ ### Example Project Structure
155
+
156
+ ```
157
+ my-teensy-project/
158
+ ├── platformio.ini # PlatformIO config
159
+ ├── cnext_build.py # Auto-generated transpilation script
160
+ ├── src/
161
+ │ ├── main.cpp # C++ entry point
162
+ │ ├── ConfigStorage.cnx # c-next source
163
+ │ ├── ConfigStorage.c # Generated (committed)
164
+ │ ├── SensorProcessor.cnx # c-next source
165
+ │ └── SensorProcessor.c # Generated (committed)
166
+ └── include/
167
+ └── AppConfig.h # Shared types
168
+ ```
169
+
170
+ ### Uninstall
171
+
172
+ To remove c-next integration:
173
+
174
+ ```bash
175
+ cnext --pio-uninstall
176
+ ```
177
+
178
+ This removes:
179
+
180
+ - `cnext_build.py` script
181
+ - `extra_scripts` reference from `platformio.ini`
182
+
183
+ Your `.cnx` files and generated `.c` files remain untouched.
184
+
185
+ ### Manual Integration
186
+
187
+ If you prefer manual control, you can also run the transpiler explicitly:
188
+
189
+ ```bash
190
+ # Transpile all .cnx files in src/
191
+ cnext --project src
192
+
193
+ # Or transpile specific files
194
+ cnext src/ConfigStorage.cnx
195
+ cnext src/SensorProcessor.cnx
196
+ ```
197
+
198
+ ## Philosophy
199
+
200
+ C-Next follows the TypeScript model for adoption:
201
+
202
+ 1. **Not all-or-nothing** — Drop a single `.cnx` file into an existing C project
203
+ 2. **Clean escape hatch** — Generated C is idiomatic and maintainable
204
+ 3. **Helpful, not burdensome** — If you know C, you can read C-Next immediately
205
+
206
+ ### Core Principles
207
+
208
+ **KISS (Keep It Simple, Stupid)**
209
+ Every feature must pass the simplicity test: "Can a senior C developer read this cold and understand it in 30 seconds?" If not, it's too clever.
210
+
211
+ **DRY (Don't Repeat Yourself)**
212
+ Configuration belongs in one place. No magic numbers scattered through code. Named constants and register bindings enforce single sources of truth.
213
+
214
+ **Pragmatic, Not Dogmatic**
215
+ C-Next makes the right thing easy and the wrong thing hard, but doesn't prevent escape hatches. Generated C is always readable and maintainable.
216
+
217
+ ### C Preprocessor Compatibility
218
+
219
+ C-Next uses the standard C preprocessor — no custom module system. This means:
220
+
221
+ - `#include` directives pass through to generated C
222
+ - Include C-Next files: `#include "utils.cnx"` → `#include "utils.h"` in generated C
223
+ - Works with both `<file.cnx>` and `"file.cnx"` syntax
224
+ - MISRA preprocessor guidelines apply
225
+ - Full compatibility with existing toolchains (PlatformIO, arm-gcc, etc.)
226
+ - Conditional compilation (`#ifdef`) works as expected
227
+
228
+ Generated headers automatically include guards:
229
+
230
+ ```c
231
+ #ifndef MYFILE_H
232
+ #define MYFILE_H
233
+ // ...
234
+ #endif /* MYFILE_H */
235
+ ```
236
+
237
+ ### The Simplicity Constraint
238
+
239
+ | Rust's Path | C-Next's Path |
240
+ | ---------------------------- | --------------------------------------- |
241
+ | Add concepts to catch errors | Remove the ability to make errors |
242
+ | Borrow checker complexity | Startup allocation = predictable memory |
243
+ | Lifetime annotations | Fixed runtime layout = clear lifetimes |
244
+ | `unsafe` escape hatch | Clean C is the escape hatch |
245
+
246
+ **Guiding Principle:** If Linus Torvalds wouldn't approve of the complexity, it doesn't ship. Safety through removal, not addition.
247
+
248
+ ## Core Features
249
+
250
+ ### Assignment: `<-` vs Equality: `=`
251
+
252
+ Eliminates the `if (x = 5)` bug by design:
253
+
254
+ ```cnx
255
+ x <- 5; // assignment: value flows INTO x
256
+ if (x = 5) // comparison: single equals, just like math
257
+ ```
258
+
259
+ ### Fixed-Width Types
260
+
261
+ ```cnx
262
+ u8, u16, u32, u64 // unsigned integers
263
+ i8, i16, i32, i64 // signed integers
264
+ f32, f64 // floating point
265
+ bool // boolean
266
+ ```
267
+
268
+ ### Register Bindings
269
+
270
+ Type-safe hardware access with access modifiers:
271
+
272
+ ```cnx
273
+ register GPIO7 @ 0x42004000 {
274
+ DR: u32 rw @ 0x00, // Read-Write
275
+ PSR: u32 ro @ 0x08, // Read-Only
276
+ DR_SET: u32 wo @ 0x84, // Write-Only (atomic set)
277
+ DR_CLEAR: u32 wo @ 0x88, // Write-Only (atomic clear)
278
+ DR_TOGGLE: u32 wo @ 0x8C, // Write-Only (atomic toggle)
279
+ }
280
+ ```
281
+
282
+ ### Type-Aware Bit Indexing
283
+
284
+ Integers are indexable as bit arrays:
285
+
286
+ ```cnx
287
+ u8 flags <- 0;
288
+ flags[3] <- true; // Set bit 3
289
+ flags[0, 3] <- 5; // Set 3 bits starting at bit 0
290
+ bool isSet <- flags[3]; // Read bit 3
291
+
292
+ // .length property
293
+ u8 buffer[16];
294
+ buffer.length; // 16 (array element count)
295
+ flags.length; // 8 (bit width of u8)
296
+ ```
297
+
298
+ Write-only registers generate optimized code:
299
+
300
+ ```cnx
301
+ GPIO7.DR_SET[LED_BIT] <- true; // Generates: GPIO7_DR_SET = (1 << LED_BIT);
302
+ ```
303
+
304
+ ### Scopes (ADR-016)
305
+
306
+ Organize code with automatic name prefixing. Inside scopes, explicit qualification is required:
307
+
308
+ - `this.X` for scope-local members
309
+ - `global.X` for global variables, functions, and registers
310
+
311
+ ```cnx
312
+ const u8 LED_BIT <- 3;
313
+
314
+ scope LED {
315
+ u8 brightness <- 100;
316
+
317
+ void on() { global.GPIO7.DR_SET[global.LED_BIT] <- true; }
318
+ void off() { global.GPIO7.DR_CLEAR[global.LED_BIT] <- true; }
319
+
320
+ u8 getBrightness() { return this.brightness; }
321
+ }
322
+
323
+ // Call as:
324
+ LED.on();
325
+ LED.off();
326
+ ```
327
+
328
+ Transpiles to:
329
+
330
+ ```c
331
+ const uint8_t LED_BIT = 3;
332
+
333
+ static uint8_t LED_brightness = 100;
334
+
335
+ void LED_on(void) { GPIO7_DR_SET = (1 << LED_BIT); }
336
+ void LED_off(void) { GPIO7_DR_CLEAR = (1 << LED_BIT); }
337
+
338
+ uint8_t LED_getBrightness(void) { return LED_brightness; }
339
+ ```
340
+
341
+ ### Switch Statements (ADR-025)
342
+
343
+ Safe switch with MISRA compliance:
344
+
345
+ - Braces replace break (no colons needed)
346
+ - No fallthrough allowed
347
+ - Multiple cases with `||` syntax
348
+ - Counted `default(n)` for enum exhaustiveness
349
+
350
+ ```cnx
351
+ enum EState { IDLE, RUNNING, STOPPED }
352
+
353
+ void handleState(EState state) {
354
+ switch (state) {
355
+ case EState.IDLE {
356
+ startMotor();
357
+ }
358
+ case EState.RUNNING || EState.STOPPED {
359
+ checkSensors();
360
+ }
361
+ }
362
+ }
363
+ ```
364
+
365
+ Transpiles to:
366
+
367
+ ```c
368
+ switch (state) {
369
+ case EState_IDLE: {
370
+ startMotor();
371
+ break;
372
+ }
373
+ case EState_RUNNING:
374
+ case EState_STOPPED: {
375
+ checkSensors();
376
+ break;
377
+ }
378
+ }
379
+ ```
380
+
381
+ ### Ternary Operator (ADR-022)
382
+
383
+ Safe conditional expressions with MISRA compliance:
384
+
385
+ - Parentheses required around condition
386
+ - Condition must be boolean (comparison or logical)
387
+ - No nesting allowed (use if/else instead)
388
+
389
+ ```cnx
390
+ u32 max <- (a > b) ? a : b;
391
+ u32 abs <- (x < 0) ? -x : x;
392
+ u32 result <- (a > 0 && b > 0) ? a : b;
393
+
394
+ // ERROR: Condition must be boolean
395
+ // u32 bad <- (x) ? 1 : 0;
396
+
397
+ // ERROR: Nested ternary not allowed
398
+ // i32 sign <- (x > 0) ? 1 : (x < 0) ? -1 : 0;
399
+ ```
400
+
401
+ ### Bounded Strings (ADR-045)
402
+
403
+ Safe, statically-allocated strings with compile-time capacity checking:
404
+
405
+ ```cnx
406
+ string<64> name <- "Hello"; // 64-char capacity, transpiles to char[65]
407
+ string<128> message; // Empty string, initialized to ""
408
+ const string VERSION <- "1.0.0"; // Auto-sized to string<5>
409
+
410
+ // Properties
411
+ u32 len <- name.length; // Runtime: strlen(name)
412
+ u32 cap <- name.capacity; // Compile-time: 64
413
+
414
+ // Comparison - uses strcmp
415
+ if (name = "Hello") { } // strcmp(name, "Hello") == 0
416
+
417
+ // Concatenation with capacity validation
418
+ string<32> first <- "Hello";
419
+ string<32> second <- " World";
420
+ string<64> result <- first + second; // OK: 64 >= 32 + 32
421
+
422
+ // Substring extraction with bounds checking
423
+ string<5> greeting <- name[0, 5]; // First 5 chars
424
+ ```
425
+
426
+ All operations are validated at compile time:
427
+
428
+ - Literal overflow → compile error
429
+ - Truncation on assignment → compile error
430
+ - Concatenation capacity mismatch → compile error
431
+ - Substring out of bounds → compile error
432
+
433
+ ### Callbacks (ADR-029)
434
+
435
+ Type-safe function pointers with the Function-as-Type pattern:
436
+
437
+ - A function definition creates both a callable function AND a type
438
+ - Nominal typing: type identity is the function name, not just signature
439
+ - Never null: callbacks are always initialized to their default function
440
+
441
+ ```cnx
442
+ // Define callback type with default behavior
443
+ void onReceive(const CAN_Message_T msg) {
444
+ // default: no-op
445
+ }
446
+
447
+ struct Controller {
448
+ onReceive _handler; // Type is onReceive, initialized to default
449
+ }
450
+
451
+ // User implementation must match signature
452
+ void myHandler(const CAN_Message_T msg) {
453
+ Serial.println(msg.id);
454
+ }
455
+
456
+ controller._handler <- myHandler; // OK: signature matches
457
+ controller._handler(msg); // Always safe - never null
458
+ ```
459
+
460
+ Transpiles to:
461
+
462
+ ```c
463
+ void onReceive(const CAN_Message_T msg) { }
464
+
465
+ typedef void (*onReceive_fp)(const CAN_Message_T);
466
+
467
+ struct Controller {
468
+ onReceive_fp _handler;
469
+ };
470
+
471
+ // Initialization always sets to default
472
+ struct Controller Controller_init(void) {
473
+ return (struct Controller){ ._handler = onReceive };
474
+ }
475
+ ```
476
+
477
+ ### Atomic Variables (ADR-049)
478
+
479
+ ISR-safe variables with hardware-assisted atomicity:
480
+
481
+ ```cnx
482
+ #pragma target teensy41
483
+
484
+ atomic u32 counter <- 0; // ISR-safe with LDREX/STREX
485
+ atomic clamp u8 brightness <- 100; // Combines atomic + clamp
486
+
487
+ void increment() {
488
+ counter +<- 1; // Lock-free atomic increment
489
+ }
490
+ ```
491
+
492
+ Generates optimized code based on target platform:
493
+
494
+ - **Cortex-M3/M4/M7**: LDREX/STREX retry loops (lock-free)
495
+ - **Cortex-M0/M0+**: PRIMASK disable/restore (interrupt masking)
496
+
497
+ Target detection priority: `--target` CLI flag > `platformio.ini` > `#pragma target` > default
498
+
499
+ ### Volatile Variables (ADR-108)
500
+
501
+ Prevent compiler optimization for variables that change outside normal program flow:
502
+
503
+ ```cnx
504
+ // Delay loop - prevent optimization
505
+ void delay_ms(const u32 ms) {
506
+ volatile u32 i <- 0;
507
+ volatile u32 count <- ms * 2000;
508
+
509
+ while (i < count) {
510
+ i +<- 1; // Compiler cannot optimize away
511
+ }
512
+ }
513
+
514
+ // Hardware register - reads actual memory
515
+ volatile u32 status_register @ 0x40020000;
516
+
517
+ void waitReady() {
518
+ while (status_register & 0x01 = 0) {
519
+ // Always reads from hardware
520
+ }
521
+ }
522
+ ```
523
+
524
+ **When to use:**
525
+
526
+ - ✅ Delay loops that must not be optimized away
527
+ - ✅ Memory-mapped hardware registers
528
+ - ✅ Variables polled in tight loops
529
+ - ❌ ISR-shared variables (use `atomic` instead for RMW safety)
530
+
531
+ **Key difference from `atomic`:**
532
+
533
+ - `volatile` = prevents optimization only
534
+ - `atomic` = prevents optimization + adds synchronization (ISR-safe)
535
+
536
+ ### Critical Sections (ADR-050)
537
+
538
+ Multi-statement atomic blocks with automatic interrupt masking:
539
+
540
+ ```cnx
541
+ u8 buffer[64];
542
+ u32 writeIdx <- 0;
543
+
544
+ void enqueue(u8 data) {
545
+ critical {
546
+ buffer[writeIdx] <- data;
547
+ writeIdx +<- 1;
548
+ }
549
+ }
550
+ ```
551
+
552
+ Transpiles to PRIMASK save/restore:
553
+
554
+ ```c
555
+ void enqueue(uint8_t data) {
556
+ {
557
+ uint32_t __primask = __get_PRIMASK();
558
+ __disable_irq();
559
+ buffer[writeIdx] = data;
560
+ writeIdx += 1;
561
+ __set_PRIMASK(__primask);
562
+ }
563
+ }
564
+ ```
565
+
566
+ **Safety**: `return` inside `critical { }` is a compile error (E0853).
567
+
568
+ ### NULL for C Library Interop (ADR-047)
569
+
570
+ Safe interop with C stream functions that can return NULL:
571
+
572
+ ```cnx
573
+ #include <stdio.h>
574
+
575
+ string<64> buffer;
576
+
577
+ void readInput() {
578
+ // NULL check is REQUIRED - compiler enforces it
579
+ if (fgets(buffer, buffer.size, stdin) != NULL) {
580
+ printf("Got: %s", buffer);
581
+ }
582
+ }
583
+ ```
584
+
585
+ **Constraints:**
586
+
587
+ - NULL only valid in comparison context (`!= NULL` or `= NULL`)
588
+ - Only whitelisted stream functions: `fgets`, `fputs`, `fgetc`, `fputc`
589
+ - Cannot store C pointer returns in variables
590
+ - `fopen`, `malloc`, etc. are errors (see ADR-103 for future FILE\* support)
591
+
592
+ ### Startup Allocation
593
+
594
+ Allocate at startup, run with fixed memory. Per MISRA C:2023 Dir 4.12: all memory is allocated during initialization, then forbidden. No runtime allocation means no fragmentation, no OOM, no leaks.
595
+
596
+ ## Hardware Testing
597
+
598
+ Verified on **Teensy MicroMod** (NXP i.MX RT1062):
599
+
600
+ ```bash
601
+ # Build and flash with PlatformIO
602
+ cd test-teensy
603
+ pio run -t upload
604
+ ```
605
+
606
+ See `examples/blink.cnx` for the complete LED blink example.
607
+
608
+ ## Project Structure
609
+
610
+ ```
611
+ c-next/
612
+ ├── grammar/CNext.g4 # ANTLR4 grammar definition
613
+ ├── src/
614
+ │ ├── codegen/CodeGenerator.ts # Transpiler core
615
+ │ ├── parser/ # Generated ANTLR parser
616
+ │ └── index.ts # CLI entry point
617
+ ├── examples/
618
+ │ ├── blink.cnx # LED blink (Teensy verified)
619
+ │ └── bit_test.cnx # Bit manipulation tests
620
+ ├── test-teensy/ # PlatformIO test project
621
+ └── docs/decisions/ # Architecture Decision Records
622
+ ```
623
+
624
+ ## Architecture Decision Records
625
+
626
+ Decisions are documented in `/docs/decisions/`:
627
+
628
+ ### Implemented
629
+
630
+ | ADR | Title | Description |
631
+ | ------------------------------------------------------------ | ----------------------- | ------------------------------------------------------------ |
632
+ | [ADR-001](docs/decisions/adr-001-assignment-operator.md) | Assignment Operator | `<-` for assignment, `=` for comparison |
633
+ | [ADR-003](docs/decisions/adr-003-static-allocation.md) | Static Allocation | No dynamic memory after init |
634
+ | [ADR-004](docs/decisions/adr-004-register-bindings.md) | Register Bindings | Type-safe hardware access |
635
+ | [ADR-006](docs/decisions/adr-006-simplified-references.md) | Simplified References | Pass by reference, no pointer syntax |
636
+ | [ADR-007](docs/decisions/adr-007-type-aware-bit-indexing.md) | Type-Aware Bit Indexing | Integers as bit arrays, `.length` property |
637
+ | [ADR-010](docs/decisions/adr-010-c-interoperability.md) | C Interoperability | Unified ANTLR parser architecture |
638
+ | [ADR-011](docs/decisions/adr-011-vscode-extension.md) | VS Code Extension | Live C preview with syntax highlighting |
639
+ | [ADR-012](docs/decisions/adr-012-static-analysis.md) | Static Analysis | cppcheck integration for generated C |
640
+ | [ADR-013](docs/decisions/adr-013-const-qualifier.md) | Const Qualifier | Compile-time const enforcement |
641
+ | [ADR-014](docs/decisions/adr-014-structs.md) | Structs | Data containers without methods |
642
+ | [ADR-015](docs/decisions/adr-015-null-state.md) | Null State | Zero initialization for all variables |
643
+ | [ADR-016](docs/decisions/adr-016-scope.md) | Scope | `this.`/`global.` explicit qualification |
644
+ | [ADR-017](docs/decisions/adr-017-enums.md) | Enums | Type-safe enums with C-style casting |
645
+ | [ADR-030](docs/decisions/adr-030-forward-declarations.md) | Define-Before-Use | Functions must be defined before called |
646
+ | [ADR-037](docs/decisions/adr-037-preprocessor.md) | Preprocessor | Flag-only defines, const for values |
647
+ | [ADR-043](docs/decisions/adr-043-comments.md) | Comments | Comment preservation with MISRA compliance |
648
+ | [ADR-044](docs/decisions/adr-044-primitive-types.md) | Primitive Types | Fixed-width types with `clamp`/`wrap` overflow |
649
+ | [ADR-024](docs/decisions/adr-024-type-casting.md) | Type Casting | Widening implicit, narrowing uses bit indexing |
650
+ | [ADR-022](docs/decisions/adr-022-conditional-expressions.md) | Conditional Expressions | Ternary with required parens, boolean condition, no nesting |
651
+ | [ADR-025](docs/decisions/adr-025-switch-statements.md) | Switch Statements | Safe switch with braces, `\|\|` syntax, counted `default(n)` |
652
+ | [ADR-029](docs/decisions/adr-029-function-pointers.md) | Callbacks | Function-as-Type pattern with nominal typing |
653
+ | [ADR-045](docs/decisions/adr-045-string-type.md) | Bounded Strings | `string<N>` with compile-time safety |
654
+ | [ADR-023](docs/decisions/adr-023-sizeof.md) | Sizeof | Type/value size queries with safety checks |
655
+ | [ADR-027](docs/decisions/adr-027-do-while.md) | Do-While | `do { } while ()` with boolean condition (E0701) |
656
+ | [ADR-032](docs/decisions/adr-032-nested-structs.md) | Nested Structs | Named nested structs only (no anonymous) |
657
+ | [ADR-035](docs/decisions/adr-035-array-initializers.md) | Array Initializers | `[1, 2, 3]` syntax with `[0*]` fill-all |
658
+ | [ADR-036](docs/decisions/adr-036-multidimensional-arrays.md) | Multi-dim Arrays | `arr[i][j]` with compile-time bounds enforcement |
659
+ | [ADR-040](docs/decisions/adr-040-isr-declaration.md) | ISR Type | Built-in `ISR` type for `void(void)` function pointers |
660
+ | [ADR-034](docs/decisions/adr-034-bit-fields.md) | Bitmap Types | `bitmap8`/`bitmap16`/`bitmap32` for portable bit-packed data |
661
+ | [ADR-048](docs/decisions/adr-048-cli-executable.md) | CLI Executable | `cnext` command with smart defaults |
662
+ | [ADR-049](docs/decisions/adr-049-atomic-types.md) | Atomic Types | `atomic` keyword with LDREX/STREX or PRIMASK fallback |
663
+ | [ADR-050](docs/decisions/adr-050-critical-sections.md) | Critical Sections | `critical { }` blocks with PRIMASK save/restore |
664
+ | [ADR-108](docs/decisions/adr-108-volatile-keyword.md) | Volatile Variables | `volatile` keyword prevents compiler optimization |
665
+ | [ADR-047](docs/decisions/adr-047-nullable-types.md) | NULL for C Interop | `NULL` keyword for C stream function comparisons |
666
+
667
+ ### Research (v1 Roadmap)
668
+
669
+ | ADR | Title | Description |
670
+ | ------------------------------------------------------------ | ----------------------------- | --------------------------------------- |
671
+ | [ADR-008](docs/decisions/adr-008-language-bug-prevention.md) | Language-Level Bug Prevention | Top 15 embedded bugs and prevention |
672
+ | [ADR-009](docs/decisions/adr-009-isr-safety.md) | ISR Safety | Safe interrupts without `unsafe` blocks |
673
+
674
+ ### Research (v2 Roadmap)
675
+
676
+ | ADR | Title | Description |
677
+ | --------------------------------------------------------------- | -------------------------- | --------------------------------------- |
678
+ | [ADR-100](docs/decisions/adr-100-multi-core-synchronization.md) | Multi-Core Synchronization | ESP32/RP2040 spinlock patterns |
679
+ | [ADR-101](docs/decisions/adr-101-heap-allocation.md) | Heap Allocation | Dynamic memory for desktop targets |
680
+ | [ADR-102](docs/decisions/adr-102-critical-section-analysis.md) | Critical Section Analysis | Complexity warnings and cycle analysis |
681
+ | [ADR-103](docs/decisions/adr-103-stream-handling.md) | Stream Handling | FILE\* and fopen patterns for file I/O |
682
+ | [ADR-104](docs/decisions/adr-104-isr-queues.md) | ISR-Safe Queues | Producer-consumer patterns for ISR/main |
683
+ | [ADR-105](docs/decisions/adr-105-prefixed-includes.md) | Prefixed Includes | Namespace control for includes |
684
+ | [ADR-106](docs/decisions/adr-106-isr-vector-bindings.md) | Vector Table Bindings | Register bindings for ISR vector tables |
685
+
686
+ ### Rejected
687
+
688
+ | ADR | Title | Description |
689
+ | ---------------------------------------------------------------- | ------------------- | ----------------------------------------------------------------------- |
690
+ | [ADR-041](docs/decisions/adr-041-inline-assembly.md) | Inline Assembly | Write assembly in C files; C-Next transpiles to C anyway |
691
+ | [ADR-042](docs/decisions/adr-042-error-handling.md) | Error Handling | Works with existing features (enums, pass-by-reference, struct returns) |
692
+ | [ADR-039](docs/decisions/adr-039-null-safety.md) | Null Safety | Emergent from ADR-003 + ADR-006 + ADR-015; no additional feature needed |
693
+ | [ADR-020](docs/decisions/adr-020-size-type.md) | Size Type | Fixed-width types are more predictable than platform-sized |
694
+ | [ADR-019](docs/decisions/adr-019-type-aliases.md) | Type Aliases | Fixed-width primitives already solve the problem |
695
+ | [ADR-021](docs/decisions/adr-021-increment-decrement.md) | Increment/Decrement | Use `+<- 1` instead; separation of concerns |
696
+ | [ADR-002](docs/decisions/adr-002-namespaces.md) | Namespaces | Replaced by `scope` keyword (ADR-016) |
697
+ | [ADR-005](docs/decisions/adr-005-classes-without-inheritance.md) | Classes | Use structs + free functions instead (ADR-016) |
698
+ | [ADR-018](docs/decisions/adr-018-unions.md) | Unions | Use ADR-004 register bindings or explicit byte manipulation |
699
+ | [ADR-038](docs/decisions/adr-038-static-extern.md) | Static/Extern | Use `scope` for visibility; no `static` keyword in v1 |
700
+ | [ADR-026](docs/decisions/adr-026-break-continue.md) | Break/Continue | Use structured loop conditions instead |
701
+ | [ADR-028](docs/decisions/adr-028-goto.md) | Goto | Permanently rejected; use structured alternatives |
702
+ | [ADR-031](docs/decisions/adr-031-inline-functions.md) | Inline Functions | Trust compiler; `inline` is just a hint anyway |
703
+ | [ADR-033](docs/decisions/adr-033-packed-structs.md) | Packed Structs | Use ADR-004 register bindings or explicit serialization |
704
+
705
+ ## Build Commands
706
+
707
+ ```bash
708
+ npm run build # Full build: ANTLR + TypeScript
709
+ npm run antlr # Regenerate parser from grammar
710
+ npx tsc # TypeScript only
711
+ ```
712
+
713
+ ## Contributing
714
+
715
+ Ideas and feedback welcome via issues.
716
+
717
+ ## License
718
+
719
+ MIT
720
+
721
+ ## Acknowledgments
722
+
723
+ - The R community for proving `<-` works in practice
724
+ - MISRA C consortium for codifying embedded safety wisdom
725
+ - The TypeScript team for demonstrating gradual adoption works
726
+ - ANTLR for the parser infrastructure