From 11cc5f220b9bb5a2135baaf52a67cb8b997c753d Mon Sep 17 00:00:00 2001 From: Mattias Hansson Date: Sun, 12 Jul 2026 19:31:38 +0200 Subject: [PATCH] Fixed up docs to reflect reality and for examples to work. --- README.md | 2 +- commands.md | 6 ++++- language.md | 74 ++++++++++++++++++++++++++++++++++------------------- syntax.md | 73 +++++++++++++++++++++++++++++++++++++--------------- 4 files changed, 106 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index 1c9f7ca..14db33a 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ c65gm compiles high-level source code into ACME assembler syntax for the 6502 pr - **Functions**: Named functions with parameters and call graph analysis - **Control flow**: IF/ENDIF, WHILE/WEND, FOR loops, SWITCH/CASE - **Memory operations**: PEEK/POKE/PEEKW/POKEW with zero-page optimization. Access registers as variables. -- **Operators**: Arithmetic (ADD, SUB), bitwise (AND, OR, XOR) +- **Operators**: Arithmetic (ADD, SUB), bitwise (AND, OR, XOR), shifts (SHL, SHR) - **Preprocessor**: File inclusion, macros, conditional compilation, Starlark scripting - **Standard library**: C64 screen/kernal routines, memory management, string handling, graphics (Koala), FAT16 filesystem, and more (accessed via `#include `, path set by `C65LIBPATH` environment variable) - **Optimizations**: Constant folding, self-assignment detection diff --git a/commands.md b/commands.md index 247c0b8..3af78bf 100644 --- a/commands.md +++ b/commands.md @@ -91,6 +91,7 @@ BREAK ``` // BREAK in FOR loop +BYTE i FOR i = 0 TO 100 IF i = 50 BREAK @@ -242,7 +243,8 @@ See [FUNC](#func) for syntax and examples. ## FOR -Loop with automatic counter increment. +Loop with automatic counter increment. The iterator variable must be declared +beforehand. **Syntax:** ``` @@ -253,6 +255,7 @@ FOR = TO ``` // FOR loop with literal values +BYTE i FOR i = 0 TO 10 screen = i NEXT @@ -260,6 +263,7 @@ NEXT ``` // FOR loop with variables +BYTE counter FOR counter = start TO finish process(counter) NEXT diff --git a/language.md b/language.md index 8ce02c3..500ac55 100644 --- a/language.md +++ b/language.md @@ -178,7 +178,13 @@ result = 2+3*4 // Evaluates as (2+3)*4 = 20, NOT 2+(3*4) = 14 value = 100-20+5 // Evaluates as (100-20)+5 = 85 ``` -For complex expressions, use temporary variables: +These multi-term forms are folded at compile time and only work when every +term is a literal or `CONST` (write them without spaces). `*` and `/` are +**only** available in these constant expressions, not on runtime variables. + +Runtime expressions involving a variable perform exactly one operation and +must be space-separated (`dest = a + b`). For anything more complex, use +temporary variables: ```c65 // Instead of: result = (b - c) + a @@ -238,9 +244,10 @@ WEND ### FOR Loops -Loop with automatic counter: +Loop with automatic counter. The loop variable must be declared beforehand: ```c65 +BYTE i FOR i = 0 TO 10 screen = i NEXT @@ -255,6 +262,7 @@ NEXT Exit a loop early: ```c65 +BYTE i FOR i = 0 TO 100 IF i == 50 BREAK @@ -354,15 +362,17 @@ Read a byte from memory: ```c65 value = PEEK $D020 // Read from absolute address -char = PEEK screenPtr[index] // Read with offset -byte = PEEK pointer // Read from pointer +byte = PEEK pointer // Read through a WORD pointer ``` -**Important:** For indexed access, the address must be a WORD variable in zero page. +**Indexed access:** Add `[offset]` to read at pointer+offset. The offset can +be a constant or a BYTE variable, and the pointer **must** be a WORD variable +in zero page: ```c65 WORD buffer @ $FB // Zero-page pointer value = PEEK buffer[10] // Read buffer+10 +char = PEEK buffer[index] // Read buffer+index ``` ### POKE - Writing Memory @@ -371,8 +381,18 @@ Write a byte to memory: ```c65 POKE $D020, 0 // Write to absolute address -POKE screenPtr[index], char // Write with offset -POKE pointer, value // Write to pointer +POKE pointer, value // Write through a WORD pointer +``` + +**Indexed access:** As with PEEK, `[offset]` requires a zero-page WORD +pointer. This is handy for reaching into structured data through a base +pointer: + +```c65 +WORD vic @ $FB +POINTER vic TO $D000 // VIC-II base register +POKE vic[$20], 2 // Write border color ($D020) = red +POKE vic[$21], 0 // Write background color ($D021) = black ``` ### PEEKW - Reading 16-bit Words @@ -393,7 +413,8 @@ Write a 16-bit value to memory: ```c65 POKEW $0314, irqHandler // Set IRQ vector -POKEW dataPtr[0], address // Write word with offset +POKEW dataPtr, address // Write word through a pointer +POKEW dataPtr[2], address // Write word at dataPtr+2 (zero-page pointer) ``` ### POINTER - Setting Pointers @@ -830,7 +851,7 @@ FEND FUNC updateScreen BYTE color color = frameCount & $0F - POKE screenPtr[0], color + POKE screenPtr, color frameCount++ FEND @@ -857,7 +878,7 @@ FUNC clearScreen WORD remaining = 1000 WHILE remaining > 0 - POKE screenPtr[0], 32 // Space character + POKE screenPtr, 32 // Space character screenPtr++ remaining-- WEND @@ -870,7 +891,7 @@ FEND // Print null-terminated string FUNC printString({WORD textPtr}) BYTE char - char = PEEK textPtr[0] + char = PEEK textPtr WHILE char != 0 ASM @@ -878,7 +899,7 @@ FUNC printString({WORD textPtr}) jsr $FFD2 // CHROUT ENDASM textPtr++ - char = PEEK textPtr[0] + char = PEEK textPtr WEND FEND ``` @@ -893,10 +914,11 @@ BYTE spriteEnable @ VIC2+21 FUNC enableSprite({BYTE spriteNum}) BYTE mask + BYTE i mask = 1 FOR i = 0 TO spriteNum - mask = mask * 2 + mask = mask << 1 NEXT spriteEnable = spriteEnable | mask @@ -908,14 +930,14 @@ FEND For frequently accessed pointers, use zero page: ```c65 -WORD fastPtr @ $FB // Zero page = fast indexed access +WORD fastPtr @ $FB // Zero page = fast pointer access FUNC processBuffer({WORD buffer} {BYTE size}) POINTER fastPtr TO buffer WHILE size > 0 BYTE value - value = PEEK fastPtr[0] + value = PEEK fastPtr // Process value fastPtr++ size-- @@ -1012,11 +1034,6 @@ flags = flags & %11111110 // Clear bit 0 // Toggle bit flags = flags ^ %00000001 // Toggle bit 0 - -// Test bit -IF flags & %00000001 - // Bit 0 is set -ENDIF ``` --- @@ -1049,12 +1066,14 @@ WORD tempPtr @ $FD Remember: left-to-right evaluation, no precedence! ```c65 -// Be careful with expressions -result = 2 + 3 * 4 // = 20, not 14 +// Constant expressions fold left-to-right at compile time. +// Write them without spaces: +result = 2+3*4 // = (2+3)*4 = 20, not 14 -// Use temps for clarity -temp = 3 * 4 -result = 2 + temp // Now = 14 +// Runtime expressions (with variables) do ONE operation per +// statement and must be space-separated. Use temps to order them: +temp = b + c +result = a + temp ``` ### 4. Include Guards @@ -1139,8 +1158,9 @@ address = PEEKW $FFFC POKEW $0314, handler // Operators -+ - * / // Arithmetic -& | ^ // Bitwise ++ - // Arithmetic (runtime + constants) +* / // Multiply/Divide (constant expressions only) +& | ^ << >> // Bitwise / shift ++ -- // Increment/Decrement == != < > <= >= // Comparison diff --git a/syntax.md b/syntax.md index fbf1744..9c0a826 100644 --- a/syntax.md +++ b/syntax.md @@ -12,6 +12,7 @@ C65GM uses C-style line comments. **Examples:** ``` BYTE counter = 0 // Initialize counter +BYTE i // Loop variable (must be declared) // This is a full line comment FOR i = 0 TO 10 // Loop through values counter++ // Increment @@ -623,15 +624,26 @@ $00 ### Operators -Evaluated strictly left to right: +Evaluated strictly left to right (no precedence): -- `+` Addition -- `-` Subtraction -- `*` Multiplication -- `/` Division +- `+` Addition (runtime and constant expressions) +- `-` Subtraction (runtime and constant expressions) +- `*` Multiplication (constant expressions only) +- `/` Division (constant expressions only) - `|` Bitwise OR - `&` Bitwise AND - `^` Bitwise XOR +- `<<` Shift left +- `>>` Shift right + +There are two distinct expression forms: + +- **Constant expressions** — written *without spaces* (e.g. `2+3*4`). Every + term must be a literal or a `CONST`; these are folded at compile time and + may chain any number of terms. `*` and `/` are only available here. +- **Runtime expressions** — written *with spaces* (e.g. `a + b`). These + perform exactly one operation, where at least one operand may be a variable. + Only `+ - & | ^ << >>` are supported; `*` and `/` are not. ### Constants @@ -647,13 +659,20 @@ pointer = SCREEN ### Expression Examples +Constant expressions (no spaces, all terms literals or constants): ``` value = 100+50 result = $FF-10 address = $D000+32 mask = %11110000&$0F -combined = base|offset -calculated = start+length*2 +combined = BASE|OFFSET +calculated = START+LENGTH*2 +``` + +Runtime expressions (spaces, one operation, may use variables): +``` +combined = base | offset +adjusted = value + count ``` **Critical:** No operator precedence. Evaluation is strictly left to right: @@ -682,15 +701,22 @@ INC $D000+20 ``` FOR i = 0 TO MAX_VALUE-1 IF x > THRESHOLD+10 -POKE $D020+offset, value -result = PEEK $0400+index +POKE $D020+OFFSET, value +result = PEEK $0400+INDEX ``` **Arithmetic operations:** + +Constant expressions (compile-time, all terms literal/CONST): ``` -sum = value1+value2 -product = base*factor -adjusted = original+OFFSET +sum = VALUE1+VALUE2 +adjusted = BASE+OFFSET +``` + +Runtime expressions (one operation, may use variables): +``` +sum = value1 + value2 +adjusted = original + offset ``` ### Limitations @@ -702,11 +728,15 @@ result = (a+b)*c value = base+(offset*2) ``` -**No nested expressions in assignments:** +**No multi-operation runtime expressions:** ``` -; NOT SUPPORTED: -x = y + z ; only single value or constant expression -x = a+b ; constant expression (no spaces) OK if a,b are constants +; NOT SUPPORTED (more than one operation with variables): +x = a + b + c ; chain of runtime operations +x = a + b * c ; ditto + +; SUPPORTED: +x = y + z ; single runtime operation (one operator) +x = a+b ; constant expression (no spaces) if a,b are literals/CONST ``` **Workaround for complex expressions:** @@ -720,7 +750,10 @@ result = temp - c Expressions without spaces are treated as constant expressions: ``` -value = 100+50 ; OK - constant expression -value = 100 + 50 ; ERROR - not a simple assignment -value = MAX+10 ; OK if MAX is constant -``` \ No newline at end of file +value = 100+50 ; constant expression (folded at compile time) +value = 100 + 50 ; single runtime operation (also OK) +value = MAX+10 ; constant expression, OK if MAX is a constant +``` + +The difference matters for chaining: `2+3*4` (no spaces) folds all terms at +compile time, while a spaced form allows only one operation. \ No newline at end of file