add new guys
This commit is contained in:
parent
3e63e5c271
commit
17e5fb8973
7 changed files with 2195 additions and 6 deletions
983
src/cmd/bc.y
Normal file
983
src/cmd/bc.y
Normal file
|
|
@ -0,0 +1,983 @@
|
|||
%{
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
|
||||
#define bsp_max 5000
|
||||
|
||||
Biobuf *in;
|
||||
Biobuf stdin;
|
||||
Biobuf stdout;
|
||||
char cary[1000];
|
||||
char* cp = { cary };
|
||||
char string[1000];
|
||||
char* str = { string };
|
||||
int crs = 128;
|
||||
int rcrs = 128; /* reset crs */
|
||||
int bindx = 0;
|
||||
int lev = 0;
|
||||
int ln;
|
||||
int* ttp;
|
||||
char* ss = "";
|
||||
int bstack[10] = { 0 };
|
||||
char* numb[15] =
|
||||
{
|
||||
" 0", " 1", " 2", " 3", " 4", " 5",
|
||||
" 6", " 7", " 8", " 9", " 10", " 11",
|
||||
" 12", " 13", " 14"
|
||||
};
|
||||
int* pre;
|
||||
int* post;
|
||||
|
||||
long peekc = -1;
|
||||
int sargc;
|
||||
int ifile;
|
||||
char** sargv;
|
||||
|
||||
char *funtab[] =
|
||||
{
|
||||
"<1>","<2>","<3>","<4>","<5>",
|
||||
"<6>","<7>","<8>","<9>","<10>",
|
||||
"<11>","<12>","<13>","<14>","<15>",
|
||||
"<16>","<17>","<18>","<19>","<20>",
|
||||
"<21>","<22>","<23>","<24>","<25>",
|
||||
"<26>"
|
||||
};
|
||||
char *atab[] =
|
||||
{
|
||||
"<221>","<222>","<223>","<224>","<225>",
|
||||
"<226>","<227>","<228>","<229>","<230>",
|
||||
"<231>","<232>","<233>","<234>","<235>",
|
||||
"<236>","<237>","<238>","<239>","<240>",
|
||||
"<241>","<242>","<243>","<244>","<245>",
|
||||
"<246>"
|
||||
};
|
||||
char* letr[26] =
|
||||
{
|
||||
"a","b","c","d","e","f","g","h","i","j",
|
||||
"k","l","m","n","o","p","q","r","s","t",
|
||||
"u","v","w","x","y","z"
|
||||
};
|
||||
char* dot = { "." };
|
||||
int bspace[bsp_max];
|
||||
int* bsp_nxt = { bspace };
|
||||
int bdebug = 0;
|
||||
int lflag;
|
||||
int cflag;
|
||||
int sflag;
|
||||
|
||||
int* bundle(int, ...);
|
||||
void conout(int*, char*);
|
||||
int cpeek(int, int, int);
|
||||
int getch(void);
|
||||
int* geta(char*);
|
||||
int* getf(char*);
|
||||
void getout(void);
|
||||
void output(int*);
|
||||
void pp(char*);
|
||||
void routput(int*);
|
||||
void tp(char*);
|
||||
void yyerror(char*, ...);
|
||||
int yyparse(void);
|
||||
|
||||
typedef void* pointer;
|
||||
/* #pragma varargck type "lx" pointer */
|
||||
|
||||
%}
|
||||
%union
|
||||
{
|
||||
int* iptr;
|
||||
char* cptr;
|
||||
int cc;
|
||||
}
|
||||
|
||||
%type <iptr> pstat stat stat1 def slist dlets e ase nase
|
||||
%type <iptr> slist re fprefix cargs eora cons constant lora
|
||||
%type <cptr> crs
|
||||
|
||||
%token <cptr> LETTER EQOP _AUTO DOT
|
||||
%token <cc> DIGIT SQRT LENGTH _IF FFF EQ
|
||||
%token <cc> _PRINT _WHILE _FOR NE LE GE INCR DECR
|
||||
%token <cc> _RETURN _BREAK _DEFINE BASE OBASE SCALE
|
||||
%token <cc> QSTR ERROR
|
||||
|
||||
%right '=' EQOP
|
||||
%left '+' '-'
|
||||
%left '*' '/' '%'
|
||||
%right '^'
|
||||
%left UMINUS
|
||||
|
||||
%%
|
||||
start:
|
||||
start stuff
|
||||
| stuff
|
||||
|
||||
stuff:
|
||||
pstat tail
|
||||
{
|
||||
output($1);
|
||||
}
|
||||
| def dargs ')' '{' dlist slist '}'
|
||||
{
|
||||
ttp = bundle(6, pre, $6, post , "0", numb[lev], "Q");
|
||||
conout(ttp, (char*)$1);
|
||||
rcrs = crs;
|
||||
output((int*)""); /* this is horse puk!! */
|
||||
lev = bindx = 0;
|
||||
}
|
||||
|
||||
dlist:
|
||||
tail
|
||||
| dlist _AUTO dlets tail
|
||||
|
||||
stat:
|
||||
stat1
|
||||
| nase
|
||||
{
|
||||
if(sflag)
|
||||
bundle(2, $1, "s.");
|
||||
}
|
||||
|
||||
pstat:
|
||||
stat1
|
||||
{
|
||||
if(sflag)
|
||||
bundle(2, $1, "0");
|
||||
}
|
||||
| nase
|
||||
{
|
||||
if(!sflag)
|
||||
bundle(2, $1, "ps.");
|
||||
}
|
||||
|
||||
stat1:
|
||||
{
|
||||
bundle(1, "");
|
||||
}
|
||||
| ase
|
||||
{
|
||||
bundle(2, $1, "s.");
|
||||
}
|
||||
| SCALE '=' e
|
||||
{
|
||||
bundle(2, $3, "k");
|
||||
}
|
||||
| SCALE EQOP e
|
||||
{
|
||||
bundle(4, "K", $3, $2, "k");
|
||||
}
|
||||
| BASE '=' e
|
||||
{
|
||||
bundle(2, $3, "i");
|
||||
}
|
||||
| BASE EQOP e
|
||||
{
|
||||
bundle(4, "I", $3, $2, "i");
|
||||
}
|
||||
| OBASE '=' e
|
||||
{
|
||||
bundle(2, $3, "o");
|
||||
}
|
||||
| OBASE EQOP e
|
||||
{
|
||||
bundle(4, "O", $3, $2, "o");
|
||||
}
|
||||
| QSTR
|
||||
{
|
||||
bundle(3, "[", $1, "]P");
|
||||
}
|
||||
| _BREAK
|
||||
{
|
||||
bundle(2, numb[lev-bstack[bindx-1]], "Q");
|
||||
}
|
||||
| _PRINT e
|
||||
{
|
||||
bundle(2, $2, "ps.");
|
||||
}
|
||||
| _RETURN e
|
||||
{
|
||||
bundle(4, $2, post, numb[lev], "Q");
|
||||
}
|
||||
| _RETURN
|
||||
{
|
||||
bundle(4, "0", post, numb[lev], "Q");
|
||||
}
|
||||
| '{' slist '}'
|
||||
{
|
||||
$$ = $2;
|
||||
}
|
||||
| FFF
|
||||
{
|
||||
bundle(1, "fY");
|
||||
}
|
||||
| _IF crs BLEV '(' re ')' stat
|
||||
{
|
||||
conout($7, $2);
|
||||
bundle(3, $5, $2, " ");
|
||||
}
|
||||
| _WHILE crs '(' re ')' stat BLEV
|
||||
{
|
||||
bundle(3, $6, $4, $2);
|
||||
conout($$, $2);
|
||||
bundle(3, $4, $2, " ");
|
||||
}
|
||||
| fprefix crs re ';' e ')' stat BLEV
|
||||
{
|
||||
bundle(5, $7, $5, "s.", $3, $2);
|
||||
conout($$, $2);
|
||||
bundle(5, $1, "s.", $3, $2, " ");
|
||||
}
|
||||
| '~' LETTER '=' e
|
||||
{
|
||||
bundle(3, $4, "S", $2);
|
||||
}
|
||||
|
||||
fprefix:
|
||||
_FOR '(' e ';'
|
||||
{
|
||||
$$ = $3;
|
||||
}
|
||||
|
||||
BLEV:
|
||||
=
|
||||
{
|
||||
--bindx;
|
||||
}
|
||||
|
||||
slist:
|
||||
stat
|
||||
| slist tail stat
|
||||
{
|
||||
bundle(2, $1, $3);
|
||||
}
|
||||
|
||||
tail:
|
||||
'\n'
|
||||
{
|
||||
ln++;
|
||||
}
|
||||
| ';'
|
||||
|
||||
re:
|
||||
e EQ e
|
||||
{
|
||||
$$ = bundle(3, $1, $3, "=");
|
||||
}
|
||||
| e '<' e
|
||||
{
|
||||
bundle(3, $1, $3, ">");
|
||||
}
|
||||
| e '>' e
|
||||
{
|
||||
bundle(3, $1, $3, "<");
|
||||
}
|
||||
| e NE e
|
||||
{
|
||||
bundle(3, $1, $3, "!=");
|
||||
}
|
||||
| e GE e
|
||||
{
|
||||
bundle(3, $1, $3, "!>");
|
||||
}
|
||||
| e LE e
|
||||
{
|
||||
bundle(3, $1, $3, "!<");
|
||||
}
|
||||
| e
|
||||
{
|
||||
bundle(2, $1, " 0!=");
|
||||
}
|
||||
|
||||
nase:
|
||||
'(' e ')'
|
||||
{
|
||||
$$ = $2;
|
||||
}
|
||||
| cons
|
||||
{
|
||||
bundle(3, " ", $1, " ");
|
||||
}
|
||||
| DOT cons
|
||||
{
|
||||
bundle(3, " .", $2, " ");
|
||||
}
|
||||
| cons DOT cons
|
||||
{
|
||||
bundle(5, " ", $1, ".", $3, " ");
|
||||
}
|
||||
| cons DOT
|
||||
{
|
||||
bundle(4, " ", $1, ".", " ");
|
||||
}
|
||||
| DOT
|
||||
{
|
||||
$<cptr>$ = "l.";
|
||||
}
|
||||
| LETTER '[' e ']'
|
||||
{
|
||||
bundle(3, $3, ";", geta($1));
|
||||
}
|
||||
| LETTER INCR
|
||||
{
|
||||
bundle(4, "l", $1, "d1+s", $1);
|
||||
}
|
||||
| INCR LETTER
|
||||
{
|
||||
bundle(4, "l", $2, "1+ds", $2);
|
||||
}
|
||||
| DECR LETTER
|
||||
{
|
||||
bundle(4, "l", $2, "1-ds", $2);
|
||||
}
|
||||
| LETTER DECR
|
||||
{
|
||||
bundle(4, "l", $1, "d1-s", $1);
|
||||
}
|
||||
| LETTER '[' e ']' INCR
|
||||
{
|
||||
bundle(7, $3, ";", geta($1), "d1+" ,$3, ":" ,geta($1));
|
||||
}
|
||||
| INCR LETTER '[' e ']'
|
||||
{
|
||||
bundle(7, $4, ";", geta($2), "1+d", $4, ":", geta($2));
|
||||
}
|
||||
| LETTER '[' e ']' DECR
|
||||
{
|
||||
bundle(7, $3, ";", geta($1), "d1-", $3, ":", geta($1));
|
||||
}
|
||||
| DECR LETTER '[' e ']'
|
||||
{
|
||||
bundle(7, $4, ";", geta($2), "1-d", $4, ":" ,geta($2));
|
||||
}
|
||||
| SCALE INCR
|
||||
{
|
||||
bundle(1, "Kd1+k");
|
||||
}
|
||||
| INCR SCALE
|
||||
{
|
||||
bundle(1, "K1+dk");
|
||||
}
|
||||
| SCALE DECR
|
||||
{
|
||||
bundle(1, "Kd1-k");
|
||||
}
|
||||
| DECR SCALE
|
||||
{
|
||||
bundle(1, "K1-dk");
|
||||
}
|
||||
| BASE INCR
|
||||
{
|
||||
bundle(1, "Id1+i");
|
||||
}
|
||||
| INCR BASE
|
||||
{
|
||||
bundle(1, "I1+di");
|
||||
}
|
||||
| BASE DECR
|
||||
{
|
||||
bundle(1, "Id1-i");
|
||||
}
|
||||
| DECR BASE
|
||||
{
|
||||
bundle(1, "I1-di");
|
||||
}
|
||||
| OBASE INCR
|
||||
{
|
||||
bundle(1, "Od1+o");
|
||||
}
|
||||
| INCR OBASE
|
||||
{
|
||||
bundle(1, "O1+do");
|
||||
}
|
||||
| OBASE DECR
|
||||
{
|
||||
bundle(1, "Od1-o");
|
||||
}
|
||||
| DECR OBASE
|
||||
{
|
||||
bundle(1, "O1-do");
|
||||
}
|
||||
| LETTER '(' cargs ')'
|
||||
{
|
||||
bundle(4, $3, "l", getf($1), "x");
|
||||
}
|
||||
| LETTER '(' ')'
|
||||
{
|
||||
bundle(3, "l", getf($1), "x");
|
||||
}
|
||||
| LETTER = {
|
||||
bundle(2, "l", $1);
|
||||
}
|
||||
| LENGTH '(' e ')'
|
||||
{
|
||||
bundle(2, $3, "Z");
|
||||
}
|
||||
| SCALE '(' e ')'
|
||||
{
|
||||
bundle(2, $3, "X");
|
||||
}
|
||||
| '?'
|
||||
{
|
||||
bundle(1, "?");
|
||||
}
|
||||
| SQRT '(' e ')'
|
||||
{
|
||||
bundle(2, $3, "v");
|
||||
}
|
||||
| '~' LETTER
|
||||
{
|
||||
bundle(2, "L", $2);
|
||||
}
|
||||
| SCALE
|
||||
{
|
||||
bundle(1, "K");
|
||||
}
|
||||
| BASE
|
||||
{
|
||||
bundle(1, "I");
|
||||
}
|
||||
| OBASE
|
||||
{
|
||||
bundle(1, "O");
|
||||
}
|
||||
| '-' e
|
||||
{
|
||||
bundle(3, " 0", $2, "-");
|
||||
}
|
||||
| e '+' e
|
||||
{
|
||||
bundle(3, $1, $3, "+");
|
||||
}
|
||||
| e '-' e
|
||||
{
|
||||
bundle(3, $1, $3, "-");
|
||||
}
|
||||
| e '*' e
|
||||
{
|
||||
bundle(3, $1, $3, "*");
|
||||
}
|
||||
| e '/' e
|
||||
{
|
||||
bundle(3, $1, $3, "/");
|
||||
}
|
||||
| e '%' e
|
||||
{
|
||||
bundle(3, $1, $3, "%%");
|
||||
}
|
||||
| e '^' e
|
||||
{
|
||||
bundle(3, $1, $3, "^");
|
||||
}
|
||||
|
||||
ase:
|
||||
LETTER '=' e
|
||||
{
|
||||
bundle(3, $3, "ds", $1);
|
||||
}
|
||||
| LETTER '[' e ']' '=' e
|
||||
{
|
||||
bundle(5, $6, "d", $3, ":", geta($1));
|
||||
}
|
||||
| LETTER EQOP e
|
||||
{
|
||||
bundle(6, "l", $1, $3, $2, "ds", $1);
|
||||
}
|
||||
| LETTER '[' e ']' EQOP e
|
||||
{
|
||||
bundle(9, $3, ";", geta($1), $6, $5, "d", $3, ":", geta($1));
|
||||
}
|
||||
|
||||
e:
|
||||
ase
|
||||
| nase
|
||||
|
||||
cargs:
|
||||
eora
|
||||
| cargs ',' eora
|
||||
{
|
||||
bundle(2, $1, $3);
|
||||
}
|
||||
|
||||
eora:
|
||||
e
|
||||
| LETTER '[' ']'
|
||||
{
|
||||
bundle(2, "l", geta($1));
|
||||
}
|
||||
|
||||
cons:
|
||||
constant
|
||||
{
|
||||
*cp++ = 0;
|
||||
}
|
||||
|
||||
constant:
|
||||
'_'
|
||||
{
|
||||
$<cptr>$ = cp;
|
||||
*cp++ = '_';
|
||||
}
|
||||
| DIGIT
|
||||
{
|
||||
$<cptr>$ = cp;
|
||||
*cp++ = $1;
|
||||
}
|
||||
| constant DIGIT
|
||||
{
|
||||
*cp++ = $2;
|
||||
}
|
||||
|
||||
crs:
|
||||
=
|
||||
{
|
||||
$$ = cp;
|
||||
*cp++ = '<';
|
||||
*cp++ = crs/100+'0';
|
||||
*cp++ = (crs%100)/10+'0';
|
||||
*cp++ = crs%10+'0';
|
||||
*cp++ = '>';
|
||||
*cp++ = '\0';
|
||||
if(crs++ >= 220) {
|
||||
yyerror("program too big");
|
||||
getout();
|
||||
}
|
||||
bstack[bindx++] = lev++;
|
||||
}
|
||||
|
||||
def:
|
||||
_DEFINE LETTER '('
|
||||
{
|
||||
$$ = getf($2);
|
||||
pre = (int*)"";
|
||||
post = (int*)"";
|
||||
lev = 1;
|
||||
bindx = 0;
|
||||
bstack[bindx] = 0;
|
||||
}
|
||||
|
||||
dargs:
|
||||
| lora
|
||||
{
|
||||
pp((char*)$1);
|
||||
}
|
||||
| dargs ',' lora
|
||||
{
|
||||
pp((char*)$3);
|
||||
}
|
||||
|
||||
dlets:
|
||||
lora
|
||||
{
|
||||
tp((char*)$1);
|
||||
}
|
||||
| dlets ',' lora
|
||||
{
|
||||
tp((char*)$3);
|
||||
}
|
||||
|
||||
lora:
|
||||
LETTER
|
||||
{
|
||||
$<cptr>$=$1;
|
||||
}
|
||||
| LETTER '[' ']'
|
||||
{
|
||||
$$ = geta($1);
|
||||
}
|
||||
|
||||
%%
|
||||
|
||||
int
|
||||
yylex(void)
|
||||
{
|
||||
int c, ch;
|
||||
|
||||
restart:
|
||||
c = getch();
|
||||
peekc = -1;
|
||||
while(c == ' ' || c == '\t')
|
||||
c = getch();
|
||||
if(c == '\\') {
|
||||
getch();
|
||||
goto restart;
|
||||
}
|
||||
if(c >= 'a' && c <= 'z') {
|
||||
/* look ahead to look for reserved words */
|
||||
peekc = getch();
|
||||
if(peekc >= 'a' && peekc <= 'z') { /* must be reserved word */
|
||||
if(c=='p' && peekc=='r') {
|
||||
c = _PRINT;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='i' && peekc=='f') {
|
||||
c = _IF;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='w' && peekc=='h') {
|
||||
c = _WHILE;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='f' && peekc=='o') {
|
||||
c = _FOR;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='s' && peekc=='q') {
|
||||
c = SQRT;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='r' && peekc=='e') {
|
||||
c = _RETURN;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='b' && peekc=='r') {
|
||||
c = _BREAK;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='d' && peekc=='e') {
|
||||
c = _DEFINE;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='s' && peekc=='c') {
|
||||
c = SCALE;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='b' && peekc=='a') {
|
||||
c = BASE;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='i' && peekc=='b') {
|
||||
c = BASE;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='o' && peekc=='b') {
|
||||
c = OBASE;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='d' && peekc=='i') {
|
||||
c = FFF;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='a' && peekc=='u') {
|
||||
c = _AUTO;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='l' && peekc=='e') {
|
||||
c = LENGTH;
|
||||
goto skip;
|
||||
}
|
||||
if(c=='q' && peekc=='u')
|
||||
getout();
|
||||
/* could not be found */
|
||||
return ERROR;
|
||||
|
||||
skip: /* skip over rest of word */
|
||||
peekc = -1;
|
||||
for(;;) {
|
||||
ch = getch();
|
||||
if(ch < 'a' || ch > 'z')
|
||||
break;
|
||||
}
|
||||
peekc = ch;
|
||||
return c;
|
||||
}
|
||||
|
||||
/* usual case; just one single letter */
|
||||
yylval.cptr = letr[c-'a'];
|
||||
return LETTER;
|
||||
}
|
||||
if((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
|
||||
yylval.cc = c;
|
||||
return DIGIT;
|
||||
}
|
||||
switch(c) {
|
||||
case '.':
|
||||
return DOT;
|
||||
case '*':
|
||||
yylval.cptr = "*";
|
||||
return cpeek('=', EQOP, c);
|
||||
case '%':
|
||||
yylval.cptr = "%%";
|
||||
return cpeek('=', EQOP, c);
|
||||
case '^':
|
||||
yylval.cptr = "^";
|
||||
return cpeek('=', EQOP, c);
|
||||
case '+':
|
||||
ch = cpeek('=', EQOP, c);
|
||||
if(ch == EQOP) {
|
||||
yylval.cptr = "+";
|
||||
return ch;
|
||||
}
|
||||
return cpeek('+', INCR, c);
|
||||
case '-':
|
||||
ch = cpeek('=', EQOP, c);
|
||||
if(ch == EQOP) {
|
||||
yylval.cptr = "-";
|
||||
return ch;
|
||||
}
|
||||
return cpeek('-', DECR, c);
|
||||
case '=':
|
||||
return cpeek('=', EQ, '=');
|
||||
case '<':
|
||||
return cpeek('=', LE, '<');
|
||||
case '>':
|
||||
return cpeek('=', GE, '>');
|
||||
case '!':
|
||||
return cpeek('=', NE, '!');
|
||||
case '/':
|
||||
ch = cpeek('=', EQOP, c);
|
||||
if(ch == EQOP) {
|
||||
yylval.cptr = "/";
|
||||
return ch;
|
||||
}
|
||||
if(peekc == '*') {
|
||||
peekc = -1;
|
||||
for(;;) {
|
||||
ch = getch();
|
||||
if(ch == '*') {
|
||||
peekc = getch();
|
||||
if(peekc == '/') {
|
||||
peekc = -1;
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return c;
|
||||
case '"':
|
||||
yylval.cptr = str;
|
||||
while((c=getch()) != '"'){
|
||||
*str++ = c;
|
||||
if(str >= &string[999]){
|
||||
yyerror("string space exceeded");
|
||||
getout();
|
||||
}
|
||||
}
|
||||
*str++ = 0;
|
||||
return QSTR;
|
||||
default:
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
cpeek(int c, int yes, int no)
|
||||
{
|
||||
|
||||
peekc = getch();
|
||||
if(peekc == c) {
|
||||
peekc = -1;
|
||||
return yes;
|
||||
}
|
||||
return no;
|
||||
}
|
||||
|
||||
int
|
||||
getch(void)
|
||||
{
|
||||
long ch;
|
||||
|
||||
loop:
|
||||
ch = peekc;
|
||||
if(ch < 0){
|
||||
if(in == 0)
|
||||
ch = -1;
|
||||
else
|
||||
ch = Bgetc(in);
|
||||
}
|
||||
peekc = -1;
|
||||
if(ch >= 0)
|
||||
return ch;
|
||||
ifile++;
|
||||
if(ifile > sargc) {
|
||||
if(ifile >= sargc+2)
|
||||
getout();
|
||||
in = &stdin;
|
||||
Binit(in, 0, OREAD);
|
||||
ln = 0;
|
||||
goto loop;
|
||||
}
|
||||
Bterm(in);
|
||||
if((in = Bopen(sargv[ifile], OREAD)) != 0){
|
||||
ln = 0;
|
||||
ss = sargv[ifile];
|
||||
goto loop;
|
||||
}
|
||||
yyerror("cannot open input file");
|
||||
return 0; /* shut up ken */
|
||||
}
|
||||
|
||||
int*
|
||||
bundle(int a, ...)
|
||||
{
|
||||
int i, *p, *q;
|
||||
|
||||
p = &a;
|
||||
i = *p++;
|
||||
q = bsp_nxt;
|
||||
if(bdebug)
|
||||
fprint(2, "bundle %d elements at %lx\n", i, q);
|
||||
while(i-- > 0) {
|
||||
if(bsp_nxt >= &bspace[bsp_max])
|
||||
yyerror("bundling space exceeded");
|
||||
*bsp_nxt++ = *p++;
|
||||
}
|
||||
*bsp_nxt++ = 0;
|
||||
yyval.iptr = q;
|
||||
return q;
|
||||
}
|
||||
|
||||
void
|
||||
routput(int *p)
|
||||
{
|
||||
if(bdebug)
|
||||
fprint(2, "routput(%lx)\n", p);
|
||||
if(p >= &bspace[0] && p < &bspace[bsp_max]) {
|
||||
/* part of a bundle */
|
||||
while(*p != 0)
|
||||
routput((int*)(*p++));
|
||||
} else
|
||||
Bprint(&stdout, (char*)p); /* character string */
|
||||
}
|
||||
|
||||
void
|
||||
output(int *p)
|
||||
{
|
||||
routput(p);
|
||||
bsp_nxt = &bspace[0];
|
||||
Bprint(&stdout, "\n");
|
||||
Bflush(&stdout);
|
||||
cp = cary;
|
||||
crs = rcrs;
|
||||
}
|
||||
|
||||
void
|
||||
conout(int *p, char *s)
|
||||
{
|
||||
Bprint(&stdout, "[");
|
||||
routput(p);
|
||||
Bprint(&stdout, "]s%s\n", s);
|
||||
Bflush(&stdout);
|
||||
lev--;
|
||||
}
|
||||
|
||||
void
|
||||
yyerror(char *s, ...)
|
||||
{
|
||||
if(ifile > sargc)
|
||||
ss = "teletype";
|
||||
Bprint(&stdout, "c[%s on line %d, %s]pc\n", s, ln+1, ss);
|
||||
Bflush(&stdout);
|
||||
cp = cary;
|
||||
crs = rcrs;
|
||||
bindx = 0;
|
||||
lev = 0;
|
||||
bsp_nxt = &bspace[0];
|
||||
}
|
||||
|
||||
void
|
||||
pp(char *s)
|
||||
{
|
||||
/* puts the relevant stuff on pre and post for the letter s */
|
||||
bundle(3, "S", s, pre);
|
||||
pre = yyval.iptr;
|
||||
bundle(4, post, "L", s, "s.");
|
||||
post = yyval.iptr;
|
||||
}
|
||||
|
||||
void
|
||||
tp(char *s)
|
||||
{
|
||||
/* same as pp, but for temps */
|
||||
bundle(3, "0S", s, pre);
|
||||
pre = yyval.iptr;
|
||||
bundle(4, post, "L", s, "s.");
|
||||
post = yyval.iptr;
|
||||
}
|
||||
|
||||
void
|
||||
yyinit(int argc, char **argv)
|
||||
{
|
||||
Binit(&stdout, 1, OWRITE);
|
||||
sargv = argv;
|
||||
sargc = argc - 1;
|
||||
if(sargc == 0) {
|
||||
in = &stdin;
|
||||
Binit(in, 0, OREAD);
|
||||
} else if((in = Bopen(sargv[1], OREAD)) == 0)
|
||||
yyerror("cannot open input file");
|
||||
ifile = 1;
|
||||
ln = 0;
|
||||
ss = sargv[1];
|
||||
}
|
||||
|
||||
void
|
||||
getout(void)
|
||||
{
|
||||
Bprint(&stdout, "q");
|
||||
Bflush(&stdout);
|
||||
exits(0);
|
||||
}
|
||||
|
||||
int*
|
||||
getf(char *p)
|
||||
{
|
||||
return (int*)funtab[*p - 'a'];
|
||||
}
|
||||
|
||||
int*
|
||||
geta(char *p)
|
||||
{
|
||||
return (int*)atab[*p - 'a'];
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int p[2];
|
||||
|
||||
while(argc > 1 && *argv[1] == '-') {
|
||||
switch(argv[1][1]) {
|
||||
case 'd':
|
||||
bdebug++;
|
||||
break;
|
||||
case 'c':
|
||||
cflag++;
|
||||
break;
|
||||
case 'l':
|
||||
lflag++;
|
||||
break;
|
||||
case 's':
|
||||
sflag++;
|
||||
break;
|
||||
default:
|
||||
fprint(2, "Usage: bc [-l] [-c] [file ...]\n");
|
||||
exits("usage");
|
||||
}
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
if(lflag) {
|
||||
argv--;
|
||||
argc++;
|
||||
argv[1] = "/sys/lib/bclib";
|
||||
}
|
||||
if(cflag) {
|
||||
yyinit(argc, argv);
|
||||
for(;;)
|
||||
yyparse();
|
||||
exits(0);
|
||||
}
|
||||
pipe(p);
|
||||
if(fork() == 0) {
|
||||
dup(p[1], 1);
|
||||
close(p[0]);
|
||||
close(p[1]);
|
||||
yyinit(argc, argv);
|
||||
for(;;)
|
||||
yyparse();
|
||||
}
|
||||
dup(p[0], 0);
|
||||
close(p[0]);
|
||||
close(p[1]);
|
||||
execl("/bin/dc", "dc", 0);
|
||||
}
|
||||
|
|
@ -38,12 +38,12 @@ torgbv.$O: ycbcr.h rgbv.h
|
|||
|
||||
ycbcr.h: rgbycc.c
|
||||
9c rgbycc.c
|
||||
9l -o o.rgbycc rgbycc.c
|
||||
9l -o o.rgbycc rgbycc.o -ldraw -l9
|
||||
./o.rgbycc >ycbcr.h
|
||||
|
||||
rgbv.h: rgbrgbv.c
|
||||
9c rgbrgbv.c
|
||||
9l -o o.rgbrgbv rgbrgbv.c
|
||||
9l -o o.rgbrgbv rgbrgbv.o -ldraw -l9
|
||||
./o.rgbrgbv >rgbv.h
|
||||
|
||||
nuke:V: nuke-headers
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
<$PLAN9/src/mkhdr
|
||||
|
||||
TARG=`ls *.c | sed 's/\.c//'`
|
||||
LDFLAGS=$LDFLAGS -L$X11/lib -lX11
|
||||
SHORTLIB=sec fs mux regexp9 draw thread bio 9
|
||||
TARG=`ls *.[cy] | sed 's/\.c//'`
|
||||
SHORTLIB=sec fs mux regexp9 thread bio 9
|
||||
|
||||
<$PLAN9/src/mkmany
|
||||
|
||||
|
|
@ -11,4 +10,21 @@ DIRS=`ls -l |sed -n 's/^d.* //p' |egrep -v "^($BUGGERED)$"`
|
|||
|
||||
<$PLAN9/src/mkdirs
|
||||
|
||||
dir-install: $PLAN9/bin/yacc
|
||||
dir-all dir-install: $PLAN9/bin/9yacc
|
||||
|
||||
XLIB=draw bio 9
|
||||
$O.clock: clock.$O ${XLIB:%=$PLAN9/lib/lib%.a}
|
||||
$LD -o $target $prereq -L$X11/lib -lX11
|
||||
|
||||
$O.tweak: tweak.$O ${XLIB:%=$PLAN9/lib/lib%.a}
|
||||
$LD -o $target $prereq -L$X11/lib -lX11
|
||||
|
||||
%.tab.h %.tab.c: %.y
|
||||
$YACC $YFLAGS -s $stem $prereq
|
||||
|
||||
%.o: %.tab.c
|
||||
9c -o $target $stem.tab.c
|
||||
|
||||
CLEANFILES=$CLEANFILES bc.tab.[ch] units.tab.[ch]
|
||||
|
||||
|
||||
|
|
|
|||
33
src/cmd/mtime.c
Normal file
33
src/cmd/mtime.c
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: mtime file...\n");
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int errors, i;
|
||||
Dir *d;
|
||||
|
||||
ARGBEGIN{
|
||||
default:
|
||||
usage();
|
||||
}ARGEND
|
||||
|
||||
errors = 0;
|
||||
for(i=0; i<argc; i++){
|
||||
if((d = dirstat(argv[i])) == nil){
|
||||
fprint(2, "stat %s: %r\n", argv[i]);
|
||||
errors = 1;
|
||||
}else{
|
||||
print("%11lud %s\n", d->mtime, argv[i]);
|
||||
free(d);
|
||||
}
|
||||
}
|
||||
exits(errors ? "errors" : nil);
|
||||
}
|
||||
231
src/cmd/news.c
Normal file
231
src/cmd/news.c
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
/*
|
||||
* news foo prints /lib/news/foo
|
||||
* news -a prints all news items, latest first
|
||||
* news -n lists names of new items
|
||||
* news prints items changed since last news
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
|
||||
#define NINC 50 /* Multiples of directory allocation */
|
||||
char *NEWS = "#9/news";
|
||||
char TFILE[] = "%s/lib/newstime";
|
||||
|
||||
/*
|
||||
* The following items should not be printed.
|
||||
*/
|
||||
char* ignore[] =
|
||||
{
|
||||
"core",
|
||||
"dead.letter",
|
||||
0
|
||||
};
|
||||
|
||||
typedef
|
||||
struct
|
||||
{
|
||||
long time;
|
||||
char *name;
|
||||
vlong length;
|
||||
} File;
|
||||
File* n_list;
|
||||
int n_count;
|
||||
int n_items;
|
||||
Biobuf bout;
|
||||
|
||||
int fcmp(const void *a, const void *b);
|
||||
void read_dir(int update);
|
||||
void print_item(char *f);
|
||||
void eachitem(void (*emit)(char*), int all, int update);
|
||||
void note(char *s);
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
NEWS = unsharp(NEWS);
|
||||
|
||||
Binit(&bout, 1, OWRITE);
|
||||
if(argc == 1) {
|
||||
eachitem(print_item, 0, 1);
|
||||
exits(0);
|
||||
}
|
||||
ARGBEGIN{
|
||||
case 'a': /* print all */
|
||||
eachitem(print_item, 1, 0);
|
||||
break;
|
||||
|
||||
case 'n': /* names only */
|
||||
eachitem(note, 0, 0);
|
||||
if(n_items)
|
||||
Bputc(&bout, '\n');
|
||||
break;
|
||||
|
||||
default:
|
||||
fprint(2, "news: bad option %c\n", ARGC());
|
||||
exits("usage");
|
||||
}ARGEND
|
||||
for(i=0; i<argc; i++)
|
||||
print_item(argv[i]);
|
||||
exits(0);
|
||||
}
|
||||
|
||||
int
|
||||
fcmp(const void *a, const void *b)
|
||||
{
|
||||
long x;
|
||||
|
||||
x = ((File*)b)->time - ((File*)a)->time;
|
||||
if(x < 0)
|
||||
return -1;
|
||||
if(x > 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* read_dir: get the file names and modification dates for the
|
||||
* files in /usr/news into n_list; sort them in reverse by
|
||||
* modification date.
|
||||
*/
|
||||
void
|
||||
read_dir(int update)
|
||||
{
|
||||
Dir *d;
|
||||
char newstime[100], *home;
|
||||
int i, j, n, na, fd;
|
||||
|
||||
n_count = 0;
|
||||
n_list = malloc(NINC*sizeof(File));
|
||||
na = NINC;
|
||||
home = getenv("home");
|
||||
if(home) {
|
||||
sprint(newstime, TFILE, home);
|
||||
d = dirstat(newstime);
|
||||
if(d != nil) {
|
||||
n_list[n_count].name = strdup("");
|
||||
n_list[n_count].time =d->mtime-1;
|
||||
n_list[n_count].length = 0;
|
||||
n_count++;
|
||||
free(d);
|
||||
}
|
||||
if(update) {
|
||||
fd = create(newstime, OWRITE, 0644);
|
||||
if(fd >= 0)
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
fd = open(NEWS, OREAD);
|
||||
if(fd < 0) {
|
||||
fprint(2, "news: ");
|
||||
perror(NEWS);
|
||||
exits(NEWS);
|
||||
}
|
||||
|
||||
n = dirreadall(fd, &d);
|
||||
for(i=0; i<n; i++) {
|
||||
for(j=0; ignore[j]; j++)
|
||||
if(strcmp(ignore[j], d[i].name) == 0)
|
||||
goto ign;
|
||||
if(na <= n_count) {
|
||||
na += NINC;
|
||||
n_list = realloc(n_list, na*sizeof(File));
|
||||
}
|
||||
n_list[n_count].name = strdup(d[i].name);
|
||||
n_list[n_count].time = d[i].mtime;
|
||||
n_list[n_count].length = d[i].length;
|
||||
n_count++;
|
||||
ign:;
|
||||
}
|
||||
free(d);
|
||||
|
||||
close(fd);
|
||||
qsort(n_list, n_count, sizeof(File), fcmp);
|
||||
}
|
||||
|
||||
void
|
||||
print_item(char *file)
|
||||
{
|
||||
char name[4096], *p, *ep;
|
||||
Dir *dbuf;
|
||||
int f, c;
|
||||
int bol, bop;
|
||||
|
||||
sprint(name, "%s/%s", NEWS, file);
|
||||
f = open(name, OREAD);
|
||||
if(f < 0) {
|
||||
fprint(2, "news: ");
|
||||
perror(name);
|
||||
return;
|
||||
}
|
||||
strcpy(name, "...");
|
||||
dbuf = dirfstat(f);
|
||||
if(dbuf == nil)
|
||||
return;
|
||||
Bprint(&bout, "\n%s (%s) %s\n", file,
|
||||
dbuf->muid[0]? dbuf->muid : dbuf->uid,
|
||||
asctime(localtime(dbuf->mtime)));
|
||||
free(dbuf);
|
||||
|
||||
bol = 1; /* beginning of line ...\n */
|
||||
bop = 1; /* beginning of page ...\n\n */
|
||||
for(;;) {
|
||||
c = read(f, name, sizeof(name));
|
||||
if(c <= 0)
|
||||
break;
|
||||
p = name;
|
||||
ep = p+c;
|
||||
while(p < ep) {
|
||||
c = *p++;
|
||||
if(c == '\n') {
|
||||
if(!bop) {
|
||||
Bputc(&bout, c);
|
||||
if(bol)
|
||||
bop = 1;
|
||||
bol = 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(bol) {
|
||||
Bputc(&bout, '\t');
|
||||
bol = 0;
|
||||
bop = 0;
|
||||
}
|
||||
Bputc(&bout, c);
|
||||
}
|
||||
}
|
||||
if(!bol)
|
||||
Bputc(&bout, '\n');
|
||||
close(f);
|
||||
}
|
||||
|
||||
void
|
||||
eachitem(void (*emit)(char*), int all, int update)
|
||||
{
|
||||
int i;
|
||||
|
||||
read_dir(update);
|
||||
for(i=0; i<n_count; i++) {
|
||||
if(n_list[i].name[0] == 0) { /* newstime */
|
||||
if(all)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if(n_list[i].length == 0) /* in progress */
|
||||
continue;
|
||||
(*emit)(n_list[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
note(char *file)
|
||||
{
|
||||
|
||||
if(!n_items)
|
||||
Bprint(&bout, "news:");
|
||||
Bprint(&bout, " %s", file);
|
||||
n_items++;
|
||||
}
|
||||
131
src/cmd/primes.c
Normal file
131
src/cmd/primes.c
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
#define ptsiz (sizeof(pt)/sizeof(pt[0]))
|
||||
#define whsiz (sizeof(wheel)/sizeof(wheel[0]))
|
||||
#define tabsiz (sizeof(table)/sizeof(table[0]))
|
||||
#define tsiz8 (tabsiz*8)
|
||||
|
||||
double big = 9.007199254740992e15;
|
||||
|
||||
int pt[] =
|
||||
{
|
||||
2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
|
||||
31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
|
||||
73, 79, 83, 89, 97,101,103,107,109,113,
|
||||
127,131,137,139,149,151,157,163,167,173,
|
||||
179,181,191,193,197,199,211,223,227,229,
|
||||
};
|
||||
double wheel[] =
|
||||
{
|
||||
10, 2, 4, 2, 4, 6, 2, 6, 4, 2,
|
||||
4, 6, 6, 2, 6, 4, 2, 6, 4, 6,
|
||||
8, 4, 2, 4, 2, 4, 8, 6, 4, 6,
|
||||
2, 4, 6, 2, 6, 6, 4, 2, 4, 6,
|
||||
2, 6, 4, 2, 4, 2,10, 2,
|
||||
};
|
||||
uchar table[1000];
|
||||
uchar bittab[] =
|
||||
{
|
||||
1, 2, 4, 8, 16, 32, 64, 128,
|
||||
};
|
||||
|
||||
void mark(double nn, long k);
|
||||
void ouch(void);
|
||||
|
||||
void
|
||||
main(int argc, char *argp[])
|
||||
{
|
||||
int i;
|
||||
double k, temp, v, limit, nn;
|
||||
|
||||
if(argc <= 1) {
|
||||
fprint(2, "usage: primes starting [ending]\n");
|
||||
exits("usage");
|
||||
}
|
||||
nn = atof(argp[1]);
|
||||
limit = big;
|
||||
if(argc > 2) {
|
||||
limit = atof(argp[2]);
|
||||
if(limit < nn)
|
||||
exits(0);
|
||||
if(limit > big)
|
||||
ouch();
|
||||
}
|
||||
if(nn < 0 || nn > big)
|
||||
ouch();
|
||||
if(nn == 0)
|
||||
nn = 1;
|
||||
|
||||
if(nn < 230) {
|
||||
for(i=0; i<ptsiz; i++) {
|
||||
if(pt[i] < nn)
|
||||
continue;
|
||||
if(pt[i] > limit)
|
||||
exits(0);
|
||||
print("%d\n", pt[i]);
|
||||
if(limit >= big)
|
||||
exits(0);
|
||||
}
|
||||
nn = 230;
|
||||
}
|
||||
|
||||
modf(nn/2, &temp);
|
||||
nn = 2.*temp + 1;
|
||||
/*
|
||||
* clear the sieve table.
|
||||
*/
|
||||
for(;;) {
|
||||
for(i=0; i<tabsiz; i++)
|
||||
table[i] = 0;
|
||||
/*
|
||||
* run the sieve.
|
||||
*/
|
||||
v = sqrt(nn+tsiz8);
|
||||
mark(nn, 3);
|
||||
mark(nn, 5);
|
||||
mark(nn, 7);
|
||||
for(i=0,k=11; k<=v; k+=wheel[i]) {
|
||||
mark(nn, k);
|
||||
i++;
|
||||
if(i >= whsiz)
|
||||
i = 0;
|
||||
}
|
||||
/*
|
||||
* now get the primes from the table
|
||||
* and print them.
|
||||
*/
|
||||
for(i=0; i<tsiz8; i+=2) {
|
||||
if(table[i>>3] & bittab[i&07])
|
||||
continue;
|
||||
temp = nn + i;
|
||||
if(temp > limit)
|
||||
exits(0);
|
||||
print("%.0f\n", temp);
|
||||
if(limit >= big)
|
||||
exits(0);
|
||||
}
|
||||
nn += tsiz8;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mark(double nn, long k)
|
||||
{
|
||||
double t1;
|
||||
long j;
|
||||
|
||||
modf(nn/k, &t1);
|
||||
j = k*t1 - nn;
|
||||
if(j < 0)
|
||||
j += k;
|
||||
for(; j<tsiz8; j+=k)
|
||||
table[j>>3] |= bittab[j&07];
|
||||
}
|
||||
|
||||
void
|
||||
ouch(void)
|
||||
{
|
||||
fprint(2, "limits exceeded\n");
|
||||
exits("limits");
|
||||
}
|
||||
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