#include <bio.h>
#include <ctype.h>
#include <mp.h>
-#include <pool.h>
#include <thread.h>
+#include <libsec.h>
-int inbase = 10, outbase, divmode, sep, fail, prompt;
+int inbase = 10, outbase, divmode, sep, heads, fail, prompt;
enum { MAXARGS = 16 };
typedef struct Num Num;
r = emalloc(sizeof(Num));
r->ref = 1;
- r->p = emalloc(0);
+ r->p = emalloc(sizeof(mpdigit));
mpassign(mpzero, r);
return r;
}
}else
mpasr(a, mptoi(b), a);
break;
- case '<': itomp(mpcmp(a, b) < 0, a); break;
- case '>': itomp(mpcmp(a, b) > 0, a); break;
- case LOLE: itomp(mpcmp(a, b) <= 0, a); break;
- case LOGE: itomp(mpcmp(a, b) >= 0, a); break;
- case LOEQ: itomp(mpcmp(a, b) == 0, a); break;
- case LONE: itomp(mpcmp(a, b) != 0, a); break;
+ case '<': itomp(mpcmp(a, b) < 0, a); a->b = 0; break;
+ case '>': itomp(mpcmp(a, b) > 0, a); a->b = 0; break;
+ case LOLE: itomp(mpcmp(a, b) <= 0, a); a->b = 0; break;
+ case LOGE: itomp(mpcmp(a, b) >= 0, a); a->b = 0; break;
+ case LOEQ: itomp(mpcmp(a, b) == 0, a); a->b = 0; break;
+ case LONE: itomp(mpcmp(a, b) != 0, a); a->b = 0; break;
case LOLAND:
a->b = b->b;
if(mpcmp(a, mpzero) == 0)
else
mpassign(b, a);
break;
+ case '$':
+ a->b = b->b;
+ mpxtend(b, mptoi(a), a);
+ break;
}
numdecref(b);
return a;
return *p;
}
+static void
+printhead(int n, int s, int sp, char *t)
+{
+ char *q;
+ int i, j, k;
+
+ for(i = 1; i < n; i *= 10)
+ ;
+ while(i /= 10, i != 0){
+ q = t;
+ *--q = 0;
+ for(j = 0, k = 0; j < n; j += s, k++){
+ if(k == sep && sep != 0){
+ *--q = ' ';
+ k = 0;
+ }
+ if(j >= i || j == 0 && i == 1)
+ *--q = '0' + j / i % 10;
+ else
+ *--q = ' ';
+ }
+ for(j = 0; j < sp; j++)
+ *--q = ' ';
+ print("%s\n", q);
+ }
+}
+
void
numprint(Num *n)
{
int b;
- int l, i;
+ int l, i, st, sp;
char *s, *t, *p, *q;
if(n == nil) return;
l = strlen(s);
t = emalloc(l * 2 + 4);
q = t + l * 2 + 4;
+ if(heads){
+ switch(b){
+ case 16: st = 4; sp = 2; break;
+ case 8: st = 3; sp = 1; break;
+ case 2: st = 1; sp = 2; break;
+ default: st = 0; sp = 0;
+ }
+ if(n->sign < 0)
+ sp++;
+ if(st != 0)
+ printhead(mpsignif(n), st, sp, q);
+ }
*--q = 0;
for(p = s + l - 1, i = 0; p >= s && *p != '-'; p--, i++){
if(sep != 0 && i == sep){
if(mpcmp(n, mpzero) != 0)
switch(b){
case 16: *--q = 'x'; *--q = '0'; break;
- case 10: if(outbase != 0 && outbase != 10) {*--q = 'd'; *--q = '0';} break;
+ case 10: if(outbase != 0 && outbase != 10 || inbase != 10) {*--q = 'd'; *--q = '0';} break;
case 8: *--q = '0'; break;
case 2: *--q = 'b'; *--q = '0'; break;
}
free(t);
}
+void
+numdecrefs(int n, Num **x)
+{
+ int i;
+
+ for(i = 0; i < n; i++)
+ numdecref(x[i]);
+}
+
Num *
fncall(Symbol *s, int n, Num **x)
{
int i;
- if(s->t != SYMFUNC)
+ if(s->t != SYMFUNC){
+ numdecrefs(n, x);
return error("%s: not a function", s->name);
- else if(s->nargs >= 0 && s->nargs != n)
+ }
+ else if(s->nargs >= 0 && s->nargs != n){
+ numdecrefs(n, x);
return error("%s: wrong number of arguments", s->name);
+ }
for(i = 0; i < n; i++)
if(x[i] == nil)
return nil;
%left unary
%left '*' '/' '%'
%right LOEXP
+%right '$'
%{
int save;
save = outbase;
if(!fail)
outbase = mptoi($3);
- if(outbase != 2 && outbase != 8 && outbase != 10 && outbase != 16){
+ if(outbase != 0 && outbase != 2 && outbase != 8 && outbase != 10 && outbase != 16){
error("no.");
outbase = save;
}
numdecref(last);
last = nil;
}
+ | '\'' { save = inbase; inbase = 10; } expr {
+ inbase = save;
+ save = heads;
+ if(!fail)
+ heads = mptoi($3);
+ if(heads != 0 && heads != 1){
+ error("no.");
+ heads = save;
+ }
+ numdecref($3);
+ numdecref(last);
+ last = nil;
+ }
| error
expr: LNUM
| '+' expr %prec unary { $$ = $2; }
| '-' expr %prec unary { $$ = nummod($2); if($$ != nil) mpsub(mpzero, $$, $$); }
| '~' expr %prec unary { $$ = nummod($2); if($$ != nil) mpnot($$, $$); }
- | '!' expr %prec unary { $$ = nummod($2); if($$ != nil) itomp(mpcmp($$, mpzero) == 0, $$); }
+ | '!' expr %prec unary { $$ = nummod($2); if($$ != nil) {itomp(mpcmp($$, mpzero) == 0, $$); $$->b = 0; } }
+ | '$' expr { $$ = nummod($2); if($$ != nil) if($2->sign > 0) mpxtend($2, mpsignif($2), $$); else mpassign($2, $$); }
| expr '?' expr ':' expr %prec '?' {
if($1 == nil || mpcmp($1, mpzero) != 0){
$$ = $3;
if($$ == nil) error("no last result");
else numincref($$);
}
+ | expr '$' expr { $$ = numbin('$', $1, $3); }
elist: { $$.n = 0; } | elist1
elist1: expr { $$.x[0] = $1; $$.n = 1; }
if(c == '\n') prompted = 0;
if(isdigit(c)){
for(p = buf, *p++ = c; c = Bgetc(in), isalnum(c) || c == '_'; )
- if(p < buf + sizeof(buf) - 1)
+ if(p < buf + sizeof(buf) - 1 && c != '_')
*p++ = c;
*p = 0;
Bungetc(in);
return r;
}
+Num *
+fnpb(int, Num **a)
+{
+ Num *r;
+ int b;
+
+ if(toint(a[1], &b, 1)){
+ out:
+ numdecref(a[0]);
+ numdecref(a[1]);
+ return nil;
+ }
+ if(b != 0 && b != 2 && b != 8 && b != 10 && b != 16){
+ error("unsupported base");
+ goto out;
+ }
+ r = nummod(a[0]);
+ if(b == 0)
+ r->b = 0;
+ else
+ r->b = STRONG | b;
+ return r;
+}
+
Num *
fnabs(int, Num **a)
{
numdecref(a[1]);
return nil;
}
+ a[0] = nummod(a[0]);
mptrunc(a[0], i, a[0]);
return a[0];
}
int i;
if(toint(a[1], &i, 1)) return nil;
+ a[0] = nummod(a[0]);
mpxtend(a[0], i, a[0]);
return a[0];
}
+Num *
+fnclog(int n, Num **a)
+{
+ int r;
+
+ if(n != 1 && n != 2){
+ numdecrefs(n, a);
+ return error("clog: wrong number of arguments");
+ }
+ if(mpcmp(a[0], mpzero) <= 0 || n == 2 && mpcmp(a[1], mpone) <= 0){
+ numdecref(a[0]);
+ return error("invalid argument");
+ }
+ if(n == 1 || mpcmp(a[1], mptwo) == 0){
+ a[0] = nummod(a[0]);
+ mpsub(a[0], mpone, a[0]);
+ itomp(mpsignif(a[0]), a[0]);
+ a[0]->b = 0;
+ if(n == 2) numdecref(a[1]);
+ return a[0];
+ }
+ a[0] = nummod(a[0]);
+ for(r = 0; mpcmp(a[0], mpone) > 0; r++){
+ mpadd(a[0], a[1], a[0]);
+ mpsub(a[0], mpone, a[0]);
+ mpdiv(a[0], a[1], a[0], nil);
+ }
+ itomp(r, a[0]);
+ a[0]->b = 0;
+ numdecref(a[1]);
+ return a[0];
+}
+
Num *
fnubits(int, Num **a)
{
}
a[0] = nummod(a[0]);
itomp(mpsignif(a[0]), a[0]);
- a[0]->b = 10;
+ a[0]->b = 0;
return a[0];
}
a[0] = nummod(a[0]);
if(a[0]->sign < 0) mpadd(a[0], mpone, a[0]);
itomp(mpsignif(a[0]) + 1, a[0]);
- a[0]->b = 10;
+ a[0]->b = 0;
+ return a[0];
+}
+
+Num *
+fnnsa(int, Num **a)
+{
+ int n, i;
+ mpdigit d;
+
+ a[0] = nummod(a[0]);
+ if(a[0]->sign < 0){
+ numdecref(a[0]);
+ return error("invalid argument");
+ }
+ n = 0;
+ for(i = 0; i < a[0]->top; i++){
+ d = a[0]->p[i];
+ for(; d != 0; d &= d-1)
+ n++;
+ }
+ itomp(n, a[0]);
+ a[0]->b = 0;
+ return a[0];
+}
+
+Num *
+fngcd(int, Num **a)
+{
+ a[0] = nummod(a[0]);
+ a[0]->b = basemax(a[0]->b, a[1]->b);
+ mpextendedgcd(a[0], a[1], a[0], nil, nil);
+ return a[0];
+}
+
+Num *
+fnrand(int, Num **a)
+{
+ Num *n;
+
+ n = numalloc();
+ n->b = a[0]->b;
+ mpnrand(a[0], genrandom, n);
+ numdecref(a[0]);
+ return n;
+}
+
+Num *
+fnminv(int, Num **a)
+{
+ mpint *x;
+
+ a[0] = nummod(a[0]);
+ x = mpnew(0);
+ mpextendedgcd(a[0], a[1], x, a[0], nil);
+ if(mpcmp(x, mpone) != 0)
+ error("no modular inverse");
+ else
+ mpmod(a[0], a[1], a[0]);
+ mpfree(x);
+ numdecref(a[1]);
+ return a[0];
+}
+
+Num *
+fnrev(int, Num **a)
+{
+ mpdigit v, m;
+ int i, j, n;
+
+ if(toint(a[1], &n, 1)){
+ numdecref(a[0]);
+ numdecref(a[1]);
+ return nil;
+ }
+ a[0] = nummod(a[0]);
+ mptrunc(a[0], n, a[0]);
+ for(i = 0; i < a[0]->top; i++){
+ v = a[0]->p[i];
+ m = -1;
+ for(j = sizeof(mpdigit) * 8; j >>= 1; ){
+ m ^= m << j;
+ v = v >> j & m | v << j & ~m;
+ }
+ a[0]->p[i] = v;
+ }
+ for(i = 0; i < a[0]->top / 2; i++){
+ v = a[0]->p[i];
+ a[0]->p[i] = a[0]->p[a[0]->top - 1 - i];
+ a[0]->p[a[0]->top - 1 - i] = v;
+ }
+ mpleft(a[0], n - a[0]->top * sizeof(mpdigit) * 8, a[0]);
+ numdecref(a[1]);
return a[0];
}
+Num *
+fncat(int n, Num **a)
+{
+ int i, w;
+ Num *r;
+ if(n % 2 != 0){
+ error("cat: odd number of arguments");
+ i = 0;
+ fail:
+ for(; i < n; i++)
+ numdecref(a[i]);
+ return nil;
+ }
+ r = numalloc();
+ for(i = 0; i < n; i += 2){
+ if(toint(a[i+1], &w, 1)) goto fail;
+ mpleft(r, w, r);
+ if(a[i]->sign < 0 || mpsignif(a[i]) > w){
+ a[i] = nummod(a[i]);
+ mptrunc(a[i], w, a[i]);
+ }
+ r->b = basemax(r->b, a[i]->b);
+ mpor(r, a[i], r);
+ numdecref(a[i]);
+ numdecref(a[i+1]);
+ }
+ return r;
+}
void
main(int argc, char **argv)
regfunc("dec", fndec, 1);
regfunc("oct", fnoct, 1);
regfunc("bin", fnbin, 1);
+ regfunc("pb", fnpb, 2);
regfunc("abs", fnabs, 1);
regfunc("round", fnround, 2);
regfunc("floor", fnfloor, 2);
regfunc("ceil", fnceil, 2);
regfunc("trunc", fntrunc, 2);
regfunc("xtend", fnxtend, 2);
+ regfunc("clog", fnclog, -1);
regfunc("ubits", fnubits, 1);
regfunc("sbits", fnsbits, 1);
+ regfunc("nsa", fnnsa, 1);
+ regfunc("gcd", fngcd, 2);
+ regfunc("minv", fnminv, 2);
+ regfunc("rand", fnrand, 1);
+ regfunc("rev", fnrev, 2);
+ regfunc("cat", fncat, -1);
prompt = 1;
ARGBEGIN{