Spinning donut ᴾᴴᴾ - chung-leong/zigar GitHub Wiki
JavaScript | PHP
In this exercise, we're going to take a piece of C code that has gone viral on YouTube and make it in run in PHP. The code in question is in the shape of a donut:
k;double sin()
,cos();main(){float A=
0,B=0,i,j,z[1760];char b[
1760];printf("\x1b[2J");for(;;
){memset(b,32,1760);memset(z,0,7040)
;for(j=0;6.28>j;j+=0.07)for(i=0;6.28
>i;i+=0.02){float c=sin(i),d=cos(j),e=
sin(A),f=sin(j),g=cos(A),h=d+2,D=1/(c*
h*e+f*g+5),l=cos (i),m=cos(B),n=s\
in(B),t=c*h*g-f* e;int x=40+30*D*
(l*h*m-t*n),y= 12+15*D*(l*h*n
+t*m),o=x+80*y, N=8*((f*e-c*d*g
)*m-c*d*e-f*g-l *d*n);if(22>y&&
y>0&&x>0&&80>x&&D>z[o]){z[o]=D;;;b[o]=
".,-~:;=!*#$@"[N>0?N:0];}}/*#****!!-*/
printf("\x1b[H");for(k=0;1761>k;k++)
putchar(k%80?b[k]:10);A+=0.04;B+=
0.02;}}/*****####*******!!=;:~
~::==!!!**********!!!==::-
.,~~;;;========;;;:~-.
..,--------,*/
When compiled and run, it prints a spinning donut in the terminal. Completely useless? Yes, but it's totally cool!
Creating the spinning donut
Per usual, we'll start by creating the basic directory structure:
mkdir donut
cd donut
mkdir src zig
In the sub-directory zig, create donut.c and paste in the C code above.
In the same directory, create donut.zig:
const std = @import("std");
extern fn c_main(c_int, [*c][*c]u8) c_int;
pub fn run() void {
_ = c_main(0, null);
}
All the code does is import the main function from the C code and run it.
In the same directory, create build.extra.zig:
const std = @import("std");
const cfg = @import("build.cfg.zig");
pub fn getCSourceFiles(_: *std.Build, args: anytype) []const []const u8 {
args.module.addCSourceFile(.{
.file = .{ .cwd_relative = cfg.module_dir ++ "donut.c" },
.flags = &.{
"-std=c89",
"-Dmain=c_main",
},
});
return &.{};
}
This file is used by Zigar's built-in build file. Normally, getCSourceFiles() would return a
list of C files that need to compiled into the final executable. We can't do that here because
we're using C code that isn't legal anymore. We have to tell the compiler to compile the code in
accordance with the C standard circa 1989. We're able to do that since the build file helpfully
gives us direct access to the
main module.
The second compiler flag renames main() to c_main(). We need to do this since it's illegal to
invoke a C program's main function directly. On certain platforms (e.g. Windows), the result is
an immediate crash.
You have to use module_dir to get the full path to the C file because Zigar compiles modules
in a temporary directory.
The final step involves importing the Zig function and calling it in PHP. In src, create
donut.php:
<?php
$m = zigar_use(__DIR__ . '/../zig/donut.zig');
$m->run();
Then run it:
php src/donut.php
You should see a spinning donut.
Source code
You can find the complete source code for this example here.
Conclusion
The C code used in this example is, of course, utterly frivolous. The important takeaway is that you enjoy the full power of a C compiler when you program in Zig. The Zig compiler is actually more powerful than something like Clang because it's a cross-compiler. You can easily, for instance, compile the same code for WebAssembly as you can see here here.