Initial commit

This commit is contained in:
RoyR
2026-03-14 14:14:37 -04:00
commit da2fcb6260
22 changed files with 6775 additions and 0 deletions

1257
MANUAL.md Normal file

File diff suppressed because it is too large Load Diff

101
Makefile Normal file
View File

@@ -0,0 +1,101 @@
# Makefile for Common compiler test suite and examples
CC = gcc
CFLAGS = -std=c99 -Wall -O2
NASM = nasm
NASMFLAGS = -f elf32
LD = gcc
LDFLAGS = -m32
# Compiler
COMPILER = common
COMPILER_SRC = common.c
# Test runner
TEST_RUNNER = test_runner
TEST_RUNNER_SRC = test_runner.c
# Example programs
EXAMPLES_DIR = examples
EXAMPLES = hello fibonacci arrays pointers bubblesort bitwise types switch primes strings calculator
# Default target
.PHONY: all
all: $(COMPILER) $(TEST_RUNNER)
# Build the Common compiler
$(COMPILER): $(COMPILER_SRC)
$(CC) $(CFLAGS) -o $@ $<
@echo "Built Common compiler"
# Build the test runner
$(TEST_RUNNER): $(TEST_RUNNER_SRC)
$(CC) $(CFLAGS) -o $@ $<
@echo "Built test runner"
# Run tests
.PHONY: test
test: $(COMPILER) $(TEST_RUNNER)
@echo "Running test suite..."
./$(TEST_RUNNER)
# Build all examples
.PHONY: examples
examples: $(COMPILER) $(EXAMPLES)
# Pattern rule for building examples
# Usage: make hello, make fibonacci, etc.
$(EXAMPLES): %: $(EXAMPLES_DIR)/%.cm $(COMPILER)
@echo "Building $@..."
./$(COMPILER) $(EXAMPLES_DIR)/$@.cm $@.asm
$(NASM) $(NASMFLAGS) $@.asm -o $@.o
$(LD) $(LDFLAGS) $@.o -o $@
@echo "Built $@ successfully"
# Run all examples
.PHONY: run-examples
run-examples: examples
@echo "=== Running Examples ==="
@for prog in $(EXAMPLES); do \
echo ""; \
echo ">>> Running $$prog..."; \
./$$prog || true; \
done
# Clean all generated files
.PHONY: clean
clean:
rm -f $(COMPILER) $(TEST_RUNNER)
rm -f *.asm *.o $(EXAMPLES)
rm -f /tmp/test.cm /tmp/test.asm /tmp/test.o /tmp/test /tmp/test.out /tmp/test.err
@echo "Cleaned all generated files"
# Help
.PHONY: help
help:
@echo "Common Compiler Makefile"
@echo ""
@echo "Targets:"
@echo " all - Build compiler and test runner (default)"
@echo " test - Run the test suite"
@echo " examples - Build all example programs"
@echo " run-examples - Build and run all examples"
@echo " clean - Remove all generated files"
@echo ""
@echo "Build individual examples:"
@echo " make hello"
@echo " make fibonacci"
@echo " make arrays"
@echo " make pointers"
@echo " make bubblesort"
@echo " make bitwise"
@echo " make types"
@echo " make switch"
@echo " make primes"
@echo " make strings"
@echo " make calculator"
@echo ""
@echo "Run individual examples:"
@echo " make hello && ./hello"
@echo " make fibonacci && ./fibonacci"
@echo " etc."

332
QUICKREF.md Normal file
View File

