|
|
1.1 root 1: /* conv - programmer's calculator
2: * conv evaluates expressions in c style syntax and reports the results
3: * in hexadecimal, decimal, octal, binary, and ascii character constants.
4: * If arguments are present, they are each evaluated as independent
5: * expressions, otherwise each line of standard input is evaluated.
6: * Input numbers follow the style of the old conv, ie
7: * #digits - hexadecimal
8: * 0xdigits - hexadecimal
9: * 0Xdigits - hexadecimal
10: * 0digits - octal
11: * $digits - binary
12: * digits - decimal
13: * 'character - ascii character constant
14: * The only expressions not allowed are those involving arrays, pointers,
15: * structure members, and addresses. All of the integer arithmetic ops
16: * are supported including variables, assignment ops, conditional expressions,
17: * and the comma operator.
18: * In addition, there is an iterative conditional expression
19: * <expr1> ?? <expr2> :: <expr3>
20: * which evaluates to while (<expr1>) <expr2>; <expr3>, that is evaluating
21: * <expr2> as often as <expr1> evaluates to true, then returning the value
22: * of <expr3>.
23: * Bug: function definition and evaluation should be permitted.
24: */
25: %{
26: #include <ctype.h>
27:
28: #define NNODES 1000
29:
30: char *version = "Conv Version 2.00.\n";
31:
32: typedef union yynode {
33: struct {
34: int n_op;
35: union yynode *n1_ln;
36: union yynode *n1_rn;
37: } yyn1;
38: struct {
39: int n_op;
40: long n2_val;
41: } yyn2;
42: struct {
43: char n3_name[];
44: } yyn3;
45: } NODE;
46: #define n_ln yyn1.n1_ln
47: #define n_rn yyn1.n1_rn
48: #define n_val yyn2.n2_val
49: #define n_name yyn3.n3_name
50:
51: #define NULL ((NODE *)0)
52: NODE *node();
53: NODE *vnode();
54: NODE *nnode();
55: NODE *hash();
56: NODE *dotp;
57: long getcc();
58: long getv();
59:
60: %}
61:
62: %union {
63: int yy_op;
64: long yy_val;
65: NODE *yy_nod;
66: }
67:
68: %start list
69:
70: %token NUMBER NAME CALL LINK
71: %token INC DEC INCBEF DECBEF INCAFT DECAFT
72:
73: %left ','
74: %right '=' ADDEQ SUBEQ MULEQ DIVEQ REMEQ ANDEQ IOREQ EOREQ SHLEQ SHREQ
75: %left QUQU COCO
76: %left '?' ':'
77: %left OR
78: %left AND
79: %left '|'
80: %left '^'
81: %left '&'
82: %left EQ NE
83: %left '<' '>' LE GE
84: %left SHL SHR
85: %left '+' '-'
86: %left '*' '/' '%'
87: %right '~' '!' UMINUS
88:
89: %type <yy_op> '=' ADDEQ SUBEQ MULEQ DIVEQ REMEQ ANDEQ IOREQ EOREQ SHLEQ SHREQ
90: %type <yy_op> '?' ':' OR AND '|' '^' '&'
91: %type <yy_op> EQ NE '<' '>' LE GE
92: %type <yy_op> SHL SHR '+' '-' '*' '/' '%'
93: %type <yy_op> '~' '!' UMINUS '(' ')' ','
94: %type <yy_op> INC DEC INCAFT INCBEF DECAFT DECBEF
95: %type <yy_nod> NAME
96: %type <yy_val> NUMBER
97: %type <yy_nod> expr
98:
99: %%
100:
101: list: /* empty */
102: | list '\n'
103: | list expr '\n' {
104: eval($2, dotp->n_ln);
105: switch ($2->n_op) {
106: case IOREQ:
107: case EOREQ:
108: case ANDEQ:
109: case SHLEQ:
110: case SHREQ:
111: case REMEQ:
112: case DIVEQ:
113: case MULEQ:
114: case SUBEQ:
115: case ADDEQ:
116: case '=':
117: break;
118: default:
119: putv(dotp->n_ln);
120: }
121: nfree($2);
122: }
123: | list error '\n' {
124: yyerrok;
125: }
126: ;
127:
128:
129: expr: expr ',' expr {
130: $$ = node($2, $1, $3);
131: }
132: | NAME '=' expr {
133: $$ = node($2, $1, $3);
134: }
135: | NAME ADDEQ expr {
136: $$ = node($2, $1, $3);
137: }
138: | NAME SUBEQ expr {
139: $$ = node($2, $1, $3);
140: }
141: | NAME MULEQ expr {
142: $$ = node($2, $1, $3);
143: }
144: | NAME DIVEQ expr {
145: $$ = node($2, $1, $3);
146: }
147: | NAME REMEQ expr {
148: $$ = node($2, $1, $3);
149: }
150: | NAME ANDEQ expr {
151: $$ = node($2, $1, $3);
152: }
153: | NAME IOREQ expr {
154: $$ = node($2, $1, $3);
155: }
156: | NAME EOREQ expr {
157: $$ = node($2, $1, $3);
158: }
159: | NAME SHLEQ expr {
160: $$ = node($2, $1, $3);
161: }
162: | NAME SHREQ expr {
163: $$ = node($2, $1, $3);
164: }
165: | NAME INC {
166: $$ = node(INCAFT, $1, NULL);
167: }
168: | NAME DEC {
169: $$ = node(DECAFT, $1, NULL);
170: }
171: | INC NAME {
172: $$ = node(INCBEF, $2, NULL);
173: }
174: | DEC NAME {
175: $$ = node(DECBEF, $2, NULL);
176: }
177: | expr QUQU expr COCO expr {
178: $$ = node($2, $1, node($4, $3, $5));
179: }
180: | expr '?' expr ':' expr {
181: $$ = node($2, $1, node($4, $3, $5));
182: }
183: | expr OR expr {
184: $$ = node($2, $1, $3);
185: }
186: | expr AND expr {
187: $$ = node($2, $1, $3);
188: }
189: | expr '|' expr {
190: $$ = node($2, $1, $3);
191: }
192: | expr '^' expr {
193: $$ = node($2, $1, $3);
194: }
195: | expr '&' expr {
196: $$ = node($2, $1, $3);
197: }
198: | expr EQ expr {
199: $$ = node($2, $1, $3);
200: }
201: | expr NE expr {
202: $$ = node($2, $1, $3);
203: }
204: | expr '<' expr {
205: $$ = node($2, $1, $3);
206: }
207: | expr '>' expr {
208: $$ = node($2, $1, $3);
209: }
210: | expr LE expr {
211: $$ = node($2, $1, $3);
212: }
213: | expr GE expr {
214: $$ = node($2, $1, $3);
215: }
216: | expr SHR expr {
217: $$ = node($2, $1, $3);
218: }
219: | expr SHL expr {
220: $$ = node($2, $1, $3);
221: }
222: | expr '+' expr {
223: $$ = node($2, $1, $3);
224: }
225: | expr '-' expr {
226: $$ = node($2, $1, $3);
227: }
228: | expr '*' expr {
229: $$ = node($2, $1, $3);
230: }
231: | expr '/' expr {
232: $$ = node($2, $1, $3);
233: }
234: | expr '%' expr {
235: $$ = node($2, $1, $3);
236: }
237: | '-' expr %prec UMINUS {
238: $$ = node(UMINUS, $2, NULL);
239: }
240: | '~' expr %prec UMINUS {
241: $$ = node($1, $2, NULL);
242: }
243: | '!' expr %prec UMINUS {
244: $$ = node($1, $2, NULL);
245: }
246: | NAME {
247: $$ = $1;
248: }
249: | NUMBER {
250: $$ = vnode($1);
251: }
252: | '(' expr ')' {
253: $$ = node($1, $2, NULL);
254: }
255: ;
256:
257:
258: %%
259:
260: yylex()
261: {
262: register int c;
263: char *seq = "=";
264: char tmpbuf[64];
265: register char *p;
266:
267: again:
268: while ((c=getc()) == ' ' || c == '\t')
269: ;
270:
271: if (isalnum(c) || c == '#' || c == '$') {
272: tmpbuf[0] = c;
273: c = getc();
274: for (p = tmpbuf+1; p < &tmpbuf[64] && isalnum(c); c = getc())
275: *p++ = c;
276: ungetc(c);
277: *p++ = 0;
278: c = tmpbuf[0];
279: if (c == '#' || c == '$' || isdigit(c)) {
280: yylval.yy_val = getv(tmpbuf);
281: return (NUMBER);
282: }
283: yylval.yy_nod = hash(tmpbuf);
284: return (NAME);
285: }
286: switch (c) {
287:
288: case '\'':
289: yylval.yy_val = getcc();
290: return NUMBER;
291: case '\\': if (substr("\n", 1, 0))
292: goto again;
293: return yylval.yy_op = c;
294: case '+': return substr("=+", ADDEQ, INC, c);
295: case '-': return substr("=-", SUBEQ, DEC, c);
296: case '*': return substr(seq, MULEQ, c);
297: case '/': return substr(seq, DIVEQ, c);
298: case '%': return substr(seq, REMEQ, c);
299: case '&': return substr("=&", ANDEQ, AND, c);
300: case '|': return substr("=|", IOREQ, OR, c);
301: case '^': return substr(seq, EOREQ, c);
302: case '=': return substr(seq, EQ, c);
303: case '!': return substr(seq, NE, c);
304: case '<': if ((c = substr("<=", SHL, LE, c)) == SHL)
305: return substr(seq, SHLEQ, c);
306: return yylval.yy_op = c;
307: case '>': if ((c = substr(">=", SHR, GE, c)) == SHR)
308: return substr(seq, SHREQ, c);
309: return yylval.yy_op = c;
310: case '.':
311: yylval.yy_nod = dotp;
312: return NAME;
313: }
314: return yylval.yy_op = c;
315: }
316:
317: NODE *reg[32];
318:
319: NODE *
320: hash(bp)
321: char *bp;
322: {
323: int hash;
324: {
325: register char *p;
326: register c;
327:
328: hash = 0;
329: p = bp;
330: while (c = *p++)
331: hash += c;
332: }
333: {
334: register NODE *rp, **ep;
335:
336: bp[sizeof(NODE)] = 0;
337: for (ep = ®[hash & 31]; rp = *ep; ep = &rp->n_rn) {
338: if (strcmp(bp, rp->n_ln->n_rn->n_name) == 0)
339: return (rp->n_ln);
340: }
341: rp = node(NAME, vnode((long) 0), nnode(bp));
342: *ep = node(LINK, rp, NULL);
343: return (rp);
344: }
345: }
346:
347: /*
348: * Depending on the next character, return one of several tokens.
349: */
350: substr(cp, t1)
351: register char *cp;
352: int t1;
353: {
354: register int cn;
355: register int *tp;
356:
357: tp = &t1;
358: cn = getc();
359: while (*cp)
360: if (*cp++ == cn)
361: return yylval.yy_op = *tp;
362: else
363: tp += 1;
364: ungetc(cn);
365: return yylval.yy_op = *tp;
366: }
367:
368: int peekc;
369: char *inputs = 0;
370:
371: getc()
372: {
373: register int c;
374:
375: if (peekc) {
376: c = peekc;
377: peekc = 0;
378: } else if (inputs != 0) {
379: if (c = *inputs)
380: inputs += 1;
381: else
382: c = -1;
383: } else
384: c = getchar();
385: return c;
386: }
387:
388: ungetc(c)
389: {
390: peekc = c;
391: }
392:
393: main(argc, argv)
394: char *argv[];
395: {
396: dotp = node(NAME, vnode((long) 0), NULL);
397: if (argc > 1) {
398: while (--argc > 0) {
399: ++argv;
400: if (!strcmp(*argv, "-V")) {
401: printf(version);
402: exit(0);
403: }
404: inputs = malloc(strlen(*argv)+2);
405: strcpy(inputs, *argv);
406: strcat(inputs, "\n");
407: yyparse();
408: }
409: } else {
410: inputs = 0;
411: yyparse();
412: }
413: return 0;
414: }
415: yyerror() { puts("Syntax"); }
416:
417: NODE _nodes_[NNODES];
418: NODE *_np_ = &_nodes_[0];
419:
420: NODE *
421: alloc()
422: {
423: register NODE *np;
424:
425: np = _np_;
426: for (;;) {
427: if (np->n_op == 0) {
428: _np_ = np;
429: return (np);
430: }
431: if (++np >= &_nodes_[NNODES])
432: np = &_nodes_[0];
433: if (np == _np_)
434: break;
435: }
436: puts("No space");
437: exit(1);
438: }
439:
440: nfree(np)
441: register NODE *np;
442: {
443: if (np->n_op != NAME && np->n_op != NUMBER) {
444: if (np->n_rn != NULL)
445: nfree(np->n_rn);
446: nfree(np->n_ln);
447: }
448: if (np->n_op != NAME) {
449: np->n_op = 0;
450: if (np < _np_)
451: _np_ = np;
452: }
453: }
454:
455: NODE *
456: node(op, nl, nr)
457: NODE *nl, *nr;
458: {
459: register NODE *np;
460:
461: np = alloc();
462: np->n_op = op;
463: np->n_ln = nl;
464: np->n_rn = nr;
465: return (np);
466: }
467:
468: NODE *
469: vnode(va)
470: long va;
471: {
472: register NODE *np;
473:
474: np = alloc();
475: np->n_op = NUMBER;
476: np->n_val = va;
477: return (np);
478: }
479:
480: NODE *
481: nnode(cp)
482: register char *cp;
483: {
484: register NODE *np;
485: register char *p;
486:
487: np = alloc();
488: p = np->n_name;
489: while (p < np+1)
490: *p++ = *cp++;
491: return (np);
492: }
493:
494: eval(np, dp)
495: register NODE *np, *dp;
496: {
497: NODE lval, rval, *lptr;
498:
499: dp->n_op = NUMBER;
500: again:
501: switch (np->n_op) {
502: case '=':
503: case ADDEQ:
504: case SUBEQ:
505: case MULEQ:
506: case DIVEQ:
507: case REMEQ:
508: case SHREQ:
509: case SHLEQ:
510: case ANDEQ:
511: case EOREQ:
512: case IOREQ:
513: eval(np->n_rn, &rval);
514: /* Fall through */
515: case INCBEF:
516: case DECBEF:
517: case INCAFT:
518: case DECAFT:
519: lptr = np->n_ln->n_ln;
520: break;
521: case NAME:
522: lptr = np->n_ln;
523: break;
524: case ',':
525: case '|':
526: case '^':
527: case '&':
528: case EQ:
529: case NE:
530: case '<':
531: case '>':
532: case LE:
533: case GE:
534: case SHR:
535: case SHL:
536: case '+':
537: case '-':
538: case '*':
539: case '/':
540: case '%':
541: eval(np->n_rn, &rval);
542: /* Fall through */
543: case UMINUS:
544: case '~':
545: case '!':
546: case QUQU:
547: case '?':
548: case OR:
549: case AND:
550: eval(np->n_ln, &lval);
551: break;
552: case NUMBER:
553: lptr = np;
554: break;
555: case '(':
556: np = np->n_ln;
557: goto again;
558: default:
559: printf("Bad operator: %d\n", np->n_op);
560: return;
561: }
562: switch (np->n_op) {
563: case ',':
564: np = np->n_rn;
565: goto again;
566: case '=':
567: lptr->n_val = rval.n_val;
568: *dp = *lptr;
569: break;
570: case ADDEQ:
571: lptr->n_val += rval.n_val;
572: *dp = *lptr;
573: break;
574: case SUBEQ:
575: lptr->n_val -= rval.n_val;
576: *dp = *lptr;
577: break;
578: case MULEQ:
579: lptr->n_val *= rval.n_val;
580: *dp = *lptr;
581: break;
582: case DIVEQ:
583: lptr->n_val /= rval.n_val;
584: *dp = *lptr;
585: break;
586: case REMEQ:
587: lptr->n_val %= rval.n_val;
588: *dp = *lptr;
589: break;
590: case SHREQ:
591: lptr->n_val >>= rval.n_val;
592: *dp = *lptr;
593: break;
594: case SHLEQ:
595: lptr->n_val <<= rval.n_val;
596: *dp = *lptr;
597: break;
598: case ANDEQ:
599: lptr->n_val &= rval.n_val;
600: *dp = *lptr;
601: break;
602: case EOREQ:
603: lptr->n_val ^= rval.n_val;
604: *dp = *lptr;
605: break;
606: case IOREQ:
607: lptr->n_val |= rval.n_val;
608: *dp = *lptr;
609: break;
610: case INCBEF:
611: ++lptr->n_val;
612: *dp = *lptr;
613: break;
614: case DECBEF:
615: --lptr->n_val;
616: *dp = *lptr;
617: break;
618: case INCAFT:
619: *dp = *lptr;
620: lptr->n_val++;
621: break;
622: case DECAFT:
623: *dp = *lptr;
624: lptr->n_val++;
625: break;
626: case NAME:
627: *dp = *lptr;
628: break;
629: case NUMBER:
630: *dp = *lptr;
631: break;
632: case '|':
633: dp->n_val = lval.n_val | rval.n_val;
634: break;
635: case '^':
636: dp->n_val = lval.n_val ^ rval.n_val;
637: break;
638: case '&':
639: dp->n_val = lval.n_val & rval.n_val;
640: break;
641: case EQ:
642: dp->n_val = lval.n_val == rval.n_val;
643: break;
644: case NE:
645: dp->n_val = lval.n_val != rval.n_val;
646: break;
647: case '<':
648: dp->n_val = lval.n_val < rval.n_val;
649: break;
650: case '>':
651: dp->n_val = lval.n_val > rval.n_val;
652: break;
653: case LE:
654: dp->n_val = lval.n_val <= rval.n_val;
655: break;
656: case GE:
657: dp->n_val = lval.n_val >= rval.n_val;
658: break;
659: case SHR:
660: dp->n_val = lval.n_val >> rval.n_val;
661: break;
662: case SHL:
663: dp->n_val = lval.n_val << rval.n_val;
664: break;
665: case '+':
666: dp->n_val = lval.n_val + rval.n_val;
667: break;
668: case '-':
669: dp->n_val = lval.n_val - rval.n_val;
670: break;
671: case '*':
672: dp->n_val = lval.n_val * rval.n_val;
673: break;
674: case '/':
675: dp->n_val = lval.n_val / rval.n_val;
676: break;
677: case '%':
678: dp->n_val = lval.n_val % rval.n_val;
679: break;
680: case UMINUS:
681: dp->n_val = - lval.n_val;
682: break;
683: case '~':
684: dp->n_val = ~ lval.n_val;
685: break;
686: case '!':
687: dp->n_val = ! lval.n_val;
688: break;
689: case QUQU:
690: if (lval.n_val)
691: eval(np->n_rn->n_ln, &rval);
692: else
693: np = np->n_rn->n_rn;
694: goto again;
695: case '?':
696: if (lval.n_val)
697: np = np->n_rn->n_ln;
698: else
699: np = np->n_rn->n_rn;
700: goto again;
701: case OR:
702: if (lval.n_val != 0) {
703: *dp = lval;
704: break;
705: }
706: np = np->n_rn;
707: goto again;
708: case AND:
709: if (lval.n_val == 0) {
710: *dp = lval;
711: break;
712: }
713: np = np->n_rn;
714: goto again;
715: }
716: }
717:
718: long
719: getcc()
720: {
721: register int c, d;
722: c = getc();
723: d = getc();
724: if (d != '\'') ungetc(d);
725: return c;
726: }
727:
728: char digits[16] = "0123456789ABCDEF";
729:
730: long
731: getv(dp)
732: register char *dp;
733: {
734: register int d;
735: register long v;
736: register int b;
737:
738: v = 0;
739: b = 10; d = *dp++;
740: switch (d) {
741: case '#': b = 16; d = *dp++; break;
742: case '$': b = 2; d = *dp++; break;
743: case '0': b = 8; d = *dp++;
744: if (d == 'x' || d == 'X') {
745: b = 16; d = *dp++;
746: }
747: break;
748: }
749: while ((isdigit(d) && (d -= '0') < b)
750: || (isupper(d) && (d += 10 - 'A') < b)
751: || (islower(d) && (d += 10 - 'a') < b)) {
752: v = v * b + d;
753: d = *dp++;
754: if (d == 0)
755: return v;
756: }
757: printf("Bad digit: 0%o\n", dp[-1]);
758: return v;
759: }
760:
761: putv(v) NODE *v;
762: {
763: long l;
764: register c;
765: long m;
766:
767: l = v->n_val;
768: /*
769: * hex, decimal, octal
770: */
771: printf( "#%X %D 0%O $", l, l, l);
772: /*
773: * binary
774: */
775: for (c=32, m=l; m; --c, m<<=1)
776: if (m < 0)
777: break;
778: do {
779: printf( m<0? "1": "0");
780: m <<= 1;
781: } while (--c);
782: /*
783: * char
784: */
785: printf( " '");
786: if ((c=(char)l) < 0) {
787: printf( "~");
788: c &= 0177;
789: }
790: if (c<' ' || c=='\177') {
791: printf( "^");
792: if (c == '\177')
793: c = '?';
794: else
795: c += '@';
796: }
797: printf( "%c'\n", c);
798: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.