1*37da2899SCharles.Forsythimplement Fc; 2*37da2899SCharles.Forsythinclude "sys.m"; 3*37da2899SCharles.Forsyth sys: Sys; 4*37da2899SCharles.Forsythinclude "draw.m"; 5*37da2899SCharles.Forsythinclude "math.m"; 6*37da2899SCharles.Forsyth math: Math; 7*37da2899SCharles.Forsythinclude "string.m"; 8*37da2899SCharles.Forsyth str: String; 9*37da2899SCharles.Forsythinclude "regex.m"; 10*37da2899SCharles.Forsyth regex: Regex; 11*37da2899SCharles.Forsyth 12*37da2899SCharles.ForsythFc: module { 13*37da2899SCharles.Forsyth init: fn(nil: ref Draw->Context, argv: list of string); 14*37da2899SCharles.Forsyth}; 15*37da2899SCharles.Forsyth 16*37da2899SCharles.Forsyth 17*37da2899SCharles.ForsythUNARY, BINARY, SPECIAL: con iota; 18*37da2899SCharles.Forsyth 19*37da2899SCharles.ForsythoSWAP, oDUP, oREP, oSUM, oPRNUM, oMULT, 20*37da2899SCharles.ForsythoPLUS, oMINUS, oDIV, oDIVIDE, oMOD, oSHIFTL, oSHIFTR, 21*37da2899SCharles.ForsythoAND, oOR, oXOR, oNOT, oUMINUS, oFACTORIAL, 22*37da2899SCharles.ForsythoPOW, oHYPOT, oATAN2, oJN, oYN, oSCALBN, oCOPYSIGN, 23*37da2899SCharles.ForsythoFDIM, oFMIN, oFMAX, oNEXTAFTER, oREMAINDER, oFMOD, 24*37da2899SCharles.ForsythoPOW10, oSQRT, oEXP, oEXPM1, oLOG, oLOG10, oLOG1P, 25*37da2899SCharles.ForsythoCOS, oCOSH, oSIN, oSINH, oTAN, oTANH, oACOS, oASIN, oACOSH, 26*37da2899SCharles.ForsythoASINH, oATAN, oATANH, oERF, oERFC, 27*37da2899SCharles.ForsythoJ0, oJ1, oY0, oY1, oILOGB, oFABS, oCEIL, 28*37da2899SCharles.ForsythoFLOOR, oFINITE, oISNAN, oRINT, oLGAMMA, oMODF, 29*37da2899SCharles.ForsythoDEG, oRAD: con iota; 30*37da2899SCharles.ForsythOp: adt { 31*37da2899SCharles.Forsyth name: string; 32*37da2899SCharles.Forsyth kind: int; 33*37da2899SCharles.Forsyth op: int; 34*37da2899SCharles.Forsyth}; 35*37da2899SCharles.Forsyth 36*37da2899SCharles.Forsythops := array[] of { 37*37da2899SCharles.ForsythOp 38*37da2899SCharles.Forsyth("swap", SPECIAL, oSWAP), 39*37da2899SCharles.Forsyth("dup", SPECIAL, oDUP), 40*37da2899SCharles.Forsyth("rep", SPECIAL, oREP), 41*37da2899SCharles.Forsyth("sum", SPECIAL, oSUM), 42*37da2899SCharles.Forsyth("p", SPECIAL, oPRNUM), 43*37da2899SCharles.Forsyth("x", BINARY, oMULT), 44*37da2899SCharles.Forsyth("×", BINARY, oMULT), 45*37da2899SCharles.Forsyth("pow", BINARY, oPOW), 46*37da2899SCharles.Forsyth("xx", BINARY, oPOW), 47*37da2899SCharles.Forsyth("+", BINARY, oPLUS), 48*37da2899SCharles.Forsyth("-", BINARY, oMINUS), 49*37da2899SCharles.Forsyth("/", BINARY, oDIVIDE), 50*37da2899SCharles.Forsyth("div", BINARY, oDIV), 51*37da2899SCharles.Forsyth("%", BINARY, oMOD), 52*37da2899SCharles.Forsyth("shl", BINARY, oSHIFTL), 53*37da2899SCharles.Forsyth("shr", BINARY, oSHIFTR), 54*37da2899SCharles.Forsyth("and", BINARY, oAND), 55*37da2899SCharles.Forsyth("or", BINARY, oOR), 56*37da2899SCharles.Forsyth("⋀", BINARY, oAND), 57*37da2899SCharles.Forsyth("⋁", BINARY, oOR), 58*37da2899SCharles.Forsyth("xor", BINARY, oXOR), 59*37da2899SCharles.Forsyth("not", UNARY, oNOT), 60*37da2899SCharles.Forsyth("_", UNARY, oUMINUS), 61*37da2899SCharles.Forsyth("factorial", UNARY, oFACTORIAL), 62*37da2899SCharles.Forsyth("!", UNARY, oFACTORIAL), 63*37da2899SCharles.Forsyth("pow", BINARY, oPOW), 64*37da2899SCharles.Forsyth("hypot", BINARY, oHYPOT), 65*37da2899SCharles.Forsyth("atan2", BINARY, oATAN2), 66*37da2899SCharles.Forsyth("jn", BINARY, oJN), 67*37da2899SCharles.Forsyth("yn", BINARY, oYN), 68*37da2899SCharles.Forsyth("scalbn", BINARY, oSCALBN), 69*37da2899SCharles.Forsyth("copysign", BINARY, oCOPYSIGN), 70*37da2899SCharles.Forsyth("fdim", BINARY, oFDIM), 71*37da2899SCharles.Forsyth("fmin", BINARY, oFMIN), 72*37da2899SCharles.Forsyth("fmax", BINARY, oFMAX), 73*37da2899SCharles.Forsyth("nextafter", BINARY, oNEXTAFTER), 74*37da2899SCharles.Forsyth("remainder", BINARY, oREMAINDER), 75*37da2899SCharles.Forsyth("fmod", BINARY, oFMOD), 76*37da2899SCharles.Forsyth("pow10", UNARY, oPOW10), 77*37da2899SCharles.Forsyth("sqrt", UNARY, oSQRT), 78*37da2899SCharles.Forsyth("exp", UNARY, oEXP), 79*37da2899SCharles.Forsyth("expm1", UNARY, oEXPM1), 80*37da2899SCharles.Forsyth("log", UNARY, oLOG), 81*37da2899SCharles.Forsyth("log10", UNARY, oLOG10), 82*37da2899SCharles.Forsyth("log1p", UNARY, oLOG1P), 83*37da2899SCharles.Forsyth("cos", UNARY, oCOS), 84*37da2899SCharles.Forsyth("cosh", UNARY, oCOSH), 85*37da2899SCharles.Forsyth("sin", UNARY, oSIN), 86*37da2899SCharles.Forsyth("sinh", UNARY, oSINH), 87*37da2899SCharles.Forsyth("tan", UNARY, oTAN), 88*37da2899SCharles.Forsyth("tanh", UNARY, oTANH), 89*37da2899SCharles.Forsyth("acos", UNARY, oACOS), 90*37da2899SCharles.Forsyth("asin", UNARY, oASIN), 91*37da2899SCharles.Forsyth("acosh", UNARY, oACOSH), 92*37da2899SCharles.Forsyth("asinh", UNARY, oASINH), 93*37da2899SCharles.Forsyth("atan", UNARY, oATAN), 94*37da2899SCharles.Forsyth("atanh", UNARY, oATANH), 95*37da2899SCharles.Forsyth("erf", UNARY, oERF), 96*37da2899SCharles.Forsyth("erfc", UNARY, oERFC), 97*37da2899SCharles.Forsyth("j0", UNARY, oJ0), 98*37da2899SCharles.Forsyth("j1", UNARY, oJ1), 99*37da2899SCharles.Forsyth("y0", UNARY, oY0), 100*37da2899SCharles.Forsyth("y1", UNARY, oY1), 101*37da2899SCharles.Forsyth("ilogb", UNARY, oILOGB), 102*37da2899SCharles.Forsyth("fabs", UNARY, oFABS), 103*37da2899SCharles.Forsyth("ceil", UNARY, oCEIL), 104*37da2899SCharles.Forsyth("floor", UNARY, oFLOOR), 105*37da2899SCharles.Forsyth("finite", UNARY, oFINITE), 106*37da2899SCharles.Forsyth("isnan", UNARY, oISNAN), 107*37da2899SCharles.Forsyth("rint", UNARY, oRINT), 108*37da2899SCharles.Forsyth("rad", UNARY, oRAD), 109*37da2899SCharles.Forsyth("deg", UNARY, oDEG), 110*37da2899SCharles.Forsyth("lgamma", SPECIAL, oLGAMMA), 111*37da2899SCharles.Forsyth("modf", SPECIAL, oMODF), 112*37da2899SCharles.Forsyth}; 113*37da2899SCharles.Forsyth 114*37da2899SCharles.ForsythnHEX, nBINARY, nOCTAL, nRADIX1, nRADIX2, nREAL, nCHAR: con iota; 115*37da2899SCharles.Forsythpats0 := array[] of { 116*37da2899SCharles.ForsythnHEX => "-?0[xX][0-9a-fA-F]+", 117*37da2899SCharles.ForsythnBINARY => "-?0[bB][01]+", 118*37da2899SCharles.ForsythnOCTAL => "-?0[0-7]+", 119*37da2899SCharles.ForsythnRADIX1 => "-?[0-9][rR][0-8]+", 120*37da2899SCharles.ForsythnRADIX2 => "-?[0-3][0-9][rR][0-9a-zA-Z]+", 121*37da2899SCharles.ForsythnREAL => "-?(([0-9]+(\\.[0-9]+)?)|([0-9]*(\\.[0-9]+)))([eE]-?[0-9]+)?", 122*37da2899SCharles.ForsythnCHAR => "@.", 123*37da2899SCharles.Forsyth}; 124*37da2899SCharles.ForsythRADIX, ANNOTATE, CHAR: con 1 << (iota + 10); 125*37da2899SCharles.Forsyth 126*37da2899SCharles.Forsythoutbase := 10; 127*37da2899SCharles.Forsythpats: array of Regex->Re; 128*37da2899SCharles.Forsythstack: list of real; 129*37da2899SCharles.Forsythlast_op: Op; 130*37da2899SCharles.Forsythstderr: ref Sys->FD; 131*37da2899SCharles.Forsyth 132*37da2899SCharles.Forsythusage() 133*37da2899SCharles.Forsyth{ 134*37da2899SCharles.Forsyth sys->fprint(stderr, 135*37da2899SCharles.Forsyth "usage: fc [-xdbB] [-r radix] <postfix expression>\n" + 136*37da2899SCharles.Forsyth "option specifies output format:\n" + 137*37da2899SCharles.Forsyth "\t-d decimal (default)\n" + 138*37da2899SCharles.Forsyth "\t-x hex\n" + 139*37da2899SCharles.Forsyth "\t-o octal\n" + 140*37da2899SCharles.Forsyth "\t-b binary\n" + 141*37da2899SCharles.Forsyth "\t-B annotated binary\n" + 142*37da2899SCharles.Forsyth "\t-c character\n" + 143*37da2899SCharles.Forsyth "\t-r <radix> specified base in Limbo 99r9999 format\n" + 144*37da2899SCharles.Forsyth "operands are decimal(default), hex(0x), octal(0), binary(0b), radix(99r)\n"); 145*37da2899SCharles.Forsyth sys->fprint(stderr, "operators are:\n"); 146*37da2899SCharles.Forsyth for (i := 0; i < len ops; i++) 147*37da2899SCharles.Forsyth sys->fprint(stderr, "%s ", ops[i].name); 148*37da2899SCharles.Forsyth sys->fprint(stderr, "\n"); 149*37da2899SCharles.Forsyth raise "fail:usage"; 150*37da2899SCharles.Forsyth} 151*37da2899SCharles.Forsyth 152*37da2899SCharles.Forsythinit(nil: ref Draw->Context, argv: list of string) 153*37da2899SCharles.Forsyth{ 154*37da2899SCharles.Forsyth sys = load Sys Sys->PATH; 155*37da2899SCharles.Forsyth stderr = sys->fildes(2); 156*37da2899SCharles.Forsyth math = load Math Math->PATH; 157*37da2899SCharles.Forsyth regex = load Regex Regex->PATH; 158*37da2899SCharles.Forsyth if (regex == nil) { 159*37da2899SCharles.Forsyth sys->fprint(stderr, "fc: cannot load %s: %r\n", Regex->PATH); 160*37da2899SCharles.Forsyth raise "fail:error"; 161*37da2899SCharles.Forsyth } 162*37da2899SCharles.Forsyth 163*37da2899SCharles.Forsyth initpats(); 164*37da2899SCharles.Forsyth 165*37da2899SCharles.Forsyth if (argv == nil || tl argv == nil) 166*37da2899SCharles.Forsyth return; 167*37da2899SCharles.Forsyth argv = tl argv; 168*37da2899SCharles.Forsyth a := hd argv; 169*37da2899SCharles.Forsyth if (len a > 1 && a[0] == '-' && number(a).t0 == 0) { 170*37da2899SCharles.Forsyth case a[1] { 171*37da2899SCharles.Forsyth 'd' => 172*37da2899SCharles.Forsyth outbase = 10; 173*37da2899SCharles.Forsyth 'x' => 174*37da2899SCharles.Forsyth outbase = 16; 175*37da2899SCharles.Forsyth 'o' => 176*37da2899SCharles.Forsyth outbase = 8; 177*37da2899SCharles.Forsyth 'b' => 178*37da2899SCharles.Forsyth outbase = 2; 179*37da2899SCharles.Forsyth 'c' => 180*37da2899SCharles.Forsyth outbase = CHAR; 181*37da2899SCharles.Forsyth 'r' => 182*37da2899SCharles.Forsyth r := 0; 183*37da2899SCharles.Forsyth if (len a > 2) 184*37da2899SCharles.Forsyth r = int a[2:]; 185*37da2899SCharles.Forsyth else if (tl argv == nil) 186*37da2899SCharles.Forsyth usage(); 187*37da2899SCharles.Forsyth else { 188*37da2899SCharles.Forsyth argv = tl argv; 189*37da2899SCharles.Forsyth r = int hd argv; 190*37da2899SCharles.Forsyth } 191*37da2899SCharles.Forsyth if (r < 2 || r > 36) 192*37da2899SCharles.Forsyth usage(); 193*37da2899SCharles.Forsyth outbase = r | RADIX; 194*37da2899SCharles.Forsyth 'B' => 195*37da2899SCharles.Forsyth outbase = 2 | ANNOTATE; 196*37da2899SCharles.Forsyth * => 197*37da2899SCharles.Forsyth sys->fprint(stderr, "fc: unknown option -%c\n", a[1]); 198*37da2899SCharles.Forsyth usage(); 199*37da2899SCharles.Forsyth } 200*37da2899SCharles.Forsyth argv = tl argv; 201*37da2899SCharles.Forsyth } 202*37da2899SCharles.Forsyth 203*37da2899SCharles.Forsyth math->FPcontrol(0, Math->INVAL|Math->ZDIV|Math->OVFL|Math->UNFL|Math->INEX); 204*37da2899SCharles.Forsyth 205*37da2899SCharles.Forsyth for (; argv != nil; argv = tl argv) { 206*37da2899SCharles.Forsyth (ok, x) := number(hd argv); 207*37da2899SCharles.Forsyth if (ok) 208*37da2899SCharles.Forsyth stack = x :: stack; 209*37da2899SCharles.Forsyth else { 210*37da2899SCharles.Forsyth op := find(hd argv); 211*37da2899SCharles.Forsyth exec(op); 212*37da2899SCharles.Forsyth last_op = op; 213*37da2899SCharles.Forsyth } 214*37da2899SCharles.Forsyth } 215*37da2899SCharles.Forsyth 216*37da2899SCharles.Forsyth sp: list of real; 217*37da2899SCharles.Forsyth for (; stack != nil; stack = tl stack) 218*37da2899SCharles.Forsyth sp = hd stack :: sp; 219*37da2899SCharles.Forsyth 220*37da2899SCharles.Forsyth # print stack bottom first 221*37da2899SCharles.Forsyth for (; sp != nil; sp = tl sp) 222*37da2899SCharles.Forsyth printnum(hd sp); 223*37da2899SCharles.Forsyth} 224*37da2899SCharles.Forsyth 225*37da2899SCharles.Forsythprintnum(n: real) 226*37da2899SCharles.Forsyth{ 227*37da2899SCharles.Forsyth case outbase { 228*37da2899SCharles.Forsyth CHAR => 229*37da2899SCharles.Forsyth sys->print("@%c\n", int n); 230*37da2899SCharles.Forsyth 2 => 231*37da2899SCharles.Forsyth sys->print("%s\n", binary(big n)); 232*37da2899SCharles.Forsyth 2 | ANNOTATE => 233*37da2899SCharles.Forsyth sys->print("%s\n", annotatebinary(big n)); 234*37da2899SCharles.Forsyth 8 => 235*37da2899SCharles.Forsyth sys->print("%#bo\n", big n); 236*37da2899SCharles.Forsyth 10 => 237*37da2899SCharles.Forsyth sys->print("%g\n", n); 238*37da2899SCharles.Forsyth 16 => 239*37da2899SCharles.Forsyth sys->print("%#bx\n", big n); 240*37da2899SCharles.Forsyth * => 241*37da2899SCharles.Forsyth if ((outbase & RADIX) == 0) 242*37da2899SCharles.Forsyth error("unknown output base " + string outbase); 243*37da2899SCharles.Forsyth sys->print("%s\n", big2string(big n, outbase & ~RADIX)); 244*37da2899SCharles.Forsyth } 245*37da2899SCharles.Forsyth} 246*37da2899SCharles.Forsyth 247*37da2899SCharles.Forsyth# convert to binary string, keeping multiples of 8 digits. 248*37da2899SCharles.Forsythbinary(n: big): string 249*37da2899SCharles.Forsyth{ 250*37da2899SCharles.Forsyth s := "0b"; 251*37da2899SCharles.Forsyth for (j := 7; j > 0; j--) 252*37da2899SCharles.Forsyth if ((n & (big 16rff << (j * 8))) != big 0) 253*37da2899SCharles.Forsyth break; 254*37da2899SCharles.Forsyth for (i := 63; i >= 0; i--) 255*37da2899SCharles.Forsyth if (i / 8 <= j) 256*37da2899SCharles.Forsyth s[len s] = (int (n >> i) & 1) + '0'; 257*37da2899SCharles.Forsyth return s; 258*37da2899SCharles.Forsyth} 259*37da2899SCharles.Forsyth 260*37da2899SCharles.Forsythannotatebinary(n: big): string 261*37da2899SCharles.Forsyth{ 262*37da2899SCharles.Forsyth s := binary(n); 263*37da2899SCharles.Forsyth a := s + "\n "; 264*37da2899SCharles.Forsyth ndig := len s - 2; 265*37da2899SCharles.Forsyth for (i := ndig - 1; i >= 0; i--) 266*37da2899SCharles.Forsyth a[len a] = (i % 10) + '0'; 267*37da2899SCharles.Forsyth if (ndig < 10) 268*37da2899SCharles.Forsyth return a; 269*37da2899SCharles.Forsyth a += "\n "; 270*37da2899SCharles.Forsyth for (i = ndig - 1; i >= 10; i--) { 271*37da2899SCharles.Forsyth if (i % 10 == 0) 272*37da2899SCharles.Forsyth a[len a] = (i / 10) + '0'; 273*37da2899SCharles.Forsyth else 274*37da2899SCharles.Forsyth a[len a] = ' '; 275*37da2899SCharles.Forsyth } 276*37da2899SCharles.Forsyth return a; 277*37da2899SCharles.Forsyth} 278*37da2899SCharles.Forsyth 279*37da2899SCharles.Forsythfind(name: string): Op 280*37da2899SCharles.Forsyth{ 281*37da2899SCharles.Forsyth # XXX could do binary search here if we weren't a lousy performer anyway 282*37da2899SCharles.Forsyth for (i := 0; i < len ops; i++) 283*37da2899SCharles.Forsyth if (name == ops[i].name) 284*37da2899SCharles.Forsyth break; 285*37da2899SCharles.Forsyth if (i == len ops) 286*37da2899SCharles.Forsyth error("invalid operator '" + name + "'"); 287*37da2899SCharles.Forsyth return ops[i]; 288*37da2899SCharles.Forsyth} 289*37da2899SCharles.Forsyth 290*37da2899SCharles.Forsythexec(op: Op) 291*37da2899SCharles.Forsyth{ 292*37da2899SCharles.Forsyth case op.kind { 293*37da2899SCharles.Forsyth UNARY => 294*37da2899SCharles.Forsyth unaryop(op.name, op.op); 295*37da2899SCharles.Forsyth BINARY => 296*37da2899SCharles.Forsyth binaryop(op.name, op.op); 297*37da2899SCharles.Forsyth SPECIAL => 298*37da2899SCharles.Forsyth specialop(op.name, op.op); 299*37da2899SCharles.Forsyth } 300*37da2899SCharles.Forsyth} 301*37da2899SCharles.Forsyth 302*37da2899SCharles.Forsythunaryop(name: string, op: int) 303*37da2899SCharles.Forsyth{ 304*37da2899SCharles.Forsyth assure(1, name); 305*37da2899SCharles.Forsyth v := hd stack; 306*37da2899SCharles.Forsyth case op { 307*37da2899SCharles.Forsyth oNOT => 308*37da2899SCharles.Forsyth v = real !(int v); 309*37da2899SCharles.Forsyth oUMINUS => 310*37da2899SCharles.Forsyth v = -v; 311*37da2899SCharles.Forsyth oFACTORIAL => 312*37da2899SCharles.Forsyth n := int v; 313*37da2899SCharles.Forsyth v = 1.0; 314*37da2899SCharles.Forsyth while (n > 0) 315*37da2899SCharles.Forsyth v *= real n--; 316*37da2899SCharles.Forsyth oPOW10 => 317*37da2899SCharles.Forsyth v = math->pow10(int v); 318*37da2899SCharles.Forsyth oSQRT => 319*37da2899SCharles.Forsyth v = math->sqrt(v); 320*37da2899SCharles.Forsyth oEXP => 321*37da2899SCharles.Forsyth v = math->exp(v); 322*37da2899SCharles.Forsyth oEXPM1 => 323*37da2899SCharles.Forsyth v = math->expm1(v); 324*37da2899SCharles.Forsyth oLOG => 325*37da2899SCharles.Forsyth v = math->log(v); 326*37da2899SCharles.Forsyth oLOG10 => 327*37da2899SCharles.Forsyth v = math->log10(v); 328*37da2899SCharles.Forsyth oLOG1P => 329*37da2899SCharles.Forsyth v = math->log1p(v); 330*37da2899SCharles.Forsyth oCOS => 331*37da2899SCharles.Forsyth v = math->cos(v); 332*37da2899SCharles.Forsyth oCOSH => 333*37da2899SCharles.Forsyth v = math->cosh(v); 334*37da2899SCharles.Forsyth oSIN => 335*37da2899SCharles.Forsyth v = math->sin(v); 336*37da2899SCharles.Forsyth oSINH => 337*37da2899SCharles.Forsyth v = math->sinh(v); 338*37da2899SCharles.Forsyth oTAN => 339*37da2899SCharles.Forsyth v = math->tan(v); 340*37da2899SCharles.Forsyth oTANH => 341*37da2899SCharles.Forsyth v = math->tanh(v); 342*37da2899SCharles.Forsyth oACOS => 343*37da2899SCharles.Forsyth v = math->acos(v); 344*37da2899SCharles.Forsyth oASIN => 345*37da2899SCharles.Forsyth v = math->asin(v); 346*37da2899SCharles.Forsyth oACOSH => 347*37da2899SCharles.Forsyth v = math->acosh(v); 348*37da2899SCharles.Forsyth oASINH => 349*37da2899SCharles.Forsyth v = math->asinh(v); 350*37da2899SCharles.Forsyth oATAN => 351*37da2899SCharles.Forsyth v = math->atan(v); 352*37da2899SCharles.Forsyth oATANH => 353*37da2899SCharles.Forsyth v = math->atanh(v); 354*37da2899SCharles.Forsyth oERF => 355*37da2899SCharles.Forsyth v = math->erf(v); 356*37da2899SCharles.Forsyth oERFC => 357*37da2899SCharles.Forsyth v = math->erfc(v); 358*37da2899SCharles.Forsyth oJ0 => 359*37da2899SCharles.Forsyth v = math->j0(v); 360*37da2899SCharles.Forsyth oJ1 => 361*37da2899SCharles.Forsyth v = math->j1(v); 362*37da2899SCharles.Forsyth oY0 => 363*37da2899SCharles.Forsyth v = math->y0(v); 364*37da2899SCharles.Forsyth oY1 => 365*37da2899SCharles.Forsyth v = math->y1(v); 366*37da2899SCharles.Forsyth oILOGB => 367*37da2899SCharles.Forsyth v = real math->ilogb(v); 368*37da2899SCharles.Forsyth oFABS => 369*37da2899SCharles.Forsyth v = math->fabs(v); 370*37da2899SCharles.Forsyth oCEIL => 371*37da2899SCharles.Forsyth v = math->ceil(v); 372*37da2899SCharles.Forsyth oFLOOR => 373*37da2899SCharles.Forsyth v = math->floor(v); 374*37da2899SCharles.Forsyth oFINITE => 375*37da2899SCharles.Forsyth v = real math->finite(v); 376*37da2899SCharles.Forsyth oISNAN => 377*37da2899SCharles.Forsyth v = real math->isnan(v); 378*37da2899SCharles.Forsyth oRINT => 379*37da2899SCharles.Forsyth v = math->rint(v); 380*37da2899SCharles.Forsyth oRAD => 381*37da2899SCharles.Forsyth v = (v / 360.0) * 2.0 * Math->Pi; 382*37da2899SCharles.Forsyth oDEG => 383*37da2899SCharles.Forsyth v = v / (2.0 * Math->Pi) * 360.0; 384*37da2899SCharles.Forsyth * => 385*37da2899SCharles.Forsyth error("unknown unary operator '" + name + "'"); 386*37da2899SCharles.Forsyth } 387*37da2899SCharles.Forsyth stack = v :: tl stack; 388*37da2899SCharles.Forsyth} 389*37da2899SCharles.Forsyth 390*37da2899SCharles.Forsythbinaryop(name: string, op: int) 391*37da2899SCharles.Forsyth{ 392*37da2899SCharles.Forsyth assure(2, name); 393*37da2899SCharles.Forsyth v1 := hd stack; 394*37da2899SCharles.Forsyth v0 := hd tl stack; 395*37da2899SCharles.Forsyth case op { 396*37da2899SCharles.Forsyth oMULT => 397*37da2899SCharles.Forsyth v0 = v0 * v1; 398*37da2899SCharles.Forsyth oPLUS => 399*37da2899SCharles.Forsyth v0 = v0 + v1; 400*37da2899SCharles.Forsyth oMINUS => 401*37da2899SCharles.Forsyth v0 = v0 - v1; 402*37da2899SCharles.Forsyth oDIVIDE => 403*37da2899SCharles.Forsyth v0 = v0 / v1; 404*37da2899SCharles.Forsyth oDIV => 405*37da2899SCharles.Forsyth v0 = real (big v0 / big v1); 406*37da2899SCharles.Forsyth oMOD => 407*37da2899SCharles.Forsyth v0 = real (big v0 % big v1); 408*37da2899SCharles.Forsyth oSHIFTL => 409*37da2899SCharles.Forsyth v0 = real (big v0 << int v1); 410*37da2899SCharles.Forsyth oSHIFTR => 411*37da2899SCharles.Forsyth v0 = real (big v0 >> int v1); 412*37da2899SCharles.Forsyth oAND => 413*37da2899SCharles.Forsyth v0 = real (big v0 & big v1); 414*37da2899SCharles.Forsyth oOR => 415*37da2899SCharles.Forsyth v0 = real (big v0 | big v1); 416*37da2899SCharles.Forsyth oXOR => 417*37da2899SCharles.Forsyth v0 = real (big v0 ^ big v1); 418*37da2899SCharles.Forsyth oPOW => 419*37da2899SCharles.Forsyth v0 = math->pow(v0, v1); 420*37da2899SCharles.Forsyth oHYPOT => 421*37da2899SCharles.Forsyth v0 = math->hypot(v0, v1); 422*37da2899SCharles.Forsyth oATAN2 => 423*37da2899SCharles.Forsyth v0 = math->atan2(v0, v1); 424*37da2899SCharles.Forsyth oJN => 425*37da2899SCharles.Forsyth v0 = math->jn(int v0, v1); 426*37da2899SCharles.Forsyth oYN => 427*37da2899SCharles.Forsyth v0 = math->yn(int v0, v1); 428*37da2899SCharles.Forsyth oSCALBN => 429*37da2899SCharles.Forsyth v0 = math->scalbn(v0, int v1); 430*37da2899SCharles.Forsyth oCOPYSIGN => 431*37da2899SCharles.Forsyth v0 = math->copysign(v0, v1); 432*37da2899SCharles.Forsyth oFDIM => 433*37da2899SCharles.Forsyth v0 = math->fdim(v0, v1); 434*37da2899SCharles.Forsyth oFMIN => 435*37da2899SCharles.Forsyth v0 = math->fmin(v0, v1); 436*37da2899SCharles.Forsyth oFMAX => 437*37da2899SCharles.Forsyth v0 = math->fmax(v0, v1); 438*37da2899SCharles.Forsyth oNEXTAFTER => 439*37da2899SCharles.Forsyth v0 = math->nextafter(v0, v1); 440*37da2899SCharles.Forsyth oREMAINDER => 441*37da2899SCharles.Forsyth v0 = math->remainder(v0, v1); 442*37da2899SCharles.Forsyth oFMOD => 443*37da2899SCharles.Forsyth v0 = math->fmod(v0, v1); 444*37da2899SCharles.Forsyth * => 445*37da2899SCharles.Forsyth error("unknown binary operator '" + name + "'"); 446*37da2899SCharles.Forsyth } 447*37da2899SCharles.Forsyth stack = v0 :: tl tl stack; 448*37da2899SCharles.Forsyth} 449*37da2899SCharles.Forsyth 450*37da2899SCharles.Forsythspecialop(name: string, op: int) 451*37da2899SCharles.Forsyth{ 452*37da2899SCharles.Forsyth case op { 453*37da2899SCharles.Forsyth oSWAP => 454*37da2899SCharles.Forsyth assure(2, name); 455*37da2899SCharles.Forsyth stack = hd tl stack :: hd stack :: tl tl stack; 456*37da2899SCharles.Forsyth oDUP => 457*37da2899SCharles.Forsyth assure(1, name); 458*37da2899SCharles.Forsyth stack = hd stack :: stack; 459*37da2899SCharles.Forsyth oREP => 460*37da2899SCharles.Forsyth if (last_op.kind != BINARY) 461*37da2899SCharles.Forsyth error("invalid operator '" + last_op.name + "' for rep"); 462*37da2899SCharles.Forsyth while (stack != nil && tl stack != nil) 463*37da2899SCharles.Forsyth exec(last_op); 464*37da2899SCharles.Forsyth oSUM => 465*37da2899SCharles.Forsyth for (sum := 0.0; stack != nil; stack = tl stack) 466*37da2899SCharles.Forsyth sum += hd stack; 467*37da2899SCharles.Forsyth stack = sum :: nil; 468*37da2899SCharles.Forsyth oPRNUM => 469*37da2899SCharles.Forsyth assure(1, name); 470*37da2899SCharles.Forsyth printnum(hd stack); 471*37da2899SCharles.Forsyth stack = tl stack; 472*37da2899SCharles.Forsyth oLGAMMA => 473*37da2899SCharles.Forsyth assure(1, name); 474*37da2899SCharles.Forsyth (s, lg) := math->lgamma(hd stack); 475*37da2899SCharles.Forsyth stack = lg :: real s :: tl stack; 476*37da2899SCharles.Forsyth oMODF => 477*37da2899SCharles.Forsyth assure(1, name); 478*37da2899SCharles.Forsyth (i, r) := math->modf(hd stack); 479*37da2899SCharles.Forsyth stack = r :: real i :: tl stack; 480*37da2899SCharles.Forsyth * => 481*37da2899SCharles.Forsyth error("unknown operator '" + name + "'"); 482*37da2899SCharles.Forsyth } 483*37da2899SCharles.Forsyth} 484*37da2899SCharles.Forsyth 485*37da2899SCharles.Forsythinitpats() 486*37da2899SCharles.Forsyth{ 487*37da2899SCharles.Forsyth pats = array[len pats0] of Regex->Re; 488*37da2899SCharles.Forsyth for (i := 0; i < len pats0; i++) { 489*37da2899SCharles.Forsyth (re, e) := regex->compile("^" + pats0[i] + "$", 0); 490*37da2899SCharles.Forsyth if (re == nil) { 491*37da2899SCharles.Forsyth sys->fprint(stderr, "fc: bad number pattern '^%s$': %s\n", pats0[i], e); 492*37da2899SCharles.Forsyth raise "fail:error"; 493*37da2899SCharles.Forsyth } 494*37da2899SCharles.Forsyth pats[i] = re; 495*37da2899SCharles.Forsyth } 496*37da2899SCharles.Forsyth} 497*37da2899SCharles.Forsyth 498*37da2899SCharles.Forsythnumber(s: string): (int, real) 499*37da2899SCharles.Forsyth{ 500*37da2899SCharles.Forsyth case s { 501*37da2899SCharles.Forsyth "pi" or 502*37da2899SCharles.Forsyth "π" => 503*37da2899SCharles.Forsyth return (1, Math->Pi); 504*37da2899SCharles.Forsyth "e" => 505*37da2899SCharles.Forsyth return (1, 2.71828182845904509); 506*37da2899SCharles.Forsyth "nan" or 507*37da2899SCharles.Forsyth "NaN" => 508*37da2899SCharles.Forsyth return (1, Math->NaN); 509*37da2899SCharles.Forsyth "-nan" or 510*37da2899SCharles.Forsyth "-NaN" => 511*37da2899SCharles.Forsyth return (1, -Math->NaN); 512*37da2899SCharles.Forsyth "infinity" or 513*37da2899SCharles.Forsyth "Infinity" or 514*37da2899SCharles.Forsyth "∞" => 515*37da2899SCharles.Forsyth return (1, Math->Infinity); 516*37da2899SCharles.Forsyth "-infinity" or 517*37da2899SCharles.Forsyth "-Infinity" or 518*37da2899SCharles.Forsyth "-∞" => 519*37da2899SCharles.Forsyth return (1, -Math->Infinity); 520*37da2899SCharles.Forsyth "eps" or 521*37da2899SCharles.Forsyth "macheps" => 522*37da2899SCharles.Forsyth return (1, Math->MachEps); 523*37da2899SCharles.Forsyth } 524*37da2899SCharles.Forsyth for (i := 0; i < len pats; i++) { 525*37da2899SCharles.Forsyth if (regex->execute(pats[i], s) != nil) 526*37da2899SCharles.Forsyth break; 527*37da2899SCharles.Forsyth } 528*37da2899SCharles.Forsyth case i { 529*37da2899SCharles.Forsyth nHEX => 530*37da2899SCharles.Forsyth return base(s, 2, 16); 531*37da2899SCharles.Forsyth nBINARY => 532*37da2899SCharles.Forsyth return base(s, 2, 2); 533*37da2899SCharles.Forsyth nOCTAL => 534*37da2899SCharles.Forsyth return base(s, 1, 8); 535*37da2899SCharles.Forsyth nRADIX1 => 536*37da2899SCharles.Forsyth return base(s, 2, int s); 537*37da2899SCharles.Forsyth nRADIX2 => 538*37da2899SCharles.Forsyth return base(s, 3, int s); 539*37da2899SCharles.Forsyth nREAL => 540*37da2899SCharles.Forsyth return (1, real s); 541*37da2899SCharles.Forsyth nCHAR => 542*37da2899SCharles.Forsyth return (1, real s[1]); 543*37da2899SCharles.Forsyth } 544*37da2899SCharles.Forsyth return (0, Math->NaN); 545*37da2899SCharles.Forsyth} 546*37da2899SCharles.Forsyth 547*37da2899SCharles.Forsythbase(s: string, i: int, radix: int): (int, real) 548*37da2899SCharles.Forsyth{ 549*37da2899SCharles.Forsyth neg := s[0] == '-'; 550*37da2899SCharles.Forsyth if (neg) 551*37da2899SCharles.Forsyth i++; 552*37da2899SCharles.Forsyth n := big 0; 553*37da2899SCharles.Forsyth if (radix == 10) 554*37da2899SCharles.Forsyth n = big s[i:]; 555*37da2899SCharles.Forsyth else if (radix == 0 || radix > 36) 556*37da2899SCharles.Forsyth return (0, Math->NaN); 557*37da2899SCharles.Forsyth else { 558*37da2899SCharles.Forsyth for (; i < len s; i++) { 559*37da2899SCharles.Forsyth c := s[i]; 560*37da2899SCharles.Forsyth if ('0' <= c && c <= '9') 561*37da2899SCharles.Forsyth n = (n * big radix) + big(c - '0'); 562*37da2899SCharles.Forsyth else if ('a' <= c && c < 'a' + radix - 10) 563*37da2899SCharles.Forsyth n = (n * big radix) + big(c - 'a' + 10); 564*37da2899SCharles.Forsyth else if ('A' <= c && c < 'A' + radix - 10) 565*37da2899SCharles.Forsyth n = (n * big radix) + big(c - 'A' + 10); 566*37da2899SCharles.Forsyth else 567*37da2899SCharles.Forsyth return (0, Math->NaN); 568*37da2899SCharles.Forsyth } 569*37da2899SCharles.Forsyth } 570*37da2899SCharles.Forsyth if (neg) 571*37da2899SCharles.Forsyth n = -n; 572*37da2899SCharles.Forsyth return (1, real n); 573*37da2899SCharles.Forsyth} 574*37da2899SCharles.Forsyth 575*37da2899SCharles.Forsyth# stolen from /appl/cmd/sh/expr.b 576*37da2899SCharles.Forsythbig2string(n: big, radix: int): string 577*37da2899SCharles.Forsyth{ 578*37da2899SCharles.Forsyth if (neg := n < big 0) { 579*37da2899SCharles.Forsyth n = -n; 580*37da2899SCharles.Forsyth } 581*37da2899SCharles.Forsyth s := ""; 582*37da2899SCharles.Forsyth do { 583*37da2899SCharles.Forsyth c: int; 584*37da2899SCharles.Forsyth d := int (n % big radix); 585*37da2899SCharles.Forsyth if (d < 10) 586*37da2899SCharles.Forsyth c = '0' + d; 587*37da2899SCharles.Forsyth else 588*37da2899SCharles.Forsyth c = 'a' + d - 10; 589*37da2899SCharles.Forsyth s[len s] = c; 590*37da2899SCharles.Forsyth n /= big radix; 591*37da2899SCharles.Forsyth } while (n > big 0); 592*37da2899SCharles.Forsyth t := s; 593*37da2899SCharles.Forsyth for (i := len s - 1; i >= 0; i--) 594*37da2899SCharles.Forsyth t[len s - 1 - i] = s[i]; 595*37da2899SCharles.Forsyth if (radix != 10) 596*37da2899SCharles.Forsyth t = string radix + "r" + t; 597*37da2899SCharles.Forsyth if (neg) 598*37da2899SCharles.Forsyth return "-" + t; 599*37da2899SCharles.Forsyth return t; 600*37da2899SCharles.Forsyth} 601*37da2899SCharles.Forsyth 602*37da2899SCharles.Forsytherror(e: string) 603*37da2899SCharles.Forsyth{ 604*37da2899SCharles.Forsyth sys->fprint(stderr, "fc: %s\n", e); 605*37da2899SCharles.Forsyth raise "fail:error"; 606*37da2899SCharles.Forsyth} 607*37da2899SCharles.Forsyth 608*37da2899SCharles.Forsythassure(n: int, opname: string) 609*37da2899SCharles.Forsyth{ 610*37da2899SCharles.Forsyth if (len stack < n) 611*37da2899SCharles.Forsyth error("stack too small for op '" + opname + "'"); 612*37da2899SCharles.Forsyth} 613