import "../std/plugin.zc" include include include include @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; }