%{
#include <u.h>
#include <libc.h>
#include <ctype.h>
#include <bio.h>
#include <draw.h>
#include <event.h>
#include <memdraw.h>
#define DX 248
#define DY 248
#ifdef USED /* plan9port */
#define system system9
#define CC "9c"
#define LD "9l"
#else
#define CC "8c"
#define LD "8l"
#endif
char *newname;
char *cmd;
Fmt codefmt;
int yylex(void);
int yyparse(void);
void yyerror(char*);
void checkref(char*);
void checkrefn(int);
%}
%union
{
char* s;
int i;
}
%token NAME NEW OLD NUM EOF ERROR
%token <s> FN NAME
%type <s> index zindex newname command expr fileref value
%type <i> NUM
%right '='
%right '?' ':'
%left '|'
%left '^'
%left '&'
%left EQ NE
%right LSH RSH
%left '<' '>' LE GE
%left '+' '-'
%left '*' '/' '%'
%right POW
%right '!'
%%
start: command EOF { cmd = $1; return 0; }
index:
'[' expr ',' expr ']' { $$ = smprint("%s, %s", $2, $4); }
zindex:
index
| { $$ = "x, y"; }
newname:
NEW { $$ = "new"; }
| NEW NAME { $$ = $2; }
| NAME { $$ = $1; }
command:
newname zindex '=' expr
{ newname = $1; $$ = smprint("T = %s; *WIMAGE(%s, %s) = CLIP(T);", $4, $1, $2); }
| expr
{ newname = "new"; $$ = smprint("T = %s; *WIMAGE(new, x,y) = CLIP(T);", $1); }
expr:
value
| fileref
| 'x' { $$ = "x"; }
| 'y' { $$ = "y"; }
| 'X' { $$ = "X"; }
| 'Y' { $$ = "Y"; }
| 'Z' { $$ = "Z"; }
| "(" expr ")" { $$ = $2; }
| FN "(" expr ")" { $$ = smprint("%s(%s)", $1, $3); }
| '-' expr %prec '!' { $$ = smprint("-(%s)", $2); }
| '!' expr { $$ = smprint("!(%s)", $2); }
| expr '+' expr { $$ = smprint("(%s)+(%s)", $1, $3); }
| expr '-' expr { $$ = smprint("(%s)-(%s)", $1, $3); }
| expr '*' expr { $$ = smprint("(%s)*(%s)", $1, $3); }
| expr '/' expr { $$ = smprint("DIV(%s, %s)", $1, $3); }
| expr '%' expr { $$ = smprint("MOD(%s, %s)", $1, $3); }
| expr '<' expr { $$ = smprint("(%s) < (%s)", $1, $3); }
| expr '>' expr { $$ = smprint("(%s) > (%s)", $1, $3); }
| expr LE expr { $$ = smprint("(%s) <= (%s)", $1, $3); }
| expr GE expr { $$ = smprint("(%s) >= (%s)", $1, $3); }
| expr EQ expr { $$ = smprint("(%s) == (%s)", $1, $3); }
| expr NE expr { $$ = smprint("(%s) != (%s)", $1, $3); }
| expr LSH expr { $$ = smprint("(%s) << (%s)", $1, $3); }
| expr RSH expr { $$ = smprint("(%s) >> (%s)", $1, $3); }
| expr '^' expr { $$ = smprint("(%s) ^ (%s)", $1, $3); }
| expr '&' expr { $$ = smprint("(%s) & (%s)", $1, $3); }
| expr '|' expr { $$ = smprint("(%s) | (%s)", $1, $3); }
| expr '?' expr ':' expr { $$ = smprint("(%s) ? (%s) : (%s)", $1, $3, $5); }
| expr POW expr { $$ = smprint("POW(%s, %s)", $1, $3); }
fileref:
NAME zindex { checkref($1); $$ = smprint("IMAGE(%s, %s)", $1, $2); }
| "$" NUM zindex { checkrefn($2); $$ = smprint("IMAGE(OLD[%d-1], %s)", $2, $3); }
| OLD zindex { checkrefn(1); $$ = smprint("IMAGE(old, %s)", $2); }
value:
NUM { $$ = smprint("%d", $1); }
%%
char *inp;
#define follow(x, y) (*inp == x ? (inp++, y) : c)
#define follow2(x, y, x1, y1) (*inp == x ? (inp++, y) : *inp == x1 ? (inp++, y1) : c)
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
yylex()
{
int c;
while((c = *inp) != 0 && isspace(c))
inp++;
if(c == 0)
return EOF;
inp++;
switch(c){
case '+':
case '-':
case '/':
case '%':
case '?':
case ':':
case '|':
case '^':
case '&':
case '$':
case '[':
case ']':
case ',':
case 'X':
case 'Y':
case 'Z':
case '(':
case ')':
return c;
case '*':
return follow('*', POW);
case '<':
return follow2('=', LE, '<', LSH);
case '>':
return follow2('=', GE, '>', RSH);
case '=':
return follow('=', EQ);
case '!':
return follow('=', NE);
}
if(isdigit(c)){
int n = c - '0';
while((c = *inp) != 0 && isdigit(c)) {
n = n * 10 + c - '0';
inp++;
}
yylval.i = n;
return NUM;
}
if(islower(c)){
char buf[100];
char *p = buf;
char *ep = buf+sizeof buf-1;
*p++ = c;
while(p<ep && islower(*inp))
*p++ = *inp++;
*p = 0;
if(buf[1]==0 && (buf[0]=='x' || buf[0]=='y'))
return buf[0];
yylval.s = strdup(buf);
if(strcmp(buf, "new") == 0)
return NEW;
if(strcmp(buf, "log") == 0 || strcmp(buf, "sin") == 0 || strcmp(buf, "cos") == 0 || strcmp(buf, "sqrt") == 0)
return FN;
return NAME;
}
kaboom("unexpected %c", c);
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);
return -1;
}
return 0;
}
void show(Memimage*);
void
xquit(int argc, char **argv)
{
USED(argc);
USED(argv);
exits(0);
}
struct {
char *name;
char *path;
Memimage *m;
int ref;
} *files;
int nfiles;
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)
{
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]);
files[i].name = strdup(name);
files[i].path = nil;
files[i].m = m;
}
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++;
}
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 != GREY8 || !eqrect(m->r, Rect(0, 0, DX, DY))){
m1 = allocmemimage(Rect(0, 0, DX, DY), GREY8);
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 fd;
if((fd = create(name, OWRITE, 0666)) < 0){
fprint(2, "create %s: %r\n", name);
return -1;
}
if(writememimage(fd, m) < 0){
fprint(2, "writememimage %s: %r\n", name);
close(fd);
return -1;
}
close(fd);
return 0;
}
void
xfiles(int argc, char **argv)
{
USED(argv);
int i;
if(argc != 1){
fprint(2, "usage: f\n");
return;
}
for(i=0; i<nfiles; i++)
print("$%d %s %s\n", i+1, files[i].name, files[i].path ? files[i].path : "");
}
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]);
iput(argv[1], m);
}
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]);
}
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 X 248\n"
"#define Y 248\n"
"#define Z 255\n"
"\n"
"uchar\n"
"IMAGE(uchar *p, int x, int y)\n"
"{\n"
" if(x < 0 || y < 0 || x >= X || y >= Y) return 0;\n"
" return p[y*X+x];\n"
"}\n"
"\n"
"uchar*\n"
"WIMAGE(uchar *p, int x, int y)\n"
"{\n"
" static uchar devnull;\n"
" if(x < 0 || y < 0 || x >= X || y >= Y) return &devnull;\n"
" return &p[y*X+x];\n"
"}\n"
"\n"
"#define CLIP(x) ((x) < 0 ? 0 : (x) > 255 ? 255 : (x))\n"
"\n"
"void main(void) {\n"
" int x, y, 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, "\tuchar* OLD[%d+1]; USED(OLD);\n", nfiles);
fprint(fd, "\tuchar* old = 0; USED(old);\n");
fprint(fd, "\tMemimage *M[%d+1];\n", nfiles);
isnew = namei(name, 0) == 0;
if(isnew){
fprint(fd, "\tMemimage *NEW = allocmemimage(Rect(0, 0, X, Y), GREY8);\n");
fprint(fd, "\tif(NEW == nil) sysfatal(\"allocmemimage: %%r\");\n");
fprint(fd, "\tuchar* %s = NEW->data->bdata;\n", name);
}
for(i=0; i<nfiles; i++){
fprint(fd, "\tM[%d] = READ(\"/tmp/pico-run.%d.png\");\n", i, i);
fprint(fd, "\t%s %s %s old = OLD[%d] = M[%d]->data->bdata;\n", *files[i].name ? "uchar* " :"", files[i].name, *files[i].name ? " = " : "", i, i);
if(strcmp(files[i].name, name) == 0)
fprint(fd, "Memimage* NEW = M[%d];\n", i);
}
fprint(fd, "\tfor(x=0; x<%d; x++) for(y=0; y<%d; y++) {\n", DX, DY);
fprint(fd, "\t\t%s\n", cmd);
fprint(fd, "\t}");
fprint(fd, "\tWRITE(NEW, \"/tmp/pico-run.out.png\");\n");
fprint(fd, "\texits(0);\n}\n");
close(fd);
if(system(CC " -o /tmp/pico-run.o /tmp/pico-run.c") < 0)
goto cleanup;
if(system(LD " -o /tmp/pico-run /tmp/pico-run.o") < 0)
goto cleanup;
for(i=0; i<nfiles; i++)
writei(files[i].m, smprint("/tmp/pico-run.%d.png", i));
if(system("/tmp/pico-run") < 0)
goto cleanup;
m = readi("/tmp/pico-run.out.png");
if(m){
if(strcmp(name, "new") != 0)
iput(name, m);
else
iput("", m);
if(!quiet)
show(m);
}
remove("/tmp/pico-run.c");
cleanup:
remove("/tmp/pico-run.o");
remove("/tmp/pico-run");
remove("/tmp/pico-run.out.png");
for(i=0; i<nfiles; i++)
remove(smprint("/tmp/pico-run.%d.png", i));
}
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
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);
}
#ifdef USED /* plan9port */
void
doresize(void)
{
// wish this worked
drawresizewindow(Rect(0, 0, DX, DY));
}
int
newwin(void)
{
int pid;
winsize = "248x248";
notedisable("sys: child");
pid = rfork(RFPROC|RFFDG|RFNOWAIT);
if(pid < 0)
fprint(2, "fork: %r\n");
return pid;
}
#else /* plan 9 */
void
doresize(void)
{
}
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, DY);
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;
}
#endif
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, ZP);
flushimage(display, 1);
}
void
showloop(Memimage *m)
{
if(initdraw(0, 0, "pico") < 0){
fprint(2, "initdraw: %r\n");
return;
}
einit(Emouse|Ekeyboard);
doresize();
if((displayed = allocimage(display, Rect(0, 0, DX, DY), GREY8, 0, DBlack)) == nil){
fprint(2, "allocimage: %r\n");
return;
}
if(loadimage(displayed, displayed->r, byteaddr(m, ZP), DX*DY) < 0){
fprint(2, "loadimage: %r\n");
return;
}
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)
{
if(newwin() != 0)
return;
showloop(m);
exits(0);
}
|