File size: 2,893 Bytes
2166d7e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | # Hybrid code generator: AST → SUBLEQ machine code
# Converts unified Befunge/Brainfuck AST to deterministic SUBLEQ triads
# Compile: nim c -d:release hybrid_codegen.nim
import hybrid_ast
import subleq_bf
import befunge_codegen
const
# Memory layout: fixed zones (matches subleq_bf.nim)
Z = 0 # zero (constant 0)
ONE = 3 # one (constant 1)
M1 = 4 # minus one (constant -1)
P = 5 # BF pointer
NP = 6 # negative pointer (-P)
T = 7 # temp
U = 8 # temp
CODE0 = 9
NEXT = low(int)
proc codegenBrainfuck*(prog: Program; tapeCells = 256): Transpiled =
if tapeCells <= 0:
var err: Transpiled
err.error = "tapeCells must be positive"
return err
var code: seq[int]
var baseFix: seq[int]
var loops: seq[tuple[patch, body: int]]
proc here(): int = CODE0 + code.len
proc tri(a, b: int; c = NEXT) =
let at = here()
code.add a
code.add b
code.add (if c == NEXT: at + 3 else: c)
proc viaPtr(a, b, field: int) =
let target = here() + 3 + field
tri(NP, target)
baseFix.add target - CODE0
tri(a, b)
tri(P, target)
proc loadTest() =
tri(T, T)
viaPtr(0, T, 0)
tri(U, U)
tri(T, U)
# Generate code for each instruction
for i, instr in prog.instrs:
case instr.kind
of ikPtrInc:
tri(M1, P)
tri(ONE, NP)
of ikPtrDec:
tri(ONE, P)
tri(M1, NP)
of ikCellInc:
viaPtr(M1, 0, 1)
of ikCellDec:
viaPtr(ONE, 0, 1)
of ikCellOut:
viaPtr(0, -1, 0)
of ikCellIn:
viaPtr(-1, 0, 1)
of ikLoopStart:
loadTest()
let p = here()
tri(Z, T, p + 6)
tri(Z, Z, p + 9)
tri(Z, U, 0)
loops.add (patch: p + 6 + 2 - CODE0, body: p + 9)
of ikLoopEnd:
if loops.len == 0:
var err: Transpiled
err.error = "unmatched loop end"
return err
let lp = loops.pop()
loadTest()
let p = here()
tri(Z, T, p + 6)
tri(Z, Z, lp.body)
tri(Z, U, p + 12)
tri(Z, Z, lp.body)
code[lp.patch] = p + 12
of ikHalt:
tri(Z, Z, -1)
else:
var err: Transpiled
err.error = "unimplemented instruction: " & $instr.kind
return err
if prog.instrs.len == 0 or prog.instrs[prog.instrs.len - 1].kind != ikHalt:
tri(Z, Z, -1)
let base = CODE0 + code.len
result.tapeBase = base
result.tapeCells = tapeCells
result.mem = newSeq[int](base + tapeCells)
result.mem[2] = CODE0
result.mem[ONE] = 1
result.mem[M1] = -1
for i, v in code:
result.mem[CODE0 + i] = v
for idx in baseFix:
result.mem[CODE0 + idx] += base
proc codegen*(prog: Program; tapeCells = 256): Transpiled =
case prog.mode
of modeBrainfuck:
codegenBrainfuck(prog, tapeCells)
of modeBefunge:
codegenBefunge(prog, tapeCells)
of modeHybrid:
codegenBrainfuck(prog, tapeCells)
|