2015-11-22 22:47:58 +00:00
|
|
|
%{
|
|
|
|
|
|
|
|
#include <u.h>
|
|
|
|
#include <libc.h>
|
|
|
|
#include <bio.h>
|
|
|
|
#include <mp.h>
|
|
|
|
|
|
|
|
typedef struct Sym Sym;
|
|
|
|
typedef struct Node Node;
|
|
|
|
|
|
|
|
enum {
|
|
|
|
FSET = 1,
|
|
|
|
FUSE = 2,
|
|
|
|
FARG = 4,
|
|
|
|
FLOC = 8,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Sym
|
|
|
|
{
|
|
|
|
Sym* l;
|
|
|
|
int f;
|
|
|
|
char n[];
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Node
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
Node* l;
|
|
|
|
Node* r;
|
|
|
|
Sym* s;
|
2016-02-01 18:27:57 +00:00
|
|
|
mpint* m;
|
2015-11-22 22:47:58 +00:00
|
|
|
int n;
|
|
|
|
};
|
|
|
|
|
|
|
|
#pragma varargck type "N" Node*
|
|
|
|
|
|
|
|
int ntmp;
|
|
|
|
Node *ftmps, *atmps;
|
|
|
|
Node *modulo;
|
|
|
|
|
|
|
|
Node* new(int, Node*, Node*);
|
|
|
|
Sym* sym(char*);
|
|
|
|
|
|
|
|
Biobuf bin;
|
|
|
|
int goteof;
|
|
|
|
int lineno;
|
|
|
|
int clevel;
|
|
|
|
char* filename;
|
|
|
|
|
|
|
|
int getch(void);
|
|
|
|
void ungetc(void);
|
|
|
|
void yyerror(char*);
|
|
|
|
int yyparse(void);
|
|
|
|
void diag(Node*, char*, ...);
|
|
|
|
void com(Node*);
|
|
|
|
void fcom(Node*,Node*,Node*);
|
|
|
|
|
|
|
|
#pragma varargck argpos cprint 1
|
|
|
|
#pragma varargck argpos diag 2
|
|
|
|
|
|
|
|
%}
|
|
|
|
|
|
|
|
%union
|
|
|
|
{
|
|
|
|
Sym* sval;
|
|
|
|
Node* node;
|
|
|
|
}
|
|
|
|
|
|
|
|
%type <node> name num args expr bool block elif stmnt stmnts
|
|
|
|
|
|
|
|
%left '{' '}' ';'
|
|
|
|
%right '=' ','
|
|
|
|
%right '?' ':'
|
|
|
|
%left EQ NEQ '<' '>'
|
|
|
|
%left LSH RSH
|
|
|
|
%left '+' '-'
|
|
|
|
%left '/' '%'
|
|
|
|
%left '*'
|
|
|
|
%left '^'
|
|
|
|
%right '('
|
|
|
|
|
2016-10-20 03:15:51 +00:00
|
|
|
%token MOD IF ELSE WHILE BREAK
|
2015-11-22 22:47:58 +00:00
|
|
|
%token <sval> NAME NUM
|
|
|
|
|
|
|
|
%%
|
|
|
|
|
|
|
|
prog:
|
|
|
|
prog func
|
|
|
|
| func
|
|
|
|
|
|
|
|
func:
|
|
|
|
name args stmnt
|
|
|
|
{
|
|
|
|
fcom($1, $2, $3);
|
|
|
|
}
|
|
|
|
|
|
|
|
args:
|
|
|
|
'(' expr ')'
|
|
|
|
{
|
|
|
|
$$ = $2;
|
|
|
|
}
|
|
|
|
| '(' ')'
|
|
|
|
{
|
|
|
|
$$ = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
name:
|
|
|
|
NAME
|
|
|
|
{
|
|
|
|
$$ = new(NAME,nil,nil);
|
|
|
|
$$->s = $1;
|
|
|
|
}
|
|
|
|
num:
|
|
|
|
NUM
|
|
|
|
{
|
|
|
|
$$ = new(NUM,nil,nil);
|
|
|
|
$$->s = $1;
|
|
|
|
}
|
|
|
|
|
|
|
|
elif:
|
|
|
|
ELSE IF '(' bool ')' stmnt
|
|
|
|
{
|
|
|
|
$$ = new('?', $4, new(':', $6, nil));
|
|
|
|
}
|
|
|
|
| ELSE IF '(' bool ')' stmnt elif
|
|
|
|
{
|
|
|
|
$$ = new('?', $4, new(':', $6, $7));
|
|
|
|
}
|
|
|
|
| ELSE stmnt
|
|
|
|
{
|
|
|
|
$$ = $2;
|
|
|
|
}
|
|
|
|
|
|
|
|
sem:
|
|
|
|
sem ';'
|
|
|
|
| ';'
|
|
|
|
|
|
|
|
stmnt:
|
|
|
|
expr '=' expr sem
|
|
|
|
{
|
|
|
|
$$ = new('=', $1, $3);
|
|
|
|
}
|
|
|
|
| MOD args stmnt
|
|
|
|
{
|
|
|
|
$$ = new('m', $2, $3);
|
|
|
|
}
|
|
|
|
| IF '(' bool ')' stmnt
|
|
|
|
{
|
|
|
|
$$ = new('?', $3, new(':', $5, nil));
|
|
|
|
}
|
|
|
|
| IF '(' bool ')' stmnt elif
|
|
|
|
{
|
|
|
|
$$ = new('?', $3, new(':', $5, $6));
|
|
|
|
}
|
|
|
|
| WHILE '(' bool ')' stmnt
|
|
|
|
{
|
|
|
|
$$ = new('@', new('?', $3, new(':', $5, new('b', nil, nil))), nil);
|
|
|
|
}
|
|
|
|
| BREAK sem
|
|
|
|
{
|
|
|
|
$$ = new('b', nil, nil);
|
|
|
|
}
|
|
|
|
| expr sem
|
|
|
|
{
|
|
|
|
if($1->c == NAME)
|
|
|
|
$$ = new('e', $1, nil);
|
|
|
|
else
|
|
|
|
$$ = $1;
|
|
|
|
}
|
|
|
|
| block
|
|
|
|
|
|
|
|
block:
|
|
|
|
'{' stmnts '}'
|
|
|
|
{
|
|
|
|
$$ = $2;
|
|
|
|
}
|
|
|
|
|
|
|
|
stmnts:
|
|
|
|
stmnts stmnt
|
|
|
|
{
|
|
|
|
$$ = new('\n', $1, $2);
|
|
|
|
}
|
|
|
|
| stmnt
|
|
|
|
|
|
|
|
expr:
|
|
|
|
'(' expr ')'
|
|
|
|
{
|
|
|
|
$$ = $2;
|
|
|
|
}
|
|
|
|
| name
|
|
|
|
{
|
|
|
|
$$ = $1;
|
|
|
|
}
|
|
|
|
| num
|
|
|
|
{
|
|
|
|
$$ = $1;
|
|
|
|
}
|
|
|
|
| '-' expr
|
|
|
|
{
|
|
|
|
$$ = new(NUM, nil, nil);
|
|
|
|
$$->s = sym("0");
|
|
|
|
$$->s->f = 0;
|
|
|
|
$$ = new('-', $$, $2);
|
|
|
|
}
|
|
|
|
| expr ',' expr
|
|
|
|
{
|
|
|
|
$$ = new(',', $1, $3);
|
|
|
|
}
|
|
|
|
| expr '^' expr
|
|
|
|
{
|
|
|
|
$$ = new('^', $1, $3);
|
|
|
|
}
|
|
|
|
| expr '*' expr
|
|
|
|
{
|
|
|
|
$$ = new('*', $1, $3);
|
|
|
|
}
|
|
|
|
| expr '/' expr
|
|
|
|
{
|
|
|
|
$$ = new('/', $1, $3);
|
|
|
|
}
|
|
|
|
| expr '%' expr
|
|
|
|
{
|
|
|
|
$$ = new('%', $1, $3);
|
|
|
|
}
|
|
|
|
| expr '+' expr
|
|
|
|
{
|
|
|
|
$$ = new('+', $1, $3);
|
|
|
|
}
|
|
|
|
| expr '-' expr
|
|
|
|
{
|
|
|
|
$$ = new('-', $1, $3);
|
|
|
|
}
|
|
|
|
| bool '?' expr ':' expr
|
|
|
|
{
|
|
|
|
$$ = new('?', $1, new(':', $3, $5));
|
|
|
|
}
|
|
|
|
| name args
|
|
|
|
{
|
|
|
|
$$ = new('e', $1, $2);
|
|
|
|
}
|
2016-02-01 18:27:57 +00:00
|
|
|
| expr LSH expr
|
2015-11-22 22:47:58 +00:00
|
|
|
{
|
|
|
|
$$ = new(LSH, $1, $3);
|
|
|
|
}
|
2016-02-01 18:27:57 +00:00
|
|
|
| expr RSH expr
|
2015-11-22 22:47:58 +00:00
|
|
|
{
|
|
|
|
$$ = new(RSH, $1, $3);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool:
|
|
|
|
'(' bool ')'
|
|
|
|
{
|
|
|
|
$$ = $2;
|
|
|
|
}
|
|
|
|
| '!' bool
|
|
|
|
{
|
|
|
|
$$ = new('!', $2, nil);
|
|
|
|
}
|
|
|
|
| expr EQ expr
|
|
|
|
{
|
|
|
|
$$ = new(EQ, $1, $3);
|
|
|
|
}
|
|
|
|
| expr NEQ expr
|
|
|
|
{
|
|
|
|
$$ = new('!', new(EQ, $1, $3), nil);
|
|
|
|
}
|
|
|
|
| expr '>' expr
|
|
|
|
{
|
|
|
|
$$ = new('>', $1, $3);
|
|
|
|
}
|
|
|
|
| expr '<' expr
|
|
|
|
{
|
|
|
|
$$ = new('<', $1, $3);
|
|
|
|
}
|
|
|
|
|
|
|
|
%%
|
|
|
|
|
|
|
|
int
|
|
|
|
yylex(void)
|
|
|
|
{
|
|
|
|
static char buf[200];
|
|
|
|
char *p;
|
|
|
|
int c;
|
|
|
|
|
|
|
|
Loop:
|
|
|
|
c = getch();
|
|
|
|
switch(c){
|
|
|
|
case -1:
|
|
|
|
return -1;
|
|
|
|
case ' ':
|
|
|
|
case '\t':
|
|
|
|
case '\n':
|
|
|
|
goto Loop;
|
|
|
|
case '#':
|
|
|
|
while((c = getch()) > 0)
|
|
|
|
if(c == '\n')
|
|
|
|
break;
|
|
|
|
goto Loop;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(c){
|
|
|
|
case '?': case ':':
|
|
|
|
case '+': case '-':
|
|
|
|
case '*': case '^':
|
|
|
|
case '/': case '%':
|
|
|
|
case '{': case '}':
|
|
|
|
case '(': case ')':
|
|
|
|
case ',': case ';':
|
|
|
|
return c;
|
|
|
|
case '<':
|
|
|
|
if(getch() == '<') return LSH;
|
|
|
|
ungetc();
|
|
|
|
return '<';
|
|
|
|
case '>':
|
|
|
|
if(getch() == '>') return RSH;
|
|
|
|
ungetc();
|
|
|
|
return '>';
|
|
|
|
case '=':
|
|
|
|
if(getch() == '=') return EQ;
|
|
|
|
ungetc();
|
|
|
|
return '=';
|
|
|
|
case '!':
|
|
|
|
if(getch() == '=') return NEQ;
|
|
|
|
ungetc();
|
|
|
|
return '!';
|
|
|
|
}
|
|
|
|
|
|
|
|
ungetc();
|
|
|
|
p = buf;
|
|
|
|
for(;;){
|
|
|
|
c = getch();
|
|
|
|
if((c >= Runeself)
|
|
|
|
|| (c == '_')
|
|
|
|
|| (c >= 'a' && c <= 'z')
|
|
|
|
|| (c >= 'A' && c <= 'Z')
|
|
|
|
|| (c >= '0' && c <= '9')){
|
|
|
|
*p++ = c;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ungetc();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
*p = '\0';
|
|
|
|
|
|
|
|
if(strcmp(buf, "mod") == 0)
|
|
|
|
return MOD;
|
|
|
|
if(strcmp(buf, "if") == 0)
|
|
|
|
return IF;
|
|
|
|
if(strcmp(buf, "else") == 0)
|
|
|
|
return ELSE;
|
|
|
|
if(strcmp(buf, "while") == 0)
|
|
|
|
return WHILE;
|
|
|
|
if(strcmp(buf, "break") == 0)
|
|
|
|
return BREAK;
|
|
|
|
|
|
|
|
yylval.sval = sym(buf);
|
|
|
|
yylval.sval->f = 0;
|
|
|
|
return (buf[0] >= '0' && buf[0] <= '9') ? NUM : NAME;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
getch(void)
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
|
|
|
|
c = Bgetc(&bin);
|
|
|
|
if(c == Beof){
|
|
|
|
goteof = 1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if(c == '\n')
|
|
|
|
lineno++;
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ungetc(void)
|
|
|
|
{
|
|
|
|
Bungetc(&bin);
|
|
|
|
}
|
|
|
|
|
|
|
|
Node*
|
|
|
|
new(int c, Node *l, Node *r)
|
|
|
|
{
|
|
|
|
Node *n;
|
|
|
|
|
|
|
|
n = malloc(sizeof(Node));
|
|
|
|
n->c = c;
|
|
|
|
n->l = l;
|
|
|
|
n->r = r;
|
|
|
|
n->s = nil;
|
2016-02-01 18:27:57 +00:00
|
|
|
n->m = nil;
|
2015-11-22 22:47:58 +00:00
|
|
|
n->n = lineno;
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
Sym*
|
|
|
|
sym(char *n)
|
|
|
|
{
|
|
|
|
static Sym *tab[128];
|
|
|
|
Sym *s;
|
|
|
|
ulong h, t;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
h = 0;
|
|
|
|
for(i=0; n[i] != '\0'; i++){
|
|
|
|
t = h & 0xf8000000;
|
|
|
|
h <<= 5;
|
|
|
|
h ^= t>>27;
|
|
|
|
h ^= (ulong)n[i];
|
|
|
|
}
|
|
|
|
h %= nelem(tab);
|
|
|
|
for(s = tab[h]; s != nil; s = s->l)
|
|
|
|
if(strcmp(s->n, n) == 0)
|
|
|
|
return s;
|
|
|
|
s = malloc(sizeof(Sym)+i+1);
|
|
|
|
memmove(s->n, n, i+1);
|
|
|
|
s->f = 0;
|
|
|
|
s->l = tab[h];
|
|
|
|
tab[h] = s;
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
yyerror(char *s)
|
|
|
|
{
|
|
|
|
fprint(2, "%s:%d: %s\n", filename, lineno, s);
|
|
|
|
exits(s);
|
|
|
|
}
|
|
|
|
void
|
|
|
|
cprint(char *fmt, ...)
|
|
|
|
{
|
|
|
|
static char buf[1024], tabs[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
|
|
|
|
char *p, *x;
|
|
|
|
va_list a;
|
|
|
|
|
|
|
|
va_start(a, fmt);
|
|
|
|
vsnprint(buf, sizeof(buf), fmt, a);
|
|
|
|
va_end(a);
|
|
|
|
|
|
|
|
p = buf;
|
|
|
|
while((x = strchr(p, '\n')) != nil){
|
|
|
|
x++;
|
|
|
|
write(1, p, x-p);
|
|
|
|
p = &tabs[sizeof(tabs)-1 - clevel];
|
|
|
|
if(*p != '\0')
|
|
|
|
write(1, p, strlen(p));
|
|
|
|
p = x;
|
|
|
|
}
|
|
|
|
if(*p != '\0')
|
|
|
|
write(1, p, strlen(p));
|
|
|
|
}
|
|
|
|
|
|
|
|
Node*
|
|
|
|
alloctmp(void)
|
|
|
|
{
|
|
|
|
Node *t;
|
|
|
|
|
|
|
|
t = ftmps;
|
|
|
|
if(t != nil)
|
|
|
|
ftmps = t->l;
|
|
|
|
else {
|
|
|
|
char n[16];
|
|
|
|
|
|
|
|
snprint(n, sizeof(n), "tmp%d", ++ntmp);
|
|
|
|
t = new(NAME, nil, nil);
|
|
|
|
t->s = sym(n);
|
|
|
|
|
|
|
|
cprint("mpint *");
|
|
|
|
}
|
|
|
|
cprint("%N = mpnew(0);\n", t);
|
|
|
|
t->s->f &= ~(FSET|FUSE);
|
|
|
|
t->l = atmps;
|
|
|
|
atmps = t;
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
isconst(Node *n)
|
|
|
|
{
|
|
|
|
if(n->c == NUM)
|
|
|
|
return 1;
|
|
|
|
if(n->c == NAME){
|
|
|
|
return n->s == sym("mpzero") ||
|
|
|
|
n->s == sym("mpone") ||
|
|
|
|
n->s == sym("mptwo");
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
istmp(Node *n)
|
|
|
|
{
|
|
|
|
Node *l;
|
|
|
|
|
|
|
|
if(n->c == NAME){
|
|
|
|
for(l = atmps; l != nil; l = l->l){
|
|
|
|
if(l->s == n->s)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
freetmp(Node *t)
|
|
|
|
{
|
|
|
|
Node **ll, *l;
|
|
|
|
|
|
|
|
if(t == nil)
|
|
|
|
return;
|
|
|
|
if(t->c == ','){
|
|
|
|
freetmp(t->l);
|
|
|
|
freetmp(t->r);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(t->c != NAME)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ll = &atmps;
|
|
|
|
for(l = atmps; l != nil; l = l->l){
|
|
|
|
if(l == t){
|
|
|
|
cprint("mpfree(%N);\n", t);
|
|
|
|
*ll = t->l;
|
|
|
|
t->l = ftmps;
|
|
|
|
ftmps = t;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ll = &l->l;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
symref(Node *n, Sym *s)
|
|
|
|
{
|
|
|
|
if(n == nil)
|
|
|
|
return 0;
|
|
|
|
if(n->c == NAME && n->s == s)
|
|
|
|
return 1;
|
|
|
|
return symref(n->l, s) || symref(n->r, s);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nodeset(Node *n)
|
|
|
|
{
|
|
|
|
if(n == nil)
|
|
|
|
return;
|
|
|
|
if(n->c == NAME){
|
|
|
|
n->s->f |= FSET;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(n->c == ','){
|
|
|
|
nodeset(n->l);
|
|
|
|
nodeset(n->r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
complex(Node *n)
|
|
|
|
{
|
|
|
|
if(n->c == NAME)
|
|
|
|
return 0;
|
2016-02-01 18:27:57 +00:00
|
|
|
if(n->c == NUM && n->m->sign > 0 && mpcmp(n->m, mptwo) <= 0)
|
2015-11-22 22:47:58 +00:00
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bcom(Node *n, Node *t);
|
|
|
|
|
2016-02-01 18:27:57 +00:00
|
|
|
Node*
|
|
|
|
ccom(Node *f)
|
|
|
|
{
|
|
|
|
Node *l, *r;
|
|
|
|
|
|
|
|
if(f == nil)
|
|
|
|
return nil;
|
|
|
|
|
|
|
|
if(f->m != nil)
|
|
|
|
return f;
|
|
|
|
f->m = (void*)~0;
|
|
|
|
|
|
|
|
switch(f->c){
|
|
|
|
case NUM:
|
|
|
|
f->m = strtomp(f->s->n, nil, 0, nil);
|
|
|
|
if(f->m == nil)
|
|
|
|
diag(f, "bad constant");
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
case LSH:
|
|
|
|
case RSH:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '+':
|
|
|
|
case '-':
|
|
|
|
case '*':
|
|
|
|
case '/':
|
|
|
|
case '%':
|
|
|
|
case '^':
|
|
|
|
if(modulo == nil || modulo->c == NUM)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* wet floor */
|
|
|
|
default:
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
f->l = l = ccom(f->l);
|
|
|
|
f->r = r = ccom(f->r);
|
|
|
|
if(l == nil || r == nil || l->c != NUM || r->c != NUM)
|
|
|
|
return f;
|
|
|
|
|
|
|
|
f->m = mpnew(0);
|
|
|
|
switch(f->c){
|
|
|
|
case LSH:
|
|
|
|
case RSH:
|
|
|
|
if(mpsignif(r->m) > 32)
|
|
|
|
diag(f, "bad shift");
|
|
|
|
if(f->c == LSH)
|
|
|
|
mpleft(l->m, mptoi(r->m), f->m);
|
|
|
|
else
|
|
|
|
mpright(l->m, mptoi(r->m), f->m);
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
case '+':
|
|
|
|
mpadd(l->m, r->m, f->m);
|
|
|
|
break;
|
|
|
|
case '-':
|
|
|
|
mpsub(l->m, r->m, f->m);
|
|
|
|
break;
|
|
|
|
case '*':
|
|
|
|
mpmul(l->m, r->m, f->m);
|
|
|
|
break;
|
|
|
|
case '/':
|
|
|
|
if(modulo != nil){
|
|
|
|
mpinvert(r->m, modulo->m, f->m);
|
|
|
|
mpmul(f->m, l->m, f->m);
|
|
|
|
} else {
|
|
|
|
mpdiv(l->m, r->m, f->m, nil);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '%':
|
|
|
|
mpmod(l->m, r->m, f->m);
|
|
|
|
break;
|
|
|
|
case '^':
|
|
|
|
mpexp(l->m, r->m, modulo != nil ? modulo->m : nil, f->m);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if(modulo != nil)
|
|
|
|
mpmod(f->m, modulo->m, f->m);
|
|
|
|
|
|
|
|
out:
|
|
|
|
f->l = nil;
|
|
|
|
f->r = nil;
|
|
|
|
f->s = nil;
|
|
|
|
f->c = NUM;
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
2015-11-22 22:47:58 +00:00
|
|
|
Node*
|
|
|
|
ecom(Node *f, Node *t)
|
|
|
|
{
|
|
|
|
Node *l, *r, *t2;
|
|
|
|
|
|
|
|
if(f == nil)
|
|
|
|
return nil;
|
|
|
|
|
2016-02-01 18:27:57 +00:00
|
|
|
f = ccom(f);
|
2015-11-22 22:47:58 +00:00
|
|
|
if(f->c == NUM){
|
2016-02-01 18:27:57 +00:00
|
|
|
if(f->m->sign < 0){
|
|
|
|
f->m->sign = 1;
|
|
|
|
t = ecom(f, t);
|
|
|
|
f->m->sign = -1;
|
|
|
|
if(isconst(t))
|
|
|
|
t = ecom(t, alloctmp());
|
|
|
|
cprint("%N->sign = -1;\n", t);
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
if(mpcmp(f->m, mpzero) == 0){
|
2015-11-22 22:47:58 +00:00
|
|
|
f->c = NAME;
|
|
|
|
f->s = sym("mpzero");
|
|
|
|
f->s->f = FSET;
|
|
|
|
return ecom(f, t);
|
|
|
|
}
|
2016-02-01 18:27:57 +00:00
|
|
|
if(mpcmp(f->m, mpone) == 0){
|
2015-11-22 22:47:58 +00:00
|
|
|
f->c = NAME;
|
|
|
|
f->s = sym("mpone");
|
|
|
|
f->s->f = FSET;
|
|
|
|
return ecom(f, t);
|
|
|
|
}
|
2016-02-01 18:27:57 +00:00
|
|
|
if(mpcmp(f->m, mptwo) == 0){
|
2015-11-22 22:47:58 +00:00
|
|
|
f->c = NAME;
|
|
|
|
f->s = sym("mptwo");
|
|
|
|
f->s->f = FSET;
|
|
|
|
return ecom(f, t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(f->c == ','){
|
|
|
|
if(t != nil)
|
|
|
|
diag(f, "cannot assign list to %N", t);
|
|
|
|
f->l = ecom(f->l, nil);
|
|
|
|
f->r = ecom(f->r, nil);
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
l = r = nil;
|
|
|
|
if(f->c == NAME){
|
|
|
|
if((f->s->f & FSET) == 0)
|
|
|
|
diag(f, "name used but not set");
|
|
|
|
f->s->f |= FUSE;
|
|
|
|
if(t == nil)
|
|
|
|
return f;
|
|
|
|
if(f->s != t->s)
|
|
|
|
cprint("mpassign(%N, %N);\n", f, t);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(t == nil)
|
|
|
|
t = alloctmp();
|
|
|
|
|
|
|
|
if(f->c == '?'){
|
|
|
|
bcom(f, t);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(f->c == 'e'){
|
|
|
|
r = ecom(f->r, nil);
|
|
|
|
if(r == nil)
|
|
|
|
cprint("%N(%N);\n", f->l, t);
|
|
|
|
else
|
|
|
|
cprint("%N(%N, %N);\n", f->l, r, t);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(t->c != NAME)
|
|
|
|
diag(f, "destination %N not a name", t);
|
|
|
|
|
|
|
|
switch(f->c){
|
|
|
|
case NUM:
|
2016-02-01 18:27:57 +00:00
|
|
|
if(mpsignif(f->m) <= 32)
|
|
|
|
cprint("uitomp(%udUL, %N);\n", mptoui(f->m), t);
|
|
|
|
else if(mpsignif(f->m) <= 64)
|
|
|
|
cprint("uvtomp(%lludULL, %N);\n", mptouv(f->m), t);
|
2015-11-22 22:47:58 +00:00
|
|
|
else
|
2016-02-01 18:27:57 +00:00
|
|
|
cprint("strtomp(\"%.16B\", nil, 16, %N);\n", f->m, t);
|
2015-11-22 22:47:58 +00:00
|
|
|
goto out;
|
|
|
|
case LSH:
|
|
|
|
case RSH:
|
2016-02-01 18:27:57 +00:00
|
|
|
r = ccom(f->r);
|
|
|
|
if(r == nil || r->c != NUM || mpsignif(r->m) > 32)
|
|
|
|
diag(f, "bad shift");
|
2015-11-22 22:47:58 +00:00
|
|
|
l = f->l->c == NAME ? f->l : ecom(f->l, t);
|
2016-02-01 18:27:57 +00:00
|
|
|
if(f->c == LSH)
|
|
|
|
cprint("mpleft(%N, %d, %N);\n", l, mptoi(r->m), t);
|
|
|
|
else
|
|
|
|
cprint("mpright(%N, %d, %N);\n", l, mptoi(r->m), t);
|
2015-11-22 22:47:58 +00:00
|
|
|
goto out;
|
|
|
|
case '*':
|
|
|
|
case '/':
|
|
|
|
l = ecom(f->l, nil);
|
|
|
|
r = ecom(f->r, nil);
|
|
|
|
break;
|
|
|
|
default:
|
2016-02-01 18:27:57 +00:00
|
|
|
l = ccom(f->l);
|
|
|
|
r = ccom(f->r);
|
|
|
|
l = ecom(l, complex(l) && !symref(r, t->s) ? t : nil);
|
|
|
|
r = ecom(r, complex(r) && l->s != t->s ? t : nil);
|
2015-11-22 22:47:58 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(modulo != nil){
|
|
|
|
switch(f->c){
|
|
|
|
case '+':
|
|
|
|
cprint("mpmodadd(%N, %N, %N, %N);\n", l, r, modulo, t);
|
|
|
|
goto out;
|
|
|
|
case '-':
|
|
|
|
cprint("mpmodsub(%N, %N, %N, %N);\n", l, r, modulo, t);
|
|
|
|
goto out;
|
|
|
|
case '*':
|
|
|
|
Modmul:
|
|
|
|
if(l->s == sym("mptwo") || r->s == sym("mptwo"))
|
|
|
|
cprint("mpmodadd(%N, %N, %N, %N); // 2*%N\n",
|
|
|
|
r->s == sym("mptwo") ? l : r,
|
|
|
|
r->s == sym("mptwo") ? l : r,
|
|
|
|
modulo, t,
|
|
|
|
r);
|
|
|
|
else
|
|
|
|
cprint("mpmodmul(%N, %N, %N, %N);\n", l, r, modulo, t);
|
|
|
|
goto out;
|
|
|
|
case '/':
|
|
|
|
if(l->s == sym("mpone")){
|
|
|
|
cprint("mpinvert(%N, %N, %N);\n", r, modulo, t);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
t2 = alloctmp();
|
|
|
|
cprint("mpinvert(%N, %N, %N);\n", r, modulo, t2);
|
|
|
|
cprint("mpmodmul(%N, %N, %N, %N);\n", l, t2, modulo, t);
|
|
|
|
freetmp(t2);
|
|
|
|
goto out;
|
|
|
|
case '^':
|
|
|
|
if(r->s == sym("mptwo")){
|
|
|
|
r = l;
|
|
|
|
goto Modmul;
|
|
|
|
}
|
|
|
|
cprint("mpexp(%N, %N, %N, %N);\n", l, r, modulo, t);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(f->c){
|
|
|
|
case '+':
|
|
|
|
cprint("mpadd(%N, %N, %N);\n", l, r, t);
|
|
|
|
goto out;
|
|
|
|
case '-':
|
|
|
|
if(l->s == sym("mpzero")){
|
|
|
|
r = ecom(r, t);
|
|
|
|
cprint("%N->sign = -%N->sign;\n", t, t);
|
|
|
|
} else
|
|
|
|
cprint("mpsub(%N, %N, %N);\n", l, r, t);
|
|
|
|
goto out;
|
|
|
|
case '*':
|
|
|
|
Mul:
|
|
|
|
if(l->s == sym("mptwo") || r->s == sym("mptwo"))
|
|
|
|
cprint("mpleft(%N, 1, %N);\n", r->s == sym("mptwo") ? l : r, t);
|
|
|
|
else
|
|
|
|
cprint("mpmul(%N, %N, %N);\n", l, r, t);
|
|
|
|
goto out;
|
|
|
|
case '/':
|
|
|
|
cprint("mpdiv(%N, %N, %N, %N);\n", l, r, t, nil);
|
|
|
|
goto out;
|
|
|
|
case '%':
|
|
|
|
cprint("mpmod(%N, %N, %N);\n", l, r, t);
|
|
|
|
goto out;
|
|
|
|
case '^':
|
|
|
|
if(r->s == sym("mptwo")){
|
|
|
|
r = l;
|
|
|
|
goto Mul;
|
|
|
|
}
|
|
|
|
cprint("mpexp(%N, %N, nil, %N);\n", l, r, t);
|
|
|
|
goto out;
|
|
|
|
default:
|
|
|
|
diag(f, "unknown operation");
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
if(l != t)
|
|
|
|
freetmp(l);
|
|
|
|
if(r != t)
|
|
|
|
freetmp(r);
|
|
|
|
nodeset(t);
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bcom(Node *n, Node *t)
|
|
|
|
{
|
|
|
|
Node *f, *l, *r;
|
|
|
|
int neg = 0;
|
|
|
|
|
|
|
|
l = r = nil;
|
|
|
|
f = n->l;
|
|
|
|
Loop:
|
|
|
|
switch(f->c){
|
|
|
|
case '!':
|
|
|
|
neg = !neg;
|
|
|
|
f = f->l;
|
|
|
|
goto Loop;
|
|
|
|
case '>':
|
|
|
|
case '<':
|
|
|
|
case EQ:
|
|
|
|
l = ecom(f->l, nil);
|
|
|
|
r = ecom(f->r, nil);
|
|
|
|
if(t != nil) {
|
|
|
|
Node *b1, *b2;
|
|
|
|
|
|
|
|
b1 = ecom(n->r->l, nil);
|
|
|
|
b2 = ecom(n->r->r, nil);
|
|
|
|
cprint("mpsel(");
|
|
|
|
|
|
|
|
if(l->s == r->s)
|
|
|
|
cprint("0");
|
|
|
|
else {
|
|
|
|
if(f->c == '>')
|
|
|
|
cprint("-");
|
|
|
|
cprint("mpcmp(%N, %N)", l, r);
|
|
|
|
}
|
|
|
|
if(f->c == EQ)
|
|
|
|
neg = !neg;
|
|
|
|
else
|
|
|
|
cprint(" >> (sizeof(int)*8-1)");
|
|
|
|
|
|
|
|
cprint(", %N, %N, %N);\n", neg ? b2 : b1, neg ? b1 : b2, t);
|
|
|
|
freetmp(b1);
|
|
|
|
freetmp(b2);
|
|
|
|
} else {
|
|
|
|
cprint("if(");
|
|
|
|
|
|
|
|
if(l->s == r->s)
|
|
|
|
cprint("0");
|
|
|
|
else
|
|
|
|
cprint("mpcmp(%N, %N)", l, r);
|
|
|
|
if(f->c == EQ)
|
|
|
|
cprint(neg ? " != 0" : " == 0");
|
|
|
|
else if(f->c == '>')
|
|
|
|
cprint(neg ? " <= 0" : " > 0");
|
|
|
|
else
|
|
|
|
cprint(neg ? " >= 0" : " < 0");
|
|
|
|
|
|
|
|
cprint(")");
|
|
|
|
com(n->r);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
diag(n, "saw %N in boolean expression", f);
|
|
|
|
}
|
|
|
|
freetmp(l);
|
|
|
|
freetmp(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
com(Node *n)
|
|
|
|
{
|
|
|
|
Node *l, *r;
|
|
|
|
|
|
|
|
Loop:
|
|
|
|
if(n != nil)
|
|
|
|
switch(n->c){
|
|
|
|
case '\n':
|
|
|
|
com(n->l);
|
|
|
|
n = n->r;
|
|
|
|
goto Loop;
|
|
|
|
case '?':
|
|
|
|
bcom(n, nil);
|
|
|
|
break;
|
|
|
|
case 'b':
|
|
|
|
for(l = atmps; l != nil; l = l->l)
|
|
|
|
cprint("mpfree(%N);\n", l);
|
|
|
|
cprint("break;\n");
|
|
|
|
break;
|
|
|
|
case '@':
|
|
|
|
cprint("for(;;)");
|
|
|
|
case ':':
|
|
|
|
clevel++;
|
|
|
|
cprint("{\n");
|
|
|
|
l = ftmps;
|
|
|
|
r = atmps;
|
|
|
|
if(n->c == '@')
|
|
|
|
atmps = nil;
|
|
|
|
ftmps = nil;
|
|
|
|
com(n->l);
|
|
|
|
if(n->r != nil){
|
|
|
|
cprint("}else{\n");
|
|
|
|
ftmps = nil;
|
|
|
|
com(n->r);
|
|
|
|
}
|
|
|
|
ftmps = l;
|
|
|
|
atmps = r;
|
|
|
|
clevel--;
|
|
|
|
cprint("}\n");
|
|
|
|
break;
|
|
|
|
case 'm':
|
|
|
|
l = modulo;
|
|
|
|
modulo = ecom(n->l, nil);
|
|
|
|
com(n->r);
|
|
|
|
freetmp(modulo);
|
|
|
|
modulo = l;
|
|
|
|
break;
|
|
|
|
case 'e':
|
|
|
|
if(n->r == nil)
|
|
|
|
cprint("%N();\n", n->l);
|
|
|
|
else {
|
|
|
|
r = ecom(n->r, nil);
|
|
|
|
cprint("%N(%N);\n", n->l, r);
|
|
|
|
freetmp(r);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '=':
|
|
|
|
ecom(n->r, n->l);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Node*
|
|
|
|
flocs(Node *n, Node *r)
|
|
|
|
{
|
|
|
|
Loop:
|
|
|
|
if(n != nil)
|
|
|
|
switch(n->c){
|
|
|
|
default:
|
|
|
|
r = flocs(n->l, r);
|
|
|
|
r = flocs(n->r, r);
|
|
|
|
n = n->r;
|
|
|
|
goto Loop;
|
|
|
|
case '=':
|
|
|
|
n = n->l;
|
|
|
|
if(n == nil)
|
|
|
|
diag(n, "lhs is nil");
|
|
|
|
while(n->c == ','){
|
|
|
|
n->c = '=';
|
|
|
|
r = flocs(n, r);
|
|
|
|
n->c = ',';
|
|
|
|
n = n->r;
|
|
|
|
if(n == nil)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
if(n->c == NAME && (n->s->f & (FARG|FLOC)) == 0){
|
|
|
|
n->s->f = FLOC;
|
|
|
|
return new(',', n, r);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fcom(Node *f, Node *a, Node *b)
|
|
|
|
{
|
|
|
|
Node *a0, *l0, *l;
|
|
|
|
|
|
|
|
ntmp = 0;
|
|
|
|
ftmps = atmps = modulo = nil;
|
|
|
|
clevel = 1;
|
|
|
|
cprint("void %N(", f);
|
|
|
|
a0 = a;
|
|
|
|
while(a != nil){
|
|
|
|
if(a != a0)
|
|
|
|
cprint(", ");
|
|
|
|
l = a->c == NAME ? a : a->l;
|
|
|
|
l->s->f = FARG|FSET;
|
|
|
|
cprint("mpint *%N", l);
|
|
|
|
a = a->r;
|
|
|
|
}
|
|
|
|
cprint("){\n");
|
|
|
|
l0 = flocs(b, nil);
|
|
|
|
for(a = l0; a != nil; a = a->r)
|
|
|
|
cprint("mpint *%N = mpnew(0);\n", a->l);
|
|
|
|
com(b);
|
|
|
|
for(a = l0; a != nil; a = a->r)
|
|
|
|
cprint("mpfree(%N);\n", a->l);
|
|
|
|
clevel = 0;
|
|
|
|
cprint("}\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
diag(Node *n, char *fmt, ...)
|
|
|
|
{
|
|
|
|
static char buf[1024];
|
|
|
|
va_list a;
|
|
|
|
|
|
|
|
va_start(a, fmt);
|
|
|
|
vsnprint(buf, sizeof(buf), fmt, a);
|
|
|
|
va_end(a);
|
|
|
|
|
|
|
|
fprint(2, "%s:%d: for %N; %s\n", filename, n->n, n, buf);
|
|
|
|
exits("error");
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
Nfmt(Fmt *f)
|
|
|
|
{
|
|
|
|
Node *n = va_arg(f->args, Node*);
|
|
|
|
|
|
|
|
if(n == nil)
|
|
|
|
return fmtprint(f, "nil");
|
|
|
|
|
|
|
|
if(n->c == ',')
|
|
|
|
return fmtprint(f, "%N, %N", n->l, n->r);
|
|
|
|
|
|
|
|
switch(n->c){
|
|
|
|
case NUM:
|
2016-02-01 18:27:57 +00:00
|
|
|
if(n->m != nil)
|
|
|
|
return fmtprint(f, "%B", n->m);
|
|
|
|
/* wet floor */
|
|
|
|
case NAME:
|
2015-11-22 22:47:58 +00:00
|
|
|
return fmtprint(f, "%s", n->s->n);
|
|
|
|
case EQ:
|
|
|
|
return fmtprint(f, "==");
|
|
|
|
case IF:
|
|
|
|
return fmtprint(f, "if");
|
|
|
|
case ELSE:
|
|
|
|
return fmtprint(f, "else");
|
|
|
|
case MOD:
|
|
|
|
return fmtprint(f, "mod");
|
|
|
|
default:
|
|
|
|
return fmtprint(f, "%c", (char)n->c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
parse(int fd, char *file)
|
|
|
|
{
|
|
|
|
Binit(&bin, fd, OREAD);
|
|
|
|
filename = file;
|
|
|
|
clevel = 0;
|
|
|
|
lineno = 1;
|
|
|
|
goteof = 0;
|
|
|
|
while(!goteof)
|
|
|
|
yyparse();
|
|
|
|
Bterm(&bin);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
usage(void)
|
|
|
|
{
|
|
|
|
fprint(2, "%s [file ...]\n", argv0);
|
|
|
|
exits("usage");
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
fmtinstall('N', Nfmt);
|
|
|
|
fmtinstall('B', mpfmt);
|
|
|
|
|
|
|
|
ARGBEGIN {
|
|
|
|
default:
|
|
|
|
usage();
|
|
|
|
} ARGEND;
|
|
|
|
|
|
|
|
if(argc == 0){
|
|
|
|
parse(0, "<stdin>");
|
|
|
|
exits(nil);
|
|
|
|
}
|
|
|
|
while(*argv != nil){
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
if((fd = open(*argv, OREAD)) < 0){
|
|
|
|
fprint(2, "%s: %r\n", *argv);
|
|
|
|
exits("error");
|
|
|
|
}
|
|
|
|
parse(fd, *argv);
|
|
|
|
close(fd);
|
|
|
|
argv++;
|
|
|
|
}
|
|
|
|
exits(nil);
|
|
|
|
}
|