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));
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)
203 typedef struct Symbol Symbol;
212 Num *(*func)(int, Num **);
219 getsym(char *n, int mk)
222 for(p = &symtab[*n&63]; *p != nil; p = &(*p)->next)
223 if(strcmp((*p)->name, n) == 0)
226 *p = emalloc(sizeof(Symbol));
227 (*p)->name = strdup(n);
232 printhead(int n, int s, int sp, char *t)
237 for(i = 1; i < n; i *= 10)
239 while(i /= 10, i != 0){
242 for(j = 0, k = 0; j < n; j += s, k++){
243 if(k == sep && sep != 0){
247 if(j >= i || j == 0 && i == 1)
248 *--q = '0' + j / i % 10;
252 for(j = 0; j < sp; j++)
266 if(n->b >= STRONG || n->b != 0 && outbase == 0)
268 else if(outbase == 0)
272 s = mptoa(n, b, nil, 0);
274 t = emalloc(l * 2 + 4);
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;
286 printhead(mpsignif(n), st, sp, q);
289 for(p = s + l - 1, i = 0; p >= s && *p != '-'; p--, i++){
290 if(sep != 0 && i == sep){
295 *--q = *p + ('a' - 'A');
299 if(mpcmp(n, mpzero) != 0)
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;
314 fncall(Symbol *s, int n, Num **x)
319 return error("%s: not a function", s->name);
320 else if(s->nargs >= 0 && s->nargs != n)
321 return error("%s: wrong number of arguments", s->name);
322 for(i = 0; i < n; i++)
325 return s->func(n, x);
333 if(inbase != 16) return nil;
334 if(s->val != nil) return numincref(s->val);
335 if(strspn(s->name, "0123456789ABCDEFabcdef_") != strlen(s->name)) return nil;
337 for(p = b, q = b; *p != 0; p++)
342 strtomp(b, nil, 16, s->val);
345 return numincref(s->val);
363 %type <args> elist elist1
373 %left '<' '>' LOLE LOGE
388 input: | input line '\n' {
389 if(!fail && last != nil) {
401 stat: { last = nil; }
402 | expr { last = $1; }
403 | '_' { save = inbase; inbase = 10; } expr {
405 if(mpcmp($3, mpzero) < 0)
413 | '<' { save = inbase; inbase = 10; } expr {
417 if(inbase != 2 && inbase != 8 && inbase != 10 && inbase != 16){
425 | '>' { save = inbase; inbase = 10; } expr {
430 if(outbase != 0 && outbase != 2 && outbase != 8 && outbase != 10 && outbase != 16){
438 | '/' { save = inbase; inbase = 10; } expr {
443 if(divmode != 0 && divmode != 1){
451 | '\'' { save = inbase; inbase = 10; } expr {
456 if(heads != 0 && heads != 1){
467 | '(' expr ')' { $$ = $2; }
468 | expr '+' expr { $$ = numbin('+', $1, $3); }
469 | expr '-' expr { $$ = numbin('-', $1, $3); }
470 | expr '*' expr { $$ = numbin('*', $1, $3); }
471 | expr '/' expr { $$ = numbin('/', $1, $3); }
472 | expr '%' expr { $$ = numbin('%', $1, $3); }
473 | expr '&' expr { $$ = numbin('&', $1, $3); }
474 | expr '|' expr { $$ = numbin('|', $1, $3); }
475 | expr '^' expr { $$ = numbin('^', $1, $3); }
476 | expr LOEXP expr { $$ = numbin(LOEXP, $1, $3); }
477 | expr LOLSH expr { $$ = numbin(LOLSH, $1, $3); }
478 | expr LORSH expr { $$ = numbin(LORSH, $1, $3); }
479 | expr LOEQ expr { $$ = numbin(LOEQ, $1, $3); }
480 | expr LONE expr { $$ = numbin(LONE, $1, $3); }
481 | expr '<' expr { $$ = numbin('<', $1, $3); }
482 | expr '>' expr { $$ = numbin('>', $1, $3); }
483 | expr LOLE expr { $$ = numbin(LOLE, $1, $3); }
484 | expr LOGE expr { $$ = numbin(LOGE, $1, $3); }
485 | expr LOLAND expr { $$ = numbin(LOLAND, $1, $3); }
486 | expr LOLOR expr { $$ = numbin(LOLOR, $1, $3); }
487 | '+' expr %prec unary { $$ = $2; }
488 | '-' expr %prec unary { $$ = nummod($2); if($$ != nil) mpsub(mpzero, $$, $$); }
489 | '~' expr %prec unary { $$ = nummod($2); if($$ != nil) mpnot($$, $$); }
490 | '!' expr %prec unary { $$ = nummod($2); if($$ != nil) {itomp(mpcmp($$, mpzero) == 0, $$); $$->b = 0; } }
491 | expr '?' expr ':' expr %prec '?' {
492 if($1 == nil || mpcmp($1, mpzero) != 0){
501 | LSYMB '(' elist ')' { $$ = fncall($1, $3.n, $3.x); }
506 case SYMVAR: $$ = numincref($1->val); break;
510 else error("%s undefined", $1->name);
512 case SYMFUNC: error("%s is a function", $1->name); break;
513 default: error("%s invalid here", $1->name);
517 if($1->t != SYMNONE && $1->t != SYMVAR)
518 error("%s redefined", $1->name);
522 $1->val = numincref($3);
528 if($$ == nil) error("no last result");
532 elist: { $$.n = 0; } | elist1
533 elist1: expr { $$.x[0] = $1; $$.n = 1; }
537 error("too many arguments");
544 typedef struct Keyword Keyword;
575 if(prompt && !prompted) {print("; "); prompted = 1;}
578 while(c != '\n' && isspace(c));
579 if(c == '\n') prompted = 0;
581 for(p = buf, *p++ = c; c = Bgetc(in), isalnum(c) || c == '_'; )
582 if(p < buf + sizeof(buf) - 1 && c != '_')
591 case 0: p -= 2; break;
592 case 'b': case 'B': b = 2; break;
593 case 'd': case 'D': b = 10; break;
594 case 'x': case 'X': b = 16; break;
595 default: p--; b = 8; break;
598 yylval.n = numalloc();
599 strtomp(p, &p, b, yylval.n);
600 if(*p != 0) error("not a number: %s", buf);
604 if(isalpha(c) || c >= 0x80 || c == '_'){
605 for(p = buf, *p++ = c; c = Bgetc(in), isalnum(c) || c >= 0x80 || c == '_'; )
606 if(p < buf + sizeof(buf) - 1)
610 if(buf[0] == '_' && buf[1] == 0) return '_';
611 yylval.sym = getsym(buf, 1);
614 if(c < 128 && (kw = optab[c], kw != nil)){
616 for(; kw->name[0] == c; kw++)
631 regfunc(char *n, Num *(*f)(int, Num **), int nargs)
642 toint(Num *n, int *p, int mustpos)
644 if(mpsignif(n) > 31 || mustpos && mpcmp(n, mpzero) < 0){
645 error("invalid argument");
699 if(toint(a[1], &b, 1)){
705 if(b != 0 && b != 2 && b != 8 && b != 10 && b != 16){
706 error("unsupported base");
728 fnround(int, Num **a)
733 if(mpcmp(a[1], mpzero) <= 0){
736 return error("invalid argument");
741 mpdiv(a[0], a[1], q, r);
742 if(r->sign < 0) mpadd(r, a[1], r);
746 if(i > 0 || i == 0 && (a[0]->sign < 0) ^ (q->top != 0 && (q->p[0] & 1) != 0))
748 mpsub(a[0], r, a[0]);
756 fnfloor(int, Num **a)
760 if(mpcmp(a[1], mpzero) <= 0){
763 return error("invalid argument");
767 mpdiv(a[0], a[1], nil, r);
768 if(r->sign < 0) mpadd(r, a[1], r);
769 mpsub(a[0], r, a[0]);
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 if(mpcmp(r, mpzero) != 0){
790 mpsub(a[0], r, a[0]);
791 mpadd(a[0], a[1], a[0]);
799 fntrunc(int, Num **a)
803 if(toint(a[1], &i, 1)){
808 mptrunc(a[0], i, a[0]);
813 fnxtend(int, Num **a)
817 if(toint(a[1], &i, 1)) return nil;
818 mpxtend(a[0], i, a[0]);
823 fnubits(int, Num **a)
827 return error("invalid argument");
830 itomp(mpsignif(a[0]), a[0]);
836 fnsbits(int, Num **a)
839 if(a[0]->sign < 0) mpadd(a[0], mpone, a[0]);
840 itomp(mpsignif(a[0]) + 1, a[0]);
854 return error("invalid argument");
857 for(i = 0; i < a[0]->top; i++){
859 for(; d != 0; d &= d-1)
871 a[0]->b = basemax(a[0]->b, a[1]->b);
872 mpextendedgcd(a[0], a[1], a[0], nil, nil);
883 mpnrand(a[0], genrandom, n);
895 mpextendedgcd(a[0], a[1], x, a[0], nil);
896 if(mpcmp(x, mpone) != 0)
897 error("no modular inverse");
899 mpmod(a[0], a[1], a[0]);
911 if(toint(a[1], &n, 1)){
917 mptrunc(a[0], n, a[0]);
918 for(i = 0; i < a[0]->top; i++){
921 for(j = sizeof(mpdigit) * 8; j >>= 1; ){
923 v = v >> j & m | v << j & ~m;
927 for(i = 0; i < a[0]->top / 2; i++){
929 a[0]->p[i] = a[0]->p[a[0]->top - 1 - i];
930 a[0]->p[a[0]->top - 1 - i] = v;
932 mpleft(a[0], n - a[0]->top * sizeof(mpdigit) * 8, a[0]);
938 fncat(int n, Num **a)
944 error("cat: odd number of arguments");
952 for(i = 0; i < n; i += 2){
953 if(toint(a[i+1], &w, 1)) goto fail;
955 if(a[i]->sign < 0 || mpsignif(a[i]) > w){
957 mptrunc(a[i], w, a[i]);
959 r->b = basemax(r->b, a[i]->b);
968 main(int argc, char **argv)
972 fmtinstall('B', mpfmt);
974 for(kw = ops; kw->name[0] != 0; kw++)
975 if(optab[kw->name[0]] == nil)
976 optab[kw->name[0]] = kw;
978 regfunc("hex", fnhex, 1);
979 regfunc("dec", fndec, 1);
980 regfunc("oct", fnoct, 1);
981 regfunc("bin", fnbin, 1);
982 regfunc("pb", fnpb, 2);
983 regfunc("abs", fnabs, 1);
984 regfunc("round", fnround, 2);
985 regfunc("floor", fnfloor, 2);
986 regfunc("ceil", fnceil, 2);
987 regfunc("trunc", fntrunc, 2);
988 regfunc("xtend", fnxtend, 2);
989 regfunc("ubits", fnubits, 1);
990 regfunc("sbits", fnsbits, 1);
991 regfunc("nsa", fnnsa, 1);
992 regfunc("gcd", fngcd, 2);
993 regfunc("minv", fnminv, 2);
994 regfunc("rand", fnrand, 1);
995 regfunc("rev", fnrev, 2);
996 regfunc("cat", fncat, -1);
1000 case 'n': prompt = 0; break;
1003 in = Bfdopen(0, OREAD);
1004 if(in == nil) sysfatal("Bfdopen: %r");
1005 extern void yyparse(void);