]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/pc.y
pc: add $ operator
[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(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) {print("; "); prompted = 1;}
596         do
597                 c = Bgetc(in);
598         while(c != '\n' && isspace(c));
599         if(c == '\n') prompted = 0;
600         if(isdigit(c)){
601                 for(p = buf, *p++ = c; c = Bgetc(in), isalnum(c) || c == '_'; )
602                         if(p < buf + sizeof(buf) - 1 && c != '_')
603                                 *p++ = c;
604                 *p = 0;
605                 Bungetc(in);
606                 b = inbase;
607                 p = buf;
608                 if(*p == '0'){
609                         p++;
610                         switch(*p++){
611                         case 0: p -= 2; break;
612                         case 'b': case 'B': b = 2; break;
613                         case 'd': case 'D': b = 10; break;
614                         case 'x': case 'X': b = 16; break;
615                         default: p--; b = 8; break;
616                         }
617                 }
618                 yylval.n = numalloc();
619                 strtomp(p, &p, b, yylval.n);
620                 if(*p != 0) error("not a number: %s", buf);
621                 yylval.n->b = b;
622                 return LNUM;
623         }
624         if(isalpha(c) || c >= 0x80 || c == '_'){
625                 for(p = buf, *p++ = c; c = Bgetc(in), isalnum(c) || c >= 0x80 || c == '_'; )
626                         if(p < buf + sizeof(buf) - 1)
627                                 *p++ = c;
628                 *p = 0;
629                 Bungetc(in);
630                 if(buf[0] == '_' && buf[1] == 0) return '_';
631                 yylval.sym = getsym(buf, 1);
632                 return LSYMB;
633         }
634         if(c < 128 && (kw = optab[c], kw != nil)){
635                 b = Bgetc(in);
636                 for(; kw->name[0] == c; kw++)
637                         if(kw->name[0] == b)
638                                 return kw->tok;
639                 Bungetc(in);
640         }
641         return c;
642 }
643
644 void
645 yyerror(char *msg)
646 {
647         error("%s", msg);
648 }
649
650 void
651 regfunc(char *n, Num *(*f)(int, Num **), int nargs)
652 {
653         Symbol *s;
654         
655         s = getsym(n, 1);
656         s->t = SYMFUNC;
657         s->func = f;
658         s->nargs = nargs;
659 }
660
661 int
662 toint(Num *n, int *p, int mustpos)
663 {
664         if(mpsignif(n) > 31 || mustpos && mpcmp(n, mpzero) < 0){
665                 error("invalid argument");
666                 return -1;
667         }
668         if(p != nil)
669                 *p = mptoi(n);
670         return 0;
671 }
672
673 Num *
674 fnhex(int, Num **a)
675 {
676         Num *r;
677         
678         r = nummod(a[0]);
679         r->b = STRONG | 16;
680         return r;
681 }
682
683 Num *
684 fndec(int, Num **a)
685 {
686         Num *r;
687         
688         r = nummod(a[0]);
689         r->b = STRONG | 10;
690         return r;
691 }
692
693 Num *
694 fnoct(int, Num **a)
695 {
696         Num *r;
697         
698         r = nummod(a[0]);
699         r->b = STRONG | 8;
700         return r;
701 }
702
703 Num *
704 fnbin(int, Num **a)
705 {
706         Num *r;
707         
708         r = nummod(a[0]);
709         r->b = STRONG | 2;
710         return r;
711 }
712
713 Num *
714 fnpb(int, Num **a)
715 {
716         Num *r;
717         int b;
718         
719         if(toint(a[1], &b, 1)){
720         out:
721                 numdecref(a[0]);
722                 numdecref(a[1]);
723                 return nil;
724         }
725         if(b != 0 && b != 2 && b != 8 && b != 10 && b != 16){
726                 error("unsupported base");
727                 goto out;
728         }
729         r = nummod(a[0]);
730         if(b == 0)
731                 r->b = 0;
732         else
733                 r->b = STRONG | b;
734         return r;
735 }
736
737 Num *
738 fnabs(int, Num **a)
739 {
740         Num *r;
741         
742         r = nummod(a[0]);
743         r->sign = 1;
744         return r;
745 }
746
747 Num *
748 fnround(int, Num **a)
749 {
750         mpint *q, *r;
751         int i;
752
753         if(mpcmp(a[1], mpzero) <= 0){
754                 numdecref(a[0]);
755                 numdecref(a[1]);
756                 return error("invalid argument");
757         }
758         q = mpnew(0);
759         r = mpnew(0);
760         a[0] = nummod(a[0]);
761         mpdiv(a[0], a[1], q, r);
762         if(r->sign < 0) mpadd(r, a[1], r);
763         mpleft(r, 1, r);
764         i = mpcmp(r, a[1]);
765         mpright(r, 1, r);
766         if(i > 0 || i == 0 && (a[0]->sign < 0) ^ (q->top != 0 && (q->p[0] & 1) != 0))
767                 mpsub(r, a[1], r);
768         mpsub(a[0], r, a[0]);
769         mpfree(q);
770         mpfree(r);
771         numdecref(a[1]);
772         return a[0];
773 }
774
775 Num *
776 fnfloor(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         mpsub(a[0], r, a[0]);
790         mpfree(r);
791         numdecref(a[1]);
792         return a[0];
793 }
794
795 Num *
796 fnceil(int, Num **a)
797 {
798         mpint *r;
799
800         if(mpcmp(a[1], mpzero) <= 0){
801                 numdecref(a[0]);
802                 numdecref(a[1]);
803                 return error("invalid argument");
804         }
805         r = mpnew(0);
806         a[0] = nummod(a[0]);
807         mpdiv(a[0], a[1], nil, r);
808         if(r->sign < 0) mpadd(r, a[1], r);
809         if(mpcmp(r, mpzero) != 0){
810                 mpsub(a[0], r, a[0]);
811                 mpadd(a[0], a[1], a[0]);
812         }
813         mpfree(r);
814         numdecref(a[1]);
815         return a[0];
816 }
817
818 Num *
819 fntrunc(int, Num **a)
820 {
821         int i;
822         
823         if(toint(a[1], &i, 1)){
824                 numdecref(a[0]);
825                 numdecref(a[1]);
826                 return nil;
827         }
828         mptrunc(a[0], i, a[0]);
829         return a[0];
830 }
831
832 Num *
833 fnxtend(int, Num **a)
834 {
835         int i;
836         
837         if(toint(a[1], &i, 1)) return nil;
838         mpxtend(a[0], i, a[0]);
839         return a[0];
840 }
841
842 Num *
843 fnclog(int n, Num **a)
844 {
845         int r;
846
847         if(n != 1 && n != 2){
848                 numdecrefs(n, a);
849                 return error("clog: wrong number of arguments");
850         }
851         if(mpcmp(a[0], mpzero) <= 0 || n == 2 && mpcmp(a[1], mpone) <= 0){
852                 numdecref(a[0]);
853                 return error("invalid argument");
854         }
855         if(n == 1 || mpcmp(a[1], mptwo) == 0){
856                 a[0] = nummod(a[0]);
857                 mpsub(a[0], mpone, a[0]);
858                 itomp(mpsignif(a[0]), a[0]);
859                 a[0]->b = 0;
860                 if(n == 2) numdecref(a[1]);
861                 return a[0];
862         }
863         a[0] = nummod(a[0]);
864         for(r = 0; mpcmp(a[0], mpone) > 0; r++){
865                 mpadd(a[0], a[1], a[0]);
866                 mpsub(a[0], mpone, a[0]);
867                 mpdiv(a[0], a[1], a[0], nil);
868         }
869         itomp(r, a[0]);
870         a[0]->b = 0;
871         numdecref(a[1]);
872         return a[0];
873 }
874
875 Num *
876 fnubits(int, Num **a)
877 {
878         if(a[0]->sign < 0){
879                 numdecref(a[0]);
880                 return error("invalid argument");
881         }
882         a[0] = nummod(a[0]);
883         itomp(mpsignif(a[0]), a[0]);
884         a[0]->b = 0;
885         return a[0];
886 }
887
888 Num *
889 fnsbits(int, Num **a)
890 {
891         a[0] = nummod(a[0]);
892         if(a[0]->sign < 0) mpadd(a[0], mpone, a[0]);
893         itomp(mpsignif(a[0]) + 1, a[0]);
894         a[0]->b = 0;
895         return a[0];
896 }
897
898 Num *
899 fnnsa(int, Num **a)
900 {
901         int n, i;
902         mpdigit d;
903
904         a[0] = nummod(a[0]);
905         if(a[0]->sign < 0){
906                 numdecref(a[0]);
907                 return error("invalid argument");
908         }
909         n = 0;
910         for(i = 0; i < a[0]->top; i++){
911                 d = a[0]->p[i];
912                 for(; d != 0; d &= d-1)
913                         n++;
914         }
915         itomp(n, a[0]);
916         a[0]->b = 0;
917         return a[0];
918 }
919
920 Num *
921 fngcd(int, Num **a)
922 {
923         a[0] = nummod(a[0]);
924         a[0]->b = basemax(a[0]->b, a[1]->b);
925         mpextendedgcd(a[0], a[1], a[0], nil, nil);
926         return a[0];
927 }
928
929 Num *
930 fnrand(int, Num **a)
931 {
932         Num *n;
933
934         n = numalloc();
935         n->b = a[0]->b;
936         mpnrand(a[0], genrandom, n);
937         numdecref(a[0]);
938         return n;
939 }
940
941 Num *
942 fnminv(int, Num **a)
943 {
944         mpint *x;
945
946         a[0] = nummod(a[0]);
947         x = mpnew(0);
948         mpextendedgcd(a[0], a[1], x, a[0], nil);
949         if(mpcmp(x, mpone) != 0)
950                 error("no modular inverse");
951         else
952                 mpmod(a[0], a[1], a[0]);
953         mpfree(x);
954         numdecref(a[1]);
955         return a[0];
956 }
957
958 Num *
959 fnrev(int, Num **a)
960 {
961         mpdigit v, m;
962         int i, j, n;
963         
964         if(toint(a[1], &n, 1)){
965                 numdecref(a[0]);
966                 numdecref(a[1]);
967                 return nil;
968         }
969         a[0] = nummod(a[0]);
970         mptrunc(a[0], n, a[0]);
971         for(i = 0; i < a[0]->top; i++){
972                 v = a[0]->p[i];
973                 m = -1;
974                 for(j = sizeof(mpdigit) * 8; j >>= 1; ){
975                         m ^= m << j;
976                         v = v >> j & m | v << j & ~m;
977                 }
978                 a[0]->p[i] = v;
979         }
980         for(i = 0; i < a[0]->top / 2; i++){
981                 v = a[0]->p[i];
982                 a[0]->p[i] = a[0]->p[a[0]->top - 1 - i];
983                 a[0]->p[a[0]->top - 1 - i] = v;
984         }
985         mpleft(a[0], n - a[0]->top * sizeof(mpdigit) * 8, a[0]);
986         numdecref(a[1]);
987         return a[0];
988 }
989
990 Num *
991 fncat(int n, Num **a)
992 {
993         int i, w;
994         Num *r;
995
996         if(n % 2 != 0){
997                 error("cat: odd number of arguments");
998                 i = 0;
999         fail:
1000                 for(; i < n; i++)
1001                         numdecref(a[i]);
1002                 return nil;
1003         }
1004         r = numalloc();
1005         for(i = 0; i < n; i += 2){
1006                 if(toint(a[i+1], &w, 1)) goto fail;
1007                 mpleft(r, w, r);
1008                 if(a[i]->sign < 0 || mpsignif(a[i]) > w){
1009                         a[i] = nummod(a[i]);
1010                         mptrunc(a[i], w, a[i]);
1011                 }
1012                 r->b = basemax(r->b, a[i]->b);
1013                 mpor(r, a[i], r);
1014                 numdecref(a[i]);
1015                 numdecref(a[i+1]);
1016         }
1017         return r;
1018 }
1019
1020 void
1021 main(int argc, char **argv)
1022 {
1023         Keyword *kw;
1024         
1025         fmtinstall('B', mpfmt);
1026         
1027         for(kw = ops; kw->name[0] != 0; kw++)
1028                 if(optab[kw->name[0]] == nil)
1029                         optab[kw->name[0]] = kw;
1030         
1031         regfunc("hex", fnhex, 1);
1032         regfunc("dec", fndec, 1);
1033         regfunc("oct", fnoct, 1);
1034         regfunc("bin", fnbin, 1);
1035         regfunc("pb", fnpb, 2);
1036         regfunc("abs", fnabs, 1);
1037         regfunc("round", fnround, 2);
1038         regfunc("floor", fnfloor, 2);
1039         regfunc("ceil", fnceil, 2);
1040         regfunc("trunc", fntrunc, 2);
1041         regfunc("xtend", fnxtend, 2);
1042         regfunc("clog", fnclog, -1);
1043         regfunc("ubits", fnubits, 1);
1044         regfunc("sbits", fnsbits, 1);
1045         regfunc("nsa", fnnsa, 1);
1046         regfunc("gcd", fngcd, 2);
1047         regfunc("minv", fnminv, 2);
1048         regfunc("rand", fnrand, 1);
1049         regfunc("rev", fnrev, 2);
1050         regfunc("cat", fncat, -1);
1051
1052         prompt = 1;
1053         ARGBEGIN{
1054         case 'n': prompt = 0; break;
1055         }ARGEND;
1056         
1057         in = Bfdopen(0, OREAD);
1058         if(in == nil) sysfatal("Bfdopen: %r");
1059         extern void yyparse(void);
1060         yyparse();
1061 }