aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-09-09 05:14:44 +0200
committerhachem <im@hachem.wtf>2026-09-09 05:14:44 +0200
commit8b76d35b0a045e0a3277be422513b938ef33dcce (patch)
treeb876d92ba3afb810e38f3f83792fc3fb849dd457 /docs
parentb9eff51ee157b22d8fa46aeecac7b95d5ed345d9 (diff)
feat: fasm backend
Diffstat (limited to 'docs')
-rw-r--r--docs/language.md21
1 files changed, 18 insertions, 3 deletions
diff --git a/docs/language.md b/docs/language.md
index 42b178e..79d7866 100644
--- a/docs/language.md
+++ b/docs/language.md
@@ -1,6 +1,6 @@
# hdass language reference
-hdass emits NASM for x86-64; fasm and masm are planned. The compiler output itself isn't tied to an OS, but the examples and toolchain here target Linux (Linux syscall numbers, `nasm -f elf64`, `ld`). Pipeline: `lex → parse → analyze → emit`.
+hdass emits NASM or FASM for x86-64 (`-t nasm` by default, `-t fasm`); masm is planned. The instruction bodies are the same Intel syntax for both — only the framing (headers, sections, constants, data) differs. The compiler output itself isn't tied to an OS, but the examples and toolchain here target Linux (Linux syscall numbers, ELF64, `ld`). Pipeline: `lex → parse → analyze → emit`.
## A first program
@@ -154,6 +154,13 @@ while rcx > 0
}
```
+An optional `.name` right after `while` names the loop's generated labels, so they read as `.name` (top) and `.name_end` (exit) instead of the anonymous `.while_N` — handy for finding a loop in the emitted assembly. Give nested loops distinct names.
+
+```hdass
+while .countdown rcx > 0 // emits `.countdown:` … `jmp .countdown` … `.countdown_end:`
+ rcx -= 1
+```
+
## Dereference (`^`)
`^reg` is the memory at the address in `reg` — NASM's `[reg]`. On the left of `=` it stores there. The store width comes from the value operand, so a sized sub-register picks the size:
@@ -262,14 +269,22 @@ See [examples/mandelbrot.hdass](../examples/mandelbrot.hdass) for a float progra
## Building a program
```bash
-hdass program.hdass -o program.asm
+hdass program.hdass -o program.asm # nasm (default)
nasm -f elf64 program.asm -o program.o
ld -e main program.o -o program
./program
```
+Or target fasm with `-t fasm`, which assembles in one step:
+
+```bash
+hdass -t fasm program.hdass -o program.asm
+fasm program.asm program.o
+ld -e main program.o -o program
+```
+
The [README](../README.md) has a Docker setup with these tools.
## Some stinkies
-Clobbering is your responsibility: `syscall` trashes `rcx` and `r11`, while a callee can trash any registers it touches, so nothing is saved automatically. `examples/fibonacci.hdass`, for example, keeps its counter in `r15` for this reason. Register widths must also match, meaning something like `rax = r1.8` would become `mov rax, al`, which will not assemble. Division clobbers extra registers: `/` `%` and their `=` forms use `idiv` through `rax:rdx`, so both are overwritten regardless of the destination. The divisor can be anything — a register, a constant, or an immediate — but an immediate or an `rax`/`rdx` divisor is first copied into `r11`, so those also clobber `r11`. Finally, the entry procedure has no `ret`; it should end with an exit syscall.
+Clobbering is your responsibility: `syscall` trashes `rcx` and `r11`, while a callee can trash any registers it touches, so nothing is saved automatically. `examples/fibonacci.hdass`, for example, keeps its counter in `r15` for this reason. Register widths must also match, meaning something like `rax = r1.8` would become `mov rax, al`, which will not assemble. Division clobbers extra registers: `/` `%` and their `=` forms use `idiv` through `rax:rdx`, so both are overwritten regardless of the destination. The divisor can be anything — a register, a constant, or an immediate — but an immediate or an `rax`/`rdx` divisor is first copied into `r11`, so those also clobber `r11`. Labels and procedures become plain assembler symbols, so avoid names the target assembler reserves: `loop`, for instance, is an instruction mnemonic that fasm rejects as a label (nasm allows it). Finally, the entry procedure has no `ret`; it should end with an exit syscall.