341 lines · 4.4 KB · C
RawDownload
#include <u.h>#include <libc.h> char *ntab[] = {	0,	"sqrt 9 - {sqrt {9}!} over {sqrt 9}")	"sqrt 9 - 9 over 9")	"sqrt {9}! - 9 over {sqrt 9}")	"sqrt 9 + 9 over 9")	"sqrt {9}! - 9 over 9")	"9-{9 over {sqrt 9}}")	"sqrt {9}! + 9 over 9")	"9 - 9 over 9")	"sqrt {9}! + 9 over {sqrt 9}")	"sqrt 9 + 9 over 9")	"9 +  {sqrt {9}!} over {sqrt 9}")	"9+{9 over {sqrt 9}}"}; enum{	Vbox,	Hbox	Tbox,}; typedef struct Box Box;struct Box{	Box	*next;	Point	sz;		/* computed size */	Rect	glue;		/* additional space around edges */	Image	*img;	int	type; 	int	nelem;		/* leaves */	Font	*font;	union{		char *s;		Point pt;	} e[];}; typedef struct{	char	tok[50];	int	ntok;	int	ttype;	int	eof;	Font	*font;	Box	*b, *c;	char	*s;}Lex; Lex ldat; enum{	End,	Sqrt,	Over,	Text,	Left,}; Pointboxsize(Box *b){	Box *prev;	Pt p, p1;	int mode; 	p = Pt(0, 0);	mode = Hbox;loop:	switch(t->type){	case Vbox:	case Hbox:		mode = t->type;		goto step;	} 	if(b->sz.x > 0 || b->sz.y > 0)		p1 = b->sz;	else		p1 = Point(stringwidth(b->font, b->tok), font->height); 	switch(mode){	case Hbox:		if(p1.y > p.y)			p.y = p1.y;		p.x += p1.x;		break;	case Vbox:		if(p1.x > p.x)			p.x = p1.x;		p.y += p1.y;	} step:	b = b->next;	if(b)		goto loop;	return p;} Box*appendbox(Box *h, Box *b){	if(h){		p = h;		while(p->next)			p = p->next;		p->next = b;	} else		h = b;	return h;} Box*newbox(int type, void *e, int ne){	Box *b, *p; 	b = malloc(sizeof *b+ne);	b->font = ldat.font;	memset(b, 0, sizeof b);	memcpy(b->e, e, ne);	return b;} struct{	int	type;	char	*tok;	int	len;}key[] = {	Over,	"over",	4,	Sqrt,	"sqrt",	4,}; intlex0(Lex *l){	int c; 	while(isspace(*l->s))		l->s++;	l->ntok = 0; 	switch(c = *l->s++){	case 0:		return 0;	case '{':	case '}':		return c;	default:	loop:		if(l->ntok == nelem(l->tok)-1)			sysfatal("token too long");		l->tok[l->ntok++] = c;		c = *l->s++;		if(isalpha(c) || isdigit(c))			goto loop;		for(i = 0; i < nelem(key); i++)			if(key[i].len == l->ntok)			if(memcmp(key[i].tok, l->tok, l->ntok) == 0){				l->ntok = 0;				return key[i].type;			}		l->ok[l->ntok] = 0;		/* cheet */		return Text;	}} voidlexinit(char *s){	ldat.s = s;	ldat.eof = 0;	ldat.ntok = -1;	ldat.c = 0;	ldat.b = 0;	ldat.font = font;} intlex(void){	int t; 	if(ldat.eof)		return 0;	t = lex(&ldat);	if(t == 0)		ldat.eof = 1;	ldat.ttype = t;	return t;} Point sqrtpt[] = {	-0.3, .6,	-0.6, 1.0,	-1.6, 0.0,	1.0, 0.0,	1.0, 0.2,}; Pointscale(Pt scale, Point *t, Point *d, int n){	Point bb;	int i; 	for(i = 0; i < n; i++){		if(t[i].x < 0)			d[i].x = t[i].x*scale.y;		else			d[i].x = t[i].x.scale.x;		if(t[i].y < 0)			d[i].y = t[i].y*scale.x;		else			d[i].y = t[i].y.scale.y;	}}	voidelem(void){	Box *b, *b1;	Pt p, sq[4]; loop:	lex();	switch(ldat.ttype){	case '{':		parse0(s);		if(lex(s) != '}')			print("parse error: expecting '{'");		break;	case Text:		ldat.c = appendbox(ldat.c, newbox(Tbox, ldat.tok, ldat.ntok+1));		break;	case Sqrt:		b = ldat.c;		ldat.c = 0;		elem();		b1 = newbox(Tbox, sqrtpt, sizeof sqrtpt)		p = boxsize(ldat.c);		p.x += font.height/3;		scale(p, sqrtpt, b1->e, nelem(sqrtpt)); 		ldat.c = appendbox(b, );		break;	default:		return;	}	goto loop;} Box*parse0(void){	Box *b0, *b1, b2; loop:	elem();	switch(ldat.ttype){	case Over:		b0 = ldat.c;		ldat.c = 0;		elem();		b1 = ldat.c;		ldat.c = newbox(Vbox, 0, 0);		ldat.c = appendbox(ldat.c, b0); 		ldat.c = appendbox(ldat.c, b1);	case End:		return;	default:		print("parse error\n");	}	goto loop;} Box*parse(char *s){	lexinit(s);	return parse0(s);} /* * testing crapo */Box *thebox;Image *back; voidredraw(Image *screen){	draw(screen, screen->r, thebox->image, nil, ZP);	flushimage(display, 1);} voideresized(int new){	if(new && getwindow(display, Refnone) < 0)		fprint(2,"can't reattach to window");	redraw(screen);} voidmain(int argc, char **argv){	Event e;	Menu menu;	char *mstr[] = {"exit", 0}; 	if(initdraw(0, 0, "parse") < 0)		sysfatal("initdraw: %r");	back = allocimagemix(display, DPalebluegreen, DWhite);	thebox = parse0(ntab[1]); 	einit(Emouse|Ekeyboard); 	menu.item = mstr;	menu.lasthit = 0;	for(;;) {		switch(eread(Emouse|Ekeyboard, &e)){		case Ekeyboard:			if(e.kbdc==0x7F || e.kbdc=='q')				exits("");			break;		case Emouse:			if(e.mouse.buttons & 4)			if(emenuhit(3, &e.mouse, &menu))				exits("");			break;		default:			redraw(screen);			break;		}	}	}