Initial commit
This commit is contained in:
101
Makefile
Normal file
101
Makefile
Normal 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
332
QUICKREF.md
Normal 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
349
README.md
Normal 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
286
README_TESTS.md
Normal 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
623
TROUBLESHOOTING.md
Normal 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/)*
|
||||
48
examples/arrays.cm
Normal file
48
examples/arrays.cm
Normal 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
60
examples/bitwise.cm
Normal 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
40
examples/bubblesort.cm
Normal 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
101
examples/calculator.cm
Normal 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
23
examples/fibonacci.cm
Normal 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
11
examples/hello.cm
Normal 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
159
examples/linkedlist.cm
Normal 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
38
examples/pointers.cm
Normal 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
68
examples/primes.cm
Normal 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
70
examples/strings.cm
Normal 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
65
examples/switch.cm
Normal 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
50
examples/types.cm
Normal 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
18
run_tests.sh
Normal 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
619
test_runner.c
Normal 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
1024
test_suite.cm
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user