#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. Load more
#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; } void addop(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; } void push(Token *t) { t->next = opstackbot; opstackbot = t; } void pop(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); } void popdel(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); } void parse(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"); } } int calcstack(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; } double calc(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; } double convx(Rectangle *r, int x) { return (xmax - xmin) * (x - r->min.x) / (r->max.x - r->min.x) + xmin; } int deconvx(Rectangle *r, double dx) { return (dx - xmin) * (r->max.x - r->min.x) / (xmax - xmin) + r->min.x + 0.5; } double convy(Rectangle *r, int y) { return (ymax - ymin) * (r->max.y - y) / (r->max.y - r->min.y) + ymin; } int deconvy(Rectangle *r, double dy) { return (ymax - dy) * (r->max.y - r->min.y) / (ymax - ymin) + r->min.y + 0.5; } void pixel(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; } } void drawinter(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); } void drawgraph(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); } void tickfmt(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); } } int xticklabel(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; } int yticklabel(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;