]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/pc.y
merge
[plan9front.git] / sys / src / cmd / pc.y
1 %{
2 #include <u.h>
3 #include <libc.h>
4 #include <bio.h>
5 #include <ctype.h>
6 #include <mp.h>
7 #include <thread.h>
8 #include <libsec.h>
9
10 int inbase = 10, outbase, divmode, sep, heads, fail, prompt;
11 enum { MAXARGS = 16 };
12
13 typedef struct Num Num;
14 struct Num {
15         mpint;
16         int b;
17         Ref;
18 };
19 enum { STRONG = 0x100 };
20
21 void *
22 emalloc(int n)
23 {
24         void *v;
25         
26         v = malloc(n);
27         if(v == nil)
28                 sysfatal("malloc: %r");
29         memset(v, 0, n);
30         setmalloctag(v, getcallerpc(&n));
31         return v;
32 }
33
34 void *
35 error(char *fmt, ...)
36 {
37         va_list va;
38         Fmt f;
39         char buf[256];
40         
41         fmtfdinit(&f, 2, buf, sizeof(buf));
42         va_start(va, fmt);
43         fmtvprint(&f, fmt, va);
44         fmtrune(&f, '\n');
45         fmtfdflush(&f);
46         va_end(va);
47         fail++;
48         return nil;
49 }
50
51 Num *
52 numalloc(void)
53 {
54         Num *r;
55         
56         r = emalloc(sizeof(Num));
57         r->ref = 1;
58         r->p = emalloc(0);
59         mpassign(mpzero, r);
60         return r;
61 }
62
63 Num *
64 numincref(Num *n)
65 {
66         incref(n);
67         return n;
68 }
69
70 Num *
71 numdecref(Num *n)
72 {
73         if(n == nil) return nil;
74         if(decref(n) == 0){
75                 free(n->p);
76                 free(n);
77                 return nil;
78         }
79         return n;
80 }
81
82 Num *
83 nummod(Num *n)
84 {
85         Num *m;
86
87         if(n == nil) return nil;
88         if(n->ref == 1) return n;
89         m = numalloc();
90         mpassign(n, m);
91         m->b = n->b;
92         numdecref(n);
93         return m;
94 }
95
96 int
97 basemax(int a, int b)
98 {
99         if(a == STRONG+10 && b >= STRONG) return b;
100         if(b == STRONG+10 && a >= STRONG) return a;
101         if(a == 10) return b;
102         if(b == 10) return a;
103         if(a < b) return b;
104         return a;
105 }
106
107 %}
108 %token LOEXP LOLSH LORSH LOEQ LONE LOLE LOGE LOLAND LOLOR
109 %{
110
111 Num *
112 numbin(int op, Num *a, Num *b)
113 {
114         mpint *r;
115         
116         if(fail || a == nil || b == nil) return nil;
117         a = nummod(a);
118         a->b = basemax(a->b, b->b);
119         switch(op){
120         case '+': mpadd(a, b, a); break;
121         case '-': mpsub(a, b, a); break;
122         case '*': mpmul(a, b, a); break;
123         case '/':
124                 if(mpcmp(b, mpzero) == 0){
125                         numdecref(a);
126                         numdecref(b);
127                         return error("division by zero");
128                 }
129                 r = mpnew(0);
130                 mpdiv(a, b, a, r);
131                 if(!divmode && r->sign < 0)
132                         if(b->sign > 0)
133                                 mpsub(a, mpone, a);
134                         else
135                                 mpadd(a, mpone, a);
136                 mpfree(r);
137                 break;
138         case '%':
139                 if(mpcmp(b, mpzero) == 0){
140                         numdecref(a);
141                         numdecref(b);
142                         return error("division by zero");
143                 }       
144                 mpdiv(a, b, nil, a);
145                 if(!divmode && a->sign < 0)
146                         if(b->sign > 0)
147                                 mpadd(a, b, a);
148                         else
149                                 mpsub(a, b, a);
150                 break;
151         case '&': mpand(a, b, a); break;
152         case '|': mpor(a, b, a); break;
153         case '^': mpxor(a, b, a); break;
154         case LOEXP:
155                 if(mpcmp(b, mpzero) < 0){
156                         numdecref(a);
157                         numdecref(b);
158                         return error("negative exponent");
159                 }
160                 mpexp(a, b, nil, a);
161                 break;
162         case LOLSH:
163                 if(mpsignif(b) >= 31){
164                         if(b->sign > 0)
165                                 error("left shift overflow");
166                         itomp(-(mpcmp(a, mpzero) < 0), a);
167                 }else
168                         mpasr(a, -mptoi(b), a);
169                 break;  
170         case LORSH:
171                 if(mpsignif(b) >= 31){
172                         if(b->sign < 0)
173                                 error("right shift overflow");
174                         itomp(-(mpcmp(a, mpzero) < 0), a);
175                 }else
176                         mpasr(a, mptoi(b), a);
177                 break;
178         case '<': itomp(mpcmp(a, b) < 0, a); a->b = 0; break;
179         case '>': itomp(mpcmp(a, b) > 0, a); a->b = 0; break;
180         case LOLE: itomp(mpcmp(a, b) <= 0, a); a->b = 0; break;
181         case LOGE: itomp(mpcmp(a, b) >= 0, a); a->b = 0; break;
182         case LOEQ: itomp(mpcmp(a, b) == 0, a); a->b = 0; break;
183         case LONE: itomp(mpcmp(a, b) != 0, a); a->b = 0; break;
184         case LOLAND:
185                 a->b = b->b;
186                 if(mpcmp(a, mpzero) == 0)
187                         mpassign(mpzero, a);
188                 else
189                         mpassign(b, a);
190                 break;
191         case LOLOR:
192                 a->b = b->b;
193                 if(mpcmp(a, mpzero) != 0)
194                         mpassign(mpone, a);
195                 else
196                         mpassign(b, a);
197                 break;
198         }
199         numdecref(b);
200         return a;
201 }
202
203 typedef struct Symbol Symbol;
204 struct Symbol {
205         enum {
206                 SYMNONE,
207                 SYMVAR,
208                 SYMFUNC,
209         } t;
210         Num *val;
211         int nargs;
212         Num *(*func)(int, Num **); 
213         char *name;
214         Symbol *next;
215 };
216 Symbol *symtab[64];
217
218 Symbol *
219 getsym(char *n, int mk)
220 {
221         Symbol **p;
222         for(p = &symtab[*n&63]; *p != nil; p = &(*p)->next)
223                 if(strcmp((*p)->name, n) == 0)
224                         return *p;
225         if(!mk) return nil;
226         *p = emalloc(sizeof(Symbol));
227         (*p)->name = strdup(n);
228         return *p;
229 }
230
231 static void
232 printhead(int n, int s, int sp, char *t)
233 {
234         char *q;
235         int i, j, k;
236         
237         for(i = 1; i < n; i *= 10)
238                 ;
239         while(i /= 10, i != 0){
240                 q = t;
241                 *--q = 0;
242                 for(j = 0, k = 0; j < n; j += s, k++){
243                         if(k == sep && sep != 0){
244                                 *--q = ' ';
245                                 k = 0;
246                         }
247                         if(j >= i || j == 0 && i == 1)
248                                 *--q = '0' + j / i % 10;
249                         else
250                                 *--q = ' ';
251                 }
252                 for(j = 0; j < sp; j++)
253                         *--q = ' ';
254                 print("%s\n", q);
255         }
256 }
257
258 void
259 numprint(Num *n)
260 {
261         int b;
262         int l, i, st, sp;
263         char *s, *t, *p, *q;
264
265         if(n == nil) return;
266         if(n->b >= STRONG || n->b != 0 && outbase == 0)
267                 b = n->b & ~STRONG;
268         else if(outbase == 0)
269                 b = 10;
270         else
271                 b = outbase;
272         s = mptoa(n, b, nil, 0);
273         l = strlen(s);
274         t = emalloc(l * 2 + 4);
275         q = t + l * 2 + 4;
276         if(heads){
277                 switch(b){
278                 case 16: st = 4; sp = 2; break;
279                 case 8: st = 3; sp = 1; break;
280                 case 2: st = 1; sp = 2; break;
281                 default: st = 0; sp = 0;
282                 }
283                 if(n->sign < 0)
284                         sp++;
285                 if(st != 0)
286                         printhead(mpsignif(n), st, sp, q);
287         }
288         *--q = 0;
289         for(p = s + l - 1, i = 0; p >= s && *p != '-'; p--, i++){
290                 if(sep != 0 && i == sep){
291                         *--q = '_';
292                         i = 0;
293                 }
294                 if(*p >= 'A')
295                         *--q = *p + ('a' - 'A');
296                 else
297                         *--q = *p;
298         }
299         if(mpcmp(n, mpzero) != 0)
300                 switch(b){
301                 case 16: *--q = 'x'; *--q = '0'; break;
302                 case 10: if(outbase != 0 && outbase != 10) {*--q = 'd'; *--q = '0';} break;
303                 case 8: *--q = '0'; break;
304                 case 2: *--q = 'b'; *--q = '0'; break;
305                 }
306         if(p >= s)
307                 *--q = '-';
308         print("%s\n", q);
309         free(s);
310         free(t);
311 }
312
313 Num *
314 fncall(Symbol *s, int n, Num **x)
315 {
316         int i;
317
318         if(s->t != SYMFUNC)
319                 return error("%s: not a function", s->name);
320         else if(s->nargs >= 0 && s->nargs != n)
321                 return error("%s: wrong number of arguments", s->name);
322         for(i = 0; i < n; i++)
323                 if(x[i] == nil)
324                         return nil;
325         return s->func(n, x);
326 }
327
328 Num *
329 hexfix(Symbol *s)
330 {
331         char *b, *p, *q;
332
333         if(inbase != 16) return nil;
334         if(s->val != nil) return numincref(s->val);
335         if(strspn(s->name, "0123456789ABCDEFabcdef_") != strlen(s->name)) return nil;
336         b = strdup(s->name);
337         for(p = b, q = b; *p != 0; p++)
338                 if(*p != '_')
339                         *q++ = *p;
340         *q = 0;
341         s->val = numalloc();
342         strtomp(b, nil, 16, s->val);
343         s->val->b = 16;
344         free(b);
345         return numincref(s->val);
346 }
347
348 %}
349
350 %union {
351         Num *n;
352         Symbol *sym;
353         struct {
354                 Num *x[MAXARGS];
355                 int n;
356         } args;
357 }
358
359 %token <n> LNUM
360 %token <sym> LSYMB
361
362 %type <n> expr
363 %type <args> elist elist1
364
365 %right '='
366 %right '?'
367 %left LOLOR
368 %left LOLAND
369 %left '|'
370 %left '^'
371 %left '&'
372 %left LOEQ LONE
373 %left '<' '>' LOLE LOGE
374 %left LOLSH LORSH
375 %left '+' '-'
376 %left unary
377 %left '*' '/' '%'
378 %right LOEXP
379
380 %{
381         int save;
382         Num *last;
383         Num *lastp;
384 %}
385
386 %%
387
388 input: | input line '\n' {
389                 if(!fail && last != nil) {
390                         numprint(last);
391                         numdecref(lastp);
392                         lastp = last;
393                 }
394                 fail = 0;
395                 last = nil;
396         }
397
398 line: stat
399         | line ';' stat
400
401 stat: { last = nil; }
402         | expr { last = $1; }
403         | '_' { save = inbase; inbase = 10; } expr {
404                 inbase = save;
405                 if(mpcmp($3, mpzero) < 0)
406                         error("no.");
407                 if(!fail) 
408                         sep = mptoi($3);
409                 numdecref($3);
410                 numdecref(last);
411                 last = nil;
412         }
413         | '<' { save = inbase; inbase = 10; } expr {
414                 inbase = save;
415                 if(!fail) 
416                         inbase = mptoi($3);
417                 if(inbase != 2 && inbase != 8 && inbase != 10 && inbase != 16){
418                         error("no.");
419                         inbase = save;
420                 }
421                 numdecref($3);
422                 numdecref(last);
423                 last = nil;
424         }
425         | '>' { save = inbase; inbase = 10; } expr {
426                 inbase = save;
427                 save = outbase;
428                 if(!fail) 
429                         outbase = mptoi($3);
430                 if(outbase != 0 && outbase != 2 && outbase != 8 && outbase != 10 && outbase != 16){
431                         error("no.");
432                         outbase = save;
433                 }
434                 numdecref($3);
435                 numdecref(last);
436                 last = nil;
437         }
438         | '/' { save = inbase; inbase = 10; } expr {
439                 inbase = save;
440                 save = divmode;
441                 if(!fail) 
442                         divmode = mptoi($3);
443                 if(divmode != 0 && divmode != 1){
444                         error("no.");
445                         divmode = save;
446                 }
447                 numdecref($3);
448                 numdecref(last);
449                 last = nil;
450         }
451         | '\'' { save = inbase; inbase = 10; } expr {
452                 inbase = save;
453                 save = heads;
454                 if(!fail) 
455                         heads = mptoi($3);
456                 if(heads != 0 && heads != 1){
457                         error("no.");
458                         heads = save;
459                 }
460                 numdecref($3);
461                 numdecref(last);
462                 last = nil;
463         }
464         | error
465
466 expr: LNUM
467         | '(' expr ')' { $$ = $2; }
468         | expr '+' expr { $$ = numbin('+', $1, $3); }
469         | expr '-' expr { $$ = numbin('-', $1, $3); }
470         | expr '*' expr { $$ = numbin('*', $1, $3); }
471         | expr '/' expr { $$ = numbin('/', $1, $3); }
472         | expr '%' expr { $$ = numbin('%', $1, $3); }
473         | expr '&' expr { $$ = numbin('&', $1, $3); }
474         | expr '|' expr { $$ = numbin('|', $1, $3); }
475         | expr '^' expr { $$ = numbin('^', $1, $3); }   
476         | expr LOEXP expr { $$ = numbin(LOEXP, $1, $3); }
477         | expr LOLSH expr { $$ = numbin(LOLSH, $1, $3); }
478         | expr LORSH expr { $$ = numbin(LORSH, $1, $3); }
479         | expr LOEQ expr { $$ = numbin(LOEQ, $1, $3); }
480         | expr LONE expr { $$ = numbin(LONE, $1, $3); }
481         | expr '<' expr { $$ = numbin('<', $1, $3); }
482         | expr '>' expr { $$ = numbin('>', $1, $3); }
483         | expr LOLE expr { $$ = numbin(LOLE, $1, $3); }
484         | expr LOGE expr { $$ = numbin(LOGE, $1, $3); }
485         | expr LOLAND expr { $$ = numbin(LOLAND, $1, $3); }
486         | expr LOLOR expr { $$ = numbin(LOLOR, $1, $3); }
487         | '+' expr %prec unary { $$ = $2; }
488         | '-' expr %prec unary { $$ = nummod($2); if($$ != nil) mpsub(mpzero, $$, $$); }
489         | '~' expr %prec unary { $$ = nummod($2); if($$ != nil) mpnot($$, $$); }
490         | '!' expr %prec unary { $$ = nummod($2); if($$ != nil) {itomp(mpcmp($$, mpzero) == 0, $$); $$->b = 0; } }
491         | expr '?' expr ':' expr %prec '?' {
492                 if($1 == nil || mpcmp($1, mpzero) != 0){
493                         $$ = $3;
494                         numdecref($5);
495                 }else{
496                         $$ = $5;
497                         numdecref($3);
498                 }
499                 numdecref($1);
500         }
501         | LSYMB '(' elist ')' { $$ = fncall($1, $3.n, $3.x); }
502         | LSYMB {
503                 Num *n;
504                 $$ = nil;
505                 switch($1->t){
506                 case SYMVAR: $$ = numincref($1->val); break;
507                 case SYMNONE:
508                         n = hexfix($1);
509                         if(n != nil) $$ = n;
510                         else error("%s undefined", $1->name);
511                         break;
512                 case SYMFUNC: error("%s is a function", $1->name); break;
513                 default: error("%s invalid here", $1->name);
514                 }
515         }
516         | LSYMB '=' expr {
517                 if($1->t != SYMNONE && $1->t != SYMVAR)
518                         error("%s redefined", $1->name);
519                 else if(!fail){
520                         $1->t = SYMVAR;
521                         numdecref($1->val);
522                         $1->val = numincref($3);
523                 }
524                 $$ = $3;
525         }
526         | '@' {
527                 $$ = lastp;
528                 if($$ == nil) error("no last result");
529                 else numincref($$);
530         }
531
532 elist: { $$.n = 0; } | elist1
533 elist1: expr { $$.x[0] = $1; $$.n = 1; }
534         | elist1 ',' expr {
535                 $$ = $1;
536                 if($$.n >= MAXARGS)
537                         error("too many arguments");
538                 else
539                         $$.x[$$.n++] = $3;
540         }
541
542 %%
543
544 typedef struct Keyword Keyword;
545 struct Keyword {
546         char *name;
547         int tok;
548 };
549
550 Keyword ops[] = {
551         "**", LOEXP,
552         "<<", LOLSH,
553         "<=", LOLE,
554         ">>", LORSH,
555         ">=", LOGE,
556         "==", LOEQ,
557         "&&", LOLAND,
558         "||", LOLOR,
559         "", 0,
560 };
561
562 Keyword *optab[128];
563
564
565 Biobuf *in;
566 int prompted;
567
568 int
569 yylex(void)
570 {
571         int c, b;
572         char buf[512], *p;
573         Keyword *kw;
574         
575         if(prompt && !prompted) {print("; "); prompted = 1;}
576         do
577                 c = Bgetc(in);
578         while(c != '\n' && isspace(c));
579         if(c == '\n') prompted = 0;
580         if(isdigit(c)){
581                 for(p = buf, *p++ = c; c = Bgetc(in), isalnum(c) || c == '_'; )
582                         if(p < buf + sizeof(buf) - 1 && c != '_')
583                                 *p++ = c;
584                 *p = 0;
585                 Bungetc(in);
586                 b = inbase;
587                 p = buf;
588                 if(*p == '0'){
589                         p++;
590                         switch(*p++){
591                         case 0: p -= 2; break;
592                         case 'b': case 'B': b = 2; break;
593                         case 'd': case 'D': b = 10; break;
594                         case 'x': case 'X': b = 16; break;
595                         default: p--; b = 8; break;
596                         }
597                 }
598                 yylval.n = numalloc();
599                 strtomp(p, &p, b, yylval.n);
600                 if(*p != 0) error("not a number: %s", buf);
601                 yylval.n->b = b;
602                 return LNUM;
603         }
604         if(isalpha(c) || c >= 0x80 || c == '_'){
605                 for(p = buf, *p++ = c; c = Bgetc(in), isalnum(c) || c >= 0x80 || c == '_'; )
606                         if(p < buf + sizeof(buf) - 1)
607                                 *p++ = c;
608                 *p = 0;
609                 Bungetc(in);
610                 if(buf[0] == '_' && buf[1] == 0) return '_';
611                 yylval.sym = getsym(buf, 1);
612                 return LSYMB;
613         }
614         if(c < 128 && (kw = optab[c], kw != nil)){
615                 b = Bgetc(in);
616                 for(; kw->name[0] == c; kw++)
617                         if(kw->name[0] == b)
618                                 return kw->tok;
619                 Bungetc(in);
620         }
621         return c;
622 }
623
624 void
625 yyerror(char *msg)
626 {
627         error("%s", msg);
628 }
629
630 void
631 regfunc(char *n, Num *(*f)(int, Num **), int nargs)
632 {
633         Symbol *s;
634         
635         s = getsym(n, 1);
636         s->t = SYMFUNC;
637         s->func = f;
638         s->nargs = nargs;
639 }
640
641 int
642 toint(Num *n, int *p, int mustpos)
643 {
644         if(mpsignif(n) > 31 || mustpos && mpcmp(n, mpzero) < 0){
645                 error("invalid argument");
646                 return -1;
647         }
648         if(p != nil)
649                 *p = mptoi(n);
650         return 0;
651 }
652
653 Num *
654 fnhex(int, Num **a)
655 {
656         Num *r;
657         
658         r = nummod(a[0]);
659         r->b = STRONG | 16;
660         return r;
661 }
662
663 Num *
664 fndec(int, Num **a)
665 {
666         Num *r;
667         
668         r = nummod(a[0]);
669         r->b = STRONG | 10;
670         return r;
671 }
672
673 Num *
674 fnoct(int, Num **a)
675 {
676         Num *r;
677         
678         r = nummod(a[0]);
679         r->b = STRONG | 8;
680         return r;
681 }
682
683 Num *
684 fnbin(int, Num **a)
685 {
686         Num *r;
687         
688         r = nummod(a[0]);
689         r->b = STRONG | 2;
690         return r;
691 }
692
693 Num *
694 fnpb(int, Num **a)
695 {
696         Num *r;
697         int b;
698         
699         if(toint(a[1], &b, 1)){
700         out:
701                 numdecref(a[0]);
702                 numdecref(a[1]);
703                 return nil;
704         }
705         if(b != 0 && b != 2 && b != 8 && b != 10 && b != 16){
706                 error("unsupported base");
707                 goto out;
708         }
709         r = nummod(a[0]);
710         if(b == 0)
711                 r->b = 0;
712         else
713                 r->b = STRONG | b;
714         return r;
715 }
716
717 Num *
718 fnabs(int, Num **a)
719 {
720         Num *r;
721         
722         r = nummod(a[0]);
723         r->sign = 1;
724         return r;
725 }
726
727 Num *
728 fnround(int, Num **a)
729 {
730         mpint *q, *r;
731         int i;
732
733         if(mpcmp(a[1], mpzero) <= 0){
734                 numdecref(a[0]);
735                 numdecref(a[1]);
736                 return error("invalid argument");
737         }
738         q = mpnew(0);
739         r = mpnew(0);
740         a[0] = nummod(a[0]);
741         mpdiv(a[0], a[1], q, r);
742         if(r->sign < 0) mpadd(r, a[1], r);
743         mpleft(r, 1, r);
744         i = mpcmp(r, a[1]);
745         mpright(r, 1, r);
746         if(i > 0 || i == 0 && (a[0]->sign < 0) ^ (q->top != 0 && (q->p[0] & 1) != 0))
747                 mpsub(r, a[1], r);
748         mpsub(a[0], r, a[0]);
749         mpfree(q);
750         mpfree(r);
751         numdecref(a[1]);
752         return a[0];
753 }
754
755 Num *
756 fnfloor(int, Num **a)
757 {
758         mpint *r;
759
760         if(mpcmp(a[1], mpzero) <= 0){
761                 numdecref(a[0]);
762                 numdecref(a[1]);
763                 return error("invalid argument");
764         }
765         r = mpnew(0);
766         a[0] = nummod(a[0]);
767         mpdiv(a[0], a[1], nil, r);
768         if(r->sign < 0) mpadd(r, a[1], r);
769         mpsub(a[0], r, a[0]);
770         mpfree(r);
771         numdecref(a[1]);
772         return a[0];
773 }
774
775 Num *
776 fnceil(int, Num **a)
777 {
778         mpint *r;
779
780         if(mpcmp(a[1], mpzero) <= 0){
781                 numdecref(a[0]);
782                 numdecref(a[1]);
783                 return error("invalid argument");
784         }
785         r = mpnew(0);
786         a[0] = nummod(a[0]);
787         mpdiv(a[0], a[1], nil, r);
788         if(r->sign < 0) mpadd(r, a[1], r);
789         if(mpcmp(r, mpzero) != 0){
790                 mpsub(a[0], r, a[0]);
791                 mpadd(a[0], a[1], a[0]);
792         }
793         mpfree(r);
794         numdecref(a[1]);
795         return a[0];
796 }
797
798 Num *
799 fntrunc(int, Num **a)
800 {
801         int i;
802         
803         if(toint(a[1], &i, 1)){
804                 numdecref(a[0]);
805                 numdecref(a[1]);
806                 return nil;
807         }
808         mptrunc(a[0], i, a[0]);
809         return a[0];
810 }
811
812 Num *
813 fnxtend(int, Num **a)
814 {
815         int i;
816         
817         if(toint(a[1], &i, 1)) return nil;
818         mpxtend(a[0], i, a[0]);
819         return a[0];
820 }
821
822 Num *
823 fnubits(int, Num **a)
824 {
825         if(a[0]->sign < 0){
826                 numdecref(a[0]);
827                 return error("invalid argument");
828         }
829         a[0] = nummod(a[0]);
830         itomp(mpsignif(a[0]), a[0]);
831         a[0]->b = 0;
832         return a[0];
833 }
834
835 Num *
836 fnsbits(int, Num **a)
837 {
838         a[0] = nummod(a[0]);
839         if(a[0]->sign < 0) mpadd(a[0], mpone, a[0]);
840         itomp(mpsignif(a[0]) + 1, a[0]);
841         a[0]->b = 0;
842         return a[0];
843 }
844
845 Num *
846 fnnsa(int, Num **a)
847 {
848         int n, i;
849         mpdigit d;
850
851         a[0] = nummod(a[0]);
852         if(a[0]->sign < 0){
853                 numdecref(a[0]);
854                 return error("invalid argument");
855         }
856         n = 0;
857         for(i = 0; i < a[0]->top; i++){
858                 d = a[0]->p[i];
859                 for(; d != 0; d &= d-1)
860                         n++;
861         }
862         itomp(n, a[0]);
863         a[0]->b = 0;
864         return a[0];
865 }
866
867 Num *
868 fngcd(int, Num **a)
869 {
870         a[0] = nummod(a[0]);
871         a[0]->b = basemax(a[0]->b, a[1]->b);
872         mpextendedgcd(a[0], a[1], a[0], nil, nil);
873         return a[0];
874 }
875
876 Num *
877 fnrand(int, Num **a)
878 {
879         Num *n;
880
881         n = numalloc();
882         n->b = a[0]->b;
883         mpnrand(a[0], genrandom, n);
884         numdecref(a[0]);
885         return n;
886 }
887
888 Num *
889 fnminv(int, Num **a)
890 {
891         mpint *x;
892
893         a[0] = nummod(a[0]);
894         x = mpnew(0);
895         mpextendedgcd(a[0], a[1], x, a[0], nil);
896         if(mpcmp(x, mpone) != 0)
897                 error("no modular inverse");
898         else
899                 mpmod(a[0], a[1], a[0]);
900         mpfree(x);
901         numdecref(a[1]);
902         return a[0];
903 }
904
905 Num *
906 fnrev(int, Num **a)
907 {
908         mpdigit v, m;
909         int i, j, n;
910         
911         if(toint(a[1], &n, 1)){
912                 numdecref(a[0]);
913                 numdecref(a[1]);
914                 return nil;
915         }
916         a[0] = nummod(a[0]);
917         mptrunc(a[0], n, a[0]);
918         for(i = 0; i < a[0]->top; i++){
919                 v = a[0]->p[i];
920                 m = -1;
921                 for(j = sizeof(mpdigit) * 8; j >>= 1; ){
922                         m ^= m << j;
923                         v = v >> j & m | v << j & ~m;
924                 }
925                 a[0]->p[i] = v;
926         }
927         for(i = 0; i < a[0]->top / 2; i++){
928                 v = a[0]->p[i];
929                 a[0]->p[i] = a[0]->p[a[0]->top - 1 - i];
930                 a[0]->p[a[0]->top - 1 - i] = v;
931         }
932         mpleft(a[0], n - a[0]->top * sizeof(mpdigit) * 8, a[0]);
933         numdecref(a[1]);
934         return a[0];
935 }
936
937 Num *
938 fncat(int n, Num **a)
939 {
940         int i, w;
941         Num *r;
942
943         if(n % 2 != 0){
944                 error("cat: odd number of arguments");
945                 i = 0;
946         fail:
947                 for(; i < n; i++)
948                         numdecref(a[i]);
949                 return nil;
950         }
951         r = numalloc();
952         for(i = 0; i < n; i += 2){
953                 if(toint(a[i+1], &w, 1)) goto fail;
954                 mpleft(r, w, r);
955                 if(a[i]->sign < 0 || mpsignif(a[i]) > w){
956                         a[i] = nummod(a[i]);
957                         mptrunc(a[i], w, a[i]);
958                 }
959                 r->b = basemax(r->b, a[i]->b);
960                 mpor(r, a[i], r);
961                 numdecref(a[i]);
962                 numdecref(a[i+1]);
963         }
964         return r;
965 }
966
967 void
968 main(int argc, char **argv)
969 {
970         Keyword *kw;
971         
972         fmtinstall('B', mpfmt);
973         
974         for(kw = ops; kw->name[0] != 0; kw++)
975                 if(optab[kw->name[0]] == nil)
976                         optab[kw->name[0]] = kw;
977         
978         regfunc("hex", fnhex, 1);
979         regfunc("dec", fndec, 1);
980         regfunc("oct", fnoct, 1);
981         regfunc("bin", fnbin, 1);
982         regfunc("pb", fnpb, 2);
983         regfunc("abs", fnabs, 1);
984         regfunc("round", fnround, 2);
985         regfunc("floor", fnfloor, 2);
986         regfunc("ceil", fnceil, 2);
987         regfunc("trunc", fntrunc, 2);
988         regfunc("xtend", fnxtend, 2);
989         regfunc("ubits", fnubits, 1);
990         regfunc("sbits", fnsbits, 1);
991         regfunc("nsa", fnnsa, 1);
992         regfunc("gcd", fngcd, 2);
993         regfunc("minv", fnminv, 2);
994         regfunc("rand", fnrand, 1);
995         regfunc("rev", fnrev, 2);
996         regfunc("cat", fncat, -1);
997
998         prompt = 1;
999         ARGBEGIN{
1000         case 'n': prompt = 0; break;
1001         }ARGEND;
1002         
1003         in = Bfdopen(0, OREAD);
1004         if(in == nil) sysfatal("Bfdopen: %r");
1005         extern void yyparse(void);
1006         yyparse();
1007 }