add new guys
This commit is contained in:
parent
3e63e5c271
commit
17e5fb8973
7 changed files with 2195 additions and 6 deletions
795
src/cmd/units.y
Normal file
795
src/cmd/units.y
Normal file
|
|
@ -0,0 +1,795 @@
|
|||
%{
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
|
||||
enum
|
||||
{
|
||||
Ndim = 15, /* number of dimensions */
|
||||
Nsym = 40, /* size of a name */
|
||||
Nvar = 203, /* hash table size */
|
||||
Maxe = 695, /* log of largest number */
|
||||
};
|
||||
|
||||
typedef struct Var Var;
|
||||
typedef struct Node Node;
|
||||
typedef struct Prefix Prefix;
|
||||
|
||||
struct Node
|
||||
{
|
||||
double val;
|
||||
schar dim[Ndim];
|
||||
};
|
||||
struct Var
|
||||
{
|
||||
Rune name[Nsym];
|
||||
Node node;
|
||||
Var* link;
|
||||
};
|
||||
struct Prefix
|
||||
{
|
||||
double val;
|
||||
char* name;
|
||||
Rune* pname;
|
||||
};
|
||||
|
||||
char buf[100];
|
||||
int digval;
|
||||
Biobuf* fi;
|
||||
Biobuf linebuf;
|
||||
Var* fund[Ndim];
|
||||
Rune line[1000];
|
||||
ulong lineno;
|
||||
int linep;
|
||||
int nerrors;
|
||||
Node one;
|
||||
int peekrune;
|
||||
Node retnode1;
|
||||
Node retnode2;
|
||||
Node retnode;
|
||||
Rune sym[Nsym];
|
||||
Var* vars[Nvar];
|
||||
int vflag;
|
||||
|
||||
#define div unitsdiv
|
||||
|
||||
extern void add(Node*, Node*, Node*);
|
||||
extern void div(Node*, Node*, Node*);
|
||||
extern int specialcase(Node*, Node*, Node*);
|
||||
extern double fadd(double, double);
|
||||
extern double fdiv(double, double);
|
||||
extern double fmul(double, double);
|
||||
extern int gdigit(void*);
|
||||
extern Var* lookup(int);
|
||||
extern void main(int, char*[]);
|
||||
extern void mul(Node*, Node*, Node*);
|
||||
extern void ofile(void);
|
||||
extern double pname(void);
|
||||
extern void printdim(char*, int, int);
|
||||
extern int ralpha(int);
|
||||
extern int readline(void);
|
||||
extern void sub(Node*, Node*, Node*);
|
||||
extern int Ufmt(Fmt*);
|
||||
extern void xpn(Node*, Node*, int);
|
||||
extern void yyerror(char*, ...);
|
||||
extern int yylex(void);
|
||||
extern int yyparse(void);
|
||||
|
||||
typedef Node* indnode;
|
||||
/* #pragma varargck type "U" indnode */
|
||||
|
||||
%}
|
||||
%union
|
||||
{
|
||||
Node node;
|
||||
Var* var;
|
||||
int numb;
|
||||
double val;
|
||||
}
|
||||
|
||||
%type <node> prog expr expr0 expr1 expr2 expr3 expr4
|
||||
|
||||
%token <val> VAL
|
||||
%token <var> VAR
|
||||
%token <numb> SUP
|
||||
%%
|
||||
prog:
|
||||
':' VAR expr
|
||||
{
|
||||
int f;
|
||||
|
||||
f = $2->node.dim[0];
|
||||
$2->node = $3;
|
||||
$2->node.dim[0] = 1;
|
||||
if(f)
|
||||
yyerror("redefinition of %S", $2->name);
|
||||
else
|
||||
if(vflag)
|
||||
print("%S\t%U\n", $2->name, &$2->node);
|
||||
}
|
||||
| ':' VAR '#'
|
||||
{
|
||||
int f, i;
|
||||
|
||||
for(i=1; i<Ndim; i++)
|
||||
if(fund[i] == 0)
|
||||
break;
|
||||
if(i >= Ndim) {
|
||||
yyerror("too many dimensions");
|
||||
i = Ndim-1;
|
||||
}
|
||||
fund[i] = $2;
|
||||
|
||||
f = $2->node.dim[0];
|
||||
$2->node = one;
|
||||
$2->node.dim[0] = 1;
|
||||
$2->node.dim[i] = 1;
|
||||
if(f)
|
||||
yyerror("redefinition of %S", $2->name);
|
||||
else
|
||||
if(vflag)
|
||||
print("%S\t#\n", $2->name);
|
||||
}
|
||||
| '?' expr
|
||||
{
|
||||
retnode1 = $2;
|
||||
}
|
||||
| '?'
|
||||
{
|
||||
retnode1 = one;
|
||||
}
|
||||
|
||||
expr:
|
||||
expr4
|
||||
| expr '+' expr4
|
||||
{
|
||||
add(&$$, &$1, &$3);
|
||||
}
|
||||
| expr '-' expr4
|
||||
{
|
||||
sub(&$$, &$1, &$3);
|
||||
}
|
||||
|
||||
expr4:
|
||||
expr3
|
||||
| expr4 '*' expr3
|
||||
{
|
||||
mul(&$$, &$1, &$3);
|
||||
}
|
||||
| expr4 '/' expr3
|
||||
{
|
||||
div(&$$, &$1, &$3);
|
||||
}
|
||||
|
||||
expr3:
|
||||
expr2
|
||||
| expr3 expr2
|
||||
{
|
||||
mul(&$$, &$1, &$2);
|
||||
}
|
||||
|
||||
expr2:
|
||||
expr1
|
||||
| expr2 SUP
|
||||
{
|
||||
xpn(&$$, &$1, $2);
|
||||
}
|
||||
| expr2 '^' expr1
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=1; i<Ndim; i++)
|
||||
if($3.dim[i]) {
|
||||
yyerror("exponent has units");
|
||||
$$ = $1;
|
||||
break;
|
||||
}
|
||||
if(i >= Ndim) {
|
||||
i = $3.val;
|
||||
if(i != $3.val)
|
||||
yyerror("exponent not integral");
|
||||
xpn(&$$, &$1, i);
|
||||
}
|
||||
}
|
||||
|
||||
expr1:
|
||||
expr0
|
||||
| expr1 '|' expr0
|
||||
{
|
||||
div(&$$, &$1, &$3);
|
||||
}
|
||||
|
||||
expr0:
|
||||
VAR
|
||||
{
|
||||
if($1->node.dim[0] == 0) {
|
||||
yyerror("undefined %S", $1->name);
|
||||
$$ = one;
|
||||
} else
|
||||
$$ = $1->node;
|
||||
}
|
||||
| VAL
|
||||
{
|
||||
$$ = one;
|
||||
$$.val = $1;
|
||||
}
|
||||
| '(' expr ')'
|
||||
{
|
||||
$$ = $2;
|
||||
}
|
||||
%%
|
||||
|
||||
int
|
||||
yylex(void)
|
||||
{
|
||||
int c, i;
|
||||
|
||||
c = peekrune;
|
||||
peekrune = ' ';
|
||||
|
||||
loop:
|
||||
if((c >= '0' && c <= '9') || c == '.')
|
||||
goto numb;
|
||||
if(ralpha(c))
|
||||
goto alpha;
|
||||
switch(c) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
c = line[linep++];
|
||||
goto loop;
|
||||
case 0xd7:
|
||||
return 0x2a;
|
||||
case 0xf7:
|
||||
return 0x2f;
|
||||
case 0xb9:
|
||||
case 0x2071:
|
||||
yylval.numb = 1;
|
||||
return SUP;
|
||||
case 0xb2:
|
||||
case 0x2072:
|
||||
yylval.numb = 2;
|
||||
return SUP;
|
||||
case 0xb3:
|
||||
case 0x2073:
|
||||
yylval.numb = 3;
|
||||
return SUP;
|
||||
}
|
||||
return c;
|
||||
|
||||
alpha:
|
||||
memset(sym, 0, sizeof(sym));
|
||||
for(i=0;; i++) {
|
||||
if(i < nelem(sym))
|
||||
sym[i] = c;
|
||||
c = line[linep++];
|
||||
if(!ralpha(c))
|
||||
break;
|
||||
}
|
||||
sym[nelem(sym)-1] = 0;
|
||||
peekrune = c;
|
||||
yylval.var = lookup(0);
|
||||
return VAR;
|
||||
|
||||
numb:
|
||||
digval = c;
|
||||
yylval.val = fmtcharstod(gdigit, 0);
|
||||
return VAL;
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
char *file;
|
||||
|
||||
ARGBEGIN {
|
||||
default:
|
||||
print("usage: units [-v] [file]\n");
|
||||
exits("usage");
|
||||
case 'v':
|
||||
vflag = 1;
|
||||
break;
|
||||
} ARGEND
|
||||
|
||||
file = unsharp("#9/lib/units");
|
||||
if(argc > 0)
|
||||
file = argv[0];
|
||||
fi = Bopen(file, OREAD);
|
||||
if(fi == 0) {
|
||||
print("cant open: %s\n", file);
|
||||
exits("open");
|
||||
}
|
||||
fmtinstall('U', Ufmt);
|
||||
one.val = 1;
|
||||
|
||||
/*
|
||||
* read the 'units' file to
|
||||
* develope a database
|
||||
*/
|
||||
lineno = 0;
|
||||
for(;;) {
|
||||
lineno++;
|
||||
if(readline())
|
||||
break;
|
||||
if(line[0] == 0 || line[0] == '/')
|
||||
continue;
|
||||
peekrune = ':';
|
||||
yyparse();
|
||||
}
|
||||
|
||||
/*
|
||||
* read the console to
|
||||
* print ratio of pairs
|
||||
*/
|
||||
Bterm(fi);
|
||||
fi = &linebuf;
|
||||
Binit(fi, 0, OREAD);
|
||||
lineno = 0;
|
||||
for(;;) {
|
||||
if(lineno & 1)
|
||||
print("you want: ");
|
||||
else
|
||||
print("you have: ");
|
||||
if(readline())
|
||||
break;
|
||||
peekrune = '?';
|
||||
nerrors = 0;
|
||||
yyparse();
|
||||
if(nerrors)
|
||||
continue;
|
||||
if(lineno & 1) {
|
||||
if(specialcase(&retnode, &retnode2, &retnode1))
|
||||
print("\tis %U\n", &retnode);
|
||||
else {
|
||||
div(&retnode, &retnode2, &retnode1);
|
||||
print("\t* %U\n", &retnode);
|
||||
div(&retnode, &retnode1, &retnode2);
|
||||
print("\t/ %U\n", &retnode);
|
||||
}
|
||||
} else
|
||||
retnode2 = retnode1;
|
||||
lineno++;
|
||||
}
|
||||
print("\n");
|
||||
exits(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* all characters that have some
|
||||
* meaning. rest are usable as names
|
||||
*/
|
||||
int
|
||||
ralpha(int c)
|
||||
{
|
||||
switch(c) {
|
||||
case 0:
|
||||
case '+':
|
||||
case '-':
|
||||
case '*':
|
||||
case '/':
|
||||
case '[':
|
||||
case ']':
|
||||
case '(':
|
||||
case ')':
|
||||
case '^':
|
||||
case ':':
|
||||
case '?':
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '.':
|
||||
case '|':
|
||||
case '#':
|
||||
case 0xb9:
|
||||
case 0x2071:
|
||||
case 0xb2:
|
||||
case 0x2072:
|
||||
case 0xb3:
|
||||
case 0x2073:
|
||||
case 0xd7:
|
||||
case 0xf7:
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
gdigit(void *v)
|
||||
{
|
||||
int c;
|
||||
|
||||
USED(v);
|
||||
c = digval;
|
||||
if(c) {
|
||||
digval = 0;
|
||||
return c;
|
||||
}
|
||||
c = line[linep++];
|
||||
peekrune = c;
|
||||
return c;
|
||||
}
|
||||
|
||||
void
|
||||
yyerror(char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
|
||||
/*
|
||||
* hack to intercept message from yaccpar
|
||||
*/
|
||||
if(strcmp(fmt, "syntax error") == 0) {
|
||||
yyerror("syntax error, last name: %S", sym);
|
||||
return;
|
||||
}
|
||||
va_start(arg, fmt);
|
||||
vseprint(buf, buf+sizeof(buf), fmt, arg);
|
||||
va_end(arg);
|
||||
print("%ld: %S\n\t%s\n", lineno, line, buf);
|
||||
nerrors++;
|
||||
if(nerrors > 5) {
|
||||
print("too many errors\n");
|
||||
exits("errors");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
add(Node *c, Node *a, Node *b)
|
||||
{
|
||||
int i, d;
|
||||
|
||||
for(i=0; i<Ndim; i++) {
|
||||
d = a->dim[i];
|
||||
c->dim[i] = d;
|
||||
if(d != b->dim[i])
|
||||
yyerror("add must be like units");
|
||||
}
|
||||
c->val = fadd(a->val, b->val);
|
||||
}
|
||||
|
||||
void
|
||||
sub(Node *c, Node *a, Node *b)
|
||||
{
|
||||
int i, d;
|
||||
|
||||
for(i=0; i<Ndim; i++) {
|
||||
d = a->dim[i];
|
||||
c->dim[i] = d;
|
||||
if(d != b->dim[i])
|
||||
yyerror("sub must be like units");
|
||||
}
|
||||
c->val = fadd(a->val, -b->val);
|
||||
}
|
||||
|
||||
void
|
||||
mul(Node *c, Node *a, Node *b)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<Ndim; i++)
|
||||
c->dim[i] = a->dim[i] + b->dim[i];
|
||||
c->val = fmul(a->val, b->val);
|
||||
}
|
||||
|
||||
void
|
||||
div(Node *c, Node *a, Node *b)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<Ndim; i++)
|
||||
c->dim[i] = a->dim[i] - b->dim[i];
|
||||
c->val = fdiv(a->val, b->val);
|
||||
}
|
||||
|
||||
void
|
||||
xpn(Node *c, Node *a, int b)
|
||||
{
|
||||
int i;
|
||||
|
||||
*c = one;
|
||||
if(b < 0) {
|
||||
b = -b;
|
||||
for(i=0; i<b; i++)
|
||||
div(c, c, a);
|
||||
} else
|
||||
for(i=0; i<b; i++)
|
||||
mul(c, c, a);
|
||||
}
|
||||
|
||||
int
|
||||
specialcase(Node *c, Node *a, Node *b)
|
||||
{
|
||||
int i, d, d1, d2;
|
||||
|
||||
d1 = 0;
|
||||
d2 = 0;
|
||||
for(i=1; i<Ndim; i++) {
|
||||
d = a->dim[i];
|
||||
if(d) {
|
||||
if(d != 1 || d1)
|
||||
return 0;
|
||||
d1 = i;
|
||||
}
|
||||
d = b->dim[i];
|
||||
if(d) {
|
||||
if(d != 1 || d2)
|
||||
return 0;
|
||||
d2 = i;
|
||||
}
|
||||
}
|
||||
if(d1 == 0 || d2 == 0)
|
||||
return 0;
|
||||
|
||||
if(memcmp(fund[d1]->name, L"°C", 3*sizeof(Rune)) == 0 &&
|
||||
memcmp(fund[d2]->name, L"°F", 3*sizeof(Rune)) == 0 &&
|
||||
b->val == 1) {
|
||||
memcpy(c->dim, b->dim, sizeof(c->dim));
|
||||
c->val = a->val * 9. / 5. + 32.;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(memcmp(fund[d1]->name, L"°F", 3*sizeof(Rune)) == 0 &&
|
||||
memcmp(fund[d2]->name, L"°C", 3*sizeof(Rune)) == 0 &&
|
||||
b->val == 1) {
|
||||
memcpy(c->dim, b->dim, sizeof(c->dim));
|
||||
c->val = (a->val - 32.) * 5. / 9.;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
printdim(char *str, int d, int n)
|
||||
{
|
||||
Var *v;
|
||||
|
||||
if(n) {
|
||||
v = fund[d];
|
||||
if(v)
|
||||
sprint(strchr(str, 0), " %S", v->name);
|
||||
else
|
||||
sprint(strchr(str, 0), " [%d]", d);
|
||||
switch(n) {
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
strcat(str, "²");
|
||||
break;
|
||||
case 3:
|
||||
strcat(str, "³");
|
||||
break;
|
||||
default:
|
||||
sprint(strchr(str, 0), "^%d", n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
Ufmt(Fmt *fp)
|
||||
{
|
||||
char str[200];
|
||||
Node *n;
|
||||
int f, i, d;
|
||||
|
||||
n = va_arg(fp->args, Node*);
|
||||
sprint(str, "%g", n->val);
|
||||
|
||||
f = 0;
|
||||
for(i=1; i<Ndim; i++) {
|
||||
d = n->dim[i];
|
||||
if(d > 0)
|
||||
printdim(str, i, d);
|
||||
else
|
||||
if(d < 0)
|
||||
f = 1;
|
||||
}
|
||||
|
||||
if(f) {
|
||||
strcat(str, " /");
|
||||
for(i=1; i<Ndim; i++) {
|
||||
d = n->dim[i];
|
||||
if(d < 0)
|
||||
printdim(str, i, -d);
|
||||
}
|
||||
}
|
||||
|
||||
return fmtstrcpy(fp, str);
|
||||
}
|
||||
|
||||
int
|
||||
readline(void)
|
||||
{
|
||||
int i, c;
|
||||
|
||||
linep = 0;
|
||||
for(i=0;; i++) {
|
||||
c = Bgetrune(fi);
|
||||
if(c < 0)
|
||||
return 1;
|
||||
if(c == '\n')
|
||||
break;
|
||||
if(i < nelem(line))
|
||||
line[i] = c;
|
||||
}
|
||||
if(i >= nelem(line))
|
||||
i = nelem(line)-1;
|
||||
line[i] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Var*
|
||||
lookup(int f)
|
||||
{
|
||||
int i;
|
||||
Var *v, *w;
|
||||
double p;
|
||||
ulong h;
|
||||
|
||||
h = 0;
|
||||
for(i=0; sym[i]; i++)
|
||||
h = h*13 + sym[i];
|
||||
h %= nelem(vars);
|
||||
|
||||
for(v=vars[h]; v; v=v->link)
|
||||
if(memcmp(sym, v->name, sizeof(sym)) == 0)
|
||||
return v;
|
||||
if(f)
|
||||
return 0;
|
||||
v = malloc(sizeof(*v));
|
||||
if(v == nil) {
|
||||
fprint(2, "out of memory\n");
|
||||
exits("mem");
|
||||
}
|
||||
memset(v, 0, sizeof(*v));
|
||||
memcpy(v->name, sym, sizeof(sym));
|
||||
v->link = vars[h];
|
||||
vars[h] = v;
|
||||
|
||||
p = 1;
|
||||
for(;;) {
|
||||
p = fmul(p, pname());
|
||||
if(p == 0)
|
||||
break;
|
||||
w = lookup(1);
|
||||
if(w) {
|
||||
v->node = w->node;
|
||||
v->node.val = fmul(v->node.val, p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
Prefix prefix[] =
|
||||
{
|
||||
1e-24, "yocto", 0,
|
||||
1e-21, "zepto", 0,
|
||||
1e-18, "atto", 0,
|
||||
1e-15, "femto", 0,
|
||||
1e-12, "pico", 0,
|
||||
1e-9, "nano", 0,
|
||||
1e-6, "micro", 0,
|
||||
1e-6, "μ", 0,
|
||||
1e-3, "milli", 0,
|
||||
1e-2, "centi", 0,
|
||||
1e-1, "deci", 0,
|
||||
1e1, "deka", 0,
|
||||
1e2, "hecta", 0,
|
||||
1e2, "hecto", 0,
|
||||
1e3, "kilo", 0,
|
||||
1e6, "mega", 0,
|
||||
1e6, "meg", 0,
|
||||
1e9, "giga", 0,
|
||||
1e12, "tera", 0,
|
||||
1e15, "peta", 0,
|
||||
1e18, "exa", 0,
|
||||
1e21, "zetta", 0,
|
||||
1e24, "yotta", 0,
|
||||
0, 0, 0,
|
||||
};
|
||||
|
||||
double
|
||||
pname(void)
|
||||
{
|
||||
Rune *p;
|
||||
int i, j, c;
|
||||
|
||||
/*
|
||||
* rip off normal prefixs
|
||||
*/
|
||||
if(prefix[0].pname == nil){
|
||||
for(i=0; prefix[i].name; i++)
|
||||
prefix[i].pname = runesmprint("%s", prefix[i].name);
|
||||
}
|
||||
|
||||
for(i=0; p=prefix[i].pname; i++) {
|
||||
for(j=0; c=p[j]; j++)
|
||||
if(c != sym[j])
|
||||
goto no;
|
||||
memmove(sym, sym+j, (Nsym-j)*sizeof(*sym));
|
||||
memset(sym+(Nsym-j), 0, j*sizeof(*sym));
|
||||
return prefix[i].val;
|
||||
no:;
|
||||
}
|
||||
|
||||
/*
|
||||
* rip off 's' suffixes
|
||||
*/
|
||||
for(j=0; sym[j]; j++)
|
||||
;
|
||||
j--;
|
||||
/* j>1 is special hack to disallow ms finding m */
|
||||
if(j > 1 && sym[j] == 's') {
|
||||
sym[j] = 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* careful floating point
|
||||
*/
|
||||
double
|
||||
fmul(double a, double b)
|
||||
{
|
||||
double l;
|
||||
|
||||
if(a <= 0) {
|
||||
if(a == 0)
|
||||
return 0;
|
||||
l = log(-a);
|
||||
} else
|
||||
l = log(a);
|
||||
|
||||
if(b <= 0) {
|
||||
if(b == 0)
|
||||
return 0;
|
||||
l += log(-b);
|
||||
} else
|
||||
l += log(b);
|
||||
|
||||
if(l > Maxe) {
|
||||
yyerror("overflow in multiply");
|
||||
return 1;
|
||||
}
|
||||
if(l < -Maxe) {
|
||||
yyerror("underflow in multiply");
|
||||
return 0;
|
||||
}
|
||||
return a*b;
|
||||
}
|
||||
|
||||
double
|
||||
fdiv(double a, double b)
|
||||
{
|
||||
double l;
|
||||
|
||||
if(a <= 0) {
|
||||
if(a == 0)
|
||||
return 0;
|
||||
l = log(-a);
|
||||
} else
|
||||
l = log(a);
|
||||
|
||||
if(b <= 0) {
|
||||
if(b == 0) {
|
||||
yyerror("division by zero");
|
||||
return 1;
|
||||
}
|
||||
l -= log(-b);
|
||||
} else
|
||||
l -= log(b);
|
||||
|
||||
if(l > Maxe) {
|
||||
yyerror("overflow in divide");
|
||||
return 1;
|
||||
}
|
||||
if(l < -Maxe) {
|
||||
yyerror("underflow in divide");
|
||||
return 0;
|
||||
}
|
||||
return a/b;
|
||||
}
|
||||
|
||||
double
|
||||
fadd(double a, double b)
|
||||
{
|
||||
return a + b;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue