8 typedef struct Operator Operator;
9 typedef struct Token Token;
10 typedef struct Constant Constant;
11 typedef struct Code Code;
48 void add(void) { sp--; *sp += *(sp+1); }
49 void sub(void) { sp--; *sp -= *(sp+1); }
50 void mul(void) { sp--; *sp *= *(sp+1); }
51 void div(void) { sp--; *sp /= *(sp+1); }
52 void pot(void) { sp--; *sp = pow(*sp, *(sp+1)); }
53 void osin(void) { *sp = sin(*sp); }
54 void ocos(void) { *sp = cos(*sp); }
55 void otan(void) { *sp = tan(*sp); }
56 void oasin(void) { *sp = asin(*sp); }
57 void oacos(void) { *sp = acos(*sp); }
58 void oatan(void) { *sp = atan(*sp); }
59 void osqrt(void) { *sp = sqrt(*sp); }
60 void olog(void) { *sp = log10(*sp); }
61 void oln(void) { *sp = log(*sp); }
70 "+", OBINARY, 0, 0, add,
71 "-", OBINARY, 0, 0, sub,
72 "*", OBINARY, 0, 100, mul,
73 "/", OBINARY, 0, 100, div,
74 "^", OBINARY, 1, 200, pot,
75 "sin", OUNARY, 0, 50, osin,
76 "cos", OUNARY, 0, 50, ocos,
77 "tan", OUNARY, 0, 50, otan,
78 "asin", OUNARY, 0, 50, oasin,
79 "acos", OUNARY, 0, 50, oacos,
80 "atan", OUNARY, 0, 50, oatan,
81 "sqrt", OUNARY, 0, 50, osqrt,
82 "log", OUNARY, 0, 50, olog,
83 "ln", OUNARY, 0, 50, oln,
102 double xmin = -10, xmax = 10;
103 double ymin = -10, ymax = 10;
107 int picx = 640, picy = 480;
114 v = mallocz(size, 1);
116 sysfatal("emalloc: %r");
117 setmalloctag(v, getcallerpc(&size));
124 if(c->len >= c->cap) {
126 c->p = realloc(c->p, sizeof(Op) * c->cap);
128 sysfatal("realloc: %r");
136 t->next = opstackbot;
148 sysfatal("stack underflow");
149 opstackbot = t->next;
151 sysfatal("non-operator pop");
152 o.type = t->op->type;
164 opstackbot = t->next;
180 t = emalloc(sizeof(*t));
183 t->val = strtod(*s, s);
201 for(o = ops; o < ops + nelem(ops); o++)
202 if(strncmp(*s, o->s, strlen(o->s)) == 0) {
208 for(c = consts; c < consts + nelem(consts); c++)
209 if(strncmp(*s, c->s, strlen(c->s)) == 0) {
215 sysfatal("syntax error at %s", *s);
220 parse(Code *c, char *s)
239 if(t->op->type == OBINARY)
240 while(opstackbot != nil && opstackbot->type == TOP &&
241 (opstackbot->op->prec > t->op->prec ||
242 t->op->rassoc && opstackbot->op->prec == t->op->prec))
250 while(opstackbot != nil && opstackbot->type == TOP)
252 if(opstackbot == nil)
253 sysfatal("mismatched parentheses");
258 sysfatal("unknown token type %d", t->type);
261 while(opstackbot != nil)
262 switch(opstackbot->type) {
267 sysfatal("mismatched parentheses");
269 sysfatal("syntax error");
281 for(o = c->p; o < c->p + c->len; o++)
283 case ONUMBER: case OVAR:
289 sysfatal("syntax error");
293 sysfatal("syntax error");
299 sysfatal("syntax error");
304 calc(Code *c, double x)
309 for(o = c->p; o < c->p + c->len; o++)
317 case OUNARY: case OBINARY:
324 convx(Rectangle *r, int x)
326 return (xmax - xmin) * (x - r->min.x) / (r->max.x - r->min.x) + xmin;
330 deconvx(Rectangle *r, double dx)
332 return (dx - xmin) * (r->max.x - r->min.x) / (xmax - xmin) + r->min.x + 0.5;
336 convy(Rectangle *r, int y)
338 return (ymax - ymin) * (r->max.y - y) / (r->max.y - r->min.y) + ymin;
342 deconvy(Rectangle *r, double dy)
344 return (ymax - dy) * (r->max.y - r->min.y) / (ymax - ymin) + r->min.y + 0.5;
353 if(x >= picx || y >= picy || x < 0 || y < 0)
355 p = imagedata + (picx * y + x) * 3;
356 p[0] = p[1] = p[2] = 0;
358 draw(screen, Rect(x, y, x + 1, y + 1), color, nil, ZP);
362 drawinter(Code *co, Rectangle *r, double x1, double x2, int n)
368 ix1 = deconvx(r, x1);
369 ix2 = deconvx(r, x2);
373 iy1 = deconvy(r, y1);
378 iy2 = deconvy(r, y2);
381 if(isNaN(y1) || isNaN(y2))
385 if(iy2 >= iy1 - 1 && iy2 <= iy1 + 1)
387 if(iy1 > r->max.y && iy2 > r->max.y)
389 if(iy1 < r->min.y && iy2 < r->min.y)
391 drawinter(co, r, x1, (x1 + x2) / 2, n + 1);
392 drawinter(co, r, (x1 + x2) / 2, x2, n + 1);
396 drawgraph(Code *co, Rectangle *r)
400 for(x = r->min.x; x < r->max.x; x++)
401 drawinter(co, r, convx(r, x), convx(r, x + 1), 0);
409 color = display->black;
410 for(i = 0; i < nfns; i++)
411 drawgraph(&fns[i], &screen->r);
412 flushimage(display, 1);
418 fprint(2, "usage: fplot [-c [-s size]] [-r range] functions ...\n");
427 double xmin_, xmax_, ymin_, ymax_;
431 if(r.min.x == 0 && r.min.y == 0 && r.max.x == 0 && r.max.y == 0)
433 xmin_ = convx(&screen->r, r.min.x);
434 xmax_ = convx(&screen->r, r.max.x);
435 ymin_ = convy(&screen->r, r.max.y);
436 ymax_ = convy(&screen->r, r.min.y);
441 draw(screen, screen->r, display->white, nil, ZP);
446 parsefns(int n, char **s)
452 fns = emalloc(sizeof(*fns) * n);
453 for(i = 0; i < nfns; i++) {
454 parse(&fns[i], s[i]);
455 cur = calcstack(&fns[i]);
459 stack = emalloc(sizeof(*stack) * max);
465 while(*s && !isdigit(*s)) s++;
467 xmin = strtod(s, &s);
468 while(*s && !isdigit(*s)) s++;
470 xmax = strtod(s, &s);
471 while(*s && !isdigit(*s)) s++;
473 ymin = strtod(s, &s);
474 while(*s && !isdigit(*s)) s++;
476 ymax = strtod(s, &s);
482 while(*s && !isdigit(*s)) s++;
484 picx = strtol(s, &s, 0);
485 while(*s && !isdigit(*s)) s++;
487 picy = strtol(s, &s, 0);
491 main(int argc, char **argv)
498 case 'r': parserange(EARGF(usage())); break;
499 case 's': parsesize(EARGF(usage())); break;
500 case 'c': cflag++; break;
505 setfcr(getfcr() & ~(FPZDIV | FPINVAL));
506 parsefns(argc, argv);
508 imagedata = emalloc(picx * picy * 3);
509 memset(imagedata, 0xFF, picx * picy * 3);
510 print("%11s %11d %11d %11d %11d ", "r8g8b8", 0, 0, picx, picy);
511 r.min.x = r.min.y = 0;
514 for(i = 0; i < nfns; i++)
515 drawgraph(&fns[i], &r);
516 if(write(1, imagedata, picx * picy * 3) < picx * picy * 3)
517 sysfatal("write: %r");
519 if(initdraw(nil, nil, "fplot") < 0)
520 sysfatal("initdraw: %r");
521 einit(Emouse | Ekeyboard);
527 case 'q': exits(nil);
539 if(getwindow(display, Refnone) < 0)
540 sysfatal("getwindow: %r");