]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/pc.y
webfs(4): document -d and -D flags
[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 || inbase != 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 void
314 numdecrefs(int n, Num **x)
315 {
316         int i;
317         
318         for(i = 0; i < n; i++)
319                 numdecref(x[i]);
320 }
321
322 Num *
323 fncall(Symbol *s, int n, Num **x)
324 {
325         int i;
326
327         if(s->t != SYMFUNC){
328                 numdecrefs(n, x);
329                 return error("%s: not a function", s->name);
330         }
331         else if(s->nargs >= 0 && s->nargs != n){
332                 numdecrefs(n, x);
333                 return error("%s: wrong number of arguments", s->name);
334         }
335         for(i = 0; i < n; i++)
336                 if(x[i] == nil)
337                         return nil;
338         return s->func(n, x);
339 }
340
341 Num *
342 hexfix(Symbol *s)
343 {
344         char *b, *p, *q;
345
346         if(inbase != 16) return nil;
347         if(s->val != nil) return numincref(s->val);
348         if(strspn(s->name, "0123456789ABCDEFabcdef_") != strlen(s->name)) return nil;
349         b = strdup(s->name);
350         for(p = b, q = b; *p != 0; p++)
351                 if(*p != '_')
352                         *q++ = *p;
353         *q = 0;
354         s->val = numalloc();
355         strtomp(b, nil, 16, s->val);
356         s->val->b = 16;
357         free(b);
358         return numincref(s->val);
359 }
360
361 %}
362
363 %union {
364         Num *n;
365         Symbol *sym;
366         struct {
367                 Num *x[MAXARGS];
368                 int n;
369         } args;
370 }
371
372 %token <n> LNUM
373 %token <sym> LSYMB
374
375 %type <n> expr
376 %type <args> elist elist1
377
378 %right '='
379 %right '?'
380 %left LOLOR
381 %left LOLAND
382 %left '|'
383 %left '^'
384 %left '&'
385 %left LOEQ LONE
386 %left '<' '>' LOLE LOGE
387 %left LOLSH LORSH
388 %left '+' '-'
389 %left unary
390 %left '*' '/' '%'
391 %right LOEXP
392
393 %{
394         int save;
395         Num *last;
396         Num *lastp;
397 %}
398
399 %%
400
401 input: | input line '\n' {
402                 if(!fail && last != nil) {
403                         numprint(last);
404                         numdecref(lastp);
405                         lastp = last;
406                 }
407                 fail = 0;
408                 last = nil;
409         }
410
411 line: stat
412         | line ';' stat
413
414 stat: { last = nil; }
415         | expr { last = $1; }
416         | '_' { save = inbase; inbase = 10; } expr {
417                 inbase = save;
418                 if(mpcmp($3, mpzero) < 0)
419                         error("no.");
420                 if(!fail) 
421                         sep = mptoi($3);
422                 numdecref($3);
423                 numdecref(last);
424                 last = nil;
425         }
426         | '<' { save = inbase; inbase = 10; } expr {
427                 inbase = save;
428                 if(!fail) 
429                         inbase = mptoi($3);
430                 if(inbase != 2 && inbase != 8 && inbase != 10 && inbase != 16){
431                         error("no.");
432                         inbase = save;
433                 }
434                 numdecref($3);
435                 numdecref(last);
436                 last = nil;
437         }
438         | '>' { save = inbase; inbase = 10; } expr {
439                 inbase = save;
440                 save = outbase;
441                 if(!fail) 
442                         outbase = mptoi($3);
443                 if(outbase != 0 && outbase != 2 && outbase != 8 && outbase != 10 && outbase != 16){
444                         error("no.");
445                         outbase = save;
446                 }
447                 numdecref($3);
448                 numdecref(last);
449                 last = nil;
450         }
451         | '/' { save = inbase; inbase = 10; } expr {
452                 inbase = save;
453                 save = divmode;
454                 if(!fail) 
455                         divmode = mptoi($3);
456                 if(divmode != 0 && divmode != 1){
457                         error("no.");
458                         divmode = save;
459                 }
460                 numdecref($3);
461                 numdecref(last);
462                 last = nil;
463         }
464         | '\'' { save = inbase; inbase = 10; } expr {
465                 inbase = save;
466                 save = heads;
467                 if(!fail) 
468                         heads = mptoi($3);
469                 if(heads != 0 && heads != 1){
470                         error("no.");
471                         heads = save;
472                 }
473                 numdecref($3);
474                 numdecref(last);
475                 last = nil;
476         }
477         | error
478
479 expr: LNUM
480         | '(' expr ')' { $$ = $2; }
481         | expr '+' expr { $$ = numbin('+', $1, $3); }
482         | expr '-' expr { $$ = numbin('-', $1, $3); }
483         | expr '*' expr { $$ = numbin('*', $1, $3); }
484         | expr '/' expr { $$ = numbin('/', $1, $3); }
485         | expr '%' expr { $$ = numbin('%', $1, $3); }
486         | expr '&' expr { $$ = numbin('&', $1, $3); }
487         | expr '|' expr { $$ = numbin('|', $1, $3); }
488         | expr '^' expr { $$ = numbin('^', $1, $3); }   
489         | expr LOEXP expr { $$ = numbin(LOEXP, $1, $3); }
490         | expr LOLSH expr { $$ = numbin(LOLSH, $1, $3); }
491         | expr LORSH expr { $$ = numbin(LORSH, $1, $3); }
492         | expr LOEQ expr { $$ = numbin(LOEQ, $1, $3); }
493         | expr LONE expr { $$ = numbin(LONE, $1, $3); }
494         | expr '<' expr { $$ = numbin('<', $1, $3); }
495         | expr '>' expr { $$ = numbin('>', $1, $3); }
496         | expr LOLE expr { $$ = numbin(LOLE, $1, $3); }
497         | expr LOGE expr { $$ = numbin(LOGE, $1, $3); }
498         | expr LOLAND expr { $$ = numbin(LOLAND, $1, $3); }
499         | expr LOLOR expr { $$ = numbin(LOLOR, $1, $3); }
500         | '+' expr %prec unary { $$ = $2; }
501         | '-' expr %prec unary { $$ = nummod($2); if($$ != nil) mpsub(mpzero, $$, $$); }
502         | '~' expr %prec unary { $$ = nummod($2); if($$ != nil) mpnot($$, $$); }
503         | '!' expr %prec unary { $$ = nummod($2); if($$ != nil) {itomp(mpcmp($$, mpzero) == 0, $$); $$->b = 0; } }
504         | expr '?' expr ':' expr %prec '?' {
505                 if($1 == nil || mpcmp($1, mpzero) != 0){
506                         $$ = $3;
507                         numdecref($5);
508                 }else{
509                         $$ = $5;
510                         numdecref($3);
511                 }
512                 numdecref($1);
513         }
514         | LSYMB '(' elist ')' { $$ = fncall($1, $3.n, $3.x); }
515         | LSYMB {
516                 Num *n;
517                 $$ = nil;
518                 switch($1->t){
519                 case SYMVAR: $$ = numincref($1->val); break;
520                 case SYMNONE:
521                         n = hexfix($1);
522                         if(n != nil) $$ = n;
523                         else error("%s undefined", $1->name);
524                         break;
525                 case SYMFUNC: error("%s is a function", $1->name); break;
526                 default: error("%s invalid here", $1->name);
527                 }
528         }
529         | LSYMB '=' expr {
530                 if($1->t != SYMNONE && $1->t != SYMVAR)
531                         error("%s redefined", $1->name);
532                 else if(!fail){
533                         $1->t = SYMVAR;
534                         numdecref($1->val);
535                         $1->val = numincref($3);
536                 }
537                 $$ = $3;
538         }
539         | '@' {
540                 $$ = lastp;
541                 if($$ == nil) error("no last result");
542                 else numincref($$);
543         }
544
545 elist: { $$.n = 0; } | elist1
546 elist1: expr { $$.x[0] = $1; $$.n = 1; }
547         | elist1 ',' expr {
548                 $$ = $1;
549                 if($$.n >= MAXARGS)
550                         error("too many arguments");
551                 else
552                         $$.x[$$.n++] = $3;
553         }
554
555 %%
556
557 typedef struct Keyword Keyword;
558 struct Keyword {
559         char *name;
560         int tok;
561 };
562
563 Keyword ops[] = {
564         "**", LOEXP,
565         "<<", LOLSH,
566         "<=", LOLE,
567         ">>", LORSH,
568         ">=", LOGE,
569         "==", LOEQ,
570         "&&", LOLAND,
571         "||", LOLOR,
572         "", 0,
573 };
574
575 Keyword *optab[128];
576
577
578 Biobuf *in;
579 int prompted;
580
581 int
582 yylex(void)
583 {
584         int c, b;
585         char buf[512], *p;
586         Keyword *kw;
587         
588         if(prompt && !prompted) {print("; "); prompted = 1;}
589         do
590                 c = Bgetc(in);
591         while(c != '\n' && isspace(c));
592         if(c == '\n') prompted = 0;
593         if(isdigit(c)){
594                 for(p = buf, *p++ = c; c = Bgetc(in), isalnum(c) || c == '_'; )
595                         if(p < buf + sizeof(buf) - 1 && c != '_')
596                                 *p++ = c;
597                 *p = 0;
598                 Bungetc(in);
599                 b = inbase;
600                 p = buf;
601                 if(*p == '0'){
602                         p++;
603                         switch(*p++){
604                         case 0: p -= 2; break;
605                         case 'b': case 'B': b = 2; break;
606                         case 'd': case 'D': b = 10; break;
607                         case 'x': case 'X': b = 16; break;
608                         default: p--; b = 8; break;
609                         }
610                 }
611                 yylval.n = numalloc();
612                 strtomp(p, &p, b, yylval.n);
613                 if(*p != 0) error("not a number: %s", buf);
614                 yylval.n->b = b;
615                 return LNUM;
616         }
617         if(isalpha(c) || c >= 0x80 || c == '_'){
618                 for(p = buf, *p++ = c; c = Bgetc(in), isalnum(c) || c >= 0x80 || c == '_'; )
619                         if(p < buf + sizeof(buf) - 1)
620                                 *p++ = c;
621                 *p = 0;
622                 Bungetc(in);
623                 if(buf[0] == '_' && buf[1] == 0) return '_';
624                 yylval.sym = getsym(buf, 1);
625                 return LSYMB;
626         }
627         if(c < 128 && (kw = optab[c], kw != nil)){
628                 b = Bgetc(in);
629                 for(; kw->name[0] == c; kw++)
630                         if(kw->name[0] == b)
631                                 return kw->tok;
632                 Bungetc(in);
633         }
634         return c;
635 }
636
637 void
638 yyerror(char *msg)
639 {
640         error("%s", msg);
641 }
642
643 void
644 regfunc(char *n, Num *(*f)(int, Num **), int nargs)
645 {
646         Symbol *s;
647         
648         s = getsym(n, 1);
649         s->t = SYMFUNC;
650         s->func = f;
651         s->nargs = nargs;
652 }
653
654 int
655 toint(Num *n, int *p, int mustpos)
656 {
657         if(mpsignif(n) > 31 || mustpos && mpcmp(n, mpzero) < 0){
658                 error("invalid argument");
659                 return -1;
660         }
661         if(p != nil)
662                 *p = mptoi(n);
663         return 0;
664 }
665
666 Num *
667 fnhex(int, Num **a)
668 {
669         Num *r;
670         
671         r = nummod(a[0]);
672         r->b = STRONG | 16;
673         return r;
674 }
675
676 Num *
677 fndec(int, Num **a)
678 {
679         Num *r;
680         
681         r = nummod(a[0]);
682         r->b = STRONG | 10;
683         return r;
684 }
685
686 Num *
687 fnoct(int, Num **a)
688 {
689         Num *r;
690         
691         r = nummod(a[0]);
692         r->b = STRONG | 8;
693         return r;
694 }
695
696 Num *
697 fnbin(int, Num **a)
698 {
699         Num *r;
700         
701         r = nummod(a[0]);
702         r->b = STRONG | 2;
703         return r;
704 }
705
706 Num *
707 fnpb(int, Num **a)
708 {
709         Num *r;
710         int b;
711         
712         if(toint(a[1], &b, 1)){
713         out:
714                 numdecref(a[0]);
715                 numdecref(a[1]);
716                 return nil;
717         }
718         if(b != 0 && b != 2 && b != 8 && b != 10 && b != 16){
719                 error("unsupported base");
720                 goto out;
721         }
722         r = nummod(a[0]);
723         if(b == 0)
724                 r->b = 0;
725         else
726                 r->b = STRONG | b;
727         return r;
728 }
729
730 Num *
731 fnabs(int, Num **a)
732 {
733         Num *r;
734         
735         r = nummod(a[0]);
736         r->sign = 1;
737         return r;
738 }
739
740 Num *
741 fnround(int, Num **a)
742 {
743         mpint *q, *r;
744         int i;
745
746         if(mpcmp(a[1], mpzero) <= 0){
747                 numdecref(a[0]);
748                 numdecref(a[1]);
749                 return error("invalid argument");
750         }
751         q = mpnew(0);
752         r = mpnew(0);
753         a[0] = nummod(a[0]);
754         mpdiv(a[0], a[1], q, r);
755         if(r->sign < 0) mpadd(r, a[1], r);
756         mpleft(r, 1, r);
757         i = mpcmp(r, a[1]);
758         mpright(r, 1, r);
759         if(i > 0 || i == 0 && (a[0]->sign < 0) ^ (q->top != 0 && (q->p[0] & 1) != 0))
760                 mpsub(r, a[1], r);
761         mpsub(a[0], r, a[0]);
762         mpfree(q);
763         mpfree(r);
764         numdecref(a[1]);
765         return a[0];
766 }
767
768 Num *
769 fnfloor(int, Num **a)
770 {
771         mpint *r;
772
773         if(mpcmp(a[1], mpzero) <= 0){
774                 numdecref(a[0]);
775                 numdecref(a[1]);
776                 return error("invalid argument");
777         }
778         r = mpnew(0);
779         a[0] = nummod(a[0]);
780         mpdiv(a[0], a[1], nil, r);
781         if(r->sign < 0) mpadd(r, a[1], r);
782         mpsub(a[0], r, a[0]);
783         mpfree(r);
784         numdecref(a[1]);
785         return a[0];
786 }
787
788 Num *
789 fnceil(int, Num **a)
790 {
791         mpint *r;
792
793         if(mpcmp(a[1], mpzero) <= 0){
794                 numdecref(a[0]);
795                 numdecref(a[1]);
796                 return error("invalid argument");
797         }
798         r = mpnew(0);
799         a[0] = nummod(a[0]);
800         mpdiv(a[0], a[1], nil, r);
801         if(r->sign < 0) mpadd(r, a[1], r);
802         if(mpcmp(r, mpzero) != 0){
803                 mpsub(a[0], r, a[0]);
804                 mpadd(a[0], a[1], a[0]);
805         }
806         mpfree(r);
807         numdecref(a[1]);
808         return a[0];
809 }
810
811 Num *
812 fntrunc(int, Num **a)
813 {
814         int i;
815         
816         if(toint(a[1], &i, 1)){
817                 numdecref(a[0]);
818                 numdecref(a[1]);
819                 return nil;
820         }
821         mptrunc(a[0], i, a[0]);
822         return a[0];
823 }
824
825 Num *
826 fnxtend(int, Num **a)
827 {
828         int i;
829         
830         if(toint(a[1], &i, 1)) return nil;
831         mpxtend(a[0], i, a[0]);
832         return a[0];
833 }
834
835 Num *
836 fnclog(int n, Num **a)
837 {
838         int r;
839
840         if(n != 1 && n != 2){
841                 numdecrefs(n, a);
842                 return error("clog: wrong number of arguments");
843         }
844         if(mpcmp(a[0], mpzero) <= 0 || n == 2 && mpcmp(a[1], mpone) <= 0){
845                 numdecref(a[0]);
846                 return error("invalid argument");
847         }
848         if(n == 1 || mpcmp(a[1], mptwo) == 0){
849                 a[0] = nummod(a[0]);
850                 mpsub(a[0], mpone, a[0]);
851                 itomp(mpsignif(a[0]), a[0]);
852                 a[0]->b = 0;
853                 if(n == 2) numdecref(a[1]);
854                 return a[0];
855         }
856         a[0] = nummod(a[0]);
857         for(r = 0; mpcmp(a[0], mpone) > 0; r++){
858                 mpadd(a[0], a[1], a[0]);
859                 mpsub(a[0], mpone, a[0]);
860                 mpdiv(a[0], a[1], a[0], nil);
861         }
862         itomp(r, a[0]);
863         a[0]->b = 0;
864         numdecref(a[1]);
865         return a[0];
866 }
867
868 Num *
869 fnubits(int, Num **a)
870 {
871         if(a[0]->sign < 0){
872                 numdecref(a[0]);
873                 return error("invalid argument");
874         }
875         a[0] = nummod(a[0]);
876         itomp(mpsignif(a[0]), a[0]);
877         a[0]->b = 0;
878         return a[0];
879 }
880
881 Num *
882 fnsbits(int, Num **a)
883 {
884         a[0] = nummod(a[0]);
885         if(a[0]->sign < 0) mpadd(a[0], mpone, a[0]);
886         itomp(mpsignif(a[0]) + 1, a[0]);
887         a[0]->b = 0;
888         return a[0];
889 }
890
891 Num *
892 fnnsa(int, Num **a)
893 {
894         int n, i;
895         mpdigit d;
896
897         a[0] = nummod(a[0]);
898         if(a[0]->sign < 0){
899                 numdecref(a[0]);
900                 return error("invalid argument");
901         }
902         n = 0;
903         for(i = 0; i < a[0]->top; i++){
904                 d = a[0]->p[i];
905                 for(; d != 0; d &= d-1)
906                         n++;
907         }
908         itomp(n, a[0]);
909         a[0]->b = 0;
910         return a[0];
911 }
912
913 Num *
914 fngcd(int, Num **a)
915 {
916         a[0] = nummod(a[0]);
917         a[0]->b = basemax(a[0]->b, a[1]->b);
918         mpextendedgcd(a[0], a[1], a[0], nil, nil);
919         return a[0];
920 }
921
922 Num *
923 fnrand(int, Num **a)
924 {
925         Num *n;
926
927         n = numalloc();
928         n->b = a[0]->b;
929         mpnrand(a[0], genrandom, n);
930         numdecref(a[0]);
931         return n;
932 }
933
934 Num *
935 fnminv(int, Num **a)
936 {
937         mpint *x;
938
939         a[0] = nummod(a[0]);
940         x = mpnew(0);
941         mpextendedgcd(a[0], a[1], x, a[0], nil);
942         if(mpcmp(x, mpone) != 0)
943                 error("no modular inverse");
944         else
945                 mpmod(a[0], a[1], a[0]);
946         mpfree(x);
947         numdecref(a[1]);
948         return a[0];
949 }
950
951 Num *
952 fnrev(int, Num **a)
953 {
954         mpdigit v, m;
955         int i, j, n;
956         
957         if(toint(a[1], &n, 1)){
958                 numdecref(a[0]);
959                 numdecref(a[1]);
960                 return nil;
961         }
962         a[0] = nummod(a[0]);
963         mptrunc(a[0], n, a[0]);
964         for(i = 0; i < a[0]->top; i++){
965                 v = a[0]->p[i];
966                 m = -1;
967                 for(j = sizeof(mpdigit) * 8; j >>= 1; ){
968                         m ^= m << j;
969                         v = v >> j & m | v << j & ~m;
970                 }
971                 a[0]->p[i] = v;
972         }
973         for(i = 0; i < a[0]->top / 2; i++){
974                 v = a[0]->p[i];
975                 a[0]->p[i] = a[0]->p[a[0]->top - 1 - i];
976                 a[0]->p[a[0]->top - 1 - i] = v;
977         }
978         mpleft(a[0], n - a[0]->top * sizeof(mpdigit) * 8, a[0]);
979         numdecref(a[1]);
980         return a[0];
981 }
982
983 Num *
984 fncat(int n, Num **a)
985 {
986         int i, w;
987         Num *r;
988
989         if(n % 2 != 0){
990                 error("cat: odd number of arguments");
991                 i = 0;
992         fail:
993                 for(; i < n; i++)
994                         numdecref(a[i]);
995                 return nil;
996         }
997         r = numalloc();
998         for(i = 0; i < n; i += 2){
999                 if(toint(a[i+1], &w, 1)) goto fail;
1000                 mpleft(r, w, r);
1001                 if(a[i]->sign < 0 || mpsignif(a[i]) > w){
1002                         a[i] = nummod(a[i]);
1003                         mptrunc(a[i], w, a[i]);
1004                 }
1005                 r->b = basemax(r->b, a[i]->b);
1006                 mpor(r, a[i], r);
1007                 numdecref(a[i]);
1008                 numdecref(a[i+1]);
1009         }
1010         return r;
1011 }
1012
1013 void
1014 main(int argc, char **argv)
1015 {
1016         Keyword *kw;
1017         
1018         fmtinstall('B', mpfmt);
1019         
1020         for(kw = ops; kw->name[0] != 0; kw++)
1021                 if(optab[kw->name[0]] == nil)
1022                         optab[kw->name[0]] = kw;
1023         
1024         regfunc("hex", fnhex, 1);
1025         regfunc("dec", fndec, 1);
1026         regfunc("oct", fnoct, 1);
1027         regfunc("bin", fnbin, 1);
1028         regfunc("pb", fnpb, 2);
1029         regfunc("abs", fnabs, 1);
1030         regfunc("round", fnround, 2);
1031         regfunc("floor", fnfloor, 2);
1032         regfunc("ceil", fnceil, 2);
1033         regfunc("trunc", fntrunc, 2);
1034         regfunc("xtend", fnxtend, 2);
1035         regfunc("clog", fnclog, -1);
1036         regfunc("ubits", fnubits, 1);
1037         regfunc("sbits", fnsbits, 1);
1038         regfunc("nsa", fnnsa, 1);
1039         regfunc("gcd", fngcd, 2);
1040         regfunc("minv", fnminv, 2);
1041         regfunc("rand", fnrand, 1);
1042         regfunc("rev", fnrev, 2);
1043         regfunc("cat", fncat, -1);
1044
1045         prompt = 1;
1046         ARGBEGIN{
1047         case 'n': prompt = 0; break;
1048         }ARGEND;
1049         
1050         in = Bfdopen(0, OREAD);
1051         if(in == nil) sysfatal("Bfdopen: %r");
1052         extern void yyparse(void);
1053         yyparse();
1054 }