ref: 90c1e6b8bad7302018388c4e9c1d30fd975ad134
dir: /pico.y/
%{
#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);
}