plugins/befunge.zc
Rama main · réplica de lectura del repositorio original.
import "../std/plugin.zc"
include <ctype.h>
include <stdio.h>
include <stdlib.h>
include <string.h>
@unused fn skip_whitespace(p: char**) {
let ptr = *p;
while (ptr[0] != 0 && isspace((int)ptr[0])) {
ptr = &ptr[1];
}
*p = ptr;
}
fn befunge_transpile(body: char*, api: ZApi*) {
let out = api.out;
let grid: [char; 2000];
memset(&grid[0], 32, (size_t)2000); // 32 is space
let r = 0; let c = 0;
let p = body;
while (p[0] != 0 && (p[0] == 10 || p[0] == 13)) p = &p[1];
while (p[0] != 0) {
if (p[0] == 13) { p = &p[1]; continue; } // Skip CR
if (p[0] == 10) {
r++; c = 0;
if (r >= 25) break;
} else if (c < 80) {
grid[r * 80 + c] = p[0];
c++;
}
p = &p[1];
}
fputs(f"""{{
long stack[1024]; int sp = 0;
int x = 0, y = 0, dx = 1, dy = 0, string_mode = 0;
static void *dispatch[25][80] = {{
""", out);
for row in 0 .. 25 {
fputs(f" {{ ", out);
for col in 0 .. 80 {
if (grid[row * 80 + col] == 32) fputs("&&space_handler, ", out);
else fprintf(out, "&&cell_%d_%d, ", row, col);
}
fputs(f" }}, \n", out);
}
fputs(f" }};\n goto *dispatch[0][0];\n", out);
for row in 0 .. 25 {
for col in 0 .. 80 {
let op = (int)grid[row * 80 + col];
if (op == 32) continue;
fprintf(out, "cell_%d_%d:\n", row, col);
if (op >= 48 && op <= 57) { // 0-9
fprintf(out, " if(string_mode) stack[sp++] = %d; else stack[sp++] = %d;\n", op, op - 48);
} else if (op == 34) { // "
fputs(" string_mode = !string_mode;\n", out);
} else {
match op {
62 => fputs(" dx=1; dy=0;\n", out), // >
60 => fputs(" dx=-1; dy=0;\n", out), // <
94 => fputs(" dx=0; dy=-1;\n", out), // ^
118 => fputs(" dx=0; dy=1;\n", out), // v
43 => fputs(f" {{ long a=stack[--sp]; stack[sp-1]+=a; }}\n", out), // +
45 => fputs(f" {{ long a=stack[--sp]; stack[sp-1]-=a; }}\n", out), // -
42 => fputs(f" {{ long a=stack[--sp]; stack[sp-1]*=a; }}\n", out), // *
47 => fputs(f" {{ long a=stack[--sp]; stack[sp-1]=a?stack[sp-1]/a:0; }}\n", out), // /
37 => fputs(f" {{ long a=stack[--sp]; stack[sp-1]=a?stack[sp-1]%a:0; }}\n", out), // %
33 => fputs(" stack[sp-1] = !stack[sp-1];\n", out), // !
96 => fputs(f" {{ long a=stack[--sp]; stack[sp-1]=(stack[sp-1]>a); }}\n", out), // `
58 => fputs(f" {{ if(sp>0) {{ stack[sp]=stack[sp-1]; sp++; }} }}\n", out), // :
92 => fputs(f" {{ if(sp>1) {{ long t=stack[sp-1]; stack[sp-1]=stack[sp-2]; stack[sp-2]=t; }} }}\n", out), // \
36 => fputs(" if(sp>0) sp--;\n", out), // $
46 => fputs(" if(sp>0) printf(\"%ld \", stack[--sp]);\n", out), // .
44 => fputs(" if(sp>0) printf(\"%c\", (char)stack[--sp]);\n", out), // ,
95 => fputs(f" {{ long a=stack[--sp]; dx=a?-1:1; dy=0; }}\n", out), // _
124 => fputs(f" {{ long a=stack[--sp]; dx=0; dy=a?-1:1; }}\n", out), // |
64 => fputs(" goto end_befunge;\n", out), // @
35 => fputs(" x+=dx; y+=dy;\n", out), // #
_ => fprintf(out, " if(string_mode) stack[sp++] = %d;\n", op)
}
}
fputs(" x+=dx; y+=dy; if(x>=80) x=0; else if(x<0) x=79; if(y>=25) y=0; else if(y<0) y=24; goto *dispatch[y][x];\n", out);
}
}
fputs(f"""space_handler: x+=dx; y+=dy; if(x>=80) x=0; else if(x<0) x=79; if(y>=25) y=0; else if(y<0) y=24; goto *dispatch[y][x];
end_befunge:;
}}
""", out);
}
fn befunge_hover(body: char*, line: int, col: int) -> char* {
let p = body;
let r = 0; let c = 0;
while (p[0] != 0 && (p[0] == 10 || p[0] == 13)) p = &p[1];
while (p[0] != 0) {
if (p[0] == 13) { p = &p[1]; continue; } // Skip CR
if (r == line && c == col) {
match (int)p[0] {
62 => return ">: PC travels Right",
60 => return "<: PC travels Left",
94 => return "^: PC travels Up",
118 => return "v: PC travels Down",
63 => return "?: PC travels in a random direction",
43 => return "+: Addition (a+b)",
45 => return "-: Subtraction (a-b)",
42 => return "*: Multiplication (a*b)",
47 => return "/: Division (a/b)",
37 => return "%: Modulo (a%b)",
33 => return "!: Logical NOT",
96 => return "`: Greater Than (a > b ? 1 : 0)",
95 => return "_: Horizontal IF (pop a; if a==0 dx=1 else dx=-1)",
124 => return "|: Vertical IF (pop a; if a==0 dy=1 else dy=-1)",
34 => return "\": String mode (push ASCII till next \")",
58 => return ":: Duplicate top of stack",
92 => return "\\: Swap top two elements",
36 => return "$: Discard top of stack",
46 => return ".: Output as integer",
44 => return ",: Output as character",
35 => return "#: Bridge (skip next cell)",
103 => return "g: Get (pop y,x; push grid[y][x])",
112 => return "p: Put (pop y,x,v; grid[y][x]=v)",
38 => return "&: Input integer",
126 => return "~: Input character",
64 => return "@: End Program",
_ => return NULL
}
}
if (p[0] == 10) {
r++; c = 0;
} else {
c++;
}
p = &p[1];
}
return NULL;
}
let befunge_plugin = ZPlugin {
name: "befunge",
handler: befunge_transpile,
hover_handler: befunge_hover
};
@export
fn z_plugin_init() -> ZPlugin* { return &befunge_plugin; }