summaryrefslogtreecommitdiff
path: root/appl/cmd/mc.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/cmd/mc.b')
-rw-r--r--appl/cmd/mc.b2618
1 files changed, 108 insertions, 2510 deletions
diff --git a/appl/cmd/mc.b b/appl/cmd/mc.b
index 265d548e..631c4cc1 100644
--- a/appl/cmd/mc.b
+++ b/appl/cmd/mc.b
@@ -1,2547 +1,145 @@
-implement Calculator;
+implement Mc;
include "sys.m";
sys: Sys;
+ open, read, fprint, fildes, tokenize,
+ ORDWR, OREAD, OWRITE: import sys;
include "draw.m";
-include "arg.m";
- arg: Arg;
+ draw: Draw;
+ Font: import draw;
include "bufio.m";
bufio: Bufio;
Iobuf: import bufio;
-include "math.m";
- maths: Math;
-include "rand.m";
- rand: Rand;
-include "daytime.m";
- daytime: Daytime;
+include "env.m";
+ env: Env;
+include "arg.m";
-Calculator: module
-{
+font: ref Font;
+columns := 65;
+tabwid := 0;
+mintab := 1;
+
+Mc: module{
init: fn(nil: ref Draw->Context, argv: list of string);
};
-init(nil: ref Draw->Context, args: list of string)
+init(ctxt: ref Draw->Context, argv: list of string)
{
sys = load Sys Sys->PATH;
- arg = load Arg Arg->PATH;
- bufio = load Bufio Bufio->PATH;
- maths = load Math Math->PATH;
- rand = load Rand Rand->PATH;
- daytime = load Daytime Daytime->PATH;
-
- maths->FPcontrol(0, Math->INVAL|Math->ZDIV|Math->OVFL|Math->UNFL|Math->INEX);
-
- rand->init(daytime->now());
- rand->init(rand->rand(Big)^rand->rand(Big));
- daytime = nil;
-
- arg->init(args);
- while((c := arg->opt()) != 0){
- case(c){
- 'b' =>
- bits = 1;
- 'd' =>
- debug = 1;
- 's' =>
- strict = 1;
- }
- }
- gargs = args = arg->argv();
- if(args == nil){
- stdin = 1;
- bin = bufio->fopen(sys->fildes(0), Sys->OREAD);
- }
- else if(tl args == nil)
- bin = bufio->open(hd args, Sys->OREAD);
-
- syms = array[Hash] of ref Sym;
-
- pushscope();
- for(i := 0; keyw[i].t0 != nil; i++)
- enter(keyw[i].t0, keyw[i].t1);
- for(i = 0; conw[i].t0 != nil; i++)
- adddec(conw[i].t0, Ocon, conw[i].t1, 0);
- for(i = 0; varw[i].t0 != nil; i++)
- adddec(varw[i].t0, Ovar, varw[i].t1, 0);
- for(i = 0; funw[i].t0 != nil; i++)
- adddec(funw[i].t0, Olfun, real funw[i].t1, funw[i].t2);
-
- deg = lookup(Deg).dec;
- pbase = lookup(Base).dec;
- errdec = ref Dec;
-
- pushscope();
- for(;;){
- e: ref Node;
-
- {
- t := lex();
- if(t == Oeof)
- break;
- unlex(t);
- ls := lexes;
- e = stat(1);
- ckstat(e, Onothing, 0);
- if(ls == lexes){
- t = lex();
- error(nil, sys->sprint("syntax error near %s", opstring(t)));
- unlex(t);
- }
- consume(Onl);
- }
- exception ex{
- Eeof =>
- e = nil;
- err("premature eof");
- skip();
- "*" =>
- e = nil;
- err(ex);
- skip();
- }
- if(0 && debug)
- prtree(e, 0);
- if(e != nil && e.op != Ofn){
- (k, v) := (Onothing, 0.0);
- {
- (k, v) = estat(e);
- }
- exception ex{
- "*" =>
- e = nil;
- err(ex);
- }
- if(pexp(e))
- printnum(v, "\n");
- if(k == Oexit)
- exit;
- }
- }
- popscope();
- popscope();
-}
-
-bits: int;
-debug: int;
-strict: int;
-
-None: con -2;
-Eof: con -1;
-Eeof: con "eof";
-
-Hash: con 16;
-Big: con 1<<30;
-Maxint: con 16r7FFFFFFF;
-Nan: con Math->NaN;
-Infinity: con Math->Infinity;
-Pi: con Math->Pi;
-Eps: con 1E-10;
-Bigeps: con 1E-2;
-Ln2: con 0.6931471805599453;
-Ln10: con 2.302585092994046;
-Euler: con 2.71828182845904523536;
-Gamma: con 0.57721566490153286060;
-Phi: con 1.61803398874989484820;
-
-Oeof,
-Ostring, Onum, Oident, Ocon, Ovar, Ofun, Olfun,
-Oadd, Osub, Omul, Odiv, Omod, Oidiv, Oexp, Oand, Oor, Oxor, Olsh, Orsh,
-Oadde, Osube, Omule, Odive, Omode, Oidive, Oexpe, Oande, Oore, Oxore, Olshe, Orshe,
-Oeq, One, Ogt, Olt, Oge, Ole,
-Oinc, Opreinc, Opostinc, Odec, Opredec, Opostdec,
-Oandand, Ooror,
-Oexc, Onot, Ofact, Ocom,
-Oas, Odas,
-Oplus, Ominus, Oinv,
-Ocomma, Oscomma, Oquest, Ocolon,
-Onand, Onor, Oimp, Oimpby, Oiff,
-Olbr, Orbr, Olcbr, Orcbr, Oscolon, Onl,
-Onothing,
-Oprint, Oread,
-Oif, Oelse, Ofor, Owhile, Odo, Obreak, Ocont, Oexit, Oret, Ofn, Oinclude,
-Osigma, Opi, Ocfrac, Oderiv, Ointeg, Osolve,
-Olog, Olog10, Olog2, Ologb, Oexpf, Opow, Osqrt, Ocbrt, Ofloor, Oceil, Omin, Omax, Oabs, Ogamma, Osign, Oint, Ofrac, Oround, Oerf, Oatan2, Osin, Ocos, Otan, Oasin, Oacos, Oatan, Osinh, Ocosh, Otanh, Oasinh, Oacosh, Oatanh, Orand,
-Olast: con iota;
-
-Binary: con (1<<8);
-Preunary: con (1<<9);
-Postunary: con (1<<10);
-Assoc: con (1<<11);
-Rassoc: con (1<<12);
-Prec: con Binary-1;
-
-opss := array[Olast] of
-{
- "eof",
- "string",
- "number",
- "identifier",
- "constant",
- "variable",
- "function",
- "library function",
- "+",
- "-",
- "*",
- "/",
- "%",
- "//",
- "&",
- "|",
- "^",
- "<<",
- ">>",
- "+=",
- "-=",
- "*=",
- "/=",
- "%=",
- "//=",
- "&=",
- "|=",
- "^=",
- "<<=",
- ">>=",
- "==",
- "!=",
- ">",
- "<",
- ">=",
- "<=",
- "++",
- "++",
- "++",
- "--",
- "--",
- "--",
- "**",
- "&&",
- "||",
- "!",
- "!",
- "!",
- "~",
- "=",
- ":=",
- "+",
- "-",
- "1/",
- ",",
- ",",
- "?",
- ":",
- "↑",
- "↓",
- "->",
- "<-",
- "<->",
- "(",
- ")",
- "{",
- "}",
- ";",
- "\n",
- "",
-};
-
-ops := array[Olast] of
-{
- Oeof => 0,
- Ostring => 17,
- Onum => 17,
- Oident => 17,
- Ocon => 17,
- Ovar => 17,
- Ofun => 17,
- Olfun => 17,
- Oadd => 12|Binary|Assoc|Preunary,
- Osub => 12|Binary|Preunary,
- Omul => 13|Binary|Assoc,
- Odiv => 13|Binary,
- Omod => 13|Binary,
- Oidiv => 13|Binary,
- Oexp => 14|Binary|Rassoc,
- Oand => 8|Binary|Assoc,
- Oor => 6|Binary|Assoc,
- Oxor => 7|Binary|Assoc,
- Olsh => 11|Binary,
- Orsh => 11|Binary,
- Oadde => 2|Binary|Rassoc,
- Osube => 2|Binary|Rassoc,
- Omule => 2|Binary|Rassoc,
- Odive => 2|Binary|Rassoc,
- Omode => 2|Binary|Rassoc,
- Oidive => 2|Binary|Rassoc,
- Oexpe => 2|Binary|Rassoc,
- Oande => 2|Binary|Rassoc,
- Oore => 2|Binary|Rassoc,
- Oxore => 2|Binary|Rassoc,
- Olshe => 2|Binary|Rassoc,
- Orshe => 2|Binary|Rassoc,
- Oeq => 9|Binary,
- One => 9|Binary,
- Ogt => 10|Binary,
- Olt => 10|Binary,
- Oge => 10|Binary,
- Ole => 10|Binary,
- Oinc => 15|Rassoc|Preunary|Postunary,
- Opreinc => 15|Rassoc|Preunary,
- Opostinc => 15|Rassoc|Postunary,
- Odec => 15|Rassoc|Preunary|Postunary,
- Opredec => 15|Rassoc|Preunary,
- Opostdec => 15|Rassoc|Postunary,
- Oandand => 5|Binary|Assoc,
- Ooror => 4|Binary|Assoc,
- Oexc => 15|Rassoc|Preunary|Postunary,
- Onot => 15|Rassoc|Preunary,
- Ofact => 15|Rassoc|Postunary,
- Ocom => 15|Rassoc|Preunary,
- Oas => 2|Binary|Rassoc,
- Odas => 2|Binary|Rassoc,
- Oplus => 15|Rassoc|Preunary,
- Ominus => 15|Rassoc|Preunary,
- Oinv => 15|Rassoc|Postunary,
- Ocomma => 1|Binary|Assoc,
- Oscomma => 1|Binary|Assoc,
- Oquest => 3|Binary|Rassoc,
- Ocolon => 3|Binary|Rassoc,
- Onand => 8|Binary,
- Onor => 6|Binary,
- Oimp => 9|Binary,
- Oimpby => 9|Binary,
- Oiff => 10|Binary|Assoc,
- Olbr => 16,
- Orbr => 16,
- Onothing => 0,
-};
-
-Deg: con "degrees";
-Base: con "printbase";
-Limit: con "solvelimit";
-Step: con "solvestep";
-
-keyw := array[] of
-{
- ("include", Oinclude),
- ("if", Oif),
- ("else", Oelse),
- ("for", Ofor),
- ("while", Owhile),
- ("do", Odo),
- ("break", Obreak),
- ("continue", Ocont),
- ("exit", Oexit),
- ("return", Oret),
- ("print", Oprint),
- ("read", Oread),
- ("fn", Ofn),
- ("", 0),
-};
-
-conw := array[] of
-{
- ("π", Pi),
- ("Pi", Pi),
- ("e", Euler),
- ("γ", Gamma),
- ("Gamma", Gamma),
- ("φ", Phi),
- ("Phi", Phi),
- ("∞", Infinity),
- ("Infinity", Infinity),
- ("NaN", Nan),
- ("Nan", Nan),
- ("nan", Nan),
- ("", 0.0),
-};
-
-varw := array[] of
-{
- (Deg, 0.0),
- (Base, 10.0),
- (Limit, 100.0),
- (Step, 1.0),
- ("", 0.0),
-};
-
-funw := array[] of
-{
- ("log", Olog, 1),
- ("ln", Olog, 1),
- ("log10", Olog10, 1),
- ("log2", Olog2, 1),
- ("logb", Ologb, 2),
- ("exp", Oexpf, 1),
- ("pow", Opow, 2),
- ("sqrt", Osqrt, 1),
- ("cbrt", Ocbrt, 1),
- ("floor", Ofloor, 1),
- ("ceiling", Oceil, 1),
- ("min", Omin, 2),
- ("max", Omax, 2),
- ("abs", Oabs, 1),
- ("Γ", Ogamma, 1),
- ("gamma", Ogamma, 1),
- ("sign", Osign, 1),
- ("int", Oint, 1),
- ("frac", Ofrac, 1),
- ("round", Oround, 1),
- ("erf", Oerf, 1),
- ("atan2", Oatan2, 2),
- ("sin", Osin, 1),
- ("cos", Ocos, 1),
- ("tan", Otan, 1),
- ("asin", Oasin, 1),
- ("acos", Oacos, 1),
- ("atan", Oatan, 1),
- ("sinh", Osinh, 1),
- ("cosh", Ocosh, 1),
- ("tanh", Otanh, 1),
- ("asinh", Oasinh, 1),
- ("acosh", Oacosh, 1),
- ("atanh", Oatanh, 1),
- ("rand", Orand, 0),
- ("Σ", Osigma, 3),
- ("sigma", Osigma, 3),
- ("Π", Opi, 3),
- ("pi", Opi, 3),
- ("cfrac", Ocfrac, 3),
- ("Δ", Oderiv, 2),
- ("differential", Oderiv, 2),
- ("∫", Ointeg, 3),
- ("integral", Ointeg, 3),
- ("solve", Osolve, 1),
- ("", 0, 0),
-};
-
-stdin: int;
-bin: ref Iobuf;
-lineno: int = 1;
-file: string;
-iostack: list of (int, int, int, string, ref Iobuf);
-geof: int;
-garg: string;
-gargs: list of string;
-bufc: int = None;
-buft: int = Olast;
-lexes: int;
-lexval: real;
-lexstr: string;
-lexsym: ref Sym;
-syms: array of ref Sym;
-deg: ref Dec;
-pbase: ref Dec;
-errdec: ref Dec;
-inloop: int;
-infn: int;
-
-Node: adt
-{
- op: int;
- left: cyclic ref Node;
- right: cyclic ref Node;
- val: real;
- str: string;
- dec: cyclic ref Dec;
- src: int;
-};
-
-Dec: adt
-{
- kind: int;
- scope: int;
- sym: cyclic ref Sym;
- val: real;
- na: int;
- code: cyclic ref Node;
- old: cyclic ref Dec;
- next: cyclic ref Dec;
-};
-
-Sym: adt
-{
- name: string;
- kind: int;
- dec: cyclic ref Dec;
- next: cyclic ref Sym;
-};
-
-opstring(t: int): string
-{
- s := opss[t];
- if(s != nil)
- return s;
- for(i := 0; keyw[i].t0 != nil; i++)
- if(t == keyw[i].t1)
- return keyw[i].t0;
- for(i = 0; funw[i].t0 != nil; i++)
- if(t == funw[i].t1)
- return funw[i].t0;
- return s;
-}
-
-err(s: string)
-{
- sys->print("error: %s\n", s);
-}
-
-error(n: ref Node, s: string)
-{
- if(n != nil)
- lno := n.src;
- else
- lno = lineno;
- s = sys->sprint("line %d: %s", lno, s);
- if(file != nil)
- s = sys->sprint("file %s: %s", file, s);
- raise s;
-}
-
-fatal(s: string)
-{
- sys->print("fatal: %s\n", s);
- exit;
-}
-
-stack(s: string, f: ref Iobuf)
-{
- iostack = (bufc, buft, lineno, file, bin) :: iostack;
- bufc = None;
- buft = Olast;
- lineno = 1;
- file = s;
- bin = f;
-}
-
-unstack()
-{
- (bufc, buft, lineno, file, bin) = hd iostack;
- iostack = tl iostack;
-}
-
-doinclude(s: string)
-{
- f := bufio->open(s, Sys->OREAD);
- if(f == nil)
- error(nil, sys->sprint("cannot open %s", s));
- stack(s, f);
-}
-
-getc(): int
-{
- if((c := bufc) != None)
- bufc = None;
- else if(bin != nil)
- c = bin.getc();
- else{
- if(garg == nil){
- if(gargs == nil){
- if(geof == 0){
- geof = 1;
- c = '\n';
- }
- else
- c = Eof;
- }
- else{
- garg = hd gargs;
- gargs = tl gargs;
- c = ' ';
- }
- }
- else{
- c = garg[0];
- garg = garg[1: ];
- }
- }
- if(c == Eof && iostack != nil){
- unstack();
- return getc();
- }
- return c;
-}
-
-ungetc(c: int)
-{
- bufc = c;
-}
-
-slash(c: int): int
-{
- if(c != '\\')
- return c;
- nc := getc();
- case(nc){
- 'b' => return '\b';
- 'f' => return '\f';
- 'n' => return '\n';
- 'r' => return '\r';
- 't' => return '\t';
- }
- return nc;
-}
-
-lexstring(): int
-{
- sp := "";
- while((c := getc()) != '"'){
- if(c == Eof)
- raise Eeof;
- sp[len sp] = slash(c);
- }
- lexstr = sp;
- return Ostring;
-}
-
-lexchar(): int
-{
- while((c := getc()) != '\''){
- if(c == Eof)
- raise Eeof;
- lexval = real slash(c);
- }
- return Onum;
-}
-
-basev(c: int, base: int): int
-{
- if(c >= 'a' && c <= 'z')
- c += 10-'a';
- else if(c >= 'A' && c <= 'Z')
- c += 10-'A';
- else if(c >= '0' && c <= '9')
- c -= '0';
- else
- return -1;
- if(c >= base)
- error(nil, "bad digit");
- return c;
-}
-
-lexe(base: int): int
-{
- neg := 0;
- v := big 0;
- c := getc();
- if(c == '-')
- neg = 1;
- else
- ungetc(c);
- for(;;){
- c = getc();
- cc := basev(c, base);
- if(cc < 0){
- ungetc(c);
- break;
- }
- v = big base*v+big cc;
- }
- if(neg)
- v = -v;
- return int v;
-}
-
-lexnum(): int
-{
- base := 10;
- exp := 0;
- r := f := e := 0;
- v := big 0;
- c := getc();
- if(c == '0'){
- base = 8;
- c = getc();
- if(c == '.'){
- base = 10;
- ungetc(c);
- }
- else if(c == 'x' || c == 'X')
- base = 16;
- else
- ungetc(c);
- }
- else
- ungetc(c);
- for(;;){
- c = getc();
- if(!r && (c == 'r' || c == 'R')){
- if(f || e)
- error(nil, "bad base");
- r = 1;
- base = int v;
- if(base < 2 || base > 36)
- error(nil, "bad base");
- v = big 0;
+ if((bufio = load Bufio Bufio->PATH) == nil)
+ fatal("can't load " + Bufio->PATH);
+ if((env = load Env Env->PATH) == nil)
+ fatal("can't load " + Env->PATH);
+ if((draw = load Draw Draw->PATH) == nil)
+ fatal("can't load " + Draw->PATH);
+ if((arg := load Arg Arg->PATH) == nil)
+ fatal("can't load " + Arg->PATH);
+
+ getwidth(ctxt);
+ arg->init(argv);
+ arg->setusage("mc [-c columns] [file ...]");
+ while((c:=arg->opt()) != 0)
+ case c {
+ 'c' => columns = int arg->earg() * mintab;
+ * => arg->usage();
+ }
+ argv = arg->argv();
+ if(len argv == 0)
+ argv = "/fd/0" :: nil;
+
+ a := array[1024] of (string, int);
+ n := 0;
+ maxwidth := 0;
+ for(; argv!=nil; argv=tl argv){
+ if((bin:=bufio->open(hd argv, OREAD)) == nil){
+ fprint(fildes(2), "mc: can't open %s: %r\n", hd argv);
continue;
}
- if(c == '.'){
- if(f || e)
- error(nil, "bad real");
- f = 1;
- continue;
- }
- if(base == 10 && (c == 'e' || c == 'E')){
- if(e)
- error(nil, "bad E part");
- e = 1;
- exp = lexe(base);
- continue;
- }
- cc := basev(c, base);
- if(cc < 0){
- ungetc(c);
- break;
- }
- v = big base*v+big cc;
- if(f)
- f++;
- }
- lexval = real v;
- if(f)
- lexval /= real base**(f-1);
- if(exp){
- if(exp > 0)
- lexval *= real base**exp;
- else
- lexval *= maths->pow(real base, real exp);
- }
- return Onum;
-}
-
-lexid(): int
-{
- sp := "";
- for(;;){
- c := getc();
- if(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c >= 'α' && c <= 'ω' || c >= 'Α' && c <= 'Ω' || c == '_')
- sp[len sp] = c;
- else{
- ungetc(c);
- break;
- }
- }
- lexsym = enter(sp, Oident);
- return lexsym.kind;
-}
-
-follow(c: int, c1: int, c2: int): int
-{
- nc := getc();
- if(nc == c)
- return c1;
- ungetc(nc);
- return c2;
-}
-
-skip()
-{
- if((t := buft) != Olast){
- lex();
- if(t == Onl)
- return;
- }
- for(;;){
- c := getc();
- if(c == Eof){
- ungetc(c);
- return;
- }
- if(c == '\n'){
- lineno++;
- return;
- }
- }
-}
-
-lex(): int
-{
- lexes++;
- if((t := buft) != Olast){
- buft = Olast;
- if(t == Onl)
- lineno++;
- return t;
- }
- for(;;){
- case(c := getc()){
- Eof =>
- return Oeof;
- '#' =>
- while((c = getc()) != '\n'){
- if(c == Eof)
- raise Eeof;
+ while((s:=bin.gets('\n')) != nil){
+ if(s[len s-1] == '\n')
+ s = s[0:len s-1];
+ if(n == len a)
+ a = (array[n+1024] of (string, int))[0:] = a;
+ a[n].t0 = s;
+ a[n].t1 = wordsize(s);
+ if(a[n].t1 > maxwidth)
+ maxwidth = a[n].t1;
+ n++;
+ }
+ bin.close();
+ }
+ outcols(a[:n], maxwidth);
+}
+
+outcols(words: array of (string, int), maxwidth: int)
+{
+ maxwidth = nexttab(maxwidth+mintab-1);
+ numcols := columns / maxwidth;
+ if(numcols <= 0)
+ numcols = 1;
+ nwords := len words;
+ nlines := (nwords+numcols-1) / numcols;
+ bout := bufio->fopen(fildes(1), OWRITE);
+ for(i := 0; i < nlines; i++){
+ col := endcol := 0;
+ for(j:=i; j<nwords; j+=nlines){
+ endcol += maxwidth;
+ bout.puts(words[j].t0);
+ col += words[j].t1;
+ if(j+nlines < nwords){
+ while(col < endcol){
+ if(tabwid)
+ bout.putc('\t');
+ else
+ bout.putc(' ');
+ col = nexttab(col);
+ }
}
- lineno++;
- '\n' =>
- lineno++;
- return Onl;
- ' ' or
- '\t' or
- '\r' or
- '\v' =>
- ;
- '"' =>
- return lexstring();
- '\'' =>
- return lexchar();
- '0' to '9' =>
- ungetc(c);
- return lexnum();
- 'a' to 'z' or
- 'A' to 'Z' or
- 'α' to 'ω' or
- 'Α' to 'Ω' or
- '_' =>
- ungetc(c);
- return lexid();
- '+' =>
- c = getc();
- if(c == '=')
- return Oadde;
- ungetc(c);
- return follow('+', Oinc, Oadd);
- '-' =>
- c = getc();
- if(c == '=')
- return Osube;
- if(c == '>')
- return Oimp;
- ungetc(c);
- return follow('-', Odec, Osub);
- '*' =>
- c = getc();
- if(c == '=')
- return Omule;
- if(c == '*')
- return follow('=', Oexpe, Oexp);
- ungetc(c);
- return Omul;
- '/' =>
- c = getc();
- if(c == '=')
- return Odive;
- if(c == '/')
- return follow('=', Oidive, Oidiv);
- ungetc(c);
- return Odiv;
- '%' =>
- return follow('=', Omode, Omod);
- '&' =>
- c = getc();
- if(c == '=')
- return Oande;
- ungetc(c);
- return follow('&', Oandand, Oand);
- '|' =>
- c = getc();
- if(c == '=')
- return Oore;
- ungetc(c);
- return follow('|', Ooror, Oor);
- '^' =>
- return follow('=', Oxore, Oxor);
- '=' =>
- return follow('=', Oeq, Oas);
- '!' =>
- return follow('=', One, Oexc);
- '>' =>
- c = getc();
- if(c == '=')
- return Oge;
- if(c == '>')
- return follow('=', Orshe, Orsh);
- ungetc(c);
- return Ogt;
- '<' =>
- c = getc();
- if(c == '=')
- return Ole;
- if(c == '<')
- return follow('=', Olshe, Olsh);
- if(c == '-')
- return follow('>', Oiff, Oimpby);
- ungetc(c);
- return Olt;
- '(' =>
- return Olbr;
- ')' =>
- return Orbr;
- '{' =>
- return Olcbr;
- '}' =>
- return Orcbr;
- '~' =>
- return Ocom;
- '.' =>
- ungetc(c);
- return lexnum();
- ',' =>
- return Ocomma;
- '?' =>
- return Oquest;
- ':' =>
- return follow('=', Odas, Ocolon);
- ';' =>
- return Oscolon;
- '↑' =>
- return Onand;
- '↓' =>
- return Onor;
- '∞' =>
- lexval = Infinity;
- return Onum;
- * =>
- error(nil, sys->sprint("bad character %c", c));
}
+ bout.putc('\n');
}
+ bout.close();
}
-unlex(t: int)
-{
- lexes--;
- buft = t;
- if(t == Onl)
- lineno--;
-}
-
-mustbe(t: int)
-{
- nt := lex();
- if(nt != t)
- error(nil, sys->sprint("expected %s not %s", opstring(t), opstring(nt)));
-}
-
-consume(t: int)
-{
- nt := lex();
- if(nt != t)
- unlex(nt);
-}
-
-elex(): int
-{
- t := lex();
- if(binary(t))
- return t;
- if(hexp(t)){
- unlex(t);
- return Oscomma;
- }
- return t;
-}
-
-hexp(o: int): int
-{
- return preunary(o) || o == Olbr || atom(o);
-}
-
-atom(o: int): int
-{
- return o >= Ostring && o <= Olfun;
-}
-
-asop(o: int): int
-{
- return o == Oas || o == Odas || o >= Oadde && o <= Orshe || o >= Oinc && o <= Opostdec;
-}
-
-preunary(o: int): int
-{
- return ops[o]&Preunary;
-}
-
-postunary(o: int): int
-{
- return ops[o]&Postunary;
-}
-
-binary(o: int): int
-{
- return ops[o]&Binary;
-}
-
-prec(o: int): int
-{
- return ops[o]&Prec;
-}
-
-assoc(o: int): int
-{
- return ops[o]&Assoc;
-}
-
-rassoc(o: int): int
-{
- return ops[o]&Rassoc;
-}
-
-preop(o: int): int
-{
- case(o){
- Oadd => return Oplus;
- Osub => return Ominus;
- Oinc => return Opreinc;
- Odec => return Opredec;
- Oexc => return Onot;
- }
- return o;
-}
-
-postop(o: int): int
-{
- case(o){
- Oinc => return Opostinc;
- Odec => return Opostdec;
- Oexc => return Ofact;
- }
- return o;
-}
-
-prtree(p: ref Node, in: int)
-{
- if(p == nil)
- return;
- for(i := 0; i < in; i++)
- sys->print(" ");
- sys->print("%s ", opstring(p.op));
- case(p.op){
- Ostring =>
- sys->print("%s", p.str);
- Onum =>
- sys->print("%g", p.val);
- Ocon or
- Ovar =>
- sys->print("%s(%g)", p.dec.sym.name, p.dec.val);
- Ofun or
- Olfun =>
- sys->print("%s", p.dec.sym.name);
- }
- sys->print("\n");
- # sys->print(" - %d\n", p.src);
- prtree(p.left, in+1);
- prtree(p.right, in+1);
-}
-
-tree(o: int, l: ref Node, r: ref Node): ref Node
-{
- p := ref Node;
- p.op = o;
- p.left = l;
- p.right = r;
- p.src = lineno;
- if(asop(o)){
- if(o >= Oadde && o <= Orshe){
- p = tree(Oas, l, p);
- p.right.op += Oadd-Oadde;
- }
- }
- return p;
-}
-
-itree(n: int): ref Node
-{
- return vtree(real n);
-}
-
-vtree(v: real): ref Node
-{
- n := tree(Onum, nil, nil);
- n.val = v;
- return n;
-}
-
-ltree(s: string, a: ref Node): ref Node
-{
- n := tree(Olfun, a, nil);
- n.dec = lookup(s).dec;
- return n;
-}
-
-ptree(n: ref Node, p: real): ref Node
-{
- if(isinteger(p)){
- i := int p;
- if(i == 0)
- return itree(1);
- if(i == 1)
- return n;
- if(i == -1)
- return tree(Oinv, n, nil);
- if(i < 0)
- return tree(Oinv, tree(Oexp, n, itree(-i)), nil);
- }
- return tree(Oexp, n, vtree(p));
-}
-
-iscon(n: ref Node): int
-{
- return n.op == Onum || n.op == Ocon;
-}
-
-iszero(n: ref Node): int
-{
- return iscon(n) && eval(n) == 0.0;
-}
-
-isone(n: ref Node): int
-{
- return iscon(n) && eval(n) == 1.0;
-}
-
-isnan(n: ref Node): int
-{
- return iscon(n) && maths->isnan(eval(n));
-}
-
-isinf(n: ref Node): int
-{
- return iscon(n) && (v := eval(n)) == Infinity || v == -Infinity;
-}
-
-stat(scope: int): ref Node
-{
- e1, e2, e3, e4: ref Node;
-
- consume(Onl);
- t := lex();
- case(t){
- Olcbr =>
- if(scope)
- pushscope();
- for(;;){
- e2 = stat(1);
- if(e1 == nil)
- e1 = e2;
- else
- e1 = tree(Ocomma, e1, e2);
- consume(Onl);
- t = lex();
- if(t == Oeof)
- raise Eeof;
- if(t == Orcbr)
- break;
- unlex(t);
- }
- if(scope)
- popscope();
- return e1;
- Oprint or
- Oread or
- Oret =>
- if(t == Oret && !infn)
- error(nil, "return not in fn");
- e1= tree(t, expr(0, 1), nil);
- consume(Oscolon);
- if(t == Oread)
- allvar(e1.left);
- return e1;
- Oif =>
- # mustbe(Olbr);
- e1 = expr(0, 1);
- # mustbe(Orbr);
- e2 = stat(1);
- e3 = nil;
- consume(Onl);
- t = lex();
- if(t == Oelse)
- e3 = stat(1);
- else
- unlex(t);
- return tree(Oif, e1, tree(Ocomma, e2, e3));
- Ofor =>
- inloop++;
- mustbe(Olbr);
- e1 = expr(0, 1);
- mustbe(Oscolon);
- e2 = expr(0, 1);
- mustbe(Oscolon);
- e3 = expr(0, 1);
- mustbe(Orbr);
- e4 = stat(1);
- inloop--;
- return tree(Ocomma, e1, tree(Ofor, e2, tree(Ocomma, e4, e3)));
- Owhile =>
- inloop++;
- # mustbe(Olbr);
- e1 = expr(0, 1);
- # mustbe(Orbr);
- e2 = stat(1);
- inloop--;
- return tree(Ofor, e1, tree(Ocomma, e2, nil));
- Odo =>
- inloop++;
- e1 = stat(1);
- consume(Onl);
- mustbe(Owhile);
- # mustbe(Olbr);
- e2 = expr(0, 1);
- # mustbe(Orbr);
- consume(Oscolon);
- inloop--;
- return tree(Odo, e1, e2);
- Obreak or
- Ocont or
- Oexit =>
- if((t == Obreak || t == Ocont) && !inloop)
- error(nil, "break/continue not in loop");
- consume(Oscolon);
- return tree(t, nil, nil);
- Ofn =>
- if(infn)
- error(nil, "nested functions not allowed");
- infn++;
- mustbe(Oident);
- s := lexsym;
- d := mkdec(s, Ofun, 1);
- d.code = tree(Ofn, nil, nil);
- pushscope();
- (d.na, d.code.left) = args(0);
- allvar(d.code.left);
- pushparams(d.code.left);
- d.code.right = stat(0);
- popscope();
- infn--;
- return d.code;
- Oinclude =>
- e1 = expr(0, 0);
- if(e1.op != Ostring)
- error(nil, "bad include file");
- consume(Oscolon);
- doinclude(e1.str);
- return nil;
- * =>
- unlex(t);
- e1 = expr(0, 1);
- consume(Oscolon);
- if(debug)
- prnode(e1);
- return e1;
- }
- return nil;
-}
-
-ckstat(n: ref Node, parop: int, pr: int)
-{
- if(n == nil)
- return;
- pr |= n.op == Oprint;
- ckstat(n.left, n.op, pr);
- ckstat(n.right, n.op, pr);
- case(n.op){
- Ostring =>
- if(!pr || parop != Oprint && parop != Ocomma)
- error(n, "illegal string operation");
- }
-}
-
-pexp(e: ref Node): int
-{
- if(e == nil)
- return 0;
- if(e.op == Ocomma)
- return pexp(e.right);
- return e.op >= Ostring && e.op <= Oiff && !asop(e.op);
-}
-
-expr(p: int, zok: int): ref Node
+wordsize(s: string): int
{
- n := exp(p, zok);
- ckexp(n, Onothing);
- return n;
+ if(font != nil)
+ return font.width(s);
+ return len s;
}
-exp(p: int, zok: int): ref Node
+nexttab(col: int): int
{
- l := prim(zok);
- if(l == nil)
- return nil;
- while(binary(t := elex()) && (o := prec(t)) >= p){
- if(rassoc(t))
- r := exp(o, 0);
- else
- r = exp(o+1, 0);
- if(t == Oscomma)
- t = Ocomma;
- l = tree(t, l, r);
- }
- if(t != Oscomma)
- unlex(t);
- return l;
-}
-
-prim(zok: int): ref Node
-{
- p: ref Node;
- na: int;
-
- t := lex();
- if(preunary(t)){
- t = preop(t);
- return tree(t, exp(prec(t), 0), nil);
- }
- case(t){
- Olbr =>
- p = exp(0, zok);
- mustbe(Orbr);
- Ostring =>
- p = tree(t, nil, nil);
- p.str = lexstr;
- Onum =>
- p = tree(t, nil ,nil);
- p.val = lexval;
- Oident =>
- s := lexsym;
- d := s.dec;
- if(d == nil)
- d = mkdec(s, Ovar, 0);
- case(t = d.kind){
- Ocon or
- Ovar =>
- p = tree(t, nil, nil);
- p.dec = d;
- Ofun or
- Olfun =>
- p = tree(t, nil, nil);
- p.dec = d;
- (na, p.left) = args(prec(t));
- if(!(t == Olfun && d.val == real Osolve && na == 2))
- if(na != d.na)
- error(p, "wrong number of arguments");
- if(t == Olfun){
- case(int d.val){
- Osigma or
- Opi or
- Ocfrac or
- Ointeg =>
- if((op := p.left.left.left.op) != Oas && op != Odas)
- error(p.left, "expression not an assignment");
- Oderiv =>
- if((op := p.left.left.op) != Oas && op != Odas)
- error(p.left, "expression not an assignment");
- }
- }
- }
- * =>
- unlex(t);
- if(!zok)
- error(nil, "missing expression");
- return nil;
+ if(tabwid){
+ col += tabwid;
+ col -= col%tabwid;
+ return col;
}
- while(postunary(t = lex())){
- t = postop(t);
- p = tree(t, p, nil);
- }
- unlex(t);
- return p;
+ return col+1;
}
-ckexp(n: ref Node, parop: int)
+getwidth(ctxt: ref Draw->Context)
{
- if(n == nil)
+ if((wid:=env->getenv("acmewin")) == nil)
return;
- o := n.op;
- l := n.left;
- r := n.right;
- if(asop(o))
- var(l);
- case(o){
- Ovar =>
- s := n.dec.sym;
- d := s.dec;
- if(d == nil){
- if(strict)
- error(n, sys->sprint("%s undefined", s.name));
- d = mkdec(s, Ovar, 1);
- }
- n.dec = d;
- Odas =>
- ckexp(r, o);
- l.dec = mkdec(l.dec.sym, Ovar, 1);
- * =>
- ckexp(l, o);
- ckexp(r, o);
- if(o == Oquest && r.op != Ocolon)
- error(n, "bad '?' operator");
- if(o == Ocolon && parop != Oquest)
- error(n, "bad ':' operator");
- }
-}
-
-commas(n: ref Node): int
-{
- if(n == nil || n.op == Ofun || n.op == Olfun)
- return 0;
- c := commas(n.left)+commas(n.right);
- if(n.op == Ocomma)
- c++;
- return c;
-}
-
-allvar(n: ref Node)
-{
- if(n == nil)
+ if((fd:=open("/chan/" + wid + "/ctl", ORDWR)) == nil)
return;
- if(n.op == Ocomma){
- allvar(n.left);
- allvar(n.right);
+ buf := array[256] of byte;
+ if((n:=read(fd, buf, len buf)) <= 0)
return;
- }
- var(n);
-}
-
-args(p: int): (int, ref Node)
-{
- if(!p)
- mustbe(Olbr);
- a := exp(p, 1);
- if(!p)
- mustbe(Orbr);
- na := 0;
- if(a != nil)
- na = commas(a)+1;
- return (na, a);
-}
-
-hash(s: string): int
-{
- l := len s;
- h := 4104;
- for(i := 0; i < l; i++)
- h = 1729*h ^ s[i];
- if(h < 0)
- h = -h;
- return h&(Hash-1);
-}
-
-enter(sp: string, k: int): ref Sym
-{
- for(s := syms[hash(sp)]; s != nil; s = s.next){
- if(sp == s.name)
- return s;
- }
- s = ref Sym;
- s.name = sp;
- s.kind = k;
- h := hash(sp);
- s.next = syms[h];
- syms[h] = s;
- return s;
-}
-
-lookup(sp: string): ref Sym
-{
- return enter(sp, Oident);
-}
-
-mkdec(s: ref Sym, k: int, dec: int): ref Dec
-{
- d := ref Dec;
- d.kind = k;
- d.val = 0.0;
- d.na = 0;
- d.sym = s;
- d.scope = 0;
- if(dec)
- pushdec(d);
- return d;
-}
-
-adddec(sp: string, k: int, v: real, n: int): ref Dec
-{
- d := mkdec(enter(sp, Oident), k, 1);
- d.val = v;
- d.na = n;
- return d;
-}
-
-scope: int;
-curscope: ref Dec;
-scopes: list of ref Dec;
-
-pushscope()
-{
- scope++;
- scopes = curscope :: scopes;
- curscope = nil;
-}
-
-popscope()
-{
- popdecs();
- curscope = hd scopes;
- scopes = tl scopes;
- scope--;
-}
-
-pushparams(n: ref Node)
-{
- if(n == nil)
+ (nf, f) := tokenize(string buf[:n], " ");
+ if(nf != 8)
return;
- if(n.op == Ocomma){
- pushparams(n.left);
- pushparams(n.right);
+ f0 := tl tl tl tl tl f;
+ if((font=Font.open(ctxt.display, hd tl f0)) == nil)
return;
- }
- n.dec = mkdec(n.dec.sym, Ovar, 1);
-}
-
-pushdec(d: ref Dec)
-{
- if(0 && debug)
- sys->print("dec %s scope %d\n", d.sym.name, scope);
- d.scope = scope;
- s := d.sym;
- if(s.dec != nil && s.dec.scope == scope)
- error(nil, sys->sprint("redeclaration of %s", s.name));
- d.old = s.dec;
- s.dec = d;
- d.next = curscope;
- curscope = d;
-}
-
-popdecs()
-{
- nd: ref Dec;
- for(d := curscope; d != nil; d = nd){
- d.sym.dec = d.old;
- d.old = nil;
- nd = d.next;
- d.next = nil;
- }
- curscope = nil;
-}
-
-estat(n: ref Node): (int, real)
-{
- k: int;
- v: real;
-
- if(n == nil)
- return (Onothing, 0.0);
- l := n.left;
- r := n.right;
- case(n.op){
- Ocomma =>
- (k, v) = estat(l);
- if(k == Oexit || k == Oret || k == Obreak || k == Ocont)
- return (k, v);
- return estat(r);
- Oprint =>
- v = print(l);
- return (Onothing, v);
- Oread =>
- v = read(l);
- return (Onothing, v);
- Obreak or
- Ocont or
- Oexit =>
- return (n.op, 0.0);
- Oret =>
- return (Oret, eval(l));
- Oif =>
- v = eval(l);
- if(int v)
- return estat(r.left);
- else if(r.right != nil)
- return estat(r.right);
- else
- return (Onothing, v);
- Ofor =>
- for(;;){
- v = eval(l);
- if(!int v)
- break;
- (k, v) = estat(r.left);
- if(k == Oexit || k == Oret)
- return (k, v);
- if(k == Obreak)
- break;
- if(r.right != nil)
- v = eval(r.right);
- }
- return (Onothing, v);
- Odo =>
- for(;;){
- (k, v) = estat(l);
- if(k == Oexit || k == Oret)
- return (k, v);
- if(k == Obreak)
- break;
- v = eval(r);
- if(!int v)
- break;
- }
- return (Onothing, v);
- * =>
- return (Onothing, eval(n));
- }
- return (Onothing, 0.0);
-}
-
-eval(e: ref Node): real
-{
- lv, rv: real;
-
- if(e == nil)
- return 1.0;
- o := e.op;
- l := e.left;
- r := e.right;
- if(o != Ofun && o != Olfun)
- lv = eval(l);
- if(o != Oandand && o != Ooror && o != Oquest)
- rv = eval(r);
- case(o){
- Ostring =>
- return 0.0;
- Onum =>
- return e.val;
- Ocon or
- Ovar =>
- return e.dec.val;
- Ofun =>
- return call(e.dec, l);
- Olfun =>
- return libfun(int e.dec.val, l);
- Oadd =>
- return lv+rv;
- Osub =>
- return lv-rv;
- Omul =>
- return lv*rv;
- Odiv =>
- return lv/rv;
- Omod =>
- return real (big lv%big rv);
- Oidiv =>
- return real (big lv/big rv);
- Oand =>
- return real (big lv&big rv);
- Oor =>
- return real (big lv|big rv);
- Oxor =>
- return real (big lv^big rv);
- Olsh =>
- return real (big lv<<int rv);
- Orsh =>
- return real (big lv>>int rv);
- Oeq =>
- return real (lv == rv);
- One =>
- return real (lv != rv);
- Ogt =>
- return real (lv > rv);
- Olt =>
- return real (lv < rv);
- Oge =>
- return real (lv >= rv);
- Ole =>
- return real (lv <= rv);
- Opreinc =>
- l.dec.val += 1.0;
- return l.dec.val;
- Opostinc =>
- l.dec.val += 1.0;
- return l.dec.val-1.0;
- Opredec =>
- l.dec.val -= 1.0;
- return l.dec.val;
- Opostdec =>
- l.dec.val -= 1.0;
- return l.dec.val+1.0;
- Oexp =>
- if(isinteger(rv) && rv >= 0.0)
- return lv**int rv;
- return maths->pow(lv, rv);
- Oandand =>
- if(!int lv)
- return lv;
- return eval(r);
- Ooror =>
- if(int lv)
- return lv;
- return eval(r);
- Onot =>
- return real !int lv;
- Ofact =>
- if(isinteger(lv) && lv >= 0.0){
- n := int lv;
- lv = 1.0;
- for(i := 2; i <= n; i++)
- lv *= real i;
- return lv;
- }
- return gamma(lv+1.0);
- Ocom =>
- return real ~big lv;
- Oas or
- Odas =>
- l.dec.val = rv;
- return rv;
- Oplus =>
- return lv;
- Ominus =>
- return -lv;
- Oinv =>
- return 1.0/lv;
- Ocomma =>
- return rv;
- Oquest =>
- if(int lv)
- return eval(r.left);
- else
- return eval(r.right);
- Onand =>
- return real !(int lv&int rv);
- Onor =>
- return real !(int lv|int rv);
- Oimp =>
- return real (!int lv|int rv);
- Oimpby =>
- return real (int lv|!int rv);
- Oiff =>
- return real !(int lv^int rv);
- * =>
- fatal(sys->sprint("case %s in eval", opstring(o)));
- }
- return 0.0;
-}
-
-var(e: ref Node)
-{
- if(e == nil || e.op != Ovar || e.dec.kind != Ovar)
- error(e, "expected a variable");
+ tabwid = int hd tl tl f0;
+ mintab = font.width("0");
+ columns = int hd f0;
}
-libfun(o: int, a: ref Node): real
-{
- a1, a2: real;
-
- case(o){
- Osolve =>
- return solve(a);
- Osigma or
- Opi or
- Ocfrac =>
- return series(o, a);
- Oderiv =>
- return differential(a);
- Ointeg =>
- return integral(a);
- }
- v := 0.0;
- if(a != nil && a.op == Ocomma){
- a1 = eval(a.left);
- a2 = eval(a.right);
- }
- else
- a1 = eval(a);
- case(o){
- Olog =>
- v = maths->log(a1);
- Olog10 =>
- v = maths->log10(a1);
- Olog2 =>
- v = maths->log(a1)/maths->log(2.0);
- Ologb =>
- v = maths->log(a1)/maths->log(a2);
- Oexpf =>
- v = maths->exp(a1);
- Opow =>
- v = maths->pow(a1, a2);
- Osqrt =>
- v = maths->sqrt(a1);
- Ocbrt =>
- v = maths->cbrt(a1);
- Ofloor =>
- v = maths->floor(a1);
- Oceil =>
- v = maths->ceil(a1);
- Omin =>
- v = maths->fmin(a1, a2);
- Omax =>
- v = maths->fmax(a1, a2);
- Oabs =>
- v = maths->fabs(a1);
- Ogamma =>
- v = gamma(a1);
- Osign =>
- if(a1 > 0.0)
- v = 1.0;
- else if(a1 < 0.0)
- v = -1.0;
- else
- v = 0.0;
- Oint =>
- (vi, nil) := maths->modf(a1);
- v = real vi;
- Ofrac =>
- (nil, v) = maths->modf(a1);
- Oround =>
- v = maths->rint(a1);
- Oerf =>
- v = maths->erf(a1);
- Osin =>
- v = maths->sin(D2R(a1));
- Ocos =>
- v = maths->cos(D2R(a1));
- Otan =>
- v = maths->tan(D2R(a1));
- Oasin =>
- v = R2D(maths->asin(a1));
- Oacos =>
- v = R2D(maths->acos(a1));
- Oatan =>
- v = R2D(maths->atan(a1));
- Oatan2 =>
- v = R2D(maths->atan2(a1, a2));
- Osinh =>
- v = maths->sinh(a1);
- Ocosh =>
- v = maths->cosh(a1);
- Otanh =>
- v = maths->tanh(a1);
- Oasinh =>
- v = maths->asinh(a1);
- Oacosh =>
- v = maths->acosh(a1);
- Oatanh =>
- v = maths->atanh(a1);
- Orand =>
- v = real rand->rand(Big)/real Big;
- * =>
- fatal(sys->sprint("case %s in libfun", opstring(o)));
- }
- return v;
-}
-
-series(o: int, a: ref Node): real
-{
- p0, p1, q0, q1: real;
-
- l := a.left;
- r := a.right;
- if(o == Osigma)
- v := 0.0;
- else if(o == Opi)
- v = 1.0;
- else{
- p0 = q1 = 0.0;
- p1 = q0 = 1.0;
- v = Infinity;
- }
- i := l.left.left.dec;
- ov := i.val;
- i.val = eval(l.left.right);
- eq := 0;
- for(;;){
- rv := eval(l.right);
- if(i.val > rv)
- break;
- lv := v;
- ev := eval(r);
- if(o == Osigma)
- v += ev;
- else if(o == Opi)
- v *= ev;
- else{
- t := ev*p1+p0;
- p0 = p1;
- p1 = t;
- t = ev*q1+q0;
- q0 = q1;
- q1 = t;
- v = p1/q1;
- }
- if(v == lv && rv == Infinity){
- eq++;
- if(eq > 100)
- break;
- }
- else
- eq = 0;
- i.val += 1.0;
- }
- i.val = ov;
- return v;
-}
-
-pushe(a: ref Node, l: list of real): list of real
-{
- if(a == nil)
- return l;
- if(a.op == Ocomma){
- l = pushe(a.left, l);
- return pushe(a.right, l);
- }
- l = eval(a) :: l;
- return l;
-}
-
-pusha(f: ref Node, l: list of real, nl: list of real): (list of real, list of real)
-{
- if(f == nil)
- return (l, nl);
- if(f.op == Ocomma){
- (l, nl) = pusha(f.left, l, nl);
- return pusha(f.right, l, nl);
- }
- l = f.dec.val :: l;
- f.dec.val = hd nl;
- return (l, tl nl);
-}
-
-pop(f: ref Node, l: list of real): list of real
-{
- if(f == nil)
- return l;
- if(f.op == Ocomma){
- l = pop(f.left, l);
- return pop(f.right, l);
- }
- f.dec.val = hd l;
- return tl l;
-}
-
-rev(l: list of real): list of real
-{
- nl: list of real;
-
- for( ; l != nil; l = tl l)
- nl = hd l :: nl;
- return nl;
-}
-
-call(d: ref Dec, a: ref Node): real
-{
- l: list of real;
-
- nl := rev(pushe(a, nil));
- (l, nil) = pusha(d.code.left, nil, nl);
- l = rev(l);
- (k, v) := estat(d.code.right);
- l = pop(d.code.left, l);
- if(k == Oexit)
- exit;
- return v;
-}
-
-print(n: ref Node): real
-{
- if(n == nil)
- return 0.0;
- if(n.op == Ocomma){
- print(n.left);
- return print(n.right);
- }
- if(n.op == Ostring){
- sys->print("%s", n.str);
- return 0.0;
- }
- v := eval(n);
- printnum(v, "");
- return v;
-}
-
-read(n: ref Node): real
-{
- bio: ref Iobuf;
-
- if(n == nil)
- return 0.0;
- if(n.op == Ocomma){
- read(n.left);
- return read(n.right);
- }
- sys->print("%s ? ", n.dec.sym.name);
- if(!stdin){
- bio = bufio->fopen(sys->fildes(0), Sys->OREAD);
- stack(nil, bio);
- }
- lexnum();
- consume(Onl);
- n.dec.val = lexval;
- if(!stdin && bin == bio)
- unstack();
- return n.dec.val;
-}
-
-isint(v: real): int
-{
- return v >= -real Maxint && v <= real Maxint;
-}
-
-isinteger(v: real): int
-{
- return v == real int v && isint(v);
-}
-
-split(v: real): (int, real)
-{
- # v >= 0.0
- n := int v;
- if(real n > v)
- n--;
- return (n, v-real n);
-}
-
-n2c(n: int): int
-{
- if(n < 10)
- return n+'0';
- return n-10+'a';
-}
-
-gamma(v: real): real
-{
- (s, lg) := maths->lgamma(v);
- return real s*maths->exp(lg);
-}
-
-D2R(a: real): real
-{
- if(deg.val != 0.0)
- a *= Pi/180.0;
- return a;
-}
-
-R2D(a: real): real
-{
- if(deg.val != 0.0)
- a /= Pi/180.0;
- return a;
-}
-
-side(n: ref Node): int
-{
- if(n == nil)
- return 0;
- if(asop(n.op) || n.op == Ofun)
- return 1;
- return side(n.left) || side(n.right);
-}
-
-sametree(n1: ref Node, n2: ref Node): int
-{
- if(n1 == n2)
- return 1;
- if(n1 == nil || n2 == nil)
- return 0;
- if(n1.op != n2.op)
- return 0;
- case(n1.op){
- Ostring =>
- return n1.str == n2.str;
- Onum =>
- return n1.val == n2.val;
- Ocon or
- Ovar =>
- return n1.dec == n2.dec;
- Ofun or
- Olfun =>
- return n1.dec == n2.dec && sametree(n1.left, n2.left);
- * =>
- return sametree(n1.left, n2.left) && sametree(n1.right, n2.right);
- }
- return 0;
-}
-
-simplify(n: ref Node): ref Node
-{
- if(n == nil)
- return nil;
- op := n.op;
- l := n.left = simplify(n.left);
- r := n.right = simplify(n.right);
- if(l != nil && iscon(l) && (r == nil || iscon(r))){
- if(isnan(l))
- return l;
- if(r != nil && isnan(r))
- return r;
- return vtree(eval(n));
- }
- case(op){
- Onum or
- Ocon or
- Ovar or
- Olfun or
- Ocomma =>
- return n;
- Oplus =>
- return l;
- Ominus =>
- if(l.op == Ominus)
- return l.left;
- Oinv =>
- if(l.op == Oinv)
- return l.left;
- Oadd =>
- if(iszero(l))
- return r;
- if(iszero(r))
- return l;
- if(sametree(l, r))
- return tree(Omul, itree(2), l);
- Osub =>
- if(iszero(l))
- return simplify(tree(Ominus, r, nil));
- if(iszero(r))
- return l;
- if(sametree(l, r))
- return itree(0);
- Omul =>
- if(iszero(l))
- return l;
- if(iszero(r))
- return r;
- if(isone(l))
- return r;
- if(isone(r))
- return l;
- if(sametree(l, r))
- return tree(Oexp, l, itree(2));
- Odiv =>
- if(iszero(l))
- return l;
- if(iszero(r))
- return vtree(Infinity);
- if(isone(l))
- return ptree(r, -1.0);
- if(isone(r))
- return l;
- if(sametree(l, r))
- return itree(1);
- Oexp =>
- if(iszero(l))
- return l;
- if(iszero(r))
- return itree(1);
- if(isone(l))
- return l;
- if(isone(r))
- return l;
- * =>
- fatal(sys->sprint("case %s in simplify", opstring(op)));
- }
- return n;
-}
-
-deriv(n: ref Node, d: ref Dec): ref Node
-{
- if(n == nil)
- return nil;
- op := n.op;
- l := n.left;
- r := n.right;
- case(op){
- Onum or
- Ocon =>
- n = itree(0);
- Ovar =>
- if(d == n.dec)
- n = itree(1);
- else
- n = itree(0);
- Olfun =>
- case(int n.dec.val){
- Olog =>
- n = ptree(l, -1.0);
- Olog10 =>
- n = ptree(tree(Omul, l, vtree(Ln10)), -1.0);
- Olog2 =>
- n = ptree(tree(Omul, l, vtree(Ln2)), -1.0);
- Oexpf =>
- n = n;
- Opow =>
- return deriv(tree(Oexp, l.left, l.right), d);
- Osqrt =>
- return deriv(tree(Oexp, l, vtree(0.5)), d);
- Ocbrt =>
- return deriv(tree(Oexp, l, vtree(1.0/3.0)), d);
- Osin =>
- n = ltree("cos", l);
- Ocos =>
- n = tree(Ominus, ltree("sin", l), nil);
- Otan =>
- n = ptree(ltree("cos", l), -2.0);
- Oasin =>
- n = ptree(tree(Osub, itree(1), ptree(l, 2.0)), -0.5);
- Oacos =>
- n = tree(Ominus, ptree(tree(Osub, itree(1), ptree(l, 2.0)), -0.5), nil);
- Oatan =>
- n = ptree(tree(Oadd, itree(1), ptree(l, 2.0)), -1.0);
- Osinh =>
- n = ltree("cosh", l);
- Ocosh =>
- n = ltree("sinh", l);
- Otanh =>
- n = ptree(ltree("cosh", l), -2.0);
- Oasinh =>
- n = ptree(tree(Oadd, itree(1), ptree(l, 2.0)), -0.5);
- Oacosh =>
- n = ptree(tree(Osub, ptree(l, 2.0), itree(1)), -0.5);
- Oatanh =>
- n = ptree(tree(Osub, itree(1), ptree(l, 2.0)), -1.0);
- * =>
- return vtree(Nan);
- }
- return tree(Omul, n, deriv(l, d));
- Oplus or
- Ominus =>
- n = tree(op, deriv(l, d), nil);
- Oinv =>
- n = tree(Omul, tree(Ominus, ptree(l, -2.0), nil), deriv(l, d));
- Oadd or
- Osub or
- Ocomma =>
- n = tree(op, deriv(l, d), deriv(r, d));
- Omul =>
- n = tree(Oadd, tree(Omul, deriv(l, d), r), tree(Omul, l, deriv(r, d)));
- Odiv =>
- n = tree(Osub, tree(Omul, deriv(l, d), r), tree(Omul, l, deriv(r, d)));
- n = tree(Odiv, n, ptree(r, 2.0));
- Oexp =>
- nn := tree(Oadd, tree(Omul, deriv(l, d), tree(Odiv, r, l)), tree(Omul, ltree("log", l), deriv(r, d)));
- n = tree(Omul, n, nn);
- * =>
- n = vtree(Nan);
- }
- return n;
-}
-
-derivative(n: ref Node, d: ref Dec): ref Node
-{
- n = simplify(deriv(n, d));
- if(isnan(n))
- error(n, "no derivative");
- if(debug)
- prnode(n);
- return n;
-}
-
-newton(f: ref Node, e: ref Node, d: ref Dec, v1: real, v2: real): (int, real)
-{
- v := (v1+v2)/2.0;
- lv := 0.0;
- its := 0;
- for(;;){
- lv = v;
- d.val = v;
- v = eval(e);
- # if(v < v1 || v > v2)
- # return (0, 0.0);
- if(maths->isnan(v))
- return (0, 0.0);
- if(its > 100 || fabs(v-lv) < Eps)
- break;
- its++;
- }
- if(fabs(v-lv) > Bigeps || fabs(eval(f)) > Bigeps)
- return (0, 0.0);
- return (1, v);
-}
-
-solve(n: ref Node): real
-{
- d: ref Dec;
-
- if(n == nil)
- return Nan;
- if(n.op == Ocomma){ # solve(..., var)
- var(n.right);
- d = n.right.dec;
- n = n.left;
- if(!varmem(n, d))
- error(n, "variable not in equation");
- }
- else{
- d = findvar(n, nil);
- if(d == nil)
- error(n, "variable missing");
- if(d == errdec)
- error(n, "one variable only required");
- }
- if(n.op == Oeq)
- n.op = Osub;
- dn := derivative(n, d);
- var := tree(Ovar, nil, nil);
- var.dec = d;
- nr := tree(Osub, var, tree(Odiv, n, dn));
- ov := d.val;
- lim := lookup(Limit).dec.val;
- step := lookup(Step).dec.val;
- rval := Infinity;
- d.val = -lim-step;
- v1 := 0.0;
- v2 := eval(n);
- for(v := -lim; v <= lim; v += step){
- d.val = v;
- v1 = v2;
- v2 = eval(n);
- if(maths->isnan(v2)) # v == nan, v <= nan, v >= nan all give 1
- continue;
- if(fabs(v2) < Eps){
- if(v >= -lim && v <= lim && v != rval){
- printnum(v, " ");
- rval = v;
- }
- }
- else if(v1*v2 <= 0.0){
- (f, rv) := newton(n, nr, var.dec, v-step, v);
- if(f && rv >= -lim && rv <= lim && rv != rval){
- printnum(rv, " ");
- rval = rv;
- }
- }
- }
- d.val = ov;
- if(rval == Infinity)
- error(n, "no roots found");
- else
- sys->print("\n");
- return rval;
-}
-
-differential(n: ref Node): real
-{
- x := n.left.left.dec;
- ov := x.val;
- v := evalx(derivative(n.right, x), x, eval(n.left.right));
- x.val = ov;
- return v;
-}
-
-integral(n: ref Node): real
-{
- l := n.left;
- r := n.right;
- x := l.left.left.dec;
- ov := x.val;
- a := eval(l.left.right);
- b := eval(l.right);
- h := b-a;
- end := evalx(r, x, a) + evalx(r, x, b);
- odd := even := 0.0;
- oldarea := 0.0;
- area := h*end/2.0;
- for(i := 1; i < 1<<16; i <<= 1){
- even += odd;
- odd = 0.0;
- xv := a+h/2.0;
- for(j := 0; j < i; j++){
- odd += evalx(r, x, xv);
- xv += h;
- }
- h /= 2.0;
- oldarea = area;
- area = h*(end+4.0*odd+2.0*even)/3.0;
- if(maths->isnan(area))
- error(n, "integral not found");
- if(fabs(area-oldarea) < Eps)
- break;
- }
- if(fabs(area-oldarea) > Bigeps)
- error(n, "integral not found");
- x.val = ov;
- return area;
-}
-
-evalx(n: ref Node, d: ref Dec, v: real): real
-{
- d.val = v;
- return eval(n);
-}
-
-findvar(n: ref Node, d: ref Dec): ref Dec
-{
- if(n == nil)
- return d;
- d = findvar(n.left, d);
- d = findvar(n.right, d);
- if(n.op == Ovar){
- if(d == nil)
- d = n.dec;
- if(n.dec != d)
- d = errdec;
- }
- return d;
-}
-
-varmem(n: ref Node, d: ref Dec): int
-{
- if(n == nil)
- return 0;
- if(n.op == Ovar)
- return d == n.dec;
- return varmem(n.left, d) || varmem(n.right, d);
-}
-
-fabs(r: real): real
-{
- if(r < 0.0)
- return -r;
- return r;
-}
-
-cvt(v: real, base: int): string
-{
- if(base == 10)
- return sys->sprint("%g", v);
- neg := 0;
- if(v < 0.0){
- neg = 1;
- v = -v;
- }
- if(!isint(v)){
- n := 0;
- lg := maths->log(v)/maths->log(real base);
- if(lg < 0.0){
- (n, nil) = split(-lg);
- v *= real base**n;
- n = -n;
- }
- else{
- (n, nil) = split(lg);
- v /= real base**n;
- }
- s := cvt(v, base) + "E" + string n;
- if(neg)
- s = "-" + s;
- return s;
- }
- (n, f) := split(v);
- s := "";
- do{
- r := n%base;
- n /= base;
- s[len s] = n2c(r);
- }while(n != 0);
- ls := len s;
- for(i := 0; i < ls/2; i++){
- t := s[i];
- s[i] = s[ls-1-i];
- s[ls-1-i] = t;
- }
- if(f != 0.0){
- s[len s] = '.';
- for(i = 0; i < 16 && f != 0.0; i++){
- f *= real base;
- (n, f) = split(f);
- s[len s] = n2c(n);
- }
- }
- s = string base + "r" + s;
- if(neg)
- s = "-" + s;
- return s;
-}
-
-printnum(v: real, s: string)
-{
- base := int pbase.val;
- if(!isinteger(pbase.val) || base < 2 || base > 36)
- base = 10;
- sys->print("%s%s", cvt(v, base), s);
- if(bits){
- r := array[1] of real;
- b := array[8] of byte;
- r[0] = v;
- maths->export_real(b, r);
- for(i := 0; i < 8; i++)
- sys->print("%2.2x ", int b[i]);
- sys->print("\n");
- }
-}
-
-Left, Right, Pre, Post: con 1<<iota;
-
-lspace := array[] of { 0, 0, 2, 3, 4, 5, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0 };
-rspace := array[] of { 0, 1, 2, 3, 4, 5, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0 };
-
-preced(op1: int, op2: int, s: int): int
-{
- br := 0;
- p1 := prec(op1);
- p2 := prec(op2);
- if(p1 > p2)
- br = 1;
- else if(p1 == p2){
- if(op1 == op2){
- if(rassoc(op1))
- br = s == Left;
- else
- br = s == Right && !assoc(op1);
- }
- else{
- if(rassoc(op1))
- br = s == Left;
- else
- br = s == Right && op1 != Oadd;
- if(postunary(op1) && preunary(op2))
- br = 1;
- }
- }
- return br;
-}
-
-prnode(n: ref Node)
-{
- pnode(n, Onothing, Pre);
- sys->print("\n");
-}
-
-pnode(n: ref Node, opp: int, s: int)
+fatal(s: string)
{
- if(n == nil)
- return;
- op := n.op;
- if(br := preced(opp, op, s))
- sys->print("(");
- if(op == Oas && n.right.op >= Oadd && n.right.op <= Orsh && n.left == n.right.left){
- pnode(n.left, op, Left);
- sys->print(" %s ", opstring(n.right.op+Oadde-Oadd));
- pnode(n.right.right, op, Right);
- }
- else if(binary(op)){
- p := prec(op);
- pnode(n.left, op, Left);
- if(lspace[p])
- sys->print(" ");
- sys->print("%s", opstring(op));
- if(rspace[p])
- sys->print(" ");
- pnode(n.right, op, Right);
- }
- else if(op == Oinv){ # cannot print postunary -1
- sys->print("%s", opstring(op));
- pnode(n.left, Odiv, Right);
- }
- else if(preunary(op)){
- sys->print("%s", opstring(op));
- pnode(n.left, op, Pre);
- }
- else if(postunary(op)){
- pnode(n.left, op, Post);
- sys->print("%s", opstring(op));
- }
- else{
- case(op){
- Ostring =>
- sys->print("%s", n.str);
- Onum =>
- sys->print("%g", n.val);
- Ocon or
- Ovar =>
- sys->print("%s", n.dec.sym.name);
- Ofun or
- Olfun =>
- sys->print("%s(", n.dec.sym.name);
- pnode(n.left, Onothing, Pre);
- sys->print(")");
- * =>
- fatal(sys->sprint("bad op %s in pnode()", opstring(op)));
- }
- }
- if(br)
- sys->print(")");
+ fprint(fildes(2), "mc: %s: %r\n", s);
+ raise "fail:"+s;
}