827 lines · 15.8 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <ctype.h>#include <draw.h>#include <event.h> typedef struct Op Op;typedef struct Operator Operator;typedef struct Token Token;typedef struct Constant Constant;typedef struct Code Code; enum {	ONONE,	ONUMBER,	OVAR,	OUNARY,	OBINARY,}; struct Op {	int type;	union {		void (*f)(void);		double val;	};}; enum {	TNONE,	TNUMBER,	TVAR,	TOP,	TPARENL,	TPARENR,}; struct Token {	int type;	union {		Operator *op;		double val;	};	Token *next;}; double *stack, *sp;void omax(void) { sp--; if(sp[1]>*sp) *sp = sp[1]; }void omin(void) { sp--; if(sp[1]<*sp) *sp = sp[1]; }void add(void) { sp--; *sp += *(sp+1); }void sub(void) { sp--; *sp -= *(sp+1); }void mul(void) { sp--; *sp *= *(sp+1); }void div(void) { sp--; *sp /= *(sp+1); }void mod(void) { sp--; *sp = fmod(*sp, *(sp+1)); }void pot(void) { sp--; *sp = pow(*sp, *(sp+1)); }void oabs(void) { *sp = fabs(*sp); }void osin(void) { *sp = sin(*sp); }void ocos(void) { *sp = cos(*sp); }void otan(void) { *sp = tan(*sp); }void osinh(void) { *sp = sinh(*sp); }void ocosh(void) { *sp = cosh(*sp); }void otanh(void) { *sp = tanh(*sp); }void oasin(void) { *sp = asin(*sp); }void oacos(void) { *sp = acos(*sp); }void oatan(void) { *sp = atan(*sp); }void osqrt(void) { *sp = sqrt(*sp); }void oexp(void) { *sp = exp(*sp); }void olog(void) { *sp = log10(*sp); }void oln(void) { *sp = log(*sp); } struct Operator {	char *s;	char type;	char rassoc;	short prec;	void (*f)(void);} ops[] = {	"max",	OBINARY,	0,	0,	omax,	"min",	OBINARY,	0,	0,	omax,	"+",	OBINARY,	0,	100,	add,	"-",	OBINARY,	0,	100,	sub,	"*",	OBINARY,	0,	200,	mul,	"/",	OBINARY,	0,	200,	div,	"%",	OBINARY,	0,	200,	mod,	"^",	OBINARY,	1,	300,	pot,	"sinh",	OUNARY,		0,	400,	osinh,	"cosh",	OUNARY,		0,	400,	ocosh,	"tanh",	OUNARY,		0,	400,	otanh,	"abs",	OUNARY,		0,	400,	oabs,	"sin",	OUNARY,		0,	400,	osin,	"cos",	OUNARY,		0,	400,	ocos,	"tan",	OUNARY,		0,	400,	otan,	"asin",	OUNARY,		0,	400,	oasin,	"acos",	OUNARY,		0,	400,	oacos,	"atan",	OUNARY,		0,	400,	oatan,	"sqrt",	OUNARY,		0,	400,	osqrt,	"exp",	OUNARY,		0,	400,	oexp,	"log",	OUNARY,		0,	400,	olog,	"ln",	OUNARY,		0,	400,	oln,}; struct Constant {	char *s;	double val;} consts[] = {	"pi",	3.14159265359,	"π",	3.14159265359,	"e",	2.71828182846,}; struct Code {	Op* p;	int len, cap;} *fns;int nfns; Token *opstackbot;double xmin = -10, xmax = 10;double ymin = -10, ymax = 10;double gymin, gymax;int icolors[] = {	DBlack,	0xCC0000FF,	0x00CC00FF,	0x0000CCFF,	0xFF00CCFF,	0xFFAA00FF,	0xCCCC00FF,};Image *colors[nelem(icolors)];int cflag, aflag;char *imagedata;char *pixels;int picx = 640, picy = 480; typedef struct FRectangle FRectangle;struct FRectangle {	double xmin, xmax, ymin, ymax;} *zoomst;int nzoomst; void *emalloc(int size){	void *v;		v = mallocz(size, 1);	if(v == nil)		sysfatal("emalloc: %r");	setmalloctag(v, getcallerpc(&size));	return v;} voidaddop(Code *c, Op o){	if(c->len >= c->cap) {		c->cap += 32;		c->p = realloc(c->p, sizeof(Op) * c->cap);		if(c->p == nil)			sysfatal("realloc: %r");	}	c->p[c->len++] = o;} voidpush(Token *t){	t->next = opstackbot;	opstackbot = t;} voidpop(Code *c){	Token *t;	Op o;		t = opstackbot;	if(t == nil)		sysfatal("stack underflow");	opstackbot = t->next;	if(t->type != TOP)		sysfatal("non-operator pop");	o.type = t->op->type;	o.f = t->op->f;	addop(c, o);	free(t);} voidpopdel(void){	Token *t;		t = opstackbot;	opstackbot = t->next;	free(t);} Token *lex(char **s){	Token *t;	Operator *o;	Constant *c; 	while(isspace(**s))		(*s)++;	if(**s == 0)		return nil;		t = emalloc(sizeof(*t));	if(isdigit(**s)) {		t->type = TNUMBER;		t->val = strtod(*s, s);		return t;	}	if(**s == '(') {		t->type = TPARENL;		(*s)++;		return t;	}	if(**s == ')') {		t->type = TPARENR;		(*s)++;		return t;	}	if(**s == 'x') {		t->type = TVAR;		(*s)++;		return t;	}	for(o = ops; o < ops + nelem(ops); o++)		if(strncmp(*s, o->s, strlen(o->s)) == 0) {			t->type = TOP;			t->op = o;			*s += strlen(o->s);			return t;		}	for(c = consts; c < consts + nelem(consts); c++)		if(strncmp(*s, c->s, strlen(c->s)) == 0) {			t->type = TNUMBER;			t->val = c->val;			*s += strlen(c->s);			return t;		}	sysfatal("syntax error at %s", *s);} voidparse(Code *c, char *s){	Token *t;	Op o;		while(t = lex(&s)) {		switch(t->type) {		case TNUMBER:			o.type = ONUMBER;			o.val = t->val;			addop(c, o);			free(t);			break;		case TVAR:			o.type = OVAR;			addop(c, o);			free(t);			break;		case TOP:			if(t->op->type == OBINARY)				while(opstackbot != nil && opstackbot->type == TOP &&					(opstackbot->op->prec > t->op->prec ||					!t->op->rassoc && opstackbot->op->prec == t->op->prec))					pop(c);			push(t);			break;		case TPARENL:			push(t);			break;		case TPARENR:			while(opstackbot != nil && opstackbot->type == TOP)				pop(c);			if(opstackbot == nil)				sysfatal("mismatched parentheses");			popdel();			free(t);			break;		default:			sysfatal("unknown token type %d", t->type);		}	}	while(opstackbot != nil)		switch(opstackbot->type) {		case TOP:			pop(c);			break;		case TPARENL:			sysfatal("mismatched parentheses");		default:			sysfatal("syntax error");		}} intcalcstack(Code *c){	int cur, max;	Op *o;		cur = 0;	max = 0;	for(o = c->p; o < c->p + c->len; o++)		switch(o->type) {		case ONUMBER: case OVAR:			if(++cur > max)				max = cur;			break;		case OUNARY:			if(cur == 0)				sysfatal("syntax error");			break;		case OBINARY:			if(cur <= 1)				sysfatal("syntax error");			cur--;			break;		} 	if(cur != 1)		sysfatal("syntax error");	return max;} doublecalc(Code *c, double x){	Op *o;		sp = stack - 1;	for(o = c->p; o < c->p + c->len; o++)		switch(o->type) {		case ONUMBER:			*++sp = o->val;			break;		case OVAR:			*++sp = x;			break;		case OUNARY: case OBINARY:			o->f();		}	if(*sp < gymin) gymin = *sp;	if(*sp > gymax) gymax = *sp;	return *sp;} doubleconvx(Rectangle *r, int x){	return (xmax - xmin) * (x - r->min.x) / (r->max.x - r->min.x) + xmin;} intdeconvx(Rectangle *r, double dx){	return (dx - xmin) * (r->max.x - r->min.x) / (xmax - xmin) + r->min.x + 0.5;} doubleconvy(Rectangle *r, int y){	return (ymax - ymin) * (r->max.y - y) / (r->max.y - r->min.y) + ymin;} intdeconvy(Rectangle *r, double dy){	return (ymax - dy) * (r->max.y - r->min.y) / (ymax - ymin) + r->min.y + 0.5;} voidpixel(int x, int y, int c){	char *p; 	if(cflag) {		if(x >= picx || y >= picy || x < 0 || y < 0)			return;		p = imagedata + (picx * y + x) * 3;		p[0] = icolors[c] >> 24;		p[1] = icolors[c] >> 16;		p[2] = icolors[c] >> 8;	}else{		draw(screen, Rect(x, y, x + 1, y + 1), colors[c], nil, ZP);		if(ptinrect(Pt(x, y), screen->r))			pixels[picx * (y - screen->r.min.y) + (x - screen->r.min.x)] = 1;	}} voiddrawinter(Code *co, Rectangle *r, double x1, double x2, int n, int c){	double y1, y2;	int iy1, iy2;	int ix1, ix2; 	ix1 = deconvx(r, x1);	ix2 = deconvx(r, x2);	iy1 = iy2 = 0;	y1 = calc(co, x1);	if(!isNaN(y1)) {		iy1 = deconvy(r, y1);		pixel(ix1, iy1, c);	}	y2 = calc(co, x2);	if(!isNaN(y2)) {		iy2 = deconvy(r, y2);		pixel(ix2, iy2, c);	}	if(isNaN(y1) || isNaN(y2))		return;	if(n >= 10)		return;	if(iy2 >= iy1 - 1 && iy2 <= iy1 + 1)		return;	if(iy1 > r->max.y && iy2 > r->max.y)		return;	if(iy1 < r->min.y && iy2 < r->min.y)		return;	drawinter(co, r, x1, (x1 + x2) / 2, n + 1, c);	drawinter(co, r, (x1 + x2) / 2, x2, n + 1, c);} voiddrawgraph(Code *co, Rectangle *r, int c){	int x;		for(x = r->min.x; x < r->max.x; x++)		drawinter(co, r, convx(r, x), convx(r, x + 1), 0, c);} voidtickfmt(double d, double m, int n, char *fmt){	double e1, e2;	int x;		e1 = log10(fabs(m));	e2 = log10(fabs(m + n * d));	if(e2 > e1) e1 = e2;	if(e2 >= 4 || e2 < -3){		x = ceil(e1-log10(d)-1);		snprint(fmt, 32, "%%.%de", x);	}else{		x = ceil(-log10(d));		snprint(fmt, 32, "%%.%df", x);	}} intxticklabel(char *fmt, double g, int p, int x, int y){	char buf[32];	Rectangle lr;	int ny; 	snprint(buf, sizeof(buf), fmt, g);	lr.min = Pt(p, y+2);	lr.max = addpt(lr.min, stringsize(display->defaultfont, buf));	lr = rectsubpt(lr, Pt(Dx(lr) / 2-1, 0));	if(lr.max.y >= screen->r.max.y){		ny = y - 7 - Dy(lr);		lr = rectsubpt(lr, Pt(0, lr.min.y - ny));	}	if(rectinrect(lr, screen->r) && (lr.min.x > x || lr.max.x <= x)){		string(screen, lr.min, display->black, ZP, display->defaultfont, buf);		return 1;	}	return 0;} intyticklabel(char *fmt, double g, int p, int x, int y){	char buf[32];	Rectangle lr;	int nx; 	snprint(buf, sizeof(buf), fmt, g);	lr.min = Pt(0, 0);	lr.max = stringsize(display->defaultfont, buf);	lr = rectaddpt(lr, Pt(x-Dx(lr)-2, p - Dy(lr) / 2));	if(lr.min.x < screen->r.min.x){		nx = x + 7;		lr = rectsubpt(lr, Pt(lr.min.x - nx, 0));	}	if(rectinrect(lr, screen->r) && (lr.min.y > y || lr.max.y <= y)){		string(screen, lr.min, display->black, ZP, display->defaultfont, buf);		return 1;

Lines 1–500 of 827.