#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
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;
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 { $$ = 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, $$); $$->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; }
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)
{
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)
{
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);