]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/mpc.y
add mpc(1), extended precision code generator
[plan9front.git] / sys / src / cmd / mpc.y
1 %{
2
3 #include        <u.h>
4 #include        <libc.h>
5 #include        <bio.h>
6 #include        <mp.h>
7
8 typedef struct Sym Sym;
9 typedef struct Node Node;
10
11 enum {
12         FSET    = 1,
13         FUSE    = 2,
14         FARG    = 4,
15         FLOC    = 8,
16 };
17
18 struct Sym
19 {
20         Sym*    l;
21         int     f;
22         char    n[];
23 };
24
25 struct Node
26 {
27         int     c;
28         Node*   l;
29         Node*   r;
30         Sym*    s;
31         int     n;
32 };
33
34 #pragma varargck type "N" Node*
35
36 int     ntmp;
37 Node    *ftmps, *atmps;
38 Node    *modulo;
39
40 Node*   new(int, Node*, Node*);
41 Sym*    sym(char*);
42
43 Biobuf  bin;
44 int     goteof;
45 int     lineno;
46 int     clevel;
47 char*   filename;
48
49 int     getch(void);
50 void    ungetc(void);
51 void    yyerror(char*);
52 int     yyparse(void);
53 void    diag(Node*, char*, ...);
54 void    com(Node*);
55 void    fcom(Node*,Node*,Node*);
56
57 #pragma varargck argpos cprint 1
58 #pragma varargck argpos diag 2
59
60 %}
61
62 %union
63 {
64         Sym*    sval;
65         Node*   node;
66         long    lval;
67 }
68
69 %type   <node>  name num args expr bool block elif stmnt stmnts
70
71 %left   '{' '}' ';'
72 %right  '=' ','
73 %right  '?' ':'
74 %left   EQ NEQ '<' '>'
75 %left   LSH RSH
76 %left   '+' '-'
77 %left   '/' '%'
78 %left   '*'
79 %left   '^'
80 %right  '('
81
82 %token  <lval>  MOD IF ELSE WHILE BREAK 
83 %token  <sval>  NAME NUM
84
85 %%
86
87 prog:
88         prog func
89 |       func
90
91 func:
92         name args stmnt
93         {
94                 fcom($1, $2, $3);
95         }
96
97 args:
98         '(' expr ')'
99         {
100                 $$ = $2;
101         }
102 |       '(' ')'
103         {
104                 $$ = nil;
105         }
106
107 name:
108         NAME
109         {
110                 $$ = new(NAME,nil,nil);
111                 $$->s = $1;
112         }
113 num:
114         NUM
115         {
116                 $$ = new(NUM,nil,nil);
117                 $$->s = $1;
118         }
119
120 elif:
121         ELSE IF '(' bool ')' stmnt
122         {
123                 $$ = new('?', $4, new(':', $6, nil));
124         }
125 |       ELSE IF '(' bool ')' stmnt elif
126         {
127                 $$ = new('?', $4, new(':', $6, $7));
128         }
129 |       ELSE stmnt
130         {
131                 $$ = $2;
132         }
133
134 sem:
135         sem ';'
136 |       ';'
137
138 stmnt:
139         expr '=' expr sem
140         {
141                 $$ = new('=', $1, $3);
142         }
143 |       MOD args stmnt
144         {
145                 $$ = new('m', $2, $3);
146         }
147 |       IF '(' bool ')' stmnt
148         {
149                 $$ = new('?', $3, new(':', $5, nil));
150         }
151 |       IF '(' bool ')' stmnt elif
152         {
153                 $$ = new('?', $3, new(':', $5, $6));
154         }
155 |       WHILE '(' bool ')' stmnt
156         {
157                 $$ = new('@', new('?', $3, new(':', $5, new('b', nil, nil))), nil);
158         }
159 |       BREAK sem
160         {
161                 $$ = new('b', nil, nil);
162         }
163 |       expr sem
164         {
165                 if($1->c == NAME)
166                         $$ = new('e', $1, nil);
167                 else
168                         $$ = $1;
169         }
170 |       block
171
172 block:
173         '{' stmnts '}'
174         {
175                 $$ = $2;
176         }
177
178 stmnts:
179         stmnts stmnt
180         {
181                 $$ = new('\n', $1, $2);
182         }
183 |       stmnt
184
185 expr:
186         '(' expr ')'
187         {
188                 $$ = $2;
189         }
190 |       name
191         {
192                 $$ = $1;
193         }
194 |       num
195         {
196                 $$ = $1;
197         }
198 |       '-' expr
199         {
200                 $$ = new(NUM, nil, nil);
201                 $$->s = sym("0");
202                 $$->s->f = 0;
203                 $$ = new('-', $$, $2);
204         }
205 |       expr ',' expr
206         {
207                 $$ = new(',', $1, $3);
208         }
209 |       expr '^' expr
210         {
211                 $$ = new('^', $1, $3);
212         }
213 |       expr '*' expr
214         {
215                 $$ = new('*', $1, $3);
216         }
217 |       expr '/' expr
218         {
219                 $$ = new('/', $1, $3);
220         }
221 |       expr '%' expr
222         {
223                 $$ = new('%', $1, $3);
224         }
225 |       expr '+' expr
226         {
227                 $$ = new('+', $1, $3);
228         }
229 |       expr '-' expr
230         {
231                 $$ = new('-', $1, $3);
232         }
233 |       bool '?' expr ':' expr
234         {
235                 $$ = new('?', $1, new(':', $3, $5));
236         }
237 |       name args
238         {
239                 $$ = new('e', $1, $2);
240         }
241 |       expr LSH num
242         {
243                 $$ = new(LSH, $1, $3);
244         }
245 |       expr RSH num
246         {
247                 $$ = new(RSH, $1, $3);
248         }
249
250 bool:
251         '(' bool ')'
252         {
253                 $$ = $2;
254         }
255 |       '!' bool
256         {
257                 $$ = new('!', $2, nil);
258         }
259 |       expr EQ expr
260         {
261                 $$ = new(EQ, $1, $3);
262         }
263 |       expr NEQ expr
264         {
265                 $$ = new('!', new(EQ, $1, $3), nil);
266         }
267 |       expr '>' expr
268         {
269                 $$ = new('>', $1, $3);
270         }
271 |       expr '<' expr
272         {
273                 $$ = new('<', $1, $3);
274         }
275
276 %%
277
278 int
279 yylex(void)
280 {
281         static char buf[200];
282         char *p;
283         int c;
284
285 Loop:
286         c = getch();
287         switch(c){
288         case -1:
289                 return -1;
290         case ' ':
291         case '\t':
292         case '\n':
293                 goto Loop;
294         case '#':
295                 while((c = getch()) > 0)
296                         if(c == '\n')
297                                 break;
298                 goto Loop;
299         }
300
301         switch(c){
302         case '?': case ':':
303         case '+': case '-':
304         case '*': case '^':
305         case '/': case '%':
306         case '{': case '}':
307         case '(': case ')':
308         case ',': case ';':
309                 return c;
310         case '<':
311                 if(getch() == '<') return LSH;
312                 ungetc();
313                 return '<';
314         case '>': 
315                 if(getch() == '>') return RSH;
316                 ungetc();
317                 return '>';
318         case '=':
319                 if(getch() == '=') return EQ;
320                 ungetc();
321                 return '=';
322         case '!':
323                 if(getch() == '=') return NEQ;
324                 ungetc();
325                 return '!';
326         }
327
328         ungetc();
329         p = buf;
330         for(;;){
331                 c = getch();
332                 if((c >= Runeself)
333                 || (c == '_')
334                 || (c >= 'a' && c <= 'z')
335                 || (c >= 'A' && c <= 'Z')
336                 || (c >= '0' && c <= '9')){
337                         *p++ = c;
338                         continue;
339                 }
340                 ungetc();
341                 break;
342         }
343         *p = '\0';
344
345         if(strcmp(buf, "mod") == 0)
346                 return MOD;
347         if(strcmp(buf, "if") == 0)
348                 return IF;
349         if(strcmp(buf, "else") == 0)
350                 return ELSE;
351         if(strcmp(buf, "while") == 0)
352                 return WHILE;
353         if(strcmp(buf, "break") == 0)
354                 return BREAK;
355
356         yylval.sval = sym(buf);
357         yylval.sval->f = 0;
358         return (buf[0] >= '0' && buf[0] <= '9') ? NUM : NAME;
359 }
360
361
362 int
363 getch(void)
364 {
365         int c;
366
367         c = Bgetc(&bin);
368         if(c == Beof){
369                 goteof = 1;
370                 return -1;
371         }
372         if(c == '\n')
373                 lineno++;
374         return c;
375 }
376
377 void
378 ungetc(void)
379 {
380         Bungetc(&bin);
381 }
382
383 Node*
384 new(int c, Node *l, Node *r)
385 {
386         Node *n;
387
388         n = malloc(sizeof(Node));
389         n->c = c;
390         n->l = l;
391         n->r = r;
392         n->s = nil;
393         n->n = lineno;
394         return n;
395 }
396
397 Sym*
398 sym(char *n)
399 {
400         static Sym *tab[128];
401         Sym *s;
402         ulong h, t;
403         int i;
404
405         h = 0;
406         for(i=0; n[i] != '\0'; i++){
407                 t = h & 0xf8000000;
408                 h <<= 5;
409                 h ^= t>>27;
410                 h ^= (ulong)n[i];
411         }
412         h %= nelem(tab);
413         for(s = tab[h]; s != nil; s = s->l)
414                 if(strcmp(s->n, n) == 0)
415                         return s;
416         s = malloc(sizeof(Sym)+i+1);
417         memmove(s->n, n, i+1);
418         s->f = 0;
419         s->l = tab[h];
420         tab[h] = s;
421         return s;
422 }
423
424 void
425 yyerror(char *s)
426 {
427         fprint(2, "%s:%d: %s\n", filename, lineno, s);
428         exits(s);
429 }
430 void
431 cprint(char *fmt, ...)
432 {
433         static char buf[1024], tabs[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
434         char *p, *x;
435         va_list a;
436
437         va_start(a, fmt);
438         vsnprint(buf, sizeof(buf), fmt, a);
439         va_end(a);
440
441         p = buf;
442         while((x = strchr(p, '\n')) != nil){
443                 x++;
444                 write(1, p, x-p);
445                 p = &tabs[sizeof(tabs)-1 - clevel];
446                 if(*p != '\0')
447                         write(1, p, strlen(p));
448                 p = x;
449         }
450         if(*p != '\0')
451                 write(1, p, strlen(p));
452 }
453
454 Node*
455 alloctmp(void)
456 {
457         Node *t;
458
459         t = ftmps;
460         if(t != nil)
461                 ftmps = t->l;
462         else {
463                 char n[16];
464
465                 snprint(n, sizeof(n), "tmp%d", ++ntmp);
466                 t = new(NAME, nil, nil);
467                 t->s = sym(n);
468
469                 cprint("mpint *");
470         }
471         cprint("%N = mpnew(0);\n", t);
472         t->s->f &= ~(FSET|FUSE);
473         t->l = atmps;
474         atmps = t;
475         return t;
476 }
477
478 int
479 isconst(Node *n)
480 {
481         if(n->c == NUM)
482                 return 1;
483         if(n->c == NAME){
484                 return  n->s == sym("mpzero") ||
485                         n->s == sym("mpone") ||
486                         n->s == sym("mptwo");
487         }
488         return 0;
489 }
490
491 int
492 istmp(Node *n)
493 {
494         Node *l;
495
496         if(n->c == NAME){
497                 for(l = atmps; l != nil; l = l->l){
498                         if(l->s == n->s)
499                                 return 1;
500                 }
501         }
502         return 0;
503 }
504
505
506 void
507 freetmp(Node *t)
508 {
509         Node **ll, *l;
510
511         if(t == nil)
512                 return;
513         if(t->c == ','){
514                 freetmp(t->l);
515                 freetmp(t->r);
516                 return;
517         }
518         if(t->c != NAME)
519                 return;
520
521         ll = &atmps;
522         for(l = atmps; l != nil; l = l->l){
523                 if(l == t){
524                         cprint("mpfree(%N);\n", t);
525                         *ll = t->l;
526                         t->l = ftmps;
527                         ftmps = t;
528                         return;
529                 }
530                 ll = &l->l;
531         }
532 }
533
534 int
535 symref(Node *n, Sym *s)
536 {
537         if(n == nil)
538                 return 0;
539         if(n->c == NAME && n->s == s)
540                 return 1;
541         return symref(n->l, s) || symref(n->r, s);
542 }
543
544 void
545 nodeset(Node *n)
546 {
547         if(n == nil)
548                 return;
549         if(n->c == NAME){
550                 n->s->f |= FSET;
551                 return;
552         }
553         if(n->c == ','){
554                 nodeset(n->l);
555                 nodeset(n->r);
556         }
557 }
558
559 int
560 complex(Node *n)
561 {
562         if(n->c == NAME)
563                 return 0;
564         if(n->c == NUM && strlen(n->s->n) == 1 && atoi(n->s->n) < 3)
565                 return 0;
566         return 1;
567 }
568
569 void
570 bcom(Node *n, Node *t);
571
572 Node*
573 ecom(Node *f, Node *t)
574 {
575         Node *l, *r, *t2;
576         mpint *m;
577
578         if(f == nil)
579                 return nil;
580
581         if(f->c == NUM){
582                 m = strtomp(f->s->n, nil, 10, nil);
583                 if(mpcmp(m, mpzero) == 0){
584                         f->c = NAME;
585                         f->s = sym("mpzero");
586                         f->s->f = FSET;
587                         return ecom(f, t);
588                 }
589                 if(mpcmp(m, mpone) == 0){
590                         f->c = NAME;
591                         f->s = sym("mpone");
592                         f->s->f = FSET;
593                         return ecom(f, t);
594                 }
595                 if(mpcmp(m, mptwo) == 0){
596                         f->c = NAME;
597                         f->s = sym("mptwo");
598                         f->s->f = FSET;
599                         return ecom(f, t);
600                 }
601                 mpfree(m);
602         }
603
604         if(f->c == ','){
605                 if(t != nil)
606                         diag(f, "cannot assign list to %N", t);
607                 f->l = ecom(f->l, nil);
608                 f->r = ecom(f->r, nil);
609                 return f;
610         }
611
612         l = r = nil;
613         if(f->c == NAME){
614                 if((f->s->f & FSET) == 0)
615                         diag(f, "name used but not set");
616                 f->s->f |= FUSE;
617                 if(t == nil)
618                         return f;
619                 if(f->s != t->s)
620                         cprint("mpassign(%N, %N);\n", f, t);
621                 goto out;
622         }
623
624         if(t == nil)
625                 t = alloctmp();
626
627         if(f->c == '?'){
628                 bcom(f, t);
629                 goto out;
630         }
631
632         if(f->c == 'e'){
633                 r = ecom(f->r, nil);
634                 if(r == nil)
635                         cprint("%N(%N);\n", f->l, t);
636                 else
637                         cprint("%N(%N, %N);\n", f->l, r, t);
638                 goto out;
639         }
640
641         if(t->c != NAME)
642                 diag(f, "destination %N not a name", t);
643
644         switch(f->c){
645         case NUM:
646                 m = strtomp(f->s->n, nil, 10, nil);
647                 if(mpsignif(m) <= 32)
648                         cprint("uitomp(%udUL, %N);\n", mptoui(m), t);
649                 else if(mpsignif(m) <= 64)
650                         cprint("uvtomp(%lludULL, %N);\n", mptouv(m), t);
651                 else
652                         cprint("strtomp(\"%.16B\", nil, 16, %N);\n", m, t);
653                 mpfree(m);
654                 goto out;
655         case LSH:
656                 l = f->l->c == NAME ? f->l : ecom(f->l, t);
657                 cprint("mpleft(%N, %N, %N);\n", l, f->r, t);
658                 goto out;
659         case RSH:
660                 l = f->l->c == NAME ? f->l : ecom(f->l, t);
661                 cprint("mpright(%N, %N, %N);\n", l, f->r, t);
662                 goto out;
663         case '*':
664         case '/':
665                 l = ecom(f->l, nil);
666                 r = ecom(f->r, nil);
667                 break;
668         default:
669                 l = ecom(f->l, complex(f->l) && !symref(f->r, t->s) ? t : nil);
670                 r = ecom(f->r, complex(f->r) && l->s != t->s ? t : nil);
671                 break;
672         }
673
674
675         if(modulo != nil){
676                 switch(f->c){
677                 case '+':
678                         cprint("mpmodadd(%N, %N, %N, %N);\n", l, r, modulo, t);
679                         goto out;
680                 case '-':
681                         cprint("mpmodsub(%N, %N, %N, %N);\n", l, r, modulo, t);
682                         goto out;
683                 case '*':
684                 Modmul:
685                         if(l->s == sym("mptwo") || r->s == sym("mptwo"))
686                                 cprint("mpmodadd(%N, %N, %N, %N); // 2*%N\n",
687                                         r->s == sym("mptwo") ? l : r,
688                                         r->s == sym("mptwo") ? l : r,
689                                         modulo, t,
690                                         r);
691                         else
692                                 cprint("mpmodmul(%N, %N, %N, %N);\n", l, r, modulo, t);
693                         goto out;
694                 case '/':
695                         if(l->s == sym("mpone")){
696                                 cprint("mpinvert(%N, %N, %N);\n", r, modulo, t);
697                                 goto out;
698                         }
699                         t2 = alloctmp();
700                         cprint("mpinvert(%N, %N, %N);\n", r, modulo, t2);
701                         cprint("mpmodmul(%N, %N, %N, %N);\n", l, t2, modulo, t);
702                         freetmp(t2);
703                         goto out;
704                 case '^':
705                         if(r->s == sym("mptwo")){
706                                 r = l;
707                                 goto Modmul;
708                         }
709                         cprint("mpexp(%N, %N, %N, %N);\n", l, r, modulo, t);
710                         goto out;
711                 }
712         }
713
714         switch(f->c){
715         case '+':
716                 cprint("mpadd(%N, %N, %N);\n", l, r, t);
717                 goto out;
718         case '-':
719                 if(l->s == sym("mpzero")){
720                         r = ecom(r, t);
721                         cprint("%N->sign = -%N->sign;\n", t, t);
722                 } else
723                         cprint("mpsub(%N, %N, %N);\n", l, r, t);
724                 goto out;
725         case '*':
726         Mul:
727                 if(l->s == sym("mptwo") || r->s == sym("mptwo"))
728                         cprint("mpleft(%N, 1, %N);\n", r->s == sym("mptwo") ? l : r, t);
729                 else
730                         cprint("mpmul(%N, %N, %N);\n", l, r, t);
731                 goto out;
732         case '/':
733                 cprint("mpdiv(%N, %N, %N, %N);\n", l, r, t, nil);
734                 goto out;
735         case '%':
736                 cprint("mpmod(%N, %N, %N);\n", l, r, t);
737                 goto out;
738         case '^':
739                 if(r->s == sym("mptwo")){
740                         r = l;
741                         goto Mul;
742                 }
743                 cprint("mpexp(%N, %N, nil, %N);\n", l, r, t);
744                 goto out;
745         default:
746                 diag(f, "unknown operation");
747         }
748
749 out:
750         if(l != t)
751                 freetmp(l);
752         if(r != t)
753                 freetmp(r);
754         nodeset(t);
755         return t;
756 }
757
758 void
759 bcom(Node *n, Node *t)
760 {
761         Node *f, *l, *r;
762         int neg = 0;
763
764         l = r = nil;
765         f = n->l;
766 Loop:
767         switch(f->c){
768         case '!':
769                 neg = !neg;
770                 f = f->l;
771                 goto Loop;
772         case '>':
773         case '<':
774         case EQ:
775                 l = ecom(f->l, nil);
776                 r = ecom(f->r, nil);
777                 if(t != nil) {
778                         Node *b1, *b2;
779
780                         b1 = ecom(n->r->l, nil);
781                         b2 = ecom(n->r->r, nil);
782                         cprint("mpsel(");
783
784                         if(l->s == r->s)
785                                 cprint("0");
786                         else {
787                                 if(f->c == '>')
788                                         cprint("-");
789                                 cprint("mpcmp(%N, %N)", l, r);
790                         }
791                         if(f->c == EQ)
792                                 neg = !neg;
793                         else
794                                 cprint(" >> (sizeof(int)*8-1)");
795
796                         cprint(", %N, %N, %N);\n", neg ? b2 : b1, neg ? b1 : b2, t);
797                         freetmp(b1);
798                         freetmp(b2);
799                 } else {
800                         cprint("if(");
801
802                         if(l->s == r->s)
803                                 cprint("0");
804                         else
805                                 cprint("mpcmp(%N, %N)", l, r);
806                         if(f->c == EQ)
807                                 cprint(neg ? " != 0" : " == 0");
808                         else if(f->c == '>')
809                                 cprint(neg ? " <= 0" : " > 0");
810                         else
811                                 cprint(neg ? " >= 0" : " < 0");
812
813                         cprint(")");
814                         com(n->r);
815                 }
816                 break;
817         default:
818                 diag(n, "saw %N in boolean expression", f);
819         }
820         freetmp(l);
821         freetmp(r);
822 }
823
824 void
825 com(Node *n)
826 {
827         Node *l, *r;
828
829 Loop:
830         if(n != nil)
831         switch(n->c){
832         case '\n':
833                 com(n->l);
834                 n = n->r;
835                 goto Loop;
836         case '?':
837                 bcom(n, nil);
838                 break;
839         case 'b':
840                 for(l = atmps; l != nil; l = l->l)
841                         cprint("mpfree(%N);\n", l);
842                 cprint("break;\n");
843                 break;
844         case '@':
845                 cprint("for(;;)");
846         case ':':
847                 clevel++;
848                 cprint("{\n");
849                 l = ftmps;
850                 r = atmps;
851                 if(n->c == '@')
852                         atmps = nil;
853                 ftmps = nil;
854                 com(n->l);
855                 if(n->r != nil){
856                         cprint("}else{\n");
857                         ftmps = nil;
858                         com(n->r);
859                 }
860                 ftmps = l;
861                 atmps = r;
862                 clevel--;
863                 cprint("}\n");
864                 break;
865         case 'm':
866                 l = modulo;
867                 modulo = ecom(n->l, nil);
868                 com(n->r);
869                 freetmp(modulo);
870                 modulo = l;
871                 break;
872         case 'e':
873                 if(n->r == nil)
874                         cprint("%N();\n", n->l);
875                 else {
876                         r = ecom(n->r, nil);
877                         cprint("%N(%N);\n", n->l, r);
878                         freetmp(r);
879                 }
880                 break;
881         case '=':
882                 ecom(n->r, n->l);
883                 break;
884         }
885 }
886
887 Node*
888 flocs(Node *n, Node *r)
889 {
890 Loop:
891         if(n != nil)
892         switch(n->c){
893         default:
894                 r = flocs(n->l, r);
895                 r = flocs(n->r, r);
896                 n = n->r;
897                 goto Loop;
898         case '=':
899                 n = n->l;
900                 if(n == nil)
901                         diag(n, "lhs is nil");
902                 while(n->c == ','){
903                         n->c = '=';
904                         r = flocs(n, r);
905                         n->c = ',';
906                         n = n->r;
907                         if(n == nil)
908                                 return r;
909                 }
910                 if(n->c == NAME && (n->s->f & (FARG|FLOC)) == 0){
911                         n->s->f = FLOC;
912                         return new(',', n, r);
913                 }
914                 break;
915         }
916         return r;
917 }
918
919 void
920 fcom(Node *f, Node *a, Node *b)
921 {
922         Node *a0, *l0, *l;
923
924         ntmp = 0;
925         ftmps = atmps = modulo = nil;
926         clevel = 1;
927         cprint("void %N(", f);
928         a0 = a;
929         while(a != nil){
930                 if(a != a0)
931                         cprint(", ");
932                 l = a->c == NAME ? a : a->l;
933                 l->s->f = FARG|FSET;
934                 cprint("mpint *%N", l);
935                 a = a->r;
936         }
937         cprint("){\n");
938         l0 = flocs(b, nil);
939         for(a = l0; a != nil; a = a->r)
940                 cprint("mpint *%N = mpnew(0);\n", a->l);
941         com(b);
942         for(a = l0; a != nil; a = a->r)
943                 cprint("mpfree(%N);\n", a->l);
944         clevel = 0;
945         cprint("}\n");
946 }
947
948 void
949 diag(Node *n, char *fmt, ...)
950 {
951         static char buf[1024];
952         va_list a;
953         
954         va_start(a, fmt);
955         vsnprint(buf, sizeof(buf), fmt, a);
956         va_end(a);
957
958         fprint(2, "%s:%d: for %N; %s\n", filename, n->n, n, buf);
959         exits("error");
960 }
961
962 int
963 Nfmt(Fmt *f)
964 {
965         Node *n = va_arg(f->args, Node*);
966
967         if(n == nil)
968                 return fmtprint(f, "nil");
969
970         if(n->c == ',')
971                 return fmtprint(f, "%N, %N", n->l, n->r);
972
973         switch(n->c){
974         case NAME:
975         case NUM:
976                 return fmtprint(f, "%s", n->s->n);
977         case EQ:
978                 return fmtprint(f, "==");
979         case IF:
980                 return fmtprint(f, "if");
981         case ELSE:
982                 return fmtprint(f, "else");
983         case MOD:
984                 return fmtprint(f, "mod");
985         default:
986                 return fmtprint(f, "%c", (char)n->c);
987         }
988 }
989
990 void
991 parse(int fd, char *file)
992 {
993         Binit(&bin, fd, OREAD);
994         filename = file;
995         clevel = 0;
996         lineno = 1;
997         goteof = 0;
998         while(!goteof)
999                 yyparse();
1000         Bterm(&bin);
1001 }
1002
1003 void
1004 usage(void)
1005 {
1006         fprint(2, "%s [file ...]\n", argv0);
1007         exits("usage");
1008 }
1009
1010 void
1011 main(int argc, char *argv[])
1012 {
1013         fmtinstall('N', Nfmt);
1014         fmtinstall('B', mpfmt);
1015
1016         ARGBEGIN {
1017         default:
1018                 usage();
1019         } ARGEND;
1020
1021         if(argc == 0){
1022                 parse(0, "<stdin>");
1023                 exits(nil);
1024         }
1025         while(*argv != nil){
1026                 int fd;
1027
1028                 if((fd = open(*argv, OREAD)) < 0){
1029                         fprint(2, "%s: %r\n", *argv);
1030                         exits("error");
1031                 }
1032                 parse(fd, *argv);
1033                 close(fd);
1034                 argv++;
1035         }
1036         exits(nil);
1037 }