ref: f7cd83ffe6a65578a9f1c89646facbcbfd7179a1
parent: 75e473f518dc4a649638bf69fbfa1c48a16a7388
author: qwx <[email protected]>
date: Wed Jan 22 09:28:50 EST 2020
reimplement without yacc, only to understand that yacc remains a good idea this fixes a number of issues in the previous implementation, however.
--- /dev/null
+++ b/dat.h
@@ -1,0 +1,20 @@
+typedef struct Sym Sym;
+
+extern char wdir[], pref[];
+extern char **tok;
+extern int ntok;
+
+struct Sym{
+ int ref;
+ char *iname;
+ char *cname;
+ char *name;
+ char *path;
+};
+extern Sym *sym;
+extern int nsym;
+extern int Δx, Δy;
+
+extern char *prolog, *prepstr, *tailstr;
+
+extern int quiet;
--- /dev/null
+++ b/defs.c
@@ -1,0 +1,110 @@
+#include <u.h>
+#include <libc.h>
+#include "dat.h"
+#include "fns.h"
+
+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"
+" int fd;\n"
+" Memimage *m, *m1;\n"
+" if((fd = open(file, OREAD)) < 0)\n"
+" sysfatal(\"open: %r\");\n"
+" if((m = readmemimage(fd)) == nil)\n"
+" sysfatal(\"readmemimage: %r\");\n"
+" close(fd);\n"
+" if(m->chan != ABGR32){\n"
+" m1 = allocmemimage(m->r, ABGR32);\n"
+" memfillcolor(m1, DBlack);\n"
+" memimagedraw(m1, m1->r, m, m->r.min, memopaque, ZP, S);\n"
+" freememimage(m);\n"
+" m = m1;\n"
+" }\n"
+" return m;\n"
+"}\n\n"
+"void\n"
+"WRITE(Memimage *m, char *file)\n"
+"{\n"
+" int fd;\n"
+" if((fd = create(file, OWRITE, 0666)) < 0)\n"
+" sysfatal(\"create: %r\");\n"
+" if(writememimage(fd, m) < 0)\n"
+" sysfatal(\"writememimage: %r\");\n"
+" close(fd);\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"
+"RIMAGE(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, X, Y, T;\n"
+" Memimage *﹩new;\n"
+" if(memimageinit() < 0) sysfatal(\"initmemimage: %r\");\n"
+;
+
+char *prepstr =
+" for(﹩i=﹩im; ﹩i<﹩im+nelem(﹩im); ﹩i++){\n"
+" if(*﹩i == nil) continue;\n"
+" if(X < Dx((*﹩i)->r)) X = Dx((*﹩i)->r);\n"
+" if(Y < Dy((*﹩i)->r)) Y = Dy((*﹩i)->r);\n"
+" }\n"
+" if((﹩new = allocmemimage(Rect(0,0,X,Y), ABGR32)) == nil)\n"
+" sysfatal(\"allocmemimage: %r\");\n"
+" for(z=0; z<4; z++) for(y=0; y<Y; y++) for(x=0; x<X; x++){\n"
+;
+
+char *tailstr =
+";\n"
+" *WIMAGE(﹩new, x,y,z) = CLIP(T);\n"
+" }\n"
+" WRITE(﹩new, out);\n"
+" exits(nil);\n"
+"}\n"
+;
--- a/examples
+++ b/examples
@@ -1,20 +1,29 @@
; hget http://9front.org/img/9bind.png | png -t9 > /tmp/bind
; hget http://9front.org/img/ninefront.bit > /tmp/nine
-; pico
-# combining two images
--> r nine /tmp/nine
--> r bind /tmp/bind
--> bind + (y > 100 ? nine[x,y-100,z] : 0)
+
+; pixo <<EOF
+# read in images
+r nine /tmp/nine
+r bind /tmp/bind
+# combine two images at an offset
+bind + (y > 100 ? nine[x,y-100,z] : 0)
# extract red and alpha channels
--> z == 3 ? bind : z == 0 ? bind : 0
+z == 3 ? bind : z == 0 ? bind : 0
# halve color intensity
--> z < 3 ? bind/2 : Z
+z < 3 ? bind/2 : Z
# set black pixels' alpha to 0
--> bind[x,y,0] + bind[x,y,1] + bind[x,y,2] == 0 && z == 3 ? 0 : bind
+bind[x,y,0] + bind[x,y,1] + bind[x,y,2] == 0 && z == 3 ? 0 : bind
# set black pixels to cyan
bind[x,y,0] + bind[x,y,1] + bind[x,y,2] == 0 ? z == 0 ? 0 : z == 1 ? Z : z == 2 ? Z : bind : bind
+EOF
+
+
# doug demo
--> lerp = z != 3 ? (x < X/3 ? 0 : x > 2*X/3 ? 255 : (x-X/3)*Z/(X/3)) : Z
--> rbind = bind[X-x,y,z]
--> z != 3 ? (bind*lerp+rbind*(Z-lerp))/Z : Z
--> z != 3 ? (rbind*lerp+bind*(Z-lerp))/Z : Z
+; pixo -q <<EOF
+r bind /tmp/bind
+lerp = z != 3 ? (x < X/3 ? 0 : x > 2*X/3 ? 255 : (x-X/3)*Z/(X/3)) : Z
+rbind = bind[X-x,y,z]
+z != 3 ? (bind*lerp+rbind*(Z-lerp))/Z : Z
+z != 3 ? (rbind*lerp+bind*(Z-lerp))/Z : Z
+d
+EOF
--- /dev/null
+++ b/exec.c
@@ -1,0 +1,120 @@
+#include <u.h>
+#include <libc.h>
+#include <plumb.h>
+#include "dat.h"
+#include "fns.h"
+
+char wdir[1024], pref[64];
+char **tok;
+int ntok;
+
+static int plumbfd, mkfd;
+
+void
+show(char *path)
+{
+ if(plumbfd < 0)
+ return;
+ if(plumbsendtext(plumbfd, "pixo", nil, wdir, path) < 0)
+ fprint(2, "plumbsendtext: %r\n");
+}
+
+static int
+system(char *cmd)
+{
+ int r, argc, pid;
+ char name[64], *argv[32];
+ Waitmsg *w;
+
+ argc = tokenize(cmd, argv, nelem(argv)-1);
+ argv[argc] = nil;
+ snprint(name, sizeof name, "/bin/%s", argv[0]);
+ switch(pid = fork()){
+ case -1:
+ fprint(2, "fork: %r\n");
+ return -1;
+ case 0:
+ USED(pid);
+ exec(name, argv);
+ sysfatal("execl: %r");
+ }
+ if((w = wait()) == nil){
+ fprint(2, "system: lost children\n");
+ return -1;
+ }
+ r = 0;
+ if(w->msg != nil && w->msg[0] != 0){
+ fprint(2, "system: failure: %s\n", w->msg);
+ r = -1;
+ }
+ free(w);
+ /* FIXME: clean up temp files */
+ return r;
+}
+
+char *
+execute(void)
+{
+ int fd;
+ char **p, cmd[128];
+ Sym *s;
+ static char path[128];
+
+ snprint(path, sizeof path, "%s.c", pref);
+ if((fd = create(path, OWRITE, 0666)) < 0){
+ fprint(2, "create: %r");
+ return nil;
+ }
+ write(fd, prolog, strlen(prolog));
+ snprint(path, sizeof path, "%s.%d.bit", pref, nsym + 1);
+ fprint(fd,
+ " Memimage **﹩i, *﹩im[%d];\n"
+ " char *out = \"%s\";\n",
+ nsym > 0 ? nsym : 1, path);
+ for(s=sym; s<sym+nsym; s++)
+ if(s->ref)
+ fprint(fd, " ﹩im[%zd] = READ(\"%s\");\n",
+ s-sym, s->path);
+ fprint(fd,
+ " X = %d;\n"
+ " Y = %d;\n",
+ Δx, Δy);
+ write(fd, prepstr, strlen(prepstr));
+ fprint(fd, " T = ");
+ for(p=tok; p<tok+ntok; p++)
+ write(fd, *p, strlen(*p));
+ write(fd, tailstr, strlen(tailstr));
+ close(fd);
+ snprint(cmd, sizeof cmd, "mk -f %s.mk %s", pref, pref);
+ if(system(cmd) < 0)
+ return nil;
+ return path;
+}
+
+static void
+mkfile(void)
+{
+ char path[64];
+
+ snprint(path, sizeof path, "%s.mk", pref);
+ if((mkfd = create(path, OWRITE|ORCLOSE, 0666)) < 0)
+ sysfatal("mkfile: %r");
+ fprint(mkfd,
+ "</$objtype/mkfile\n"
+ "%s:Q: %s.c\n"
+ " $CC $CFLAGS -o %s.$O $prereq\n"
+ " $LD -o $target %s.$O\n"
+ " $target\n"
+ " rm -f $target $prereq %s.$O\n",
+ pref, pref, pref, pref, pref);
+}
+
+void
+initfiles(void)
+{
+ getwd(wdir, sizeof wdir);
+ snprint(pref, sizeof pref, "/tmp/pixo.%d", getpid());
+ mkfile();
+ if((plumbfd = plumbopen("send", OWRITE)) < 0)
+ fprint(2, "plumbopen: %r\n");
+}
--- /dev/null
+++ b/fns.h
@@ -1,0 +1,4 @@
+void show(char*);
+char* execute(void);
+void initfiles(void);
+void parse(char*);
--- a/mkfile
+++ b/mkfile
@@ -1,6 +1,11 @@
</$objtype/mkfile
-YFILES=pixo.y
-OFILES=y.tab.$O
BIN=$home/bin/$objtype
TARG=pixo
+OFILES=\
+ defs.$O\
+ exec.$O\
+ parse.$O\
+ pixo.$O\
+
+HFILES=dat.h fns.h
</sys/src/cmd/mkone
--- /dev/null
+++ b/parse.c
@@ -1,0 +1,432 @@
+#include <u.h>
+#include <libc.h>
+#include <ctype.h>
+#include "dat.h"
+#include "fns.h"
+
+Sym *sym;
+int nsym;
+int Δx, Δy;
+
+static char*
+esmprint(char *fmt, ...)
+{
+ char *p;
+ va_list arg;
+
+ va_start(arg, fmt);
+ p = vsmprint(fmt, arg);
+ va_end(arg);
+ if(p == nil)
+ sysfatal("smprint: %r");
+ return p;
+}
+
+static char *
+estrdup(char *s)
+{
+ if((s = strdup(s)) == nil)
+ sysfatal("estrdup: %r");
+ setmalloctag(s, getcallerpc(&s));
+ return s;
+}
+
+static void *
+erealloc(void *p, ulong n)
+{
+ if((p = realloc(p, n)) == nil)
+ sysfatal("realloc: %r");
+ setmalloctag(p, getcallerpc(&p));
+ return p;
+}
+
+static void *
+emalloc(ulong n)
+{
+ void *p;
+
+ if((p = mallocz(n, 1)) == nil)
+ sysfatal("emalloc: %r");
+ setmalloctag(p, getcallerpc(&n));
+ return p;
+}
+
+static void
+nuketok(void)
+{
+ char **p;
+
+ for(p=tok; p<tok+ntok; p++)
+ free(*p);
+ free(tok);
+ tok = nil;
+ ntok = 0;
+}
+
+static char **
+newtok(char *s)
+{
+ char **p;
+
+ tok = erealloc(tok, ++ntok * sizeof *tok);
+ p = tok + ntok - 1;
+ *p = s;
+ return p;
+}
+
+static char *
+addtok(char *s, int n)
+{
+ char **p;
+
+ p = newtok(s);
+ *p = emalloc(n + 1);
+ memcpy(*p, s, n);
+ return *p;
+}
+
+static Sym *
+newsym(char *name)
+{
+ Sym *s;
+
+ sym = erealloc(sym, ++nsym * sizeof *sym);
+ s = sym + nsym - 1;
+ s->iname = esmprint("$%zd", s - sym + 1);
+ s->cname = esmprint("﹩im[%zd]", s - sym);
+ s->name = name == nil ? esmprint("﹩%zd", s - sym + 1) : estrdup(name);
+ return s;
+}
+
+static Sym *
+getsym(char *name, int n)
+{
+ Sym *s;
+
+ if(n == 0)
+ n = strlen(name);
+ for(s=sym; s<sym+nsym; s++)
+ if(strncmp(s->name, name, n) == 0 && strlen(s->name) == n
+ || strncmp(s->iname, name, n) == 0 && strlen(s->iname) == n)
+ return s;
+ return nil;
+}
+
+static Sym *
+addsym(char *name)
+{
+ Sym *s;
+
+ if((s = getsym(name, 0)) == nil)
+ s = newsym(name);
+ return s;
+}
+
+static void
+cleanup(void)
+{
+ Sym *s;
+
+ nuketok();
+ for(s=sym; s<sym+nsym; s++)
+ s->ref = 0;
+}
+
+static void
+fnwrite(int argc, char **argv)
+{
+ int n, fd, dfd;
+ uchar buf[65536];
+ Sym *s;
+
+ if(argc != 3){
+ fprint(2, "usage: w name path\n");
+ return;
+ }
+ if((s = getsym(argv[1], 0)) == nil){
+ fprint(2, "fnwrite: no such image %s\n", argv[1]);
+ return;
+ }
+ if(strcmp(argv[2], s->path) == 0){
+ fprint(2, "not overwriting image with itself\n");
+ return;
+ }
+ if((fd = open(s->path, OREAD)) < 0){
+ fprint(2, "open: %r\n");
+ return;
+ }
+ if((dfd = create(argv[2], OWRITE, 0666)) < 0){
+ fprint(2, "create: %r\n");
+ return;
+ }
+ while((n = read(fd, buf, sizeof buf)) > 0)
+ if(write(dfd, buf, n) != n){
+ n = -1;
+ break;
+ }
+ close(fd);
+ close(dfd);
+ if(n < 0)
+ fprint(2, "fnwrite: %r\n");
+}
+
+static void
+fnadd(int argc, char **argv)
+{
+ char *path;
+ Sym *s;
+
+ if(argc < 2 || argc > 3){
+ fprint(2, "usage: r name [path]\n");
+ return;
+ }
+ s = addsym(argv[1]);
+ path = argc < 3 ? argv[1] : argv[2];
+ if(access(path, OREAD) < 0){
+ fprint(2, "access %s: %r\n", path);
+ return;
+ }
+ s->path = esmprint("%s%s%s",
+ path[0] == '/' ? "" : wdir,
+ path[0] == '/' ? "" : "/",
+ path);
+}
+
+static void
+fndisplay(int argc, char **argv)
+{
+ int i;
+ Sym *s;
+
+ if(argc == 1){
+ if(nsym > 0)
+ show(sym[nsym-1].path);
+ return;
+ }
+ for(i=1; i<argc; i++){
+ if((s = getsym(argv[i], 0)) != nil)
+ show(s->path);
+ else
+ fprint(2, "fndisplay: no such image %s\n", argv[i]);
+ }
+}
+
+static void
+fnsize(int argc, char **argv)
+{
+ char *p;
+
+ if(argc != 3){
+ fprint(2, "usage: s width height\n");
+ return;
+ }
+ Δx = strtol(argv[1], &p, 0);
+ if(p == argv[1]){
+ fprint(2, "fnsize: invalid width\n");
+ return;
+ }
+ Δy = strtol(argv[2], &p, 0);
+ if(p == argv[1])
+ fprint(2, "fnsize: invalid height\n");
+}
+
+static void
+fnfiles(int, char **)
+{
+ Sym *s;
+
+ for(s=sym; s<sym+nsym; s++)
+ print("%s %s %s\n", s->iname, s->name, s->path);
+}
+
+static int
+command(char *p)
+{
+ struct{
+ char *name;
+ void (*fn)(int, char**);
+ } *cp, cmd[] = {
+ "f", fnfiles,
+ "s", fnsize,
+ "r", fnadd,
+ "w", fnwrite,
+ "d", fndisplay
+ };
+ int n;
+ char *f[16];
+
+ for(cp=cmd; cp<cmd+nelem(cmd); cp++){
+ n = strlen(cp->name);
+ if(strncmp(p, cp->name, n) == 0
+ && (p[n] == 0 || isspace(p[n]))){
+ n = tokenize(p, f, nelem(f));
+ cp->fn(n, f);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int
+isbuiltin(char *p, int n)
+{
+ char **fp, *fn[] = {
+ "X", "Y", "Z",
+ "x", "y", "z"
+ };
+
+ for(fp=fn; fp<fn+nelem(fn); fp++)
+ if(strncmp(p, *fp, n) == 0 && strlen(*fp) == n)
+ return 1;
+ return 0;
+}
+
+static int
+mkcoords(char *s, char *e)
+{
+ char *p, **cp, *c[2] = {nil};
+
+ while(isspace(*s))
+ s++;
+ for(p=s+1, cp=c; p<e; p++){
+ if(*p == ']'){
+ *p = 0;
+ break;
+ }else if(*p == ','){
+ if(cp >= c + nelem(c)){
+ fprint(2, "invalid index spec\n");
+ return -1;
+ }
+ *p = 0;
+ *cp++ = p + 1;
+ }
+ }
+ p = esmprint(", %s,%s,%s)", s+1,
+ c[0] != nil ? c[0] : "y",
+ c[1] != nil ? c[1] : "z");
+ newtok(p);
+ return 0;
+}
+
+static int
+getcoords(char *s)
+{
+ char *p;
+
+ for(p=s; *p!=']' && *p!=0; p++)
+ ;
+ return *p == 0 ? -1 : p + 2 - s;
+}
+
+static int
+peekrune(char *p, Rune ro)
+{
+ Rune r;
+
+ while(isspace(*p))
+ p++;
+ chartorune(&r, p);
+ return r == ro;
+}
+
+static int
+notaword(Rune r)
+{
+ char *o, *op = "+-*/%?:^,&|<>=![], ()";
+
+ if(isdigitrune(r))
+ return 1;
+ for(o=op; o<op+strlen(op); o++)
+ if(r == *o)
+ return 1;
+ return 0;
+}
+
+static int
+getname(char *s)
+{
+ char *p, *q;
+ Rune r;
+
+ q = p = s + chartorune(&r, s);
+ while(r != 0 && !notaword(r) && !isspace(r)){
+ q = p;
+ p += chartorune(&r, p);
+ }
+ return q - s;
+}
+
+void
+parse(char *s)
+{
+ int n, m, nchar;
+ char *p, *new;
+ Rune r;
+ Sym *sp;
+
+ for(p=s, nchar=0, new=nil; *p != 0; p++){
+ if(isspace(*p))
+ continue;
+ if(nchar == 0 && command(p))
+ return;
+ if(*p == '#')
+ break;
+ nchar++;
+ n = chartorune(&r, p);
+ if(notaword(r))
+ goto next;
+ n = getname(p);
+ if(peekrune(p + n, '('))
+ goto next;
+ if(isbuiltin(p, n))
+ goto next;
+ if((sp = getsym(p, n)) == nil){
+ if(nchar > 1 || !peekrune(p + n, '=')){
+ s = emalloc(n + 1);
+ memcpy(s, p, n);
+ fprint(2, "unknown symbol %s\n", s);
+ free(s);
+ goto end;
+ }
+ new = emalloc(n + 1);
+ memcpy(new, p, n);
+ while(isspace(p[n]))
+ n++;
+ n++;
+ s = p + n;
+ goto next;
+ }
+ addtok(s, p - s);
+ sp->ref = 1;
+ newtok(estrdup("RIMAGE("));
+ newtok(estrdup(sp->cname));
+ s = p + n;
+ if(!peekrune(s, '[')){
+ newtok(estrdup(",x,y,z)"));
+ goto next;
+ }
+ if((m = getcoords(s)) < 0){
+ fprint(2, "syntax error: no matching ]\n");
+ goto end;
+ }
+ if(mkcoords(s, s + m - 1) < 0)
+ goto end;
+ s += m;
+ p += m - 1;
+ next:
+ p += n - 1;
+ }
+ if(nchar == 0)
+ return;
+ if(p > s)
+ addtok(s, p - s);
+ if((p = execute()) != nil){
+ sp = newsym(new);
+ sp->path = estrdup(p);
+ if(!quiet)
+ show(p);
+ }
+end:
+ free(new);
+ cleanup();
+}
--- /dev/null
+++ b/pixo.c
@@ -1,0 +1,30 @@
+#include <u.h>
+#include <libc.h>
+#include <ctype.h>
+#include <bio.h>
+#include "dat.h"
+#include "fns.h"
+
+int quiet;
+
+void
+main(int argc, char **argv)
+{
+ char *s;
+ Biobuf *bf;
+
+ ARGBEGIN{
+ case 'q': quiet = 1; break;
+ }ARGEND
+ initfiles();
+ if((bf = Bfdopen(0, OREAD)) == nil)
+ sysfatal("Bfdopen: %r");
+ for(;;){
+ if(!quiet)
+ print("→ ");
+ if((s = Brdstr(bf, '\n', 1)) == nil)
+ break;
+ parse(s);
+ free(s);
+ }
+}
--- a/pixo.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);
-}