forsyth20121205-174063a80cc13 years agoHistory
1061 lines · 18.6 KB · Brainfuck
RawDownload
implement Units; #line	2	"units.y"## subject to the Lucent Public License 1.02#include "sys.m";	sys: Sys; include "draw.m"; include "bufio.m";	bufio: Bufio;	Iobuf: import bufio; include "math.m";	math: Math; include "arg.m"; Ndim: con 15;	# number of dimensionsNvar: con 203;	# hash table sizeMaxe: con 695.0;	# log of largest number Node: adt{	val:	real;	dim:	array of int;	# [Ndim] schar 	mk:	fn(v: real): Node;	text:	fn(n: self Node): string;	add:	fn(a: self Node, b: Node): Node;	sub:	fn(a: self Node, b: Node): Node;	mul:	fn(a: self Node, b: Node): Node;	div:	fn(a: self Node, b: Node): Node;	xpn:	fn(a: self Node, b: int): Node;	copy: fn(a: self Node): Node;};Var: adt{	name:	string;	node:	Node;};Prefix: adt{	val:	real;	pname:	string;}; digval := 0;fi: ref Iobuf;fund := array[Ndim] of ref Var;line: string;lineno := 0;linep := 0;nerrors := 0;peekrune := 0;retnode1: Node;retnode2: Node;retnode: Node;sym: string;vars := array[Nvar] of list of ref Var;vflag := 0; YYSTYPE: adt {	node:	Node;	var:	ref Var;	numb:	int;	val:	real;}; YYLEX: adt {	lval: YYSTYPE;	lex: fn(l: self ref YYLEX): int;	error: fn(l: self ref YYLEX, msg: string);};  Units: module { 	init:	fn(nil: ref Draw->Context, args: list of string);VAL: con	57346;VAR: con	57347;SUP: con	57348; };YYEOFCODE: con 1;YYERRCODE: con 2;YYMAXDEPTH: con 200; #line	203	"units.y"  init(nil: ref Draw->Context, args: list of string){	sys = load Sys Sys->PATH;	bufio = load Bufio Bufio->PATH;	math = load Math Math->PATH; 	arg := load Arg Arg->PATH;	arg->init(args);	arg->setusage("units [-v] [file]");	while((o := arg->opt()) != 0)		case o {		'v' => vflag = 1;		* => arg->usage();	}	args = arg->argv();	arg = nil; 	file := "/lib/units";	if(args != nil)		file = hd args;	fi = bufio->open(file, Sys->OREAD);	if(fi == nil) {		sys->fprint(sys->fildes(2), "units: cannot open %s: %r\n", file);		raise "fail:open";	}	lex := ref YYLEX; 	#	# read the 'units' file to	# develop a database	#	lineno = 0;	for(;;) {		lineno++;		if(readline())			break;		if(len line == 0 || line[0] == '/')			continue;		peekrune = ':';		yyparse(lex);	} 	#	# read the console to	# print ratio of pairs	#	fi = bufio->fopen(sys->fildes(0), Sys->OREAD);	lineno = 0;	for(;;) {		if(lineno & 1)			sys->print("you want: ");		else			sys->print("you have: ");		if(readline())			break;		peekrune = '?';		nerrors = 0;		yyparse(lex);		if(nerrors)			continue;		if(lineno & 1) {			isspcl: int;			(isspcl, retnode) = specialcase(retnode2, retnode1);			if(isspcl)				sys->print("\tis %s\n", retnode.text());			else {				retnode = retnode2.div(retnode1);				sys->print("\t* %s\n", retnode.text());				retnode = retnode1.div(retnode2);				sys->print("\t/ %s\n", retnode.text());			}		} else			retnode2 = retnode1.copy();		lineno++;	}	sys->print("\n");} YYLEX.lex(lex: self ref YYLEX): int{	c := peekrune;	peekrune = ' '; 	while(c == ' ' || c == '\t'){		if(linep >= len line)			return 0;	# -1?		c = line[linep++];	}	case c {	'0' to '9' or '.' =>		digval = c;		(lex.lval.val, peekrune) = readreal(gdigit, lex);		return VAL;	'×' =>		return '*';	'÷' =>		return '/';	'¹' or	'ⁱ' =>		lex.lval.numb = 1;		return SUP;	'²' or	'⁲' =>		lex.lval.numb = 2;		return SUP;	'³' or	'⁳' =>		lex.lval.numb = 3;		return SUP;	* =>		if(ralpha(c)){			sym = "";			for(i:=0;; i++) {				sym[i] = c;				if(linep >= len line){					c = ' ';					break;				}				c = line[linep++];				if(!ralpha(c))					break;			}			peekrune = c;			lex.lval.var = lookup(0);			return VAR;		}	}	return c;} ## all characters that have some# meaning. rest are usable as names#ralpha(c: int): int{	case c {	0 or	'+'  or	'-'  or	'*'  or	'/'  or	'['  or	']'  or	'('  or	')'  or	'^'  or	':'  or	'?'  or	' '  or	'\t'  or	'.'  or	'|'  or	'#'  or	'¹'  or	'ⁱ'  or	'²'  or	'⁲'  or	'³'  or	'⁳'  or	'×'  or	'÷'  =>		return 0;	}	return 1;} gdigit(nil: ref YYLEX): int{	c := digval;	if(c) {		digval = 0;		return c;	}	if(linep >= len line)		return 0;	return line[linep++];} YYLEX.error(lex: self ref YYLEX, s: string){	#	# hack to intercept message from yaccpar	#	if(s == "syntax error") {		lex.error(sys->sprint("syntax error, last name: %s", sym));		return;	}	sys->print("%d: %s\n\t%s\n", lineno, line, s);	nerrors++;	if(nerrors > 5) {		sys->print("too many errors\n");		raise "fail:errors";	}} yyerror(s: string){	l := ref YYLEX;	l.error(s);} Node.mk(v: real): Node{	return (v, array[Ndim] of {* => 0});} Node.add(a: self Node, b: Node): Node{	c := Node.mk(fadd(a.val, b.val));	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");	}	return c;} Node.sub(a: self Node, b: Node): Node{	c := Node.mk(fadd(a.val, -b.val));	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");	}	return c;} Node.mul(a: self Node, b: Node): Node{	c := Node.mk(fmul(a.val, b.val));	for(i:=0; i<Ndim; i++)		c.dim[i] = a.dim[i] + b.dim[i];	return c;} Node.div(a: self Node, b: Node): Node{	c := Node.mk(fdiv(a.val, b.val));	for(i:=0; i<Ndim; i++)		c.dim[i] = a.dim[i] - b.dim[i];	return c;} Node.xpn(a: self Node, b: int): Node{	c := Node.mk(1.0);	if(b < 0) {		b = -b;		for(i:=0; i<b; i++)			c = c.div(a);	} else		for(i:=0; i<b; i++)			c = c.mul(a);	return c;} Node.copy(a: self Node): Node{	c := Node.mk(a.val);	c.dim[0:] = a.dim;	return c;} specialcase(a, b: Node): (int, Node){	c := Node.mk(0.0);	d1 := 0;	d2 := 0;	for(i:=1; i<Ndim; i++) {		d := a.dim[i];		if(d) {			if(d != 1 || d1)				return (0, c);			d1 = i;		}		d = b.dim[i];		if(d) {			if(d != 1 || d2)				return (0, c);			d2 = i;		}	}	if(d1 == 0 || d2 == 0)		return (0, c); 	if(fund[d1].name == "°C" &&	   fund[d2].name == "°F" &&	   b.val == 1.0) {		c = b.copy();		c.val = a.val * 9. / 5. + 32.;		return (1, c);	} 	if(fund[d1].name == "°F" &&	   fund[d2].name == "°C" &&	   b.val == 1.0) {		c = b.copy();		c.val = (a.val - 32.) * 5. / 9.;		return (1, c);	}	return (0, c);} printdim(d: int, n: int): string{	s := "";	if(n) {		v := fund[d];		if(v != nil)			s += " "+v.name;		else			s += sys->sprint(" [%d]", d);		case n {		1 =>			;		2 =>			s += "²";		3 =>			s += "³";		4 =>			s += "⁴";		* =>			s += sys->sprint("^%d", n);		}	}	return s;} Node.text(n: self Node): string{	str := sys->sprint("%.7g", n.val);	f := 0;	for(i:=1; i<len n.dim; i++) {		d := n.dim[i];		if(d > 0)			str += printdim(i, d);		else if(d < 0)			f = 1;	} 	if(f) {		str += " /";		for(i=1; i<len n.dim; i++) {			d := n.dim[i];			if(d < 0)				str += printdim(i, -d);		}	} 	return str;} readline(): int{	linep = 0;	line = "";	for(i:=0;; i++) {		c := fi.getc();		if(c < 0)			return 1;		if(c == '\n')			return 0;		line[i] = c;	}} lookup(f: int): ref Var{	h := 0;	for(i:=0; i < len sym; i++)		h = h*13 + sym[i];	if(h < 0)		h ^= int 16r80000000;	h %= len vars; 	for(vl:=vars[h]; vl != nil; vl = tl vl)		if((hd vl).name == sym)			return hd vl;	if(f)		return nil;	v := ref Var(sym, Node.mk(0.0));	vars[h] = v :: vars[h]; 	p := 1.0;	for(;;) {		p = fmul(p, pname());		if(p == 0.0)			break;		w := lookup(1);		if(w != nil) {			v.node = w.node.copy();			v.node.val = fmul(v.node.val, p);			break;		}	}	return v;} prefix: array of Prefix = array[] of {	(1e-24,	"yocto"),	(1e-21,	"zepto"),	(1e-18,	"atto"),	(1e-15,	"femto"),	(1e-12,	"pico"),

Lines 1–500 of 1061.