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 numdecrefs(int n, Num **x)
318 for(i = 0; i < n; i++)
323 fncall(Symbol *s, int n, Num **x)
329 return error("%s: not a function", s->name);
331 else if(s->nargs >= 0 && s->nargs != n){
333 return error("%s: wrong number of arguments", s->name);
335 for(i = 0; i < n; i++)
338 return s->func(n, x);
346 if(inbase != 16) return nil;
347 if(s->val != nil) return numincref(s->val);
348 if(strspn(s->name, "0123456789ABCDEFabcdef_") != strlen(s->name)) return nil;
350 for(p = b, q = b; *p != 0; p++)
355 strtomp(b, nil, 16, s->val);
358 return numincref(s->val);
376 %type <args> elist elist1
386 %left '<' '>' LOLE LOGE
401 input: | input line '\n' {
402 if(!fail && last != nil) {
414 stat: { last = nil; }
415 | expr { last = $1; }
416 | '_' { save = inbase; inbase = 10; } expr {
418 if(mpcmp($3, mpzero) < 0)
426 | '<' { save = inbase; inbase = 10; } expr {
430 if(inbase != 2 && inbase != 8 && inbase != 10 && inbase != 16){
438 | '>' { save = inbase; inbase = 10; } expr {
443 if(outbase != 0 && outbase != 2 && outbase != 8 && outbase != 10 && outbase != 16){
451 | '/' { save = inbase; inbase = 10; } expr {
456 if(divmode != 0 && divmode != 1){
464 | '\'' { save = inbase; inbase = 10; } expr {
469 if(heads != 0 && heads != 1){
480 | '(' expr ')' { $$ = $2; }
481 | expr '+' expr { $$ = numbin('+', $1, $3); }
482 | expr '-' expr { $$ = numbin('-', $1, $3); }
483 | expr '*' expr { $$ = numbin('*', $1, $3); }
484 | expr '/' expr { $$ = numbin('/', $1, $3); }
485 | expr '%' expr { $$ = numbin('%', $1, $3); }
486 | expr '&' expr { $$ = numbin('&', $1, $3); }
487 | expr '|' expr { $$ = numbin('|', $1, $3); }
488 | expr '^' expr { $$ = numbin('^', $1, $3); }
489 | expr LOEXP expr { $$ = numbin(LOEXP, $1, $3); }
490 | expr LOLSH expr { $$ = numbin(LOLSH, $1, $3); }
491 | expr LORSH expr { $$ = numbin(LORSH, $1, $3); }
492 | expr LOEQ expr { $$ = numbin(LOEQ, $1, $3); }
493 | expr LONE expr { $$ = numbin(LONE, $1, $3); }
494 | expr '<' expr { $$ = numbin('<', $1, $3); }
495 | expr '>' expr { $$ = numbin('>', $1, $3); }
496 | expr LOLE expr { $$ = numbin(LOLE, $1, $3); }
497 | expr LOGE expr { $$ = numbin(LOGE, $1, $3); }
498 | expr LOLAND expr { $$ = numbin(LOLAND, $1, $3); }
499 | expr LOLOR expr { $$ = numbin(LOLOR, $1, $3); }
500 | '+' expr %prec unary { $$ = $2; }
501 | '-' expr %prec unary { $$ = nummod($2); if($$ != nil) mpsub(mpzero, $$, $$); }
502 | '~' expr %prec unary { $$ = nummod($2); if($$ != nil) mpnot($$, $$); }
503 | '!' expr %prec unary { $$ = nummod($2); if($$ != nil) {itomp(mpcmp($$, mpzero) == 0, $$); $$->b = 0; } }
504 | expr '?' expr ':' expr %prec '?' {
505 if($1 == nil || mpcmp($1, mpzero) != 0){
514 | LSYMB '(' elist ')' { $$ = fncall($1, $3.n, $3.x); }
519 case SYMVAR: $$ = numincref($1->val); break;
523 else error("%s undefined", $1->name);
525 case SYMFUNC: error("%s is a function", $1->name); break;
526 default: error("%s invalid here", $1->name);
530 if($1->t != SYMNONE && $1->t != SYMVAR)
531 error("%s redefined", $1->name);
535 $1->val = numincref($3);
541 if($$ == nil) error("no last result");
545 elist: { $$.n = 0; } | elist1
546 elist1: expr { $$.x[0] = $1; $$.n = 1; }
550 error("too many arguments");
557 typedef struct Keyword Keyword;
588 if(prompt && !prompted) {print("; "); prompted = 1;}
591 while(c != '\n' && isspace(c));
592 if(c == '\n') prompted = 0;
594 for(p = buf, *p++ = c; c = Bgetc(in), isalnum(c) || c == '_'; )
595 if(p < buf + sizeof(buf) - 1 && c != '_')
604 case 0: p -= 2; break;
605 case 'b': case 'B': b = 2; break;
606 case 'd': case 'D': b = 10; break;
607 case 'x': case 'X': b = 16; break;
608 default: p--; b = 8; break;
611 yylval.n = numalloc();
612 strtomp(p, &p, b, yylval.n);
613 if(*p != 0) error("not a number: %s", buf);
617 if(isalpha(c) || c >= 0x80 || c == '_'){
618 for(p = buf, *p++ = c; c = Bgetc(in), isalnum(c) || c >= 0x80 || c == '_'; )
619 if(p < buf + sizeof(buf) - 1)
623 if(buf[0] == '_' && buf[1] == 0) return '_';
624 yylval.sym = getsym(buf, 1);
627 if(c < 128 && (kw = optab[c], kw != nil)){
629 for(; kw->name[0] == c; kw++)
644 regfunc(char *n, Num *(*f)(int, Num **), int nargs)
655 toint(Num *n, int *p, int mustpos)
657 if(mpsignif(n) > 31 || mustpos && mpcmp(n, mpzero) < 0){
658 error("invalid argument");
712 if(toint(a[1], &b, 1)){
718 if(b != 0 && b != 2 && b != 8 && b != 10 && b != 16){
719 error("unsupported base");
741 fnround(int, Num **a)
746 if(mpcmp(a[1], mpzero) <= 0){
749 return error("invalid argument");
754 mpdiv(a[0], a[1], q, r);
755 if(r->sign < 0) mpadd(r, a[1], r);
759 if(i > 0 || i == 0 && (a[0]->sign < 0) ^ (q->top != 0 && (q->p[0] & 1) != 0))
761 mpsub(a[0], r, a[0]);
769 fnfloor(int, Num **a)
773 if(mpcmp(a[1], mpzero) <= 0){
776 return error("invalid argument");
780 mpdiv(a[0], a[1], nil, r);
781 if(r->sign < 0) mpadd(r, a[1], r);
782 mpsub(a[0], r, a[0]);
793 if(mpcmp(a[1], mpzero) <= 0){
796 return error("invalid argument");
800 mpdiv(a[0], a[1], nil, r);
801 if(r->sign < 0) mpadd(r, a[1], r);
802 if(mpcmp(r, mpzero) != 0){
803 mpsub(a[0], r, a[0]);
804 mpadd(a[0], a[1], a[0]);
812 fntrunc(int, Num **a)
816 if(toint(a[1], &i, 1)){
821 mptrunc(a[0], i, a[0]);
826 fnxtend(int, Num **a)
830 if(toint(a[1], &i, 1)) return nil;
831 mpxtend(a[0], i, a[0]);
836 fnclog(int n, Num **a)
840 if(n != 1 && n != 2){
842 return error("clog: wrong number of arguments");
844 if(mpcmp(a[0], mpzero) <= 0 || n == 2 && mpcmp(a[1], mpone) <= 0){
846 return error("invalid argument");
848 if(n == 1 || mpcmp(a[1], mptwo) == 0){
850 mpsub(a[0], mpone, a[0]);
851 itomp(mpsignif(a[0]), a[0]);
853 if(n == 2) numdecref(a[1]);
857 for(r = 0; mpcmp(a[0], mpone) > 0; r++){
858 mpadd(a[0], a[1], a[0]);
859 mpsub(a[0], mpone, a[0]);
860 mpdiv(a[0], a[1], a[0], nil);
869 fnubits(int, Num **a)
873 return error("invalid argument");
876 itomp(mpsignif(a[0]), a[0]);
882 fnsbits(int, Num **a)
885 if(a[0]->sign < 0) mpadd(a[0], mpone, a[0]);
886 itomp(mpsignif(a[0]) + 1, a[0]);
900 return error("invalid argument");
903 for(i = 0; i < a[0]->top; i++){
905 for(; d != 0; d &= d-1)
917 a[0]->b = basemax(a[0]->b, a[1]->b);
918 mpextendedgcd(a[0], a[1], a[0], nil, nil);
929 mpnrand(a[0], genrandom, n);
941 mpextendedgcd(a[0], a[1], x, a[0], nil);
942 if(mpcmp(x, mpone) != 0)
943 error("no modular inverse");
945 mpmod(a[0], a[1], a[0]);
957 if(toint(a[1], &n, 1)){
963 mptrunc(a[0], n, a[0]);
964 for(i = 0; i < a[0]->top; i++){
967 for(j = sizeof(mpdigit) * 8; j >>= 1; ){
969 v = v >> j & m | v << j & ~m;
973 for(i = 0; i < a[0]->top / 2; i++){
975 a[0]->p[i] = a[0]->p[a[0]->top - 1 - i];
976 a[0]->p[a[0]->top - 1 - i] = v;
978 mpleft(a[0], n - a[0]->top * sizeof(mpdigit) * 8, a[0]);
984 fncat(int n, Num **a)
990 error("cat: odd number of arguments");
998 for(i = 0; i < n; i += 2){
999 if(toint(a[i+1], &w, 1)) goto fail;
1001 if(a[i]->sign < 0 || mpsignif(a[i]) > w){
1002 a[i] = nummod(a[i]);
1003 mptrunc(a[i], w, a[i]);
1005 r->b = basemax(r->b, a[i]->b);
1014 main(int argc, char **argv)
1018 fmtinstall('B', mpfmt);
1020 for(kw = ops; kw->name[0] != 0; kw++)
1021 if(optab[kw->name[0]] == nil)
1022 optab[kw->name[0]] = kw;
1024 regfunc("hex", fnhex, 1);
1025 regfunc("dec", fndec, 1);
1026 regfunc("oct", fnoct, 1);
1027 regfunc("bin", fnbin, 1);
1028 regfunc("pb", fnpb, 2);
1029 regfunc("abs", fnabs, 1);
1030 regfunc("round", fnround, 2);
1031 regfunc("floor", fnfloor, 2);
1032 regfunc("ceil", fnceil, 2);
1033 regfunc("trunc", fntrunc, 2);
1034 regfunc("xtend", fnxtend, 2);
1035 regfunc("clog", fnclog, -1);
1036 regfunc("ubits", fnubits, 1);
1037 regfunc("sbits", fnsbits, 1);
1038 regfunc("nsa", fnnsa, 1);
1039 regfunc("gcd", fngcd, 2);
1040 regfunc("minv", fnminv, 2);
1041 regfunc("rand", fnrand, 1);
1042 regfunc("rev", fnrev, 2);
1043 regfunc("cat", fncat, -1);
1047 case 'n': prompt = 0; break;
1050 in = Bfdopen(0, OREAD);
1051 if(in == nil) sysfatal("Bfdopen: %r");
1052 extern void yyparse(void);