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