10 int inbase = 10, outbase, divmode, sep, heads, fail, prompt;
11 enum { MAXARGS = 16 };
13 typedef struct Num Num;
19 enum { STRONG = 0x100 };
28 sysfatal("malloc: %r");
30 setmalloctag(v, getcallerpc(&n));
41 fmtfdinit(&f, 2, buf, sizeof(buf));
43 fmtvprint(&f, fmt, va);
56 r = emalloc(sizeof(Num));
58 r->p = emalloc(sizeof(mpdigit));
73 if(n == nil) return nil;
87 if(n == nil) return nil;
88 if(n->ref == 1) return n;
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;
108 %token LOEXP LOLSH LORSH LOEQ LONE LOLE LOGE LOLAND LOLOR
112 numbin(int op, Num *a, Num *b)
116 if(fail || a == nil || b == nil) return nil;
118 a->b = basemax(a->b, b->b);
120 case '+': mpadd(a, b, a); break;
121 case '-': mpsub(a, b, a); break;
122 case '*': mpmul(a, b, a); break;
124 if(mpcmp(b, mpzero) == 0){
127 return error("division by zero");
131 if(!divmode && r->sign < 0)
139 if(mpcmp(b, mpzero) == 0){
142 return error("division by zero");
145 if(!divmode && a->sign < 0)
151 case '&': mpand(a, b, a); break;
152 case '|': mpor(a, b, a); break;
153 case '^': mpxor(a, b, a); break;
155 if(mpcmp(b, mpzero) < 0){
158 return error("negative exponent");
163 if(mpsignif(b) >= 31){
165 error("left shift overflow");
166 itomp(-(mpcmp(a, mpzero) < 0), a);
168 mpasr(a, -mptoi(b), a);
171 if(mpsignif(b) >= 31){
173 error("right shift overflow");
174 itomp(-(mpcmp(a, mpzero) < 0), a);
176 mpasr(a, mptoi(b), a);
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;
186 if(mpcmp(a, mpzero) == 0)
193 if(mpcmp(a, mpzero) != 0)
200 mpxtend(b, mptoi(a), a);
207 typedef struct Symbol Symbol;
216 Num *(*func)(int, Num **);
223 getsym(char *n, int mk)
226 for(p = &symtab[*n&63]; *p != nil; p = &(*p)->next)
227 if(strcmp((*p)->name, n) == 0)
230 *p = emalloc(sizeof(Symbol));
231 (*p)->name = strdup(n);
236 printhead(int n, int s, int sp, char *t)
241 for(i = 1; i < n; i *= 10)
243 while(i /= 10, i != 0){
246 for(j = 0, k = 0; j < n; j += s, k++){
247 if(k == sep && sep != 0){
251 if(j >= i || j == 0 && i == 1)
252 *--q = '0' + j / i % 10;
256 for(j = 0; j < sp; j++)
270 if(n->b >= STRONG || n->b != 0 && outbase == 0)
272 else if(outbase == 0)
276 s = mptoa(n, b, nil, 0);
278 t = emalloc(l * 2 + 4);
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;
290 printhead(mpsignif(n), st, sp, q);
293 for(p = s + l - 1, i = 0; p >= s && *p != '-'; p--, i++){
294 if(sep != 0 && i == sep){
299 *--q = *p + ('a' - 'A');
303 if(mpcmp(n, mpzero) != 0)
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;
318 numdecrefs(int n, Num **x)
322 for(i = 0; i < n; i++)
327 fncall(Symbol *s, int n, Num **x)
333 return error("%s: not a function", s->name);
335 else if(s->nargs >= 0 && s->nargs != n){
337 return error("%s: wrong number of arguments", s->name);
339 for(i = 0; i < n; i++)
342 return s->func(n, x);
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;
354 for(p = b, q = b; *p != 0; p++)
359 strtomp(b, nil, 16, s->val);
362 return numincref(s->val);
380 %type <args> elist elist1
390 %left '<' '>' LOLE LOGE
406 input: | input line '\n' {
407 if(!fail && last != nil) {
419 stat: { last = nil; }
420 | expr { last = $1; }
421 | '_' { save = inbase; inbase = 10; } expr {
423 if(mpcmp($3, mpzero) < 0)
431 | '<' { save = inbase; inbase = 10; } expr {
435 if(inbase != 2 && inbase != 8 && inbase != 10 && inbase != 16){
443 | '>' { save = inbase; inbase = 10; } expr {
448 if(outbase != 0 && outbase != 2 && outbase != 8 && outbase != 10 && outbase != 16){
456 | '/' { save = inbase; inbase = 10; } expr {
461 if(divmode != 0 && divmode != 1){
469 | '\'' { save = inbase; inbase = 10; } expr {
474 if(heads != 0 && heads != 1){
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){
520 | LSYMB '(' elist ')' { $$ = fncall($1, $3.n, $3.x); }
525 case SYMVAR: $$ = numincref($1->val); break;
529 else error("%s undefined", $1->name);
531 case SYMFUNC: error("%s is a function", $1->name); break;
532 default: error("%s invalid here", $1->name);
536 if($1->t != SYMNONE && $1->t != SYMVAR)
537 error("%s redefined", $1->name);
541 $1->val = numincref($3);
547 if($$ == nil) error("no last result");
550 | expr '$' expr { $$ = numbin('$', $1, $3); }
552 elist: { $$.n = 0; } | elist1
553 elist1: expr { $$.x[0] = $1; $$.n = 1; }
557 error("too many arguments");
564 typedef struct Keyword Keyword;
595 if(prompt && !prompted) {print("; "); prompted = 1;}
598 while(c != '\n' && isspace(c));
599 if(c == '\n') prompted = 0;
601 for(p = buf, *p++ = c; c = Bgetc(in), isalnum(c) || c == '_'; )
602 if(p < buf + sizeof(buf) - 1 && c != '_')
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;
618 yylval.n = numalloc();
619 strtomp(p, &p, b, yylval.n);
620 if(*p != 0) error("not a number: %s", buf);
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)
630 if(buf[0] == '_' && buf[1] == 0) return '_';
631 yylval.sym = getsym(buf, 1);
634 if(c < 128 && (kw = optab[c], kw != nil)){
636 for(; kw->name[0] == c; kw++)
651 regfunc(char *n, Num *(*f)(int, Num **), int nargs)
662 toint(Num *n, int *p, int mustpos)
664 if(mpsignif(n) > 31 || mustpos && mpcmp(n, mpzero) < 0){
665 error("invalid argument");
719 if(toint(a[1], &b, 1)){
725 if(b != 0 && b != 2 && b != 8 && b != 10 && b != 16){
726 error("unsupported base");
748 fnround(int, Num **a)
753 if(mpcmp(a[1], mpzero) <= 0){
756 return error("invalid argument");
761 mpdiv(a[0], a[1], q, r);
762 if(r->sign < 0) mpadd(r, a[1], r);
766 if(i > 0 || i == 0 && (a[0]->sign < 0) ^ (q->top != 0 && (q->p[0] & 1) != 0))
768 mpsub(a[0], r, a[0]);
776 fnfloor(int, Num **a)
780 if(mpcmp(a[1], mpzero) <= 0){
783 return error("invalid argument");
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]);
800 if(mpcmp(a[1], mpzero) <= 0){
803 return error("invalid argument");
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]);
819 fntrunc(int, Num **a)
823 if(toint(a[1], &i, 1)){
828 mptrunc(a[0], i, a[0]);
833 fnxtend(int, Num **a)
837 if(toint(a[1], &i, 1)) return nil;
838 mpxtend(a[0], i, a[0]);
843 fnclog(int n, Num **a)
847 if(n != 1 && n != 2){
849 return error("clog: wrong number of arguments");
851 if(mpcmp(a[0], mpzero) <= 0 || n == 2 && mpcmp(a[1], mpone) <= 0){
853 return error("invalid argument");
855 if(n == 1 || mpcmp(a[1], mptwo) == 0){
857 mpsub(a[0], mpone, a[0]);
858 itomp(mpsignif(a[0]), a[0]);
860 if(n == 2) numdecref(a[1]);
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);
876 fnubits(int, Num **a)
880 return error("invalid argument");
883 itomp(mpsignif(a[0]), a[0]);
889 fnsbits(int, Num **a)
892 if(a[0]->sign < 0) mpadd(a[0], mpone, a[0]);
893 itomp(mpsignif(a[0]) + 1, a[0]);
907 return error("invalid argument");
910 for(i = 0; i < a[0]->top; i++){
912 for(; d != 0; d &= d-1)
924 a[0]->b = basemax(a[0]->b, a[1]->b);
925 mpextendedgcd(a[0], a[1], a[0], nil, nil);
936 mpnrand(a[0], genrandom, n);
948 mpextendedgcd(a[0], a[1], x, a[0], nil);
949 if(mpcmp(x, mpone) != 0)
950 error("no modular inverse");
952 mpmod(a[0], a[1], a[0]);
964 if(toint(a[1], &n, 1)){
970 mptrunc(a[0], n, a[0]);
971 for(i = 0; i < a[0]->top; i++){
974 for(j = sizeof(mpdigit) * 8; j >>= 1; ){
976 v = v >> j & m | v << j & ~m;
980 for(i = 0; i < a[0]->top / 2; i++){
982 a[0]->p[i] = a[0]->p[a[0]->top - 1 - i];
983 a[0]->p[a[0]->top - 1 - i] = v;
985 mpleft(a[0], n - a[0]->top * sizeof(mpdigit) * 8, a[0]);
991 fncat(int n, Num **a)
997 error("cat: odd number of arguments");
1005 for(i = 0; i < n; i += 2){
1006 if(toint(a[i+1], &w, 1)) goto fail;
1008 if(a[i]->sign < 0 || mpsignif(a[i]) > w){
1009 a[i] = nummod(a[i]);
1010 mptrunc(a[i], w, a[i]);
1012 r->b = basemax(r->b, a[i]->b);
1021 main(int argc, char **argv)
1025 fmtinstall('B', mpfmt);
1027 for(kw = ops; kw->name[0] != 0; kw++)
1028 if(optab[kw->name[0]] == nil)
1029 optab[kw->name[0]] = kw;
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);
1054 case 'n': prompt = 0; break;
1057 in = Bfdopen(0, OREAD);
1058 if(in == nil) sysfatal("Bfdopen: %r");
1059 extern void yyparse(void);