786 lines · 10.7 KB · Text
RawDownload
%{#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;	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; 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;	}%% intyylex(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 L'×':		return '*';	case L'÷':		return '/';	case L'¹':	case L'ⁱ':		yylval.numb = 1;		return SUP;	case L'²':	case L'⁲':		yylval.numb = 2;		return SUP;	case L'³':	case L'⁳':		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 = charstod(gdigit, 0);	return VAL;} voidmain(int argc, char *argv[]){	char *file; 	ARGBEGIN {	default:		print("usage: units [-v] [file]\n");		exits("usage");	case 'v':		vflag = 1;		break;	} ARGEND 	file = "/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 */intralpha(int c){	switch(c) {	case 0:	case '+':	case '-':	case '*':	case '/':	case '[':	case ']':	case '(':	case ')':	case '^':	case ':':	case '?':	case ' ':	case '\t':	case '.':	case '|':	case '#':	case L'¹':	case L'ⁱ':	case L'²':	case L'⁲':	case L'³':	case L'⁳':	case L'×':	case L'÷':		return 0;	}	return 1;} intgdigit(void*){	int c; 	c = digval;	if(c) {		digval = 0;		return c;	}	c = line[linep++];	peekrune = c;	return c;} voidyyerror(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");	}} voidadd(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);} voidsub(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);} voidmul(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);} voiddiv(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);} voidxpn(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);} intspecialcase(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];

Lines 1–500 of 786.