ref: 75e473f518dc4a649638bf69fbfa1c48a16a7388
parent: 90c1e6b8bad7302018388c4e9c1d30fd975ad134
author: qwx <qwx@sciops.net>
date: Sun Jan 19 15:26:42 EST 2020
fork our version of rsc's version of pico
--- a/mkfile
+++ b/mkfile
@@ -1,10 +1,6 @@
</$objtype/mkfile
-YFILES=pico.y
+YFILES=pixo.y
OFILES=y.tab.$O
BIN=$home/bin/$objtype
-TARG=pico
+TARG=pixo
</sys/src/cmd/mkone
-
-demo:V: doug.pico
- if(! test -f $O.out) mk $O.out || exit
- $O.out -q <doug.pico
--- a/pico.y
+++ /dev/null
@@ -1,811 +1,0 @@
-%{-#include <u.h>
-#include <libc.h>
-#include <ctype.h>
-#include <bio.h>
-#include <draw.h>
-#include <event.h>
-#include <memdraw.h>
-
-char *newname, *cmd, buf[64*1024], *bufp = buf;
-
-int yylex(void);
-int yyparse(void);
-void yyerror(char*);
-
-void checkref(char*);
-void checkrefn(int);
-
-char *
-sym(char *fmt, ...)
-{- va_list args;
- char *s;
-
- s = bufp;
- va_start(args, fmt);
- bufp = vseprint(s, buf+sizeof buf, fmt, args);
- va_end(args);
- if(bufp >= buf + sizeof(buf) - 1)
- sysfatal("NOPE NOPE NOPE");- *bufp++ = 0;
- return s;
-}
-
-%}
-
-%union
-{- char* s;
- int i;
- double d;
-}
-
-%token NAME NEW OLD NUM DBL EOF ERROR
-%token <s> FN NAME
-%type <s> index zindex newname command expr fileref value
-%type <i> NUM
-%type <d> DBL
-
-%right '='
-%right '?' ':'
-%left OR
-%left AND
-%left '|'
-%left '^'
-%left '&'
-%left EQ NE
-%right LSH RSH
-%left '<' '>' LE GE
-%left '+' '-'
-%left '*' '/' '%'
-%right POW
-%right '!'
-
-%%
-
-start: command EOF { cmd = $1; bufp = buf; return 0; }-
-index:
- '[' expr ',' expr ',' expr ']' { $$ = sym("%s,%s,%s", $2, $4, $6); }-
-zindex:
- index
-| { $$ = "x,y,z"; }-
-newname:
- NEW { $$ = "new"; }-| NEW NAME { $$ = $2; }-| NAME { $$ = $1; }-
-command:
- newname zindex '=' expr
- { newname = $1; $$ = sym("T = %s; *WIMAGE(%s, %s) = CLIP(T);", $4, $1, $2); }-| expr
- { newname = "new"; $$ = sym("T = %s; *WIMAGE(new, x,y,z) = CLIP(T);", $1); }-
-expr:
- value
-| fileref
-| 'x' { $$ = "x"; }-| 'y' { $$ = "y"; }-| 'z' { $$ = "z"; }-| 'X' { $$ = "X"; }-| 'Y' { $$ = "Y"; }-| 'Z' { $$ = "Z"; }-| "(" expr ")" { $$ = $2; }-| FN "(" expr ")" { $$ = sym("%s(%s)", $1, $3); }-| '-' expr %prec '!' { $$ = sym("-(%s)", $2); }-| '!' expr { $$ = sym("!(%s)", $2); }-| expr '+' expr { $$ = sym("(%s)+(%s)", $1, $3); }-| expr '-' expr { $$ = sym("(%s)-(%s)", $1, $3); }-| expr '*' expr { $$ = sym("(%s)*(%s)", $1, $3); }-| expr '/' expr { $$ = sym("DIV(%s, %s)", $1, $3); }-| expr '%' expr { $$ = sym("MOD(%s, %s)", $1, $3); }-| expr '<' expr { $$ = sym("(%s) < (%s)", $1, $3); }-| expr '>' expr { $$ = sym("(%s) > (%s)", $1, $3); }-| expr LE expr { $$ = sym("(%s) <= (%s)", $1, $3); }-| expr GE expr { $$ = sym("(%s) >= (%s)", $1, $3); }-| expr EQ expr { $$ = sym("(%s) == (%s)", $1, $3); }-| expr NE expr { $$ = sym("(%s) != (%s)", $1, $3); }-| expr LSH expr { $$ = sym("(%s) << (%s)", $1, $3); }-| expr RSH expr { $$ = sym("(%s) >> (%s)", $1, $3); }-| expr '^' expr { $$ = sym("(%s) ^ (%s)", $1, $3); }-| expr '&' expr { $$ = sym("(%s) & (%s)", $1, $3); }-| expr '|' expr { $$ = sym("(%s) | (%s)", $1, $3); }-| expr AND expr { $$ = sym("(%s) && (%s)", $1, $3); }-| expr OR expr { $$ = sym("(%s) || (%s)", $1, $3); }-| expr '?' expr ':' expr { $$ = sym("(%s) ? (%s) : (%s)", $1, $3, $5); }-| expr POW expr { $$ = sym("POW(%s, %s)", $1, $3); }-
-fileref:
- NAME zindex { checkref($1); $$ = sym("IMAGE(%s, %s)", $1, $2); }-| "$" NUM zindex { checkrefn($2); $$ = sym("IMAGE(OLD[%d-1], %s)", $2, $3); }-| OLD zindex { checkrefn(1); $$ = sym("IMAGE(old, %s)", $2); }-
-value:
- NUM { $$ = sym("%d", $1); }-| DBL { $$ = sym("%f", $1); }-
-%%
-
-char *inp;
-
-jmp_buf boomer;
-
-void
-kaboom(char *fmt, ...)
-{- va_list arg;
- va_start(arg, fmt);
- vfprint(2, fmt, arg);
- va_end(arg);
- fprint(2, "\n");
- longjmp(boomer, 1);
-}
-
-void
-yyerror(char *msg)
-{- kaboom("%s", msg);-}
-
-int
-isnum(Rune r, char *s, char *p)
-{- if(isdigit(r)
- || p - s == 1 && (r == 'x' || r == 'X')
- || p - s > 2 && (s[1] == 'x' || s[1] == 'X') && (r >= 'a' && r <= 'f' || r >= 'A' && r <= 'F'))
- return 1;
- else if(r == '.')
- return 2;
- else
- return 0;
-}
-
-int
-getnum(Rune r)
-{- int n, x, dbl;
- char s[128], *p;
-
- for(p=s, n=0, dbl=0; x = isnum(r, s, p); n=chartorune(&r, inp), inp+=n){- if(p < s+sizeof(s)-1){- *p++ = (char)r;
- if(x == 2)
- dbl = 1;
- }
- }
- *p = 0;
- inp -= n;
- if(dbl){- yylval.d = strtod(s, nil);
- return DBL;
- }else{- yylval.i = strtol(s, nil, 0);
- return NUM;
- }
-}
-
-int
-getname(Rune r)
-{- int n;
- Rune s[128], *p;
-
- for(p=s, n=0; isalpharune(r) || isdigitrune(r) || r >= 0x2080 && r <= 0x2089; n=chartorune(&r, inp), inp+=n)
- if(p < s+nelem(s)-1)
- *p++ = r;
- *p = 0;
- inp -= n;
- if(runestrcmp(s, L"x") == 0
- || runestrcmp(s, L"X") == 0
- || runestrcmp(s, L"y") == 0
- || runestrcmp(s, L"Y") == 0
- || runestrcmp(s, L"z") == 0
- || runestrcmp(s, L"Z") == 0)
- return s[0];
- yylval.s = sym("%S", s);- if(runestrcmp(s, L"new") == 0)
- return NEW;
- else if(runestrcmp(s, L"log") == 0
- || runestrcmp(s, L"sin") == 0
- || runestrcmp(s, L"cos") == 0
- || runestrcmp(s, L"sqrt") == 0)
- return FN;
- return NAME;
-}
-
-int
-follow2(Rune r0, Rune r1, int op1, Rune r2, int op2)
-{- int n;
- Rune r;
-
- if(*inp == 0)
- return 0;
- n = chartorune(&r, inp);
- if(r == r1){- inp += n;
- return op1;
- }else if(r == r2){- inp += n;
- return op2;
- }
- return r0;
-}
-
-int
-follow(Rune r0, Rune rr, int op)
-{- int n;
- Rune r;
-
- if(*inp == 0)
- return 0;
- n = chartorune(&r, inp);
- if(r == rr){- inp += n;
- return op;
- }
- return r0;
-}
-
-int
-yylex(void)
-{- Rune r;
-
- for(;;){- if(*inp == 0)
- return EOF;
- inp += chartorune(&r, inp);
- if(!isspacerune(r))
- break;
- }
- switch(r){- case '+':
- case '-':
- case '/':
- case '%':
- case '?':
- case ':':
- case '^':
- case '$':
- case '[':
- case ']':
- case ',':
- case '(':- case ')': return r;
- case '&': return follow(r, '&', AND);
- case '|': return follow(r, '|', OR);
- case '*': return follow(r, '*', POW);
- case '<': return follow2(r, '=', LE, '<', LSH);
- case '>': return follow2(r, '=', GE, '>', RSH);
- case '=': return follow(r, '=', EQ);
- case '!': return follow(r, '=', NE);
- }
- if(isdigit(r))
- return getnum(r);
- else if(isalpharune(r))
- return getname(r);
- kaboom("unexpected %C", r);- return ERROR;
-}
-
-int
-system(char *s)
-{- int pid;
-
- pid = fork();
- if(pid == 0){- execl("/bin/rc", "rc", "-c", s, nil);- _exits(0);
- }
- if(pid == -1){- fprint(2, "fork: %r\n");
- return -1;
- }
- Waitmsg *w;
- while((w = wait()) != nil && w->pid != pid)
- ;
- if(w == nil){- fprint(2, "%s: wait not found\n", s);
- return -1;
- }
- if(w->msg && w->msg[0]) {- fprint(2, "%s: failed\n", s);
- free(w);
- return -1;
- }
- free(w);
- return 0;
-}
-
-void show(Memimage*);
-
-void
-xquit(int, char **)
-{- exits(0);
-}
-
-typedef struct File File;
-struct File{- char *name;
- char *path;
- Memimage *m;
- int ref;
- int fd;
-};
-File *files;
-int nfiles;
-
-int DX = 248, DY = 248;
-
-Memimage*
-readi(char *name)
-{- int fd;
- Memimage *m, *m1;
-
- if((fd = open(name, OREAD)) < 0){- fprint(2, "open %s: %r\n", name);
- return nil;
- }
- m = readmemimage(fd);
- close(fd);
- if(m == nil){- fprint(2, "readmemimage: %r\n");
- return nil;
- }
- if(m->chan != ABGR32){- m1 = allocmemimage(m->r, ABGR32);
- memfillcolor(m1, DBlack);
- memimagedraw(m1, m1->r, m, m->r.min, memopaque, ZP, S);
- freememimage(m);
- m = m1;
- }
- return m;
-}
-
-int
-writei(Memimage *m, char *name, int tmp)
-{- int fd;
-
- if((fd = create(name, OWRITE|(tmp?ORCLOSE:0), 0666)) < 0){- fprint(2, "create %s: %r\n", name);
- return -1;
- }
- if(writememimage(fd, m) < 0){- close(fd);
- fprint(2, "writememimage %s: %r\n", name);
- return -1;
- }
- if(tmp)
- return fd;
- close(fd);
- return 0;
-}
-
-Memimage*
-namei(char *name, int warn)
-{- int i;
-
- for(i=0; i<nfiles; i++)
- if(strcmp(name, files[i].name) == 0){- files[i].ref++;
- return files[i].m;
- }
- if(warn)
- fprint(2, "no image %s\n", name);
- return nil;
-}
-
-void
-iput(char *name, Memimage *m, char *path)
-{- int i;
-
- for(i=0; i<nfiles; i++)
- if(name[0] && strcmp(name, files[i].name) == 0){- freememimage(files[i].m);
- files[i].m = m;
- return;
- }
- files = realloc(files, ++nfiles*sizeof files[0]);
- if(strlen(name) == 0)
- files[i].name = smprint("$%d", i+1);- else
- files[i].name = strdup(name);
- files[i].path = path == nil ? nil : strdup(path);
- files[i].m = m;
- files[i].fd = writei(files[i].m, sym("/tmp/pico-run.%d.bit", i), 1);- DX = Dx(m->r);
- DY = Dy(m->r);
-}
-
-void
-checkref(char *name)
-{- if(namei(name, 1) == nil)
- longjmp(boomer, 1);
-}
-
-void
-checkrefn(int n)
-{- if(n < 1 || n > nfiles)
- kaboom("no image $%d", n);- files[n-1].ref++;
-}
-
-void
-xfiles(int argc, char **)
-{- int i;
- if(argc != 1){- fprint(2, "usage: f\n");
- return;
- }
- for(i=0; i<nfiles; i++)
- print("$%d %s %s %dx%d\n", i+1, files[i].name, files[i].path ? files[i].path : "", Dx(files[i].m->r), Dy(files[i].m->r));-}
-
-void
-xread(int argc, char **argv)
-{- Memimage *m;
-
- if(argc < 2 || argc > 3){- fprint(2, "usage: r image [filename]\n");
- return;
- }
- m = readi(argc == 3 ? argv[2] : argv[1]);
- if(m != nil)
- iput(argv[1], m, argc == 3 ? argv[2] : argv[1]);
-}
-
-void
-xwrite(int argc, char **argv)
-{- if(argc < 2 || argc > 3){- fprint(2, "usage: w image [filename]\n");
- return;
- }
- Memimage *m = namei(argv[1], 1);
- if(m == nil)
- return;
- writei(m, argc == 3 ? argv[2] : argv[1], 0);
-}
-
-void
-xdisplay(int argc, char **argv)
-{- int i;
-
- if(argc == 1){- if(nfiles > 0)
- show(files[nfiles-1].m);
- return;
- }
-
- for(i=1; i<argc; i++){- Memimage *m = namei(argv[i], 1);
- if(m)
- show(m);
- }
-}
-
-char* prolog =
- "#include <u.h>\n"
- "#include <libc.h>\n"
- "#include <draw.h>\n"
- "#include <memdraw.h>\n"
- "\n"
- "Memimage*\n"
- "READ(char *file)\n"
- "{\n"- " Memimage *m;\n"
- " int fd = open(file, OREAD);\n"
- " if(fd < 0) sysfatal(\"open %s: %r\", file);\n"
- " m = readmemimage(fd);\n"
- " if(m == nil) sysfatal(\"readmemimage %s: %r\", file);\n"
- " return m;\n"
- "}\n\n"
- "void\n"
- "WRITE(Memimage *m, char *file)\n"
- "{\n"- " int fd = create(file, OWRITE, 0666);\n"
- " if(fd < 0) sysfatal(\"create %s: %r\", file);\n"
- " if(writememimage(fd, m) < 0) sysfatal(\"writememimage %s: %r\", file);\n"
- "}\n\n"
- "int\n"
- "POW(int a, int b)\n"
- "{\n"- " int t;\n"
- " if(b <= 0) return 1;\n"
- " if(b == 1) return a;\n"
- " t = POW(a, b/2);\n"
- " t *= t;\n"
- " if(b%2) t *= a;\n"
- " return t;\n"
- "}\n"
- "\n"
- "int\n"
- "DIV(int a, int b)\n"
- "{\n"- " if(b == 0) return 0;\n"
- " return a/b;\n"
- "}\n"
- "\n"
- "int\n"
- "MOD(int a, int b)\n"
- "{\n"- " if(b == 0) return 0;\n"
- " return a%b;\n"
- "}\n"
- "\n"
- "#define Z 255\n"
- "\n"
- "uchar\n"
- "IMAGE(Memimage *m, int x, int y, int z)\n"
- "{\n"- " if(x < 0 || y < 0 || z < 0 || x >= Dx(m->r) || y >= Dy(m->r) || z > 3) return 0;\n"
- " return byteaddr(m, addpt(m->r.min, Pt(x,y)))[z];\n"
- "}\n"
- "\n"
- "uchar*\n"
- "WIMAGE(Memimage *m, int x, int y, int z)\n"
- "{\n"- " static uchar devnull;\n"
- " if(x < 0 || y < 0 || z < 0 || x >= Dx(m->r) || y >= Dy(m->r) || z > 3) return &devnull;\n"
- " return byteaddr(m, addpt(m->r.min, Pt(x,y))) + z;\n"
- "}\n"
- "\n"
- "#define CLIP(x) ((x) < 0 ? 0 : (x) > 255 ? 255 : (x))\n"
- "\n"
- "void main(void) {\n"- " int x, y, z, T;\n"
- ;
-
-int quiet;
-
-void
-runprog(char *name, char *cmd)
-{- int i, fd, isnew;
- Memimage *m;
-
- if((fd = create("/tmp/pico-run.c", OWRITE, 0666)) < 0){- fprint(2, "create /tmp/pico-run.c: %r");
- return;
- }
-
- write(fd, prolog, strlen(prolog));
- fprint(fd, "\tint X = %d, Y = %d;\n", DX, DY);
- fprint(fd, "\tMemimage *old, *OLD[%d+1];\n", nfiles);
-
- isnew = namei(name, 0) == nil;
- if(isnew){- fprint(fd, "\tMemimage *new = allocmemimage(Rect(0, 0, X, Y), ABGR32);\n");
- fprint(fd, "\tif(new == nil) sysfatal(\"allocmemimage: %%r\");\n");
- if(strcmp(name, "new") != 0)
- fprint(fd, "\tMemimage *%s = new;\n", name);
- }
-
- for(i=0; i<nfiles; i++){- if(!files[i].ref)
- continue;
- fprint(fd, "\tOLD[%d] = old = READ(\"/tmp/pico-run.%d.bit\");\n", i, i);
- if(files[i].name[0] != '$'){- fprint(fd, "\tMemimage *%s = old;\n", files[i].name);
- if(strcmp(files[i].name, name) == 0)
- fprint(fd, "Memimage* new = %s;\n", files[i].name);
- }
- }
-
- fprint(fd, "\tfor(z=0; z<4; z++) for(y=0; y<Y; y++) for(x=0; x<X; x++) {\n");- fprint(fd, "\t\t%s\n", cmd);
- fprint(fd, "\t}");
- fprint(fd, "\tWRITE(new, \"/tmp/pico-run.out.bit\");\n");
- fprint(fd, "\texits(0);\n}\n");
- close(fd);
-
- if(access("/tmp/pico-run.mk", AEXIST) < 0){- if((fd = create("/tmp/pico-run.mk", OWRITE|ORCLOSE, 0666)) < 0){- fprint(2, "create /tmp/pico-run.mk: %r");
- goto cleanup;
- }
- fprint(fd, "</$objtype/mkfile\n"
- "/tmp/pico-run:Q: /tmp/pico-run.c\n"
- "\t$CC -o /tmp/pico-run.$O /tmp/pico-run.c\n"
- "\t$LD -o $target /tmp/pico-run.$O\n"
- "\t$target\n"
- "\trm -f /tmp/pico-run.$O\n");
- }
- if(system("mk -f /tmp/pico-run.mk /tmp/pico-run") < 0)- goto cleanup;
-
- m = readi("/tmp/pico-run.out.bit");- if(m){- if(strcmp(name, "new") != 0)
- iput(name, m, nil);
- else
- iput("", m, nil);- if(!quiet)
- show(m);
- }
-
- remove("/tmp/pico-run.c");-cleanup:
- remove("/tmp/pico-run");- remove("/tmp/pico-run.out.bit");- for(i=0; i<nfiles; i++)
- files[i].ref = 0;
-}
-
-struct {- char *s;
- void (*f)(int, char**);
-} cmds[] = {- "d", xdisplay,
- "f", xfiles,
- "q", xquit,
- "r", xread,
- "w", xwrite,
-};
-
-void
-main(int argc, char **argv)
-{- Biobuf b;
- char *p, *f[10];
- int nf;
- int i, l;
-
- ARGBEGIN{- case 'q':
- quiet = 1;
- break;
- }ARGEND
-
- if(memimageinit() < 0)
- sysfatal("memimageinit: %r");- Binit(&b, 0, OREAD);
- setjmp(boomer);
- for(;;){- reread:
- if(!quiet)
- fprint(2, "-> ");
- if((p = Brdline(&b, '\n')) == 0)
- break;
- p[Blinelen(&b)-1] = 0;
- while(*p != 0 && isspace(*p))
- p++;
- if(*p == 0)
- goto reread;
- for(i=0; i<nelem(cmds); i++){- l = strlen(cmds[i].s);
- if(strncmp(p, cmds[i].s, l) == 0 && (p[l] == 0 || isspace(p[l]))){- nf = tokenize(p, f, nelem(f));
- cmds[i].f(nf, f);
- goto reread;
- }
- }
-
- inp = p;
- newname = nil;
- cmd = nil;
- yyparse();
- runprog(newname, cmd);
- }
- exits(0);
-}
-
-int
-newwin(void)
-{- char *srv;
- char spec[100];
- int srvfd, pid;
-
- rfork(RFNAMEG);
-
- srv = getenv("wsys");- if(srv == 0){- fprint(2, "no graphics: $wsys not set\n");
- return -1;
- }
- srvfd = open(srv, ORDWR);
- free(srv);
- if(srvfd == -1){- fprint(2, "no graphics: can't open %s: %r\n", srv);
- return -1;
- }
-
- sprint(spec, "new -dx %d -dy %d -pid 0", DX+8 < 100 ? 100 : DX+8, DY+8 < 48 ? 48 : DY+8);
- if(mount(srvfd, -1, "/mnt/wsys", 0, spec) == -1){- fprint(2, "no graphics: mount /mnt/wsys: %r (spec=%s)\n", spec);
- return -1;
- }
- close(srvfd);
-
- switch(pid = rfork(RFFDG|RFPROC|RFNAMEG|RFENVG|RFNOTEG|RFNOWAIT)){- case -1:
- fprint(2, "no graphics: can't fork: %r\n");
- break;
- }
- if(pid == 0)
- bind("/mnt/wsys", "/dev", MBEFORE);- else
- unmount(nil, "/mnt/wsys");
- return pid;
-}
-
-Image *displayed;
-
-void
-eresized(int new)
-{- if(new && getwindow(display, Refnone) < 0)
- fprint(2,"can't reattach to window");
- draw(screen, screen->r, displayed, nil, displayed->r.min);
- flushimage(display, 1);
-}
-
-void
-showloop(Memimage *m)
-{- Rectangle r;
-
- if(initdraw(0, 0, "pico") < 0){- fprint(2, "initdraw: %r\n");
- return;
- }
- einit(Emouse|Ekeyboard);
- if((displayed = allocimage(display, m->r, m->chan, 0, DNofill)) == nil){- fprint(2, "allocimage: %r\n");
- return;
- }
- r = displayed->r;
- while(r.min.y < displayed->r.max.y){- r.max.y = r.min.y + 1;
- if(loadimage(displayed, r, byteaddr(m, r.min), Dx(r)*m->depth/8) < 0){- fprint(2, "loadimage: %r\n");
- return;
- }
- r.min.y++;
- }
- close(0);
- eresized(0);
- for(;;){- Event e;
- flushimage(display, 0);
- switch(eread(Emouse|Ekeyboard, &e)){- case Ekeyboard:
- if(e.kbdc == 'q')
- return;
- eresized(0);
- break;
- case Emouse:
- if(e.mouse.buttons&4)
- return;
- break;
- }
- }
-}
-
-void
-show(Memimage *m)
-{- DX = Dx(m->r);
- DY = Dy(m->r);
- if(newwin() != 0)
- return;
- showloop(m);
- exits(0);
-}
--- /dev/null
+++ b/pixo.y
@@ -1,0 +1,811 @@
+%{+#include <u.h>
+#include <libc.h>
+#include <ctype.h>
+#include <bio.h>
+#include <draw.h>
+#include <event.h>
+#include <memdraw.h>
+
+char *newname, *cmd, buf[64*1024], *bufp = buf;
+
+int yylex(void);
+int yyparse(void);
+void yyerror(char*);
+
+void checkref(char*);
+void checkrefn(int);
+
+char *
+sym(char *fmt, ...)
+{+ va_list args;
+ char *s;
+
+ s = bufp;
+ va_start(args, fmt);
+ bufp = vseprint(s, buf+sizeof buf, fmt, args);
+ va_end(args);
+ if(bufp >= buf + sizeof(buf) - 1)
+ sysfatal("NOPE NOPE NOPE");+ *bufp++ = 0;
+ return s;
+}
+
+%}
+
+%union
+{+ char* s;
+ int i;
+ double d;
+}
+
+%token NAME NEW OLD NUM DBL EOF ERROR
+%token <s> FN NAME
+%type <s> index zindex newname command expr fileref value
+%type <i> NUM
+%type <d> DBL
+
+%right '='
+%right '?' ':'
+%left OR
+%left AND
+%left '|'
+%left '^'
+%left '&'
+%left EQ NE
+%right LSH RSH
+%left '<' '>' LE GE
+%left '+' '-'
+%left '*' '/' '%'
+%right POW
+%right '!'
+
+%%
+
+start: command EOF { cmd = $1; bufp = buf; return 0; }+
+index:
+ '[' expr ',' expr ',' expr ']' { $$ = sym("%s,%s,%s", $2, $4, $6); }+
+zindex:
+ index
+| { $$ = "x,y,z"; }+
+newname:
+ NEW { $$ = "new"; }+| NEW NAME { $$ = $2; }+| NAME { $$ = $1; }+
+command:
+ newname zindex '=' expr
+ { newname = $1; $$ = sym("T = %s; *WIMAGE(%s, %s) = CLIP(T);", $4, $1, $2); }+| expr
+ { newname = "new"; $$ = sym("T = %s; *WIMAGE(new, x,y,z) = CLIP(T);", $1); }+
+expr:
+ value
+| fileref
+| 'x' { $$ = "x"; }+| 'y' { $$ = "y"; }+| 'z' { $$ = "z"; }+| 'X' { $$ = "X"; }+| 'Y' { $$ = "Y"; }+| 'Z' { $$ = "Z"; }+| "(" expr ")" { $$ = $2; }+| FN "(" expr ")" { $$ = sym("%s(%s)", $1, $3); }+| '-' expr %prec '!' { $$ = sym("-(%s)", $2); }+| '!' expr { $$ = sym("!(%s)", $2); }+| expr '+' expr { $$ = sym("(%s)+(%s)", $1, $3); }+| expr '-' expr { $$ = sym("(%s)-(%s)", $1, $3); }+| expr '*' expr { $$ = sym("(%s)*(%s)", $1, $3); }+| expr '/' expr { $$ = sym("DIV(%s, %s)", $1, $3); }+| expr '%' expr { $$ = sym("MOD(%s, %s)", $1, $3); }+| expr '<' expr { $$ = sym("(%s) < (%s)", $1, $3); }+| expr '>' expr { $$ = sym("(%s) > (%s)", $1, $3); }+| expr LE expr { $$ = sym("(%s) <= (%s)", $1, $3); }+| expr GE expr { $$ = sym("(%s) >= (%s)", $1, $3); }+| expr EQ expr { $$ = sym("(%s) == (%s)", $1, $3); }+| expr NE expr { $$ = sym("(%s) != (%s)", $1, $3); }+| expr LSH expr { $$ = sym("(%s) << (%s)", $1, $3); }+| expr RSH expr { $$ = sym("(%s) >> (%s)", $1, $3); }+| expr '^' expr { $$ = sym("(%s) ^ (%s)", $1, $3); }+| expr '&' expr { $$ = sym("(%s) & (%s)", $1, $3); }+| expr '|' expr { $$ = sym("(%s) | (%s)", $1, $3); }+| expr AND expr { $$ = sym("(%s) && (%s)", $1, $3); }+| expr OR expr { $$ = sym("(%s) || (%s)", $1, $3); }+| expr '?' expr ':' expr { $$ = sym("(%s) ? (%s) : (%s)", $1, $3, $5); }+| expr POW expr { $$ = sym("POW(%s, %s)", $1, $3); }+
+fileref:
+ NAME zindex { checkref($1); $$ = sym("IMAGE(%s, %s)", $1, $2); }+| "$" NUM zindex { checkrefn($2); $$ = sym("IMAGE(OLD[%d-1], %s)", $2, $3); }+| OLD zindex { checkrefn(1); $$ = sym("IMAGE(old, %s)", $2); }+
+value:
+ NUM { $$ = sym("%d", $1); }+| DBL { $$ = sym("%f", $1); }+
+%%
+
+char *inp;
+
+jmp_buf boomer;
+
+void
+kaboom(char *fmt, ...)
+{+ va_list arg;
+ va_start(arg, fmt);
+ vfprint(2, fmt, arg);
+ va_end(arg);
+ fprint(2, "\n");
+ longjmp(boomer, 1);
+}
+
+void
+yyerror(char *msg)
+{+ kaboom("%s", msg);+}
+
+int
+isnum(Rune r, char *s, char *p)
+{+ if(isdigit(r)
+ || p - s == 1 && (r == 'x' || r == 'X')
+ || p - s > 2 && (s[1] == 'x' || s[1] == 'X') && (r >= 'a' && r <= 'f' || r >= 'A' && r <= 'F'))
+ return 1;
+ else if(r == '.')
+ return 2;
+ else
+ return 0;
+}
+
+int
+getnum(Rune r)
+{+ int n, x, dbl;
+ char s[128], *p;
+
+ for(p=s, n=0, dbl=0; x = isnum(r, s, p); n=chartorune(&r, inp), inp+=n){+ if(p < s+sizeof(s)-1){+ *p++ = (char)r;
+ if(x == 2)
+ dbl = 1;
+ }
+ }
+ *p = 0;
+ inp -= n;
+ if(dbl){+ yylval.d = strtod(s, nil);
+ return DBL;
+ }else{+ yylval.i = strtol(s, nil, 0);
+ return NUM;
+ }
+}
+
+int
+getname(Rune r)
+{+ int n;
+ Rune s[128], *p;
+
+ for(p=s, n=0; isalpharune(r) || isdigitrune(r) || r >= 0x2080 && r <= 0x2089; n=chartorune(&r, inp), inp+=n)
+ if(p < s+nelem(s)-1)
+ *p++ = r;
+ *p = 0;
+ inp -= n;
+ if(runestrcmp(s, L"x") == 0
+ || runestrcmp(s, L"X") == 0
+ || runestrcmp(s, L"y") == 0
+ || runestrcmp(s, L"Y") == 0
+ || runestrcmp(s, L"z") == 0
+ || runestrcmp(s, L"Z") == 0)
+ return s[0];
+ yylval.s = sym("%S", s);+ if(runestrcmp(s, L"new") == 0)
+ return NEW;
+ else if(runestrcmp(s, L"log") == 0
+ || runestrcmp(s, L"sin") == 0
+ || runestrcmp(s, L"cos") == 0
+ || runestrcmp(s, L"sqrt") == 0)
+ return FN;
+ return NAME;
+}
+
+int
+follow2(Rune r0, Rune r1, int op1, Rune r2, int op2)
+{+ int n;
+ Rune r;
+
+ if(*inp == 0)
+ return 0;
+ n = chartorune(&r, inp);
+ if(r == r1){+ inp += n;
+ return op1;
+ }else if(r == r2){+ inp += n;
+ return op2;
+ }
+ return r0;
+}
+
+int
+follow(Rune r0, Rune rr, int op)
+{+ int n;
+ Rune r;
+
+ if(*inp == 0)
+ return 0;
+ n = chartorune(&r, inp);
+ if(r == rr){+ inp += n;
+ return op;
+ }
+ return r0;
+}
+
+int
+yylex(void)
+{+ Rune r;
+
+ for(;;){+ if(*inp == 0)
+ return EOF;
+ inp += chartorune(&r, inp);
+ if(!isspacerune(r))
+ break;
+ }
+ switch(r){+ case '+':
+ case '-':
+ case '/':
+ case '%':
+ case '?':
+ case ':':
+ case '^':
+ case '$':
+ case '[':
+ case ']':
+ case ',':
+ case '(':+ case ')': return r;
+ case '&': return follow(r, '&', AND);
+ case '|': return follow(r, '|', OR);
+ case '*': return follow(r, '*', POW);
+ case '<': return follow2(r, '=', LE, '<', LSH);
+ case '>': return follow2(r, '=', GE, '>', RSH);
+ case '=': return follow(r, '=', EQ);
+ case '!': return follow(r, '=', NE);
+ }
+ if(isdigit(r))
+ return getnum(r);
+ else if(isalpharune(r))
+ return getname(r);
+ kaboom("unexpected %C", r);+ return ERROR;
+}
+
+int
+system(char *s)
+{+ int pid;
+
+ pid = fork();
+ if(pid == 0){+ execl("/bin/rc", "rc", "-c", s, nil);+ _exits(0);
+ }
+ if(pid == -1){+ fprint(2, "fork: %r\n");
+ return -1;
+ }
+ Waitmsg *w;
+ while((w = wait()) != nil && w->pid != pid)
+ ;
+ if(w == nil){+ fprint(2, "%s: wait not found\n", s);
+ return -1;
+ }
+ if(w->msg && w->msg[0]) {+ fprint(2, "%s: failed\n", s);
+ free(w);
+ return -1;
+ }
+ free(w);
+ return 0;
+}
+
+void show(Memimage*);
+
+void
+xquit(int, char **)
+{+ exits(0);
+}
+
+typedef struct File File;
+struct File{+ char *name;
+ char *path;
+ Memimage *m;
+ int ref;
+ int fd;
+};
+File *files;
+int nfiles;
+
+int DX = 248, DY = 248;
+
+Memimage*
+readi(char *name)
+{+ int fd;
+ Memimage *m, *m1;
+
+ if((fd = open(name, OREAD)) < 0){+ fprint(2, "open %s: %r\n", name);
+ return nil;
+ }
+ m = readmemimage(fd);
+ close(fd);
+ if(m == nil){+ fprint(2, "readmemimage: %r\n");
+ return nil;
+ }
+ if(m->chan != ABGR32){+ m1 = allocmemimage(m->r, ABGR32);
+ memfillcolor(m1, DBlack);
+ memimagedraw(m1, m1->r, m, m->r.min, memopaque, ZP, S);
+ freememimage(m);
+ m = m1;
+ }
+ return m;
+}
+
+int
+writei(Memimage *m, char *name, int tmp)
+{+ int fd;
+
+ if((fd = create(name, OWRITE|(tmp?ORCLOSE:0), 0666)) < 0){+ fprint(2, "create %s: %r\n", name);
+ return -1;
+ }
+ if(writememimage(fd, m) < 0){+ close(fd);
+ fprint(2, "writememimage %s: %r\n", name);
+ return -1;
+ }
+ if(tmp)
+ return fd;
+ close(fd);
+ return 0;
+}
+
+Memimage*
+namei(char *name, int warn)
+{+ int i;
+
+ for(i=0; i<nfiles; i++)
+ if(strcmp(name, files[i].name) == 0){+ files[i].ref++;
+ return files[i].m;
+ }
+ if(warn)
+ fprint(2, "no image %s\n", name);
+ return nil;
+}
+
+void
+iput(char *name, Memimage *m, char *path)
+{+ int i;
+
+ for(i=0; i<nfiles; i++)
+ if(name[0] && strcmp(name, files[i].name) == 0){+ freememimage(files[i].m);
+ files[i].m = m;
+ return;
+ }
+ files = realloc(files, ++nfiles*sizeof files[0]);
+ if(strlen(name) == 0)
+ files[i].name = smprint("$%d", i+1);+ else
+ files[i].name = strdup(name);
+ files[i].path = path == nil ? nil : strdup(path);
+ files[i].m = m;
+ files[i].fd = writei(files[i].m, sym("/tmp/pico-run.%d.bit", i), 1);+ DX = Dx(m->r);
+ DY = Dy(m->r);
+}
+
+void
+checkref(char *name)
+{+ if(namei(name, 1) == nil)
+ longjmp(boomer, 1);
+}
+
+void
+checkrefn(int n)
+{+ if(n < 1 || n > nfiles)
+ kaboom("no image $%d", n);+ files[n-1].ref++;
+}
+
+void
+xfiles(int argc, char **)
+{+ int i;
+ if(argc != 1){+ fprint(2, "usage: f\n");
+ return;
+ }
+ for(i=0; i<nfiles; i++)
+ print("$%d %s %s %dx%d\n", i+1, files[i].name, files[i].path ? files[i].path : "", Dx(files[i].m->r), Dy(files[i].m->r));+}
+
+void
+xread(int argc, char **argv)
+{+ Memimage *m;
+
+ if(argc < 2 || argc > 3){+ fprint(2, "usage: r image [filename]\n");
+ return;
+ }
+ m = readi(argc == 3 ? argv[2] : argv[1]);
+ if(m != nil)
+ iput(argv[1], m, argc == 3 ? argv[2] : argv[1]);
+}
+
+void
+xwrite(int argc, char **argv)
+{+ if(argc < 2 || argc > 3){+ fprint(2, "usage: w image [filename]\n");
+ return;
+ }
+ Memimage *m = namei(argv[1], 1);
+ if(m == nil)
+ return;
+ writei(m, argc == 3 ? argv[2] : argv[1], 0);
+}
+
+void
+xdisplay(int argc, char **argv)
+{+ int i;
+
+ if(argc == 1){+ if(nfiles > 0)
+ show(files[nfiles-1].m);
+ return;
+ }
+
+ for(i=1; i<argc; i++){+ Memimage *m = namei(argv[i], 1);
+ if(m)
+ show(m);
+ }
+}
+
+char* prolog =
+ "#include <u.h>\n"
+ "#include <libc.h>\n"
+ "#include <draw.h>\n"
+ "#include <memdraw.h>\n"
+ "\n"
+ "Memimage*\n"
+ "READ(char *file)\n"
+ "{\n"+ " Memimage *m;\n"
+ " int fd = open(file, OREAD);\n"
+ " if(fd < 0) sysfatal(\"open %s: %r\", file);\n"
+ " m = readmemimage(fd);\n"
+ " if(m == nil) sysfatal(\"readmemimage %s: %r\", file);\n"
+ " return m;\n"
+ "}\n\n"
+ "void\n"
+ "WRITE(Memimage *m, char *file)\n"
+ "{\n"+ " int fd = create(file, OWRITE, 0666);\n"
+ " if(fd < 0) sysfatal(\"create %s: %r\", file);\n"
+ " if(writememimage(fd, m) < 0) sysfatal(\"writememimage %s: %r\", file);\n"
+ "}\n\n"
+ "int\n"
+ "POW(int a, int b)\n"
+ "{\n"+ " int t;\n"
+ " if(b <= 0) return 1;\n"
+ " if(b == 1) return a;\n"
+ " t = POW(a, b/2);\n"
+ " t *= t;\n"
+ " if(b%2) t *= a;\n"
+ " return t;\n"
+ "}\n"
+ "\n"
+ "int\n"
+ "DIV(int a, int b)\n"
+ "{\n"+ " if(b == 0) return 0;\n"
+ " return a/b;\n"
+ "}\n"
+ "\n"
+ "int\n"
+ "MOD(int a, int b)\n"
+ "{\n"+ " if(b == 0) return 0;\n"
+ " return a%b;\n"
+ "}\n"
+ "\n"
+ "#define Z 255\n"
+ "\n"
+ "uchar\n"
+ "IMAGE(Memimage *m, int x, int y, int z)\n"
+ "{\n"+ " if(x < 0 || y < 0 || z < 0 || x >= Dx(m->r) || y >= Dy(m->r) || z > 3) return 0;\n"
+ " return byteaddr(m, addpt(m->r.min, Pt(x,y)))[z];\n"
+ "}\n"
+ "\n"
+ "uchar*\n"
+ "WIMAGE(Memimage *m, int x, int y, int z)\n"
+ "{\n"+ " static uchar devnull;\n"
+ " if(x < 0 || y < 0 || z < 0 || x >= Dx(m->r) || y >= Dy(m->r) || z > 3) return &devnull;\n"
+ " return byteaddr(m, addpt(m->r.min, Pt(x,y))) + z;\n"
+ "}\n"
+ "\n"
+ "#define CLIP(x) ((x) < 0 ? 0 : (x) > 255 ? 255 : (x))\n"
+ "\n"
+ "void main(void) {\n"+ " int x, y, z, T;\n"
+ ;
+
+int quiet;
+
+void
+runprog(char *name, char *cmd)
+{+ int i, fd, isnew;
+ Memimage *m;
+
+ if((fd = create("/tmp/pico-run.c", OWRITE, 0666)) < 0){+ fprint(2, "create /tmp/pico-run.c: %r");
+ return;
+ }
+
+ write(fd, prolog, strlen(prolog));
+ fprint(fd, "\tint X = %d, Y = %d;\n", DX, DY);
+ fprint(fd, "\tMemimage *old, *OLD[%d+1];\n", nfiles);
+
+ isnew = namei(name, 0) == nil;
+ if(isnew){+ fprint(fd, "\tMemimage *new = allocmemimage(Rect(0, 0, X, Y), ABGR32);\n");
+ fprint(fd, "\tif(new == nil) sysfatal(\"allocmemimage: %%r\");\n");
+ if(strcmp(name, "new") != 0)
+ fprint(fd, "\tMemimage *%s = new;\n", name);
+ }
+
+ for(i=0; i<nfiles; i++){+ if(!files[i].ref)
+ continue;
+ fprint(fd, "\tOLD[%d] = old = READ(\"/tmp/pico-run.%d.bit\");\n", i, i);
+ if(files[i].name[0] != '$'){+ fprint(fd, "\tMemimage *%s = old;\n", files[i].name);
+ if(strcmp(files[i].name, name) == 0)
+ fprint(fd, "Memimage* new = %s;\n", files[i].name);
+ }
+ }
+
+ fprint(fd, "\tfor(z=0; z<4; z++) for(y=0; y<Y; y++) for(x=0; x<X; x++) {\n");+ fprint(fd, "\t\t%s\n", cmd);
+ fprint(fd, "\t}");
+ fprint(fd, "\tWRITE(new, \"/tmp/pico-run.out.bit\");\n");
+ fprint(fd, "\texits(0);\n}\n");
+ close(fd);
+
+ if(access("/tmp/pico-run.mk", AEXIST) < 0){+ if((fd = create("/tmp/pico-run.mk", OWRITE|ORCLOSE, 0666)) < 0){+ fprint(2, "create /tmp/pico-run.mk: %r");
+ goto cleanup;
+ }
+ fprint(fd, "</$objtype/mkfile\n"
+ "/tmp/pico-run:Q: /tmp/pico-run.c\n"
+ "\t$CC -o /tmp/pico-run.$O /tmp/pico-run.c\n"
+ "\t$LD -o $target /tmp/pico-run.$O\n"
+ "\t$target\n"
+ "\trm -f /tmp/pico-run.$O\n");
+ }
+ if(system("mk -f /tmp/pico-run.mk /tmp/pico-run") < 0)+ goto cleanup;
+
+ m = readi("/tmp/pico-run.out.bit");+ if(m){+ if(strcmp(name, "new") != 0)
+ iput(name, m, nil);
+ else
+ iput("", m, nil);+ if(!quiet)
+ show(m);
+ }
+
+ remove("/tmp/pico-run.c");+cleanup:
+ remove("/tmp/pico-run");+ remove("/tmp/pico-run.out.bit");+ for(i=0; i<nfiles; i++)
+ files[i].ref = 0;
+}
+
+struct {+ char *s;
+ void (*f)(int, char**);
+} cmds[] = {+ "d", xdisplay,
+ "f", xfiles,
+ "q", xquit,
+ "r", xread,
+ "w", xwrite,
+};
+
+void
+main(int argc, char **argv)
+{+ Biobuf b;
+ char *p, *f[10];
+ int nf;
+ int i, l;
+
+ ARGBEGIN{+ case 'q':
+ quiet = 1;
+ break;
+ }ARGEND
+
+ if(memimageinit() < 0)
+ sysfatal("memimageinit: %r");+ Binit(&b, 0, OREAD);
+ setjmp(boomer);
+ for(;;){+ reread:
+ if(!quiet)
+ fprint(2, "-> ");
+ if((p = Brdline(&b, '\n')) == 0)
+ break;
+ p[Blinelen(&b)-1] = 0;
+ while(*p != 0 && isspace(*p))
+ p++;
+ if(*p == 0)
+ goto reread;
+ for(i=0; i<nelem(cmds); i++){+ l = strlen(cmds[i].s);
+ if(strncmp(p, cmds[i].s, l) == 0 && (p[l] == 0 || isspace(p[l]))){+ nf = tokenize(p, f, nelem(f));
+ cmds[i].f(nf, f);
+ goto reread;
+ }
+ }
+
+ inp = p;
+ newname = nil;
+ cmd = nil;
+ yyparse();
+ runprog(newname, cmd);
+ }
+ exits(0);
+}
+
+int
+newwin(void)
+{+ char *srv;
+ char spec[100];
+ int srvfd, pid;
+
+ rfork(RFNAMEG);
+
+ srv = getenv("wsys");+ if(srv == 0){+ fprint(2, "no graphics: $wsys not set\n");
+ return -1;
+ }
+ srvfd = open(srv, ORDWR);
+ free(srv);
+ if(srvfd == -1){+ fprint(2, "no graphics: can't open %s: %r\n", srv);
+ return -1;
+ }
+
+ sprint(spec, "new -dx %d -dy %d -pid 0", DX+8 < 100 ? 100 : DX+8, DY+8 < 48 ? 48 : DY+8);
+ if(mount(srvfd, -1, "/mnt/wsys", 0, spec) == -1){+ fprint(2, "no graphics: mount /mnt/wsys: %r (spec=%s)\n", spec);
+ return -1;
+ }
+ close(srvfd);
+
+ switch(pid = rfork(RFFDG|RFPROC|RFNAMEG|RFENVG|RFNOTEG|RFNOWAIT)){+ case -1:
+ fprint(2, "no graphics: can't fork: %r\n");
+ break;
+ }
+ if(pid == 0)
+ bind("/mnt/wsys", "/dev", MBEFORE);+ else
+ unmount(nil, "/mnt/wsys");
+ return pid;
+}
+
+Image *displayed;
+
+void
+eresized(int new)
+{+ if(new && getwindow(display, Refnone) < 0)
+ fprint(2,"can't reattach to window");
+ draw(screen, screen->r, displayed, nil, displayed->r.min);
+ flushimage(display, 1);
+}
+
+void
+showloop(Memimage *m)
+{+ Rectangle r;
+
+ if(initdraw(0, 0, "pico") < 0){+ fprint(2, "initdraw: %r\n");
+ return;
+ }
+ einit(Emouse|Ekeyboard);
+ if((displayed = allocimage(display, m->r, m->chan, 0, DNofill)) == nil){+ fprint(2, "allocimage: %r\n");
+ return;
+ }
+ r = displayed->r;
+ while(r.min.y < displayed->r.max.y){+ r.max.y = r.min.y + 1;
+ if(loadimage(displayed, r, byteaddr(m, r.min), Dx(r)*m->depth/8) < 0){+ fprint(2, "loadimage: %r\n");
+ return;
+ }
+ r.min.y++;
+ }
+ close(0);
+ eresized(0);
+ for(;;){+ Event e;
+ flushimage(display, 0);
+ switch(eread(Emouse|Ekeyboard, &e)){+ case Ekeyboard:
+ if(e.kbdc == 'q')
+ return;
+ eresized(0);
+ break;
+ case Emouse:
+ if(e.mouse.buttons&4)
+ return;
+ break;
+ }
+ }
+}
+
+void
+show(Memimage *m)
+{+ DX = Dx(m->r);
+ DY = Dy(m->r);
+ if(newwin() != 0)
+ return;
+ showloop(m);
+ exits(0);
+}
--
⑨