@@ -0,0 +1,332 @@
# Common Language Quick Reference
## Compilation
```bash
./common source.cm output.asm
nasm -f elf32 output.asm -o output.o
gcc -m32 output.o -o program
```
## Types
```c
void // No return value
int8 int16 int32 int64 // Signed integers
uint8 uint16 uint32 uint64 // Unsigned integers
type* // Pointer to type
type[N] // Array of N elements
```
## Variables
```c
int32 x; // Declaration
int32 y = 42; // Initialization
int32 arr[10]; // Array
int32 nums[3] = {1, 2, 3}; // Array with initializer
int32 *ptr; // Pointer
```
## Operators
### Arithmetic
```c
+ - * / % // Add, Sub, Mul, Div, Mod
```
### Comparison
```c
== != < <= > >= // Equal, Not-equal, Less, etc.
```
### Logical
```c
&& || ! // AND, OR, NOT (short-circuit)
```
### Bitwise
```c
& | ^ ~ // AND, OR, XOR, NOT
<< >> // Left shift, Right shift
```
### Assignment
```c
= += -= *= /= %= // Assign, Add-assign, etc.
&= |= ^= <<= >>= // Bitwise assign ops
```
### Increment/Decrement
```c
++ -- // Increment, Decrement (pre/post)
```
### Pointer/Array
```c
&x // Address of x
*ptr // Dereference ptr
arr[i] // Array index (same as *(arr+i))
```
### Ternary
```c
cond ? true_val : false_val // Conditional expression
```
## Control Flow
### If-Else
```c
if (condition)
statement;
if (condition) {
statements;
} else {
statements;
}
```
### While Loop
```c
while (condition) {
statements;
}
```
### For Loop
```c
for (int32 i = 0; i < n; i++) {
statements;
}
```
### Switch
```c
switch (expr) {
case 1:
statements;
break;
case 2:
statements;
break;
default:
statements;
}
```
### Break/Continue/Return
```c
break; // Exit loop or switch
continue; // Next loop iteration
return; // Return from void function
return expr; // Return value
```
## Functions
### Declaration
```c
int32 add(int32 a, int32 b); // Forward declaration
```
### Definition
```c
int32 add(int32 a, int32 b) {
return a + b;
}
```
### No Parameters
```c
void func(void) {
// ...
}
```
### Main Function
```c
int32 main(void) {
// Entry point
return 0;
}
```
## Pointers
```c
int32 x = 42;
int32 *p = &x; // p points to x
*p = 100; // Set x to 100 via pointer
int32 y = *p; // Read through pointer
```
## Arrays
```c
int32 arr[5]; // Declare
arr[0] = 10; // Set element
int32 x = arr[2]; // Get element
// Array initialization
int32 nums[5] = {1, 2, 3, 4, 5};
// Arrays decay to pointers
int32 *p = arr; // p points to arr[0]
```
## Strings
```c
uint8 *str = "Hello"; // String literal
printf("%s\n", str); // Print string
// String as array
uint8 msg[] = "Hello";
msg[0] = 'h'; // Modify
```
## Comments
```c
// Single-line comment
/* Multi-line
comment */
```
## Type Casting
```c
(type)expression // Cast to type
int32 x = 1000;
uint8 y = (uint8)x; // Truncate to 8 bits
uint8 *s = (uint8*)"string"; // Pointer cast
```
## Common Patterns
### Swap
```c
void swap(int32 *a, int32 *b) {
int32 temp = *a;
*a = *b;
*b = temp;
}
```
### String Length
```c
int32 strlen(uint8 *s) {
int32 len = 0;
while (s[len]) len++;
return len;
}
```
### Array Sum
```c
int32 sum(int32 *arr, int32 n) {
int32 total = 0;
for (int32 i = 0; i < n; i++)
total += arr[i];
return total;
}
```
### Min/Max
```c
int32 min(int32 a, int32 b) {
return (a < b) ? a : b;
}
int32 max(int32 a, int32 b) {
return (a > b) ? a : b;
}
```
## Calling C Functions
```c
// Declare before use
void printf(uint8 *fmt, ...);
void *malloc(uint32 size);
void free(void *ptr);
// Use
printf("Value: %d\n", x);
void *mem = malloc(100);
free(mem);
```
## Operator Precedence (High to Low)
1. `()` `[]` `.` `->`
2. `!` `~` `++` `--` `+` `-` `*` `&` (unary) `(cast)`
3. `*` `/` `%`
4. `+` `-`
5. `<<` `>>`
6. `<` `<=` `>` `>=`
7. `==` `!=`
8. `&`
9. `^`
10. `|`
11. `&&`
12. `||`
13. `?:`
14. `=` `+=` `-=` etc.
## Limitations
- No structs/unions (use arrays)
- No enums (use int32 constants)
- No floats (integers only)
- No preprocessor (#define, #include)
- Single file compilation only
- 1D arrays only (simulate 2D: `arr[row*width+col]`)
- No goto
- No static/extern keywords
- 64-bit types partially supported
## Common Gotchas
```c
// Assignment vs. Equality
if (x = 5) // WRONG: assigns 5 to x
if (x == 5) // RIGHT: compares x to 5
// Array indexing
int32 arr[10];
arr[10] = 0; // WRONG: out of bounds
arr[9] = 0; // RIGHT: last element
// Pointer arithmetic scales by type size
int32 *p = arr;
p + 1; // Points 4 bytes ahead (size of int32)
// Semicolons required
if (x > 0)
y = 1 // WRONG: missing semicolon
if (x > 0)
y = 1; // RIGHT
```
## Error Messages
```
line N: syntax error near 'token'
line N: Unknown char 'X'
line N: expected expression
line N: too many locals/globals/strings
```
Check:
- Missing semicolons
- Mismatched braces/parentheses
- Undeclared variables
- Type mismatches
- Buffer limits exceeded

349
README.md Normal file
View File

@@ -0,0 +1,349 @@
# Common Programming Language
A minimalist, dependency-free compiler for a C-like language that targets x86-32 assembly.
## Overview
Common is a statically-typed systems programming language with:
- **No runtime dependencies** - compiles to standalone executables
- **Direct C interoperability** - call and be called by C code
- **Predictable codegen** - straightforward mapping to assembly
- **Complete type system** - 8 integer types, pointers, arrays
- **Full control flow** - if/else, loops, switch, functions
- **Zero external dependencies** - just libc, gcc, and nasm
## Quick Start
### Build the Compiler
```bash
gcc -o common common.c
```
### Hello World
Create `hello.cm`:
```c
void puts(uint8 *s);
int32 main(void) {
puts("Hello, World!");
return 0;
}
```
Compile and run:
```bash
./common hello.cm hello.asm
nasm -f elf32 hello.asm -o hello.o
gcc -m32 hello.o -o hello
./hello
```
Or use the Makefile:
```bash
make # Build compiler and test suite
make test # Run all tests
make hello # Build hello example
make examples # Build all examples
make run-examples # Build and run all examples
```
## Documentation
### For Users
- **[Quick Reference](QUICKREF.md)** - One-page cheat sheet for syntax and operators
- **[Reference Manual](MANUAL.md)** - Complete language specification (80+ pages)
- **[Troubleshooting Guide](TROUBLESHOOTING.md)** - Solutions to common problems
### For Developers
- **[Test Suite README](README_TESTS.md)** - How to run and write tests
- **[Source Code](common.c)** - Well-commented compiler implementation
## Language Features
### Types
```c
// Integers
int8 int16 int32 int64 // Signed
uint8 uint16 uint32 uint64 // Unsigned
// Pointers and arrays
int32 *ptr; // Pointer
int32 arr[10]; // Array
uint8 *str = "text"; // String
```
### Control Flow
```c
if (x > 0) { ... }
while (x < 100) { ... }
for (int32 i = 0; i < n; i++) { ... }
switch (x) { case 1: ... break; }
```
### Operators
```c
// Arithmetic: + - * / %
// Comparison: == != < <= > >=
// Logical: && || !
// Bitwise: & | ^ ~ << >>
// Pointers: & *
// Increment: ++ --
```
### Functions
```c
int32 add(int32 a, int32 b) {
return a + b;
}
int32 factorial(int32 n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
```
## Example Programs
All examples are in the `examples/` directory:
| Program | Description |
|---------|-------------|
| **hello.cm** | Hello World |
| **fibonacci.cm** | Recursive Fibonacci |
| **arrays.cm** | Array operations |
| **pointers.cm** | Pointer manipulation |
| **bubblesort.cm** | Bubble sort algorithm |
| **bitwise.cm** | Bitwise operations |
| **types.cm** | Type casting examples |
| **switch.cm** | Switch statements |
| **primes.cm** | Prime number calculator |
| **strings.cm** | String functions |
| **calculator.cm** | Expression evaluator |
| **linkedlist.cm** | Linked list (simulated) |
Build any example:
```bash
make fibonacci && ./fibonacci
make bubblesort && ./bubblesort
```
## Test Suite
The test suite includes 60+ automated tests covering:
- Arithmetic and operators
- Variables and arrays
- Control flow
- Functions and recursion
- Pointers and type casting
- All integer types
Run tests:
```bash
make test
# or
./run_tests.sh
```
## Compilation Pipeline
```
source.cm → [common compiler] → output.asm → [nasm] → output.o → [gcc] → executable
```
1. **Common compiler**: Parses source, generates NASM assembly
2. **NASM**: Assembles to ELF32 object file
3. **GCC**: Links with C runtime library
## Requirements
- **GCC** with 32-bit support (gcc-multilib)
- **NASM** assembler
- **Linux** or compatible environment (WSL works)
Installation:
```bash
# Ubuntu/Debian
sudo apt-get install build-essential gcc-multilib nasm
# Fedora/RHEL
sudo dnf install gcc glibc-devel.i686 nasm
# Arch
sudo pacman -S gcc lib32-gcc-libs nasm
```
## Language Limitations
- **Single file compilation** - no modules or includes
- **No structs/unions** - use arrays for structured data
- **No floating point** - integers only
- **No preprocessor** - no #define, #include
- **1D arrays only** - simulate 2D with manual indexing
- **Partial 64-bit support** - types exist but ops truncate to 32-bit
See [MANUAL.md](MANUAL.md) for complete details and workarounds.
## Implementation Details
**Target**: x86-32 (IA-32) ELF
**Calling convention**: cdecl
**Stack alignment**: 16-byte (System V ABI)
**Registers**:
- `eax`: return values, expressions
- `ecx`: left operand
- `edx`: scratch
- `ebp`: frame pointer
- `esp`: stack pointer
**Code sections**:
- `.text`: executable code
- `.data`: initialized globals, strings
- `.bss`: zero-initialized globals
## Architecture
The compiler is a single-pass implementation in C99:
```
┌─────────────┐
│ Lexer │ Tokenize source
├─────────────┤
│ Parser │ Build AST
├─────────────┤
│ Type Check │ Infer expression types
├─────────────┤
│ Code Gen │ Emit NASM assembly
└─────────────┘
```
Key components:
- **Lexer** (150 LOC): Tokenization with lookahead
- **Parser** (400 LOC): Recursive descent parser
- **Type System** (200 LOC): Type inference for pointer arithmetic
- **Code Generator** (800 LOC): Assembly emission
Total: ~2000 lines of C99
## C Interoperability
Common can call C functions:
```c
// Declare C functions
void printf(uint8 *fmt, ...);
void *malloc(uint32 size);
void free(void *ptr);
int32 main(void) {
printf("Allocated %d bytes\n", 100);
void *mem = malloc(100);
free(mem);
return 0;
}
```
C can call Common functions:
```c
// common.cm
int32 compute(int32 x) {
return x * x;
}
// main.c
extern int compute(int);
int main() {
printf("%d\n", compute(10));
}
```
Compile:
```bash
./common common.cm common.asm
nasm -f elf32 common.asm -o common.o
gcc -m32 main.c common.o -o program
```
## Comparison to C
### Similar to C
- Syntax and semantics
- Type system (with fewer types)
- Pointer arithmetic
- Control flow
- Function calls (cdecl)
### Different from C
- No preprocessor
- No structs/unions
- No enums
- No static/extern keywords
- No goto
- Single file only
- Simpler type system
### Simpler than C
- No type qualifiers (const, volatile)
- No storage classes (auto, register)
- No function pointers (can cast to void*)
- No variadic function definitions
- No bitfields
- No flexible array members
## Project Structure
```
.
├── common.c # Compiler source (2000 LOC)
├── Makefile # Build automation
├── run_tests.sh # Quick test script
├── MANUAL.md # Complete language reference
├── QUICKREF.md # One-page cheat sheet
├── TROUBLESHOOTING.md # Problem solutions
├── README_TESTS.md # Test suite documentation
├── test_runner.c # Automated test harness
└── examples/ # Example programs
├── hello.cm
├── fibonacci.cm
├── arrays.cm
├── pointers.cm
├── bubblesort.cm
├── bitwise.cm
├── types.cm
├── switch.cm
├── primes.cm
├── strings.cm
├── calculator.cm
└── linkedlist.cm
```
## License
Public domain / CC0. Use freely for any purpose.
## Credits
Inspired by:
- **C** - Dennis Ritchie and Brian Kernighan
- **chibicc** - Rui Ueyama's educational C compiler
- **8cc** - Rui Ueyama's C compiler
- **tcc** - Fabrice Bellard's Tiny C Compiler
Built for programmers who value:
- Simplicity over features
- Control over convenience
- Learning over abstraction
---
Start with the [Quick Reference](QUICKREF.md) or dive into the [Manual](MANUAL.md).

286
README_TESTS.md Normal file
View File

@@ -0,0 +1,286 @@
# Common Compiler - Test Suite and Examples
This directory contains a comprehensive test suite and example programs for the Common programming language compiler.
## Building the Compiler
First, build the compiler:
```bash
gcc -o common common.c
```
## Test Suite
### Building and Running Tests
The test suite is a dependency-free C99 program that automatically compiles, assembles, links, and runs test programs.
```bash
# Build the test runner
gcc -std=c99 -o test_runner test_runner.c
# Run all tests
./test_runner
```
The test runner will:
1. Compile each test program with the Common compiler
2. Assemble with NASM
3. Link with GCC
4. Execute and verify the results
5. Report pass/fail status
### Test Coverage
The test suite includes over 60 tests covering:
- **Arithmetic**: add, subtract, multiply, divide, modulo
- **Variables**: local and global variables with initialization
- **Control Flow**: if/else, while, for, switch/case, break, continue
- **Operators**:
- Comparison: ==, !=, <, <=, >, >=
- Logical: &&, ||, !
- Bitwise: &, |, ^, ~, <<, >>
- Increment/Decrement: ++, --
- Compound Assignment: +=, -=, *=, /=, etc.
- **Functions**: calls, recursion, multiple parameters
- **Arrays**: declaration, initialization, indexing
- **Pointers**: address-of, dereference, pointer arithmetic
- **Type Casting**: explicit casts between integer types
- **Integer Types**: uint8, uint16, uint32, uint64, int8, int16, int32, int64
- **Ternary Operator**: ? :
## Example Programs
The `examples/` directory contains practical programs demonstrating Common language features.
### Compiling Examples
All examples follow this pattern:
```bash
./common examples/hello.cm hello.asm
nasm -f elf32 hello.asm -o hello.o
gcc -m32 hello.o -o hello
./hello
```
Or use this one-liner:
```bash
./common examples/hello.cm hello.asm && nasm -f elf32 hello.asm && gcc -m32 hello.o -o hello && ./hello
```
### Available Examples
#### hello.cm
Basic "Hello, World!" program.
```bash
./common examples/hello.cm hello.asm && nasm -f elf32 hello.asm && gcc -m32 hello.o -o hello
./hello
```
#### fibonacci.cm
Recursive Fibonacci number calculator. Demonstrates:
- Function recursion
- Conditionals
- Loops
```bash
./common examples/fibonacci.cm fib.asm && nasm -f elf32 fib.asm && gcc -m32 fib.o -o fib
./fib
```
#### arrays.cm
Array manipulation with sum and reverse operations. Demonstrates:
- Array initialization
- Array traversal
- Function parameters with arrays
- Array modification
```bash
./common examples/arrays.cm arrays.asm && nasm -f elf32 arrays.asm && gcc -m32 arrays.o -o arrays
./arrays
```
#### pointers.cm
Pointer operations and pointer arithmetic. Demonstrates:
- Pointer declaration and dereferencing
- Address-of operator
- Pointer arithmetic
- Pointer to pointer
- Pass-by-reference with pointers
```bash
./common examples/pointers.cm ptrs.asm && nasm -f elf32 ptrs.asm && gcc -m32 ptrs.o -o ptrs
./ptrs
```
#### bubblesort.cm
Bubble sort implementation. Demonstrates:
- Nested loops
- Array sorting
- Swap algorithm
```bash
./common examples/bubblesort.cm sort.asm && nasm -f elf32 sort.asm && gcc -m32 sort.o -o sort
./sort
```
#### bitwise.cm
Comprehensive bitwise operations. Demonstrates:
- Bitwise AND, OR, XOR, NOT
- Bit shifts
- Bit counting
- Bit manipulation algorithms
```bash
./common examples/bitwise.cm bits.asm && nasm -f elf32 bits.asm && gcc -m32 bits.o -o bits
./bits
```
#### types.cm
Different integer types and type casting. Demonstrates:
- uint8, uint16, uint32
- int8, int16, int32
- Type casting
- Sign extension
- Truncation behavior
```bash
./common examples/types.cm types.asm && nasm -f elf32 types.asm && gcc -m32 types.o -o types
./types
```
#### switch.cm
Switch/case statement usage. Demonstrates:
- Switch statements
- Case labels
- Default case
- Fall-through behavior
```bash
./common examples/switch.cm switch.asm && nasm -f elf32 switch.asm && gcc -m32 switch.o -o switch
./switch
```
#### primes.cm
Prime number calculator. Demonstrates:
- Mathematical algorithms
- Optimized loop conditions
- Complex conditionals
```bash
./common examples/primes.cm primes.asm && nasm -f elf32 primes.asm && gcc -m32 primes.o -o primes
./primes
```
#### strings.cm
String manipulation functions. Demonstrates:
- String literals
- Character arrays
- String length, copy, compare
- String reversal
```bash
./common examples/strings.cm strings.asm && nasm -f elf32 strings.asm && gcc -m32 strings.o -o strings
./strings
```
#### calculator.cm
Expression calculator with global state. Demonstrates:
- Global variables
- Multiple function definitions
- Function composition
- Error handling
- State tracking
```bash
./common examples/calculator.cm calc.asm && nasm -f elf32 calc.asm && gcc -m32 calc.o -o calc
./calc
```
## Common Language Quick Reference
### Types
```c
uint8, uint16, uint32, uint64
int8, int16, int32, int64
void
```
### Variables
```c
int32 x; // Declaration
int32 y = 42; // Declaration with initialization
int32 arr[10]; // Array declaration
int32 *ptr; // Pointer declaration
```
### Control Flow
```c
if (condition) { ... }
if (condition) { ... } else { ... }
while (condition) { ... }
for (init; condition; increment) { ... }
switch (expr) {
case value: ... break;
default: ...
}
```
### Operators
```c
// Arithmetic: +, -, *, /, %
// Comparison: ==, !=, <, <=, >, >=
// Logical: &&, ||, !
// Bitwise: &, |, ^, ~, <<, >>
// Assignment: =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=
// Increment/Decrement: ++, --
// Ternary: ? :
// Address: &, *
```
### Functions
```c
int32 function_name(int32 param1, uint8 *param2) {
return value;
}
```
### Comments
```c
// Single line comment
/* Multi-line
comment */
```
## Requirements
- GCC with 32-bit support (gcc-multilib)
- NASM assembler
- Linux (or compatible environment)
On Ubuntu/Debian:
```bash
sudo apt-get install gcc-multilib nasm
```
## Troubleshooting
**Error: "cannot find -lgcc_s"**
- Install 32-bit libraries: `sudo apt-get install gcc-multilib`
**Error: "nasm: command not found"**
- Install NASM: `sudo apt-get install nasm`
**Test failures**
- Ensure the compiler binary is in the current directory: `./common`
- Check that you have write access to `/tmp/`
- Verify 32-bit support is installed
## License
The test suite and examples are provided as-is for testing and demonstration purposes.

623
TROUBLESHOOTING.md Normal file
View File

@@ -0,0 +1,623 @@
# Common Compiler Troubleshooting Guide
## Installation Issues
### Problem: "gcc: command not found"
**Solution**: Install GCC
```bash
# Ubuntu/Debian
sudo apt-get install build-essential
# Fedora/RHEL
sudo dnf install gcc
# Arch
sudo pacman -S gcc
```
### Problem: "nasm: command not found"
**Solution**: Install NASM assembler
```bash
# Ubuntu/Debian
sudo apt-get install nasm
# Fedora/RHEL
sudo dnf install nasm
# Arch
sudo pacman -S nasm
```
### Problem: "fatal error: bits/libc-header-start.h: No such file"
**Cause**: Missing 32-bit development libraries
**Solution**: Install 32-bit support
```bash
# Ubuntu/Debian
sudo apt-get install gcc-multilib
# Fedora/RHEL
sudo dnf install glibc-devel.i686 libgcc.i686
```
---
## Compilation Issues
### Problem: Compiler fails to build
**Error**:
```
gcc -o common common.c
common.c:15:10: fatal error: stdio.h: No such file or directory
```
**Solution**: Install build essentials
```bash
sudo apt-get install build-essential
```
### Problem: "Permission denied" when running compiler
**Solution**: Make compiler executable
```bash
chmod +x ./common
```
Or run directly:
```bash
gcc -o common common.c
./common source.cm output.asm
```
---
## Assembly Issues
### Problem: "error: invalid combination of opcode and operands"
**Cause**: NASM version incompatibility or corrupt assembly output
**Debug Steps**:
1. Check assembly output:
```bash
./common source.cm output.asm
cat output.asm
```
2. Verify NASM version:
```bash
nasm -version # Should be 2.x or higher
```
3. Try manual assembly:
```bash
nasm -f elf32 output.asm -o output.o
```
### Problem: "undefined reference to function_name"
**Cause**: Function called but not defined or linked
**Solutions**:
1. **Missing function definition**:
```c
// Declare AND define the function
int32 helper(int32 x) {
return x * 2;
}
```
2. **C library function not linked**:
```bash
# Make sure you're linking with gcc
gcc -m32 output.o -o program
# NOT: ld output.o -o program
```
3. **External library needed**:
```bash
gcc -m32 output.o -lm -o program # Link math library
```
---
## Linker Issues
### Problem: "cannot find -lgcc_s"
**Cause**: Missing 32-bit GCC support libraries
**Solution**:
```bash
sudo apt-get install gcc-multilib
```
### Problem: "/usr/bin/ld: i386 architecture of input file is incompatible with i386:x86-64"
**Cause**: Mixing 32-bit and 64-bit object files
**Solution**: Ensure consistent 32-bit compilation:
```bash
nasm -f elf32 output.asm -o output.o # Must be elf32
gcc -m32 output.o -o program # Must use -m32
```
### Problem: "undefined reference to main"
**Cause**: No main function in source
**Solution**: Add main function:
```c
int32 main(void) {
// Your code here
return 0;
}
```
---
## Runtime Issues
### Problem: Segmentation fault
**Common Causes**:
1. **Null pointer dereference**:
```c
int32 *ptr = 0;
*ptr = 42; // CRASH: dereferencing NULL
```
**Fix**: Check pointers before dereferencing
```c
if (ptr != 0) {
*ptr = 42;
}
```
2. **Array out of bounds**:
```c
int32 arr[10];
arr[10] = 5; // CRASH: index 10 is out of bounds (0-9)
```
**Fix**: Check array bounds
```c
if (index < 10) {
arr[index] = 5;
}
```
3. **Stack overflow (infinite recursion)**:
```c
int32 recurse(int32 n) {
return recurse(n); // CRASH: no base case
}
```
**Fix**: Add base case
```c
int32 recurse(int32 n) {
if (n <= 0) return 0;
return recurse(n - 1);
}
```
4. **Writing to read-only memory**:
```c
uint8 *str = "constant";
str[0] = 'C'; // CRASH: string literals are read-only
```
**Fix**: Use array for modifiable strings
```c
uint8 str[20];
str[0] = 'C'; // OK
```
### Problem: Wrong output values
**Debug Steps**:
1. **Check integer overflow**:
```c
int8 x = 127;
x = x + 1; // Wraps to -128
```
2. **Check division by zero**:
```c
int32 result = 10 / 0; // Undefined behavior
```
**Fix**:
```c
if (divisor != 0) {
result = dividend / divisor;
}
```
3. **Check type truncation**:
```c
int32 large = 1000;
uint8 small = (uint8)large; // Truncated to 232 (1000 % 256)
```
### Problem: Program hangs / infinite loop
**Common Causes**:
1. **Loop condition never false**:
```c
uint32 i = 10;
while (i >= 0) { // INFINITE: unsigned i never < 0
i = i - 1;
}
```
**Fix**:
```c
int32 i = 10;
while (i >= 0) {
i = i - 1;
}
```
2. **Missing loop increment**:
```c
for (int32 i = 0; i < 10; ) { // Missing i++
// ...
}
```
---
## Compiler Error Messages
### "line N: syntax error near 'token'"
**Causes**:
- Missing semicolon
- Mismatched braces/parentheses
- Invalid expression syntax
**Debug**:
1. Check line N and surrounding lines
2. Look for missing `;` on previous line
3. Count braces: `{` should match `}`
4. Check operator usage
**Example**:
```c
int32 x = 10 // ERROR: missing semicolon
int32 y = 20;
```
### "line N: Unknown char 'X'"
**Cause**: Invalid character in source
**Common Examples**:
- Smart quotes: `"` `"` instead of `"`
- Non-ASCII characters
- Tab characters in wrong places
**Fix**: Use plain ASCII text editor
### "line N: expected expression"
**Cause**: Invalid or incomplete expression
**Example**:
```c
int32 x = ; // ERROR: no expression after =
int32 y = + 5; // ERROR: + needs left operand
```
### "too many locals"
**Cause**: More than 256 local variables in a function
**Solution**:
1. Reduce number of variables
2. Use arrays instead of individual variables
3. Split into multiple functions
### "too many strings"
**Cause**: More than 512 string literals in program
**Solution**:
1. Reuse string literals
2. Build strings programmatically
3. Use character arrays
---
## Debugging Techniques
### Print Debugging
```c
void printf(uint8 *fmt, ...);
int32 main(void) {
int32 x = 10;
printf("x = %d\n", x); // Print values
int32 *ptr = &x;
printf("ptr = %p, *ptr = %d\n", ptr, *ptr); // Print pointers
return 0;
}
```
### Check Assembly Output
```bash
./common source.cm output.asm
less output.asm # Review generated assembly
```
Look for:
- Correct function labels
- Proper stack setup
- Expected instructions
### Use GDB
```bash
# Compile with debug info
gcc -m32 -g output.o -o program
# Run in debugger
gdb ./program
# GDB commands:
(gdb) break main # Set breakpoint at main
(gdb) run # Run program
(gdb) next # Step to next line
(gdb) print x # Print variable x
(gdb) backtrace # Show call stack
(gdb) quit # Exit gdb
```
### Valgrind (Memory Errors)
```bash
# Install valgrind
sudo apt-get install valgrind
# Run with valgrind
valgrind --leak-check=full ./program
```
---
## Common Mistakes
### 1. Assignment in Condition
**Wrong**:
```c
if (x = 5) { // Assigns 5 to x, always true
// ...
}
```
**Right**:
```c
if (x == 5) { // Compares x to 5
// ...
}
```
### 2. Infinite Loop with Unsigned
**Wrong**:
```c
for (uint32 i = 10; i >= 0; i--) { // Infinite: unsigned never < 0
// ...
}
```
**Right**:
```c
for (int32 i = 10; i >= 0; i--) {
// ...
}
```
### 3. Pointer vs. Value
**Wrong**:
```c
void increment(int32 x) {
x = x + 1; // Only modifies local copy
}
int32 val = 5;
increment(val);
// val is still 5
```
**Right**:
```c
void increment(int32 *x) {
*x = *x + 1; // Modifies through pointer
}
int32 val = 5;
increment(&val);
// val is now 6
```
### 4. Array Decay
**Confusing**:
```c
int32 arr[10];
int32 *ptr = arr; // arr decays to pointer
// arr and &arr are different:
arr // Pointer to first element (type: int32*)
&arr // Pointer to entire array (type: int32(*)[10])
```
### 5. String Modification
**Wrong**:
```c
uint8 *str = "Hello";
str[0] = 'h'; // CRASH: string literal is read-only
```
**Right**:
```c
uint8 str[20] = "Hello"; // Array, modifiable
str[0] = 'h'; // OK
```
---
## Performance Issues
### Slow Compilation
**Causes**:
- Very large source file
- Many string literals
**Solutions**:
- None (no optimization flags)
- Split code into modules (not supported in single-file compiler)
### Slow Execution
**Common Causes**:
1. **Inefficient algorithms**:
```c
// O(n²) - slow
for (int32 i = 0; i < n; i++)
for (int32 j = 0; j < n; j++)
// ...
```
2. **Excessive function calls**:
```c
// Fibonacci - exponential time
int32 fib(int32 n) {
if (n <= 1) return n;
return fib(n-1) + fib(n-2); // Recomputes same values
}
```
**Fix**: Use iterative version or memoization
3. **No optimizations**: The compiler doesn't optimize. Write efficient code.
---
## Getting Help
### Information to Provide
When asking for help, include:
1. **Source code** (minimal example that reproduces issue)
2. **Compilation command** used
3. **Full error message** (copy-paste, not screenshot)
4. **System information**:
```bash
uname -a
gcc --version
nasm -version
```
### Minimal Example
Reduce your code to the smallest program that shows the problem:
```c
// Minimal example showing segfault
int32 main(void) {
int32 *ptr = 0;
*ptr = 42; // Crash here
return 0;
}
```
### Check Examples First
Before reporting a bug, verify the example programs work:
```bash
make test
make examples
```
If examples work but your code doesn't, the issue is likely in your code, not the compiler.
---
## Known Issues
### 64-bit Types
**Issue**: 64-bit arithmetic truncates to 32 bits
```c
uint64 x = 5000000000; // Stored as 64-bit
uint64 y = x * 2; // Multiplied as 32-bit, overflow
```
**Workaround**: Use 32-bit types or implement 64-bit arithmetic manually
### Single File Limitation
**Issue**: Cannot split code across multiple files
**Workaround**: Put all code in one file, use forward declarations
### No Preprocessor
**Issue**: No `#define`, `#include`, etc.
**Workaround**:
- Use const variables instead of #define
- Copy/paste shared code
- Write wrapper script to concatenate files
---
## Environment-Specific Issues
### WSL (Windows Subsystem for Linux)
Usually works fine. If issues:
```bash
sudo apt update
sudo apt install gcc-multilib nasm
```
### macOS
**Problem**: macOS doesn't support Linux ELF32
**Solution**: Use a Linux VM or Docker container
### 64-bit Only Systems
**Problem**: No 32-bit support installed
**Solution**: Install multilib packages (see Installation Issues above)
---
*For more help, see the full manual (MANUAL.md) or examples (examples/)*

1433
common.c Normal file

File diff suppressed because it is too large Load Diff

48
examples/arrays.cm Normal file
View File

@@ -0,0 +1,48 @@
// Public domain / CC0. Use freely for any purpose. RoyR 2026
// arrays.cm - Array operations
// Demonstrates: arrays, loops, array initialization
void printf(uint8 *fmt);
int32 sum_array(int32 *arr, int32 len) {
int32 total = 0;
for (int32 i = 0; i < len; i = i + 1) {
total = total + arr[i];
}
return total;
}
void reverse_array(int32 *arr, int32 len) {
int32 i = 0;
int32 j = len - 1;
while (i < j) {
int32 temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i = i + 1;
j = j - 1;
}
}
int32 main(void) {
int32 numbers[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
printf("Original array: ");
for (int32 i = 0; i < 10; i = i + 1) {
printf("%d ", numbers[i]);
}
printf("\n");
int32 total = sum_array(numbers, 10);
printf("Sum: %d\n", total);
reverse_array(numbers, 10);
printf("Reversed array: ");
for (int32 i = 0; i < 10; i = i + 1) {
printf("%d ", numbers[i]);
}
printf("\n");
return 0;
}

60
examples/bitwise.cm Normal file
View File

@@ -0,0 +1,60 @@
// Public domain / CC0. Use freely for any purpose. RoyR 2026
// bitwise.cm - Bitwise operations
// Demonstrates: bitwise operators, bit manipulation, shifts
void printf(uint8 *fmt);
void print_binary(uint32 n) {
printf("0b");
for (int32 i = 31; i >= 0; i = i - 1) {
printf("%d", (n >> i) & 1);
if (i % 4 == 0 && i != 0) printf("_");
}
}
int32 count_set_bits(uint32 n) {
int32 count = 0;
while (n) {
count = count + (n & 1);
n = n >> 1;
}
return count;
}
uint32 reverse_bits(uint32 n) {
uint32 result = 0;
for (int32 i = 0; i < 32; i = i + 1) {
result = result << 1;
result = result | (n & 1);
n = n >> 1;
}
return result;
}
int32 is_power_of_two(uint32 n) {
return n && ((n & (n - 1)) == 0);
}
int32 main(void) {
uint32 a = 0xAB;
uint32 b = 0x55;
printf("a = %d = ", a); print_binary(a); printf("\n");
printf("b = %d = ", b); print_binary(b); printf("\n");
printf("\nBitwise AND: %d = ", a & b); print_binary(a & b); printf("\n");
printf("Bitwise OR: %d = ", a | b); print_binary(a | b); printf("\n");
printf("Bitwise XOR: %d = ", a ^ b); print_binary(a ^ b); printf("\n");
printf("Bitwise NOT: %d = ", ~a); print_binary(~a); printf("\n");
printf("\nLeft shift (a << 2): %d\n", a << 2);
printf("Right shift (a >> 2): %d\n", a >> 2);
printf("\nSet bits in a: %d\n", count_set_bits(a));
printf("Set bits in b: %d\n", count_set_bits(b));
printf("\nIs 64 power of two? %d\n", is_power_of_two(64));
printf("Is 63 power of two? %d\n", is_power_of_two(63));
return 0;
}

40
examples/bubblesort.cm Normal file
View File

@@ -0,0 +1,40 @@
// Public domain / CC0. Use freely for any purpose. RoyR 2026
// bubblesort.cm - Bubble sort implementation
// Demonstrates: nested loops, array manipulation, comparisons
void printf(uint8 *fmt);
void bubble_sort(int32 *arr, int32 n) {
for (int32 i = 0; i < n - 1; i = i + 1) {
for (int32 j = 0; j < n - i - 1; j = j + 1) {
if (arr[j] > arr[j + 1]) {
// Swap
int32 temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
void print_array(int32 *arr, int32 n) {
for (int32 i = 0; i < n; i = i + 1) {
printf("%d ", arr[i]);
}
printf("\n");
}
int32 main(void) {
int32 numbers[10] = { 64, 34, 25, 12, 22, 11, 90, 88, 45, 50 };
int32 n = 10;
printf("Unsorted array: ");
print_array(numbers, n);
bubble_sort(numbers, n);
printf("Sorted array: ");
print_array(numbers, n);
return 0;
}

101
examples/calculator.cm Normal file
View File

@@ -0,0 +1,101 @@
// Public domain / CC0. Use freely for any purpose. RoyR 2026
// calculator.cm - Simple expression calculator
// Demonstrates: global variables, function composition, control flow
void printf(uint8 *fmt);
// Global state for the calculator
int32 last_result = 0;
int32 operation_count = 0;
int32 add(int32 a, int32 b) {
operation_count = operation_count + 1;
last_result = a + b;
return last_result;
}
int32 subtract(int32 a, int32 b) {
operation_count = operation_count + 1;
last_result = a - b;
return last_result;
}
int32 multiply(int32 a, int32 b) {
operation_count = operation_count + 1;
last_result = a * b;
return last_result;
}
int32 divide(int32 a, int32 b) {
if (b == 0) {
printf("Error: Division by zero\n");
return 0;
}
operation_count = operation_count + 1;
last_result = a / b;
return last_result;
}
int32 power(int32 base, int32 exp) {
operation_count = operation_count + 1;
int32 result = 1;
for (int32 i = 0; i < exp; i = i + 1) {
result = result * base;
}
last_result = result;
return result;
}
int32 factorial(int32 n) {
operation_count = operation_count + 1;
if (n <= 1) {
last_result = 1;
return 1;
}
int32 result = 1;
for (int32 i = 2; i <= n; i = i + 1) {
result = result * i;
}
last_result = result;
return result;
}
void print_stats(void) {
printf("\n=== Calculator Statistics ===\n");
printf("Total operations: %d\n", operation_count);
printf("Last result: %d\n", last_result);
printf("============================\n");
}
int32 main(void) {
printf("Calculator Demo\n");
printf("===============\n\n");
// Basic arithmetic
printf("10 + 5 = %d\n", add(10, 5));
printf("10 - 5 = %d\n", subtract(10, 5));
printf("10 * 5 = %d\n", multiply(10, 5));
printf("10 / 5 = %d\n", divide(10, 5));
// Power function
printf("\n2^10 = %d\n", power(2, 10));
printf("5^3 = %d\n", power(5, 3));
// Factorial
printf("\n5! = %d\n", factorial(5));
printf("10! = %d\n", factorial(10));
// Complex expression: (5 + 3) * (10 - 2)
int32 a = add(5, 3);
int32 b = subtract(10, 2);
int32 result = multiply(a, b);
printf("\n(5 + 3) * (10 - 2) = %d\n", result);
// Division by zero test
printf("\nTesting division by zero:\n");
divide(10, 0);
print_stats();
return 0;
}

23
examples/fibonacci.cm Normal file
View File

@@ -0,0 +1,23 @@
// Public domain / CC0. Use freely for any purpose. RoyR 2026
// fibonacci.cm - Calculate Fibonacci numbers
// Demonstrates: recursion, function calls, conditionals
void printf(uint8 *fmt);
int32 fibonacci(int32 n) {
if (n <= 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
int32 main(void) {
printf("Fibonacci sequence:\n");
for (int32 i = 0; i < 15; i = i + 1) {
int32 fib = fibonacci(i);
printf("fib(%d) = %d\n", i, fib);
}
return 0;
}

11
examples/hello.cm Normal file
View File

@@ -0,0 +1,11 @@
// Public domain / CC0. Use freely for any purpose. RoyR 2026
// hello.cm - Hello World program
// Compile: ./common hello.cm hello.asm && nasm -f elf32 hello.asm && gcc -m32 hello.o -o hello
void putchar(int32 c);
void puts(uint8 *s);
int32 main(void) {
puts("Hello, World!");
return 0;
}

159
examples/linkedlist.cm Normal file
View File

@@ -0,0 +1,159 @@
// Public domain / CC0. Use freely for any purpose. RoyR 2026
// linkedlist.cm - Linked list implementation
// Demonstrates: structs simulated with arrays, complex pointer manipulation, memory layout
void printf(uint8 *fmt);
void *malloc(uint32 size);
void free(void *ptr);
// Node structure simulated as:
// [0] = data (int32)
// [4] = next pointer (int32*)
// Total size: 8 bytes per node
int32 *create_node(int32 value) {
int32 *node = (int32*)malloc(8);
node[0] = value; // data
node[1] = 0; // next = NULL
return node;
}
void insert_front(int32 **head, int32 value) {
int32 *new_node = create_node(value);
new_node[1] = (int32)(*head); // new->next = head
*head = new_node; // head = new_node
}
void insert_back(int32 **head, int32 value) {
int32 *new_node = create_node(value);
if (*head == 0) {
*head = new_node;
return;
}
int32 *current = *head;
while (current[1] != 0) {
current = (int32*)current[1];
}
current[1] = (int32)new_node;
}
int32 list_length(int32 *head) {
int32 count = 0;
int32 *current = head;
while (current != 0) {
count = count + 1;
current = (int32*)current[1];
}
return count;
}
void print_list(int32 *head) {
int32 *current = head;
printf("[");
while (current != 0) {
printf("%d", current[0]);
current = (int32*)current[1];
if (current != 0) printf(", ");
}
printf("]\n");
}
int32 find_value(int32 *head, int32 value) {
int32 *current = head;
int32 index = 0;
while (current != 0) {
if (current[0] == value) {
return index;
}
current = (int32*)current[1];
index = index + 1;
}
return -1;
}
void delete_value(int32 **head, int32 value) {
if (*head == 0) return;
// Check if head node contains the value
if ((*head)[0] == value) {
int32 *temp = *head;
*head = (int32*)(*head)[1];
free(temp);
return;
}
// Search for the value in remaining nodes
int32 *current = *head;
while (current[1] != 0) {
int32 *next = (int32*)current[1];
if (next[0] == value) {
current[1] = next[1]; // current->next = next->next
free(next);
return;
}
current = next;
}
}
void free_list(int32 *head) {
int32 *current = head;
while (current != 0) {
int32 *next = (int32*)current[1];
free(current);
current = next;
}
}
int32 main(void) {
int32 *list = 0; // Empty list (NULL)
printf("Linked List Demo\n");
printf("================\n\n");
printf("Inserting at front: 3, 2, 1\n");
insert_front(&list, 3);
insert_front(&list, 2);
insert_front(&list, 1);
print_list(list);
printf("\nInserting at back: 4, 5, 6\n");
insert_back(&list, 4);
insert_back(&list, 5);
insert_back(&list, 6);
print_list(list);
printf("\nList length: %d\n", list_length(list));
printf("\nSearching for values:\n");
int32 search_vals[4] = { 1, 4, 7, 5 };
for (int32 i = 0; i < 4; i = i + 1) {
int32 val = search_vals[i];
int32 pos = find_value(list, val);
if (pos >= 0) {
printf(" %d found at position %d\n", val, pos);
} else {
printf(" %d not found\n", val);
}
}
printf("\nDeleting value 3\n");
delete_value(&list, 3);
print_list(list);
printf("\nDeleting value 1 (head)\n");
delete_value(&list, 1);
print_list(list);
printf("\nDeleting value 6 (tail)\n");
delete_value(&list, 6);
print_list(list);
printf("\nFinal list length: %d\n", list_length(list));
free_list(list);
printf("\nList freed\n");
return 0;
}

38
examples/pointers.cm Normal file
View File

@@ -0,0 +1,38 @@
// Public domain / CC0. Use freely for any purpose. RoyR 2026
// pointers.cm - Pointer operations
// Demonstrates: pointers, pointer arithmetic, dereferencing
void printf(uint8 *fmt);
void swap(int32 *a, int32 *b) {
int32 temp = *a;
*a = *b;
*b = temp;
}
int32 main(void) {
int32 x = 42;
int32 y = 17;
printf("Before swap: x=%d, y=%d\n", x, y);
swap(&x, &y);
printf("After swap: x=%d, y=%d\n", x, y);
// Pointer arithmetic with arrays
int32 arr[5] = { 10, 20, 30, 40, 50 };
int32 *ptr = arr;
printf("\nArray traversal with pointer arithmetic:\n");
for (int32 i = 0; i < 5; i = i + 1) {
printf("arr[%d] = %d (via pointer: %d)\n", i, arr[i], *(ptr + i));
}
// Pointer to pointer
int32 value = 99;
int32 *p1 = &value;
int32 **p2 = &p1;
printf("\nPointer to pointer: **p2 = %d\n", **p2);
return 0;
}

68
examples/primes.cm Normal file
View File

@@ -0,0 +1,68 @@
// Public domain / CC0. Use freely for any purpose. RoyR 2026
// primes.cm - Prime number calculator
// Demonstrates: algorithms, loops, mathematical operations
void printf(uint8 *fmt);
int32 is_prime(int32 n) {
if (n <= 1) return 0;
if (n <= 3) return 1;
if (n % 2 == 0 || n % 3 == 0) return 0;
int32 i = 5;
while (i * i <= n) {
if (n % i == 0 || n % (i + 2) == 0) {
return 0;
}
i = i + 6;
}
return 1;
}
int32 nth_prime(int32 n) {
if (n == 1) return 2;
int32 count = 1;
int32 candidate = 3;
while (count < n) {
if (is_prime(candidate)) {
count = count + 1;
}
candidate = candidate + 2;
}
return candidate - 2;
}
int32 count_primes_under(int32 limit) {
int32 count = 0;
for (int32 i = 2; i < limit; i = i + 1) {
if (is_prime(i)) {
count = count + 1;
}
}
return count;
}
int32 main(void) {
printf("First 20 prime numbers:\n");
for (int32 i = 1; i <= 20; i = i + 1) {
printf("%d ", nth_prime(i));
if (i % 10 == 0) printf("\n");
}
printf("\n");
int32 limit = 100;
int32 count = count_primes_under(limit);
printf("\nThere are %d primes less than %d\n", count, limit);
printf("\nPrime check:\n");
int32 test_nums[8] = { 1, 2, 15, 17, 97, 100, 101, 121 };
for (int32 i = 0; i < 8; i = i + 1) {
int32 num = test_nums[i];
printf(" %d is %s\n", num, is_prime(num) ? "prime" : "not prime");
}
return 0;
}

70
examples/strings.cm Normal file
View File

@@ -0,0 +1,70 @@
// Public domain / CC0. Use freely for any purpose. RoyR 2026
// strings.cm - String manipulation
// Demonstrates: string literals, character arrays, string functions
void printf(uint8 *fmt);
int32 str_len(uint8 *s) {
int32 len = 0;
while (s[len]) {
len = len + 1;
}
return len;
}
void str_copy(uint8 *dest, uint8 *src) {
int32 i = 0;
while (src[i]) {
dest[i] = src[i];
i = i + 1;
}
dest[i] = 0;
}
int32 str_cmp(uint8 *s1, uint8 *s2) {
int32 i = 0;
while (s1[i] && s2[i]) {
if (s1[i] != s2[i]) {
return s1[i] - s2[i];
}
i = i + 1;
}
return s1[i] - s2[i];
}
void str_reverse(uint8 *s) {
int32 len = str_len(s);
int32 i = 0;
int32 j = len - 1;
while (i < j) {
uint8 temp = s[i];
s[i] = s[j];
s[j] = temp;
i = i + 1;
j = j - 1;
}
}
int32 main(void) {
uint8 *msg = "Hello, World!";
printf("Original string: %s\n", msg);
printf("Length: %d\n", str_len(msg));
uint8 buffer[100];
str_copy(buffer, msg);
printf("Copied string: %s\n", buffer);
str_reverse(buffer);
printf("Reversed: %s\n", buffer);
uint8 *s1 = "apple";
uint8 *s2 = "banana";
uint8 *s3 = "apple";
printf("\nString comparison:\n");
printf(" '%s' vs '%s': %d\n", s1, s2, str_cmp(s1, s2));
printf(" '%s' vs '%s': %d\n", s1, s3, str_cmp(s1, s3));
printf(" '%s' vs '%s': %d\n", s2, s1, str_cmp(s2, s1));
return 0;
}

65
examples/switch.cm Normal file
View File

@@ -0,0 +1,65 @@
// Public domain / CC0. Use freely for any purpose. RoyR 2026
// switch.cm - Switch statement demonstration
// Demonstrates: switch/case, default, break, fall-through
void printf(uint8 *fmt);
uint8 *get_day_name(int32 day) {
switch (day) {
case 0: return "Sunday";
case 1: return "Monday";
case 2: return "Tuesday";
case 3: return "Wednesday";
case 4: return "Thursday";
case 5: return "Friday";
case 6: return "Saturday";
default: return "Invalid day";
}
}
int32 is_weekend(int32 day) {
switch (day) {
case 0:
case 6:
return 1;
default:
return 0;
}
}
uint8 *get_grade(int32 score) {
int32 category = score / 10;
switch (category) {
case 10:
case 9:
return "A";
case 8:
return "B";
case 7:
return "C";
case 6:
return "D";
default:
return "F";
}
}
int32 main(void) {
printf("Days of the week:\n");
for (int32 i = 0; i < 8; i = i + 1) {
printf(" Day %d: %s", i, get_day_name(i));
if (is_weekend(i)) {
printf(" (weekend!)");
}
printf("\n");
}
printf("\nGrade calculator:\n");
int32 scores[6] = { 95, 87, 76, 65, 54, 100 };
for (int32 i = 0; i < 6; i = i + 1) {
printf(" Score %d: Grade %s\n", scores[i], get_grade(scores[i]));
}
return 0;
}

50
examples/types.cm Normal file
View File

@@ -0,0 +1,50 @@
// Public domain / CC0. Use freely for any purpose. RoyR 2026
// types.cm - Type casting and different integer sizes
// Demonstrates: different integer types, casting, overflow behavior
void printf(uint8 *fmt);
int32 main(void) {
// Different integer sizes
uint8 byte_val = 255;
uint16 word_val = 65535;
uint32 dword_val = 4294967295;
int8 sbyte_val = -128;
int16 sword_val = -32768;
int32 sdword_val = -2147483648;
printf("Unsigned types:\n");
printf(" uint8: %d\n", byte_val);
printf(" uint16: %d\n", word_val);
printf(" uint32: %u\n", dword_val);
printf("\nSigned types:\n");
printf(" int8: %d\n", sbyte_val);
printf(" int16: %d\n", sword_val);
printf(" int32: %d\n", sdword_val);
// Type casting
printf("\nType casting:\n");
int32 large = 1000;
uint8 small = (uint8)large;
printf(" (uint8)1000 = %d (truncated to 8 bits)\n", small);
int32 value = 298;
uint8 truncated = (uint8)value;
printf(" (uint8)298 = %d (298 %% 256 = 42)\n", truncated);
// Sign extension
int8 neg = -1;
int32 extended = neg;
printf("\nSign extension:\n");
printf(" int8(-1) extended to int32: %d\n", extended);
// Unsigned to signed
uint8 unsigned_val = 200;
int8 signed_val = (int8)unsigned_val;
printf("\nUnsigned to signed:\n");
printf(" (int8)200 = %d (interpreted as signed)\n", signed_val);
return 0;
}

18
run_tests.sh Normal file
View File

@@ -0,0 +1,18 @@
#!/bin/bash
# Public domain / CC0. Use freely for any purpose. RoyR 2026
# run_tests.sh - Quick test runner script
set -e
echo "Building Common compiler..."
gcc -o common common.c
echo "Building test runner..."
gcc -std=c99 -o test_runner test_runner.c
echo ""
echo "Running tests..."
echo "================"
./test_runner
exit $?

619
test_runner.c Normal file
View File

@@ -0,0 +1,619 @@
/*
* Public domain / CC0. Use freely for any purpose. RoyR 2026
* test_runner.c - Test harness for Common compiler
*
* Build: gcc -std=c99 -o test_runner test_runner.c
* Usage: ./test_runner
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
typedef struct {
const char *name;
const char *source;
int expected_exit;
const char *expected_output;
} Test;
static int test_count = 0;
static int test_passed = 0;
static int test_failed = 0;
static int run_command(const char *cmd) {
int status = system(cmd);
if (WIFEXITED(status)) {
return WEXITSTATUS(status);
}
return -1;
}
static char *read_file(const char *path) {
FILE *f = fopen(path, "r");
if (!f) return NULL;
fseek(f, 0, SEEK_END);
long sz = ftell(f);
rewind(f);
char *buf = malloc(sz + 1);
fread(buf, 1, sz, f);
buf[sz] = 0;
fclose(f);
return buf;
}
static void run_test(Test *t) {
char cmd[1024];
test_count++;
printf("Test %d: %s ... ", test_count, t->name);
fflush(stdout);
/* Write source file */
FILE *f = fopen("/tmp/test.cm", "w");
if (!f) { printf("FAIL (cannot write source)\n"); test_failed++; return; }
fprintf(f, "%s", t->source);
fclose(f);
/* Compile */
if (run_command("./common /tmp/test.cm /tmp/test.asm 2>/tmp/test.err") != 0) {
printf("FAIL (compiler error)\n");
test_failed++;
return;
}
/* Assemble */
if (run_command("nasm -f elf32 /tmp/test.asm -o /tmp/test.o 2>/tmp/test.err") != 0) {
printf("FAIL (assembler error)\n");
test_failed++;
return;
}
/* Link */
if (run_command("gcc -m32 /tmp/test.o -o /tmp/test 2>/tmp/test.err") != 0) {
printf("FAIL (linker error)\n");
test_failed++;
return;
}
/* Run and capture output */
int exit_code = run_command("/tmp/test > /tmp/test.out 2>&1");
/* Check exit code */
if (exit_code != t->expected_exit) {
printf("FAIL (exit=%d, expected=%d)\n", exit_code, t->expected_exit);
test_failed++;
return;
}
/* Check output if specified */
if (t->expected_output) {
char *output = read_file("/tmp/test.out");
if (!output) {
printf("FAIL (cannot read output)\n");
test_failed++;
return;
}
if (strcmp(output, t->expected_output) != 0) {
printf("FAIL (output mismatch)\n");
printf(" Expected: %s\n", t->expected_output);
printf(" Got: %s\n", output);
free(output);
test_failed++;
return;
}
free(output);
}
printf("PASS\n");
test_passed++;
}
/* ============================================
TEST CASES
============================================ */
Test tests[] = {
/* Basic arithmetic */
{
"simple_return",
"int32 main(void) { return 42; }",
42,
NULL
},
{
"addition",
"int32 main(void) { return 10 + 32; }",
42,
NULL
},
{
"subtraction",
"int32 main(void) { return 50 - 8; }",
42,
NULL
},
{
"multiplication",
"int32 main(void) { return 6 * 7; }",
42,
NULL
},
{
"division",
"int32 main(void) { return 84 / 2; }",
42,
NULL
},
{
"modulo",
"int32 main(void) { return 142 % 100; }",
42,
NULL
},
/* Variables */
{
"local_variable",
"int32 main(void) { int32 x; x = 42; return x; }",
42,
NULL
},
{
"variable_with_init",
"int32 main(void) { int32 x = 42; return x; }",
42,
NULL
},
{
"multiple_variables",
"int32 main(void) { int32 x = 10; int32 y = 32; return x + y; }",
42,
NULL
},
/* Global variables */
{
"global_variable",
"int32 g = 42;\n"
"int32 main(void) { return g; }",
42,
NULL
},
{
"global_read_write",
"int32 g;\n"
"int32 main(void) { g = 42; return g; }",
42,
NULL
},
/* Control flow */
{
"if_true",
"int32 main(void) { if (1) return 42; return 0; }",
42,
NULL
},
{
"if_false",
"int32 main(void) { if (0) return 0; return 42; }",
42,
NULL
},
{
"if_else",
"int32 main(void) { if (0) return 0; else return 42; }",
42,
NULL
},
{
"while_loop",
"int32 main(void) {\n"
" int32 x = 0;\n"
" while (x < 42) x = x + 1;\n"
" return x;\n"
"}",
42,
NULL
},
{
"for_loop",
"int32 main(void) {\n"
" int32 sum = 0;\n"
" for (int32 i = 0; i < 10; i = i + 1) sum = sum + i;\n"
" return sum;\n"
"}",
45,
NULL
},
/* Comparisons */
{
"eq_true",
"int32 main(void) { return 42 == 42; }",
1,
NULL
},
{
"eq_false",
"int32 main(void) { return 42 == 43; }",
0,
NULL
},
{
"neq_true",
"int32 main(void) { return 42 != 43; }",
1,
NULL
},
{
"lt_true",
"int32 main(void) { return 10 < 42; }",
1,
NULL
},
{
"gt_true",
"int32 main(void) { return 42 > 10; }",
1,
NULL
},
/* Logical operators */
{
"and_true",
"int32 main(void) { return 1 && 1; }",
1,
NULL
},
{
"and_false",
"int32 main(void) { return 1 && 0; }",
0,
NULL
},
{
"or_true",
"int32 main(void) { return 0 || 1; }",
1,
NULL
},
{
"or_false",
"int32 main(void) { return 0 || 0; }",
0,
NULL
},
/* Bitwise operators */
{
"bitwise_and",
"int32 main(void) { return 63 & 42; }",
42,
NULL
},
{
"bitwise_or",
"int32 main(void) { return 32 | 10; }",
42,
NULL
},
{
"bitwise_xor",
"int32 main(void) { return 50 ^ 24; }",
42,
NULL
},
{
"left_shift",
"int32 main(void) { return 21 << 1; }",
42,
NULL
},
{
"right_shift",
"int32 main(void) { return 84 >> 1; }",
42,
NULL
},
/* Unary operators */
{
"negation",
"int32 main(void) { return -(-42); }",
42,
NULL
},
{
"logical_not",
"int32 main(void) { return !0; }",
1,
NULL
},
{
"bitwise_not",
"int32 main(void) { return ~(-43); }",
42,
NULL
},
/* Increment/decrement */
{
"post_increment",
"int32 main(void) { int32 x = 41; int32 y = x++; return x; }",
42,
NULL
},
{
"pre_increment",
"int32 main(void) { int32 x = 41; int32 y = ++x; return x; }",
42,
NULL
},
{
"post_decrement",
"int32 main(void) { int32 x = 43; int32 y = x--; return x; }",
42,
NULL
},
/* Compound assignment */
{
"add_assign",
"int32 main(void) { int32 x = 10; x += 32; return x; }",
42,
NULL
},
{
"sub_assign",
"int32 main(void) { int32 x = 50; x -= 8; return x; }",
42,
NULL
},
/* Ternary operator */
{
"ternary_true",
"int32 main(void) { return 1 ? 42 : 0; }",
42,
NULL
},
{
"ternary_false",
"int32 main(void) { return 0 ? 0 : 42; }",
42,
NULL
},
/* Functions */
{
"function_call",
"int32 add(int32 a, int32 b) { return a + b; }\n"
"int32 main(void) { return add(10, 32); }",
42,
NULL
},
{
"recursive_function",
"int32 fib(int32 n) {\n"
" if (n <= 1) return n;\n"
" return fib(n - 1) + fib(n - 2);\n"
"}\n"
"int32 main(void) { return fib(10); }",
55,
NULL
},
/* Arrays */
{
"local_array",
"int32 main(void) {\n"
" int32 arr[5];\n"
" arr[0] = 42;\n"
" return arr[0];\n"
"}",
42,
NULL
},
{
"array_init",
"int32 main(void) {\n"
" int32 arr[3] = { 10, 32, 99 };\n"
" return arr[0] + arr[1];\n"
"}",
42,
NULL
},
{
"global_array",
"int32 arr[3] = { 10, 32, 99 };\n"
"int32 main(void) { return arr[0] + arr[1]; }",
42,
NULL
},
/* Pointers */
{
"address_and_deref",
"int32 main(void) {\n"
" int32 x = 42;\n"
" int32 *p = &x;\n"
" return *p;\n"
"}",
42,
NULL
},
{
"pointer_assignment",
"int32 main(void) {\n"
" int32 x = 0;\n"
" int32 *p = &x;\n"
" *p = 42;\n"
" return x;\n"
"}",
42,
NULL
},
/* Type casting */
{
"cast_to_uint8",
"int32 main(void) { return (uint8)42; }",
42,
NULL
},
{
"cast_truncate",
"int32 main(void) { return (uint8)298; }",
42,
NULL
},
/* Different integer sizes */
{
"uint8_type",
"int32 main(void) { uint8 x = 42; return x; }",
42,
NULL
},
{
"uint16_type",
"int32 main(void) { uint16 x = 42; return x; }",
42,
NULL
},
{
"int8_signed",
"int32 main(void) { int8 x = -42; return -x; }",
42,
NULL
},
/* Switch statement */
{
"switch_basic",
"int32 main(void) {\n"
" int32 x = 2;\n"
" switch (x) {\n"
" case 1: return 10;\n"
" case 2: return 42;\n"
" case 3: return 20;\n"
" }\n"
" return 0;\n"
"}",
42,
NULL
},
{
"switch_default",
"int32 main(void) {\n"
" int32 x = 99;\n"
" switch (x) {\n"
" case 1: return 10;\n"
" default: return 42;\n"
" }\n"
"}",
42,
NULL
},
/* Break/continue */
{
"break_loop",
"int32 main(void) {\n"
" int32 x = 0;\n"
" while (1) {\n"
" x = x + 1;\n"
" if (x == 42) break;\n"
" }\n"
" return x;\n"
"}",
42,
NULL
},
{
"continue_loop",
"int32 main(void) {\n"
" int32 x = 0;\n"
" int32 sum = 0;\n"
" while (x < 50) {\n"
" x = x + 1;\n"
" if (x > 42) continue;\n"
" sum = sum + 1;\n"
" }\n"
" return sum;\n"
"}",
42,
NULL
},
/* End marker */
{ NULL, NULL, 0, NULL }
};
int main(void) {
printf("Common Compiler Test Suite\n");
printf("===========================\n\n");
/* Check if compiler exists */
if (access("./common", X_OK) != 0) {
fprintf(stderr, "Error: ./common not found or not executable\n");
fprintf(stderr, "Please build it first: gcc -o common common.c\n");
return 1;
}
/* Run all tests */
for (int i = 0; tests[i].name != NULL; i++) {
run_test(&tests[i]);
}
/* Summary */
printf("\n===========================\n");
printf("Total: %d\n", test_count);
printf("Passed: %d\n", test_passed);
printf("Failed: %d\n", test_failed);
printf("===========================\n");
return test_failed > 0 ? 1 : 0;
}

1024
test_suite.cm Normal file

File diff suppressed because it is too large Load Diff