%{## 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);}; %}%module Units{ init: fn(nil: ref Draw->Context, args: list of string);} %type <node> prog expr expr0 expr1 expr2 expr3 expr4 %token <val> VAL%token <var> VAR%token <numb> SUP%%prog: ':' VAR expr { f := $2.node.dim[0]; $2.node = $3.copy(); $2.node.dim[0] = 1; if(f) yyerror(sys->sprint("redefinition of %s", $2.name)); else if(vflag) sys->print("%s\t%s\n", $2.name, $2.node.text()); }| ':' VAR '#' { for(i:=1; i<Ndim; i++) if(fund[i] == nil) break; if(i >= Ndim) { yyerror("too many dimensions"); i = Ndim-1; } fund[i] = $2; f := $2.node.dim[0]; $2.node = Node.mk(1.0); $2.node.dim[0] = 1; $2.node.dim[i] = 1; if(f) yyerror(sys->sprint("redefinition of %s", $2.name)); else if(vflag) sys->print("%s\t#\n", $2.name); }| '?' expr { retnode1 = $2.copy(); }| '?' { retnode1 = Node.mk(1.0); } expr: expr4| expr '+' expr4 { $$ = $1.add($3); }| expr '-' expr4 { $$ = $1.sub($3); } expr4: expr3| expr4 '*' expr3 { $$ = $1.mul($3); }| expr4 '/' expr3 { $$ = $1.div($3); } expr3: expr2| expr3 expr2 { $$ = $1.mul($2); } expr2: expr1| expr2 SUP { $$ = $1.xpn($2); }| expr2 '^' expr1 { for(i:=1; i<Ndim; i++) if($3.dim[i]) { yyerror("exponent has units"); $$ = $1; break; } if(i >= Ndim) { i = int $3.val; if(real i != $3.val) yyerror("exponent not integral"); $$ = $1.xpn(i); } } expr1: expr0| expr1 '|' expr0 { $$ = $1.div($3); } expr0: VAR { if($1.node.dim[0] == 0) { yyerror(sys->sprint("undefined %s", $1.name)); $$ = Node.mk(1.0); } else $$ = $1.node.copy(); }| VAL { $$ = Node.mk($1); }| '(' expr ')' { $$ = $2; }%% 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); }Lines 1–500 of 771. Load more
%{ # # 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 dimensions Nvar: con 203; # hash table size Maxe: 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); }; %} %module Units { init: fn(nil: ref Draw->Context, args: list of string); } %type <node> prog expr expr0 expr1 expr2 expr3 expr4 %token <val> VAL %token <var> VAR %token <numb> SUP %% prog: ':' VAR expr { f := $2.node.dim[0]; $2.node = $3.copy(); $2.node.dim[0] = 1; if(f) yyerror(sys->sprint("redefinition of %s", $2.name)); else if(vflag) sys->print("%s\t%s\n", $2.name, $2.node.text()); } | ':' VAR '#' { for(i:=1; i<Ndim; i++) if(fund[i] == nil) break; if(i >= Ndim) { yyerror("too many dimensions"); i = Ndim-1; } fund[i] = $2; f := $2.node.dim[0]; $2.node = Node.mk(1.0); $2.node.dim[0] = 1; $2.node.dim[i] = 1; if(f) yyerror(sys->sprint("redefinition of %s", $2.name)); else if(vflag) sys->print("%s\t#\n", $2.name); } | '?' expr { retnode1 = $2.copy(); } | '?' { retnode1 = Node.mk(1.0); } expr: expr4 | expr '+' expr4 { $$ = $1.add($3); } | expr '-' expr4 { $$ = $1.sub($3); } expr4: expr3 | expr4 '*' expr3 { $$ = $1.mul($3); } | expr4 '/' expr3 { $$ = $1.div($3); } expr3: expr2 | expr3 expr2 { $$ = $1.mul($2); } expr2: expr1 | expr2 SUP { $$ = $1.xpn($2); } | expr2 '^' expr1 { for(i:=1; i<Ndim; i++) if($3.dim[i]) { yyerror("exponent has units"); $$ = $1; break; } if(i >= Ndim) { i = int $3.val; if(real i != $3.val) yyerror("exponent not integral"); $$ = $1.xpn(i); } } expr1: expr0 | expr1 '|' expr0 { $$ = $1.div($3); } expr0: VAR { if($1.node.dim[0] == 0) { yyerror(sys->sprint("undefined %s", $1.name)); $$ = Node.mk(1.0); } else $$ = $1.node.copy(); } | VAL { $$ = Node.mk($1); } | '(' expr ')' { $$ = $2; } %% 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); }