10 int inbase = 10, outbase, divmode, sep, heads, fail, prompt, eof;
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 && !eof) {print("; "); prompted = 1;}
598 while(c != '\n' && isspace(c));
606 for(p = buf, *p++ = c; c = Bgetc(in), isalnum(c) || c == '_'; )
607 if(p < buf + sizeof(buf) - 1 && c != '_')
610 if(c >= 0) Bungetc(in);
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;
623 yylval.n = numalloc();
624 strtomp(p, &p, b, yylval.n);
625 if(*p != 0) error("not a number: %s", buf);
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)
635 if(buf[0] == '_' && buf[1] == 0) return '_';
636 yylval.sym = getsym(buf, 1);
639 if(c < 128 && (kw = optab[c], kw != nil)){
641 for(; kw->name[0] == c; kw++)
644 if(c >= 0) Bungetc(in);
656 regfunc(char *n, Num *(*f)(int, Num **), int nargs)
667 toint(Num *n, int *p, int mustpos)
669 if(mpsignif(n) > 31 || mustpos && mpcmp(n, mpzero) < 0){
670 error("invalid argument");
724 if(toint(a[1], &b, 1)){
730 if(b != 0 && b != 2 && b != 8 && b != 10 && b != 16){
731 error("unsupported base");
753 fnround(int, Num **a)
758 if(mpcmp(a[1], mpzero) <= 0){
761 return error("invalid argument");
766 mpdiv(a[0], a[1], q, r);
767 if(r->sign < 0) mpadd(r, a[1], r);
771 if(i > 0 || i == 0 && (a[0]->sign < 0) ^ (q->top != 0 && (q->p[0] & 1) != 0))
773 mpsub(a[0], r, a[0]);
781 fnfloor(int, Num **a)
785 if(mpcmp(a[1], mpzero) <= 0){
788 return error("invalid argument");
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]);
805 if(mpcmp(a[1], mpzero) <= 0){
808 return error("invalid argument");
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]);
824 fntrunc(int, Num **a)
828 if(toint(a[1], &i, 1)){
834 mptrunc(a[0], i, a[0]);
839 fnxtend(int, Num **a)
843 if(toint(a[1], &i, 1)) return nil;
845 mpxtend(a[0], i, a[0]);
850 fnclog(int n, Num **a)
854 if(n != 1 && n != 2){
856 return error("clog: wrong number of arguments");
858 if(mpcmp(a[0], mpzero) <= 0 || n == 2 && mpcmp(a[1], mpone) <= 0){
860 return error("invalid argument");
862 if(n == 1 || mpcmp(a[1], mptwo) == 0){
864 mpsub(a[0], mpone, a[0]);
865 itomp(mpsignif(a[0]), a[0]);
867 if(n == 2) numdecref(a[1]);
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);
883 fnubits(int, Num **a)
887 return error("invalid argument");
890 itomp(mpsignif(a[0]), a[0]);
896 fnsbits(int, Num **a)
899 if(a[0]->sign < 0) mpadd(a[0], mpone, a[0]);
900 itomp(mpsignif(a[0]) + 1, a[0]);
914 return error("invalid argument");
917 for(i = 0; i < a[0]->top; i++){
919 for(; d != 0; d &= d-1)
931 a[0]->b = basemax(a[0]->b, a[1]->b);
932 mpextendedgcd(a[0], a[1], a[0], nil, nil);
943 mpnrand(a[0], genrandom, n);
955 mpextendedgcd(a[0], a[1], x, a[0], nil);
956 if(mpcmp(x, mpone) != 0)
957 error("no modular inverse");
959 mpmod(a[0], a[1], a[0]);
971 if(toint(a[1], &n, 1)){
977 mptrunc(a[0], n, a[0]);
978 for(i = 0; i < a[0]->top; i++){
981 for(j = sizeof(mpdigit) * 8; j >>= 1; ){
983 v = v >> j & m | v << j & ~m;
987 for(i = 0; i < a[0]->top / 2; i++){
989 a[0]->p[i] = a[0]->p[a[0]->top - 1 - i];
990 a[0]->p[a[0]->top - 1 - i] = v;
992 mpleft(a[0], n - a[0]->top * sizeof(mpdigit) * 8, a[0]);
998 fncat(int n, Num **a)
1004 error("cat: odd number of arguments");
1012 for(i = 0; i < n; i += 2){
1013 if(toint(a[i+1], &w, 1)) goto fail;
1015 if(a[i]->sign < 0 || mpsignif(a[i]) > w){
1016 a[i] = nummod(a[i]);
1017 mptrunc(a[i], w, a[i]);
1019 r->b = basemax(r->b, a[i]->b);
1028 main(int argc, char **argv)
1032 fmtinstall('B', mpfmt);
1034 for(kw = ops; kw->name[0] != 0; kw++)
1035 if(optab[kw->name[0]] == nil)
1036 optab[kw->name[0]] = kw;
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);
1061 case 'n': prompt = 0; break;
1064 in = Bfdopen(0, OREAD);
1065 if(in == nil) sysfatal("Bfdopen: %r");
1066 extern void yyparse(void);
1069 exits(yynerrs ? "error" : nil);