1implement Units; 2 3#line 2 "units.y" 4# 5# subject to the Lucent Public License 1.02 6# 7include "sys.m"; 8 sys: Sys; 9 10include "draw.m"; 11 12include "bufio.m"; 13 bufio: Bufio; 14 Iobuf: import bufio; 15 16include "math.m"; 17 math: Math; 18 19include "arg.m"; 20 21Ndim: con 15; # number of dimensions 22Nvar: con 203; # hash table size 23Maxe: con 695.0; # log of largest number 24 25Node: adt 26{ 27 val: real; 28 dim: array of int; # [Ndim] schar 29 30 mk: fn(v: real): Node; 31 text: fn(n: self Node): string; 32 add: fn(a: self Node, b: Node): Node; 33 sub: fn(a: self Node, b: Node): Node; 34 mul: fn(a: self Node, b: Node): Node; 35 div: fn(a: self Node, b: Node): Node; 36 xpn: fn(a: self Node, b: int): Node; 37 copy: fn(a: self Node): Node; 38}; 39Var: adt 40{ 41 name: string; 42 node: Node; 43}; 44Prefix: adt 45{ 46 val: real; 47 pname: string; 48}; 49 50digval := 0; 51fi: ref Iobuf; 52fund := array[Ndim] of ref Var; 53line: string; 54lineno := 0; 55linep := 0; 56nerrors := 0; 57peekrune := 0; 58retnode1: Node; 59retnode2: Node; 60retnode: Node; 61sym: string; 62vars := array[Nvar] of list of ref Var; 63vflag := 0; 64 65YYSTYPE: adt { 66 node: Node; 67 var: ref Var; 68 numb: int; 69 val: real; 70}; 71 72YYLEX: adt { 73 lval: YYSTYPE; 74 lex: fn(l: self ref YYLEX): int; 75 error: fn(l: self ref YYLEX, msg: string); 76}; 77 78Units: module { 79 80 init: fn(nil: ref Draw->Context, args: list of string); 81VAL: con 57346; 82VAR: con 57347; 83SUP: con 57348; 84 85}; 86YYEOFCODE: con 1; 87YYERRCODE: con 2; 88YYMAXDEPTH: con 200; 89 90#line 203 "units.y" 91 92 93init(nil: ref Draw->Context, args: list of string) 94{ 95 sys = load Sys Sys->PATH; 96 bufio = load Bufio Bufio->PATH; 97 math = load Math Math->PATH; 98 99 arg := load Arg Arg->PATH; 100 arg->init(args); 101 arg->setusage("units [-v] [file]"); 102 while((o := arg->opt()) != 0) 103 case o { 104 'v' => vflag = 1; 105 * => arg->usage(); 106 } 107 args = arg->argv(); 108 arg = nil; 109 110 file := "/lib/units"; 111 if(args != nil) 112 file = hd args; 113 fi = bufio->open(file, Sys->OREAD); 114 if(fi == nil) { 115 sys->fprint(sys->fildes(2), "units: cannot open %s: %r\n", file); 116 raise "fail:open"; 117 } 118 lex := ref YYLEX; 119 120 # 121 # read the 'units' file to 122 # develop a database 123 # 124 lineno = 0; 125 for(;;) { 126 lineno++; 127 if(readline()) 128 break; 129 if(len line == 0 || line[0] == '/') 130 continue; 131 peekrune = ':'; 132 yyparse(lex); 133 } 134 135 # 136 # read the console to 137 # print ratio of pairs 138 # 139 fi = bufio->fopen(sys->fildes(0), Sys->OREAD); 140 lineno = 0; 141 for(;;) { 142 if(lineno & 1) 143 sys->print("you want: "); 144 else 145 sys->print("you have: "); 146 if(readline()) 147 break; 148 peekrune = '?'; 149 nerrors = 0; 150 yyparse(lex); 151 if(nerrors) 152 continue; 153 if(lineno & 1) { 154 isspcl: int; 155 (isspcl, retnode) = specialcase(retnode2, retnode1); 156 if(isspcl) 157 sys->print("\tis %s\n", retnode.text()); 158 else { 159 retnode = retnode2.div(retnode1); 160 sys->print("\t* %s\n", retnode.text()); 161 retnode = retnode1.div(retnode2); 162 sys->print("\t/ %s\n", retnode.text()); 163 } 164 } else 165 retnode2 = retnode1.copy(); 166 lineno++; 167 } 168 sys->print("\n"); 169} 170 171YYLEX.lex(lex: self ref YYLEX): int 172{ 173 c := peekrune; 174 peekrune = ' '; 175 176 while(c == ' ' || c == '\t'){ 177 if(linep >= len line) 178 return 0; # -1? 179 c = line[linep++]; 180 } 181 case c { 182 '0' to '9' or '.' => 183 digval = c; 184 (lex.lval.val, peekrune) = readreal(gdigit, lex); 185 return VAL; 186 '×' => 187 return '*'; 188 '÷' => 189 return '/'; 190 '¹' or 191 'ⁱ' => 192 lex.lval.numb = 1; 193 return SUP; 194 '²' or 195 '' => 196 lex.lval.numb = 2; 197 return SUP; 198 '³' or 199 '' => 200 lex.lval.numb = 3; 201 return SUP; 202 * => 203 if(ralpha(c)){ 204 sym = ""; 205 for(i:=0;; i++) { 206 sym[i] = c; 207 if(linep >= len line){ 208 c = ' '; 209 break; 210 } 211 c = line[linep++]; 212 if(!ralpha(c)) 213 break; 214 } 215 peekrune = c; 216 lex.lval.var = lookup(0); 217 return VAR; 218 } 219 } 220 return c; 221} 222 223# 224# all characters that have some 225# meaning. rest are usable as names 226# 227ralpha(c: int): int 228{ 229 case c { 230 0 or 231 '+' or 232 '-' or 233 '*' or 234 '/' or 235 '[' or 236 ']' or 237 '(' or 238 ')' or 239 '^' or 240 ':' or 241 '?' or 242 ' ' or 243 '\t' or 244 '.' or 245 '|' or 246 '#' or 247 '¹' or 248 'ⁱ' or 249 '²' or 250 '' or 251 '³' or 252 '' or 253 '×' or 254 '÷' => 255 return 0; 256 } 257 return 1; 258} 259 260gdigit(nil: ref YYLEX): int 261{ 262 c := digval; 263 if(c) { 264 digval = 0; 265 return c; 266 } 267 if(linep >= len line) 268 return 0; 269 return line[linep++]; 270} 271 272YYLEX.error(lex: self ref YYLEX, s: string) 273{ 274 # 275 # hack to intercept message from yaccpar 276 # 277 if(s == "syntax error") { 278 lex.error(sys->sprint("syntax error, last name: %s", sym)); 279 return; 280 } 281 sys->print("%d: %s\n\t%s\n", lineno, line, s); 282 nerrors++; 283 if(nerrors > 5) { 284 sys->print("too many errors\n"); 285 raise "fail:errors"; 286 } 287} 288 289yyerror(s: string) 290{ 291 l := ref YYLEX; 292 l.error(s); 293} 294 295Node.mk(v: real): Node 296{ 297 return (v, array[Ndim] of {* => 0}); 298} 299 300Node.add(a: self Node, b: Node): Node 301{ 302 c := Node.mk(fadd(a.val, b.val)); 303 for(i:=0; i<Ndim; i++) { 304 d := a.dim[i]; 305 c.dim[i] = d; 306 if(d != b.dim[i]) 307 yyerror("add must be like units"); 308 } 309 return c; 310} 311 312Node.sub(a: self Node, b: Node): Node 313{ 314 c := Node.mk(fadd(a.val, -b.val)); 315 for(i:=0; i<Ndim; i++) { 316 d := a.dim[i]; 317 c.dim[i] = d; 318 if(d != b.dim[i]) 319 yyerror("sub must be like units"); 320 } 321 return c; 322} 323 324Node.mul(a: self Node, b: Node): Node 325{ 326 c := Node.mk(fmul(a.val, b.val)); 327 for(i:=0; i<Ndim; i++) 328 c.dim[i] = a.dim[i] + b.dim[i]; 329 return c; 330} 331 332Node.div(a: self Node, b: Node): Node 333{ 334 c := Node.mk(fdiv(a.val, b.val)); 335 for(i:=0; i<Ndim; i++) 336 c.dim[i] = a.dim[i] - b.dim[i]; 337 return c; 338} 339 340Node.xpn(a: self Node, b: int): Node 341{ 342 c := Node.mk(1.0); 343 if(b < 0) { 344 b = -b; 345 for(i:=0; i<b; i++) 346 c = c.div(a); 347 } else 348 for(i:=0; i<b; i++) 349 c = c.mul(a); 350 return c; 351} 352 353Node.copy(a: self Node): Node 354{ 355 c := Node.mk(a.val); 356 c.dim[0:] = a.dim; 357 return c; 358} 359 360specialcase(a, b: Node): (int, Node) 361{ 362 c := Node.mk(0.0); 363 d1 := 0; 364 d2 := 0; 365 for(i:=1; i<Ndim; i++) { 366 d := a.dim[i]; 367 if(d) { 368 if(d != 1 || d1) 369 return (0, c); 370 d1 = i; 371 } 372 d = b.dim[i]; 373 if(d) { 374 if(d != 1 || d2) 375 return (0, c); 376 d2 = i; 377 } 378 } 379 if(d1 == 0 || d2 == 0) 380 return (0, c); 381 382 if(fund[d1].name == "°C" && 383 fund[d2].name == "°F" && 384 b.val == 1.0) { 385 c = b.copy(); 386 c.val = a.val * 9. / 5. + 32.; 387 return (1, c); 388 } 389 390 if(fund[d1].name == "°F" && 391 fund[d2].name == "°C" && 392 b.val == 1.0) { 393 c = b.copy(); 394 c.val = (a.val - 32.) * 5. / 9.; 395 return (1, c); 396 } 397 return (0, c); 398} 399 400printdim(d: int, n: int): string 401{ 402 s := ""; 403 if(n) { 404 v := fund[d]; 405 if(v != nil) 406 s += " "+v.name; 407 else 408 s += sys->sprint(" [%d]", d); 409 case n { 410 1 => 411 ; 412 2 => 413 s += "²"; 414 3 => 415 s += "³"; 416 4 => 417 s += "⁴"; 418 * => 419 s += sys->sprint("^%d", n); 420 } 421 } 422 return s; 423} 424 425Node.text(n: self Node): string 426{ 427 str := sys->sprint("%.7g", n.val); 428 f := 0; 429 for(i:=1; i<len n.dim; i++) { 430 d := n.dim[i]; 431 if(d > 0) 432 str += printdim(i, d); 433 else if(d < 0) 434 f = 1; 435 } 436 437 if(f) { 438 str += " /"; 439 for(i=1; i<len n.dim; i++) { 440 d := n.dim[i]; 441 if(d < 0) 442 str += printdim(i, -d); 443 } 444 } 445 446 return str; 447} 448 449readline(): int 450{ 451 linep = 0; 452 line = ""; 453 for(i:=0;; i++) { 454 c := fi.getc(); 455 if(c < 0) 456 return 1; 457 if(c == '\n') 458 return 0; 459 line[i] = c; 460 } 461} 462 463lookup(f: int): ref Var 464{ 465 h := 0; 466 for(i:=0; i < len sym; i++) 467 h = h*13 + sym[i]; 468 if(h < 0) 469 h ^= int 16r80000000; 470 h %= len vars; 471 472 for(vl:=vars[h]; vl != nil; vl = tl vl) 473 if((hd vl).name == sym) 474 return hd vl; 475 if(f) 476 return nil; 477 v := ref Var(sym, Node.mk(0.0)); 478 vars[h] = v :: vars[h]; 479 480 p := 1.0; 481 for(;;) { 482 p = fmul(p, pname()); 483 if(p == 0.0) 484 break; 485 w := lookup(1); 486 if(w != nil) { 487 v.node = w.node.copy(); 488 v.node.val = fmul(v.node.val, p); 489 break; 490 } 491 } 492 return v; 493} 494 495prefix: array of Prefix = array[] of { 496 (1e-24, "yocto"), 497 (1e-21, "zepto"), 498 (1e-18, "atto"), 499 (1e-15, "femto"), 500 (1e-12, "pico"), 501 (1e-9, "nano"), 502 (1e-6, "micro"), 503 (1e-6, "μ"), 504 (1e-3, "milli"), 505 (1e-2, "centi"), 506 (1e-1, "deci"), 507 (1e1, "deka"), 508 (1e2, "hecta"), 509 (1e2, "hecto"), 510 (1e3, "kilo"), 511 (1e6, "mega"), 512 (1e6, "meg"), 513 (1e9, "giga"), 514 (1e12, "tera"), 515 (1e15, "peta"), 516 (1e18, "exa"), 517 (1e21, "zetta"), 518 (1e24, "yotta") 519}; 520 521pname(): real 522{ 523 # 524 # rip off normal prefices 525 # 526Pref: 527 for(i:=0; i < len prefix; i++) { 528 p := prefix[i].pname; 529 for(j:=0; j < len p; j++) 530 if(j >= len sym || p[j] != sym[j]) 531 continue Pref; 532 sym = sym[j:]; 533 return prefix[i].val; 534 } 535 536 # 537 # rip off 's' suffixes 538 # 539 for(j:=0; j < len sym; j++) 540 ; 541 j--; 542 # j>1 is special hack to disallow ms finding m 543 if(j > 1 && sym[j] == 's') { 544 sym = sym[0:j]; 545 return 1.0; 546 } 547 return 0.0; 548} 549 550# 551# reads a floating-point number 552# 553 554readreal[T](f: ref fn(t: T): int, vp: T): (real, int) 555{ 556 s := ""; 557 c := f(vp); 558 while(c == ' ' || c == '\t') 559 c = f(vp); 560 if(c == '-' || c == '+'){ 561 s[len s] = c; 562 c = f(vp); 563 } 564 start := len s; 565 while(c >= '0' && c <= '9'){ 566 s[len s] = c; 567 c = f(vp); 568 } 569 if(c == '.'){ 570 s[len s] = c; 571 c = f(vp); 572 while(c >= '0' && c <= '9'){ 573 s[len s] = c; 574 c = f(vp); 575 } 576 } 577 if(len s > start && (c == 'e' || c == 'E')){ 578 s[len s] = c; 579 c = f(vp); 580 if(c == '-' || c == '+'){ 581 s[len s] = c; 582 c = f(vp); 583 } 584 while(c >= '0' && c <= '9'){ 585 s[len s] = c; 586 c = f(vp); 587 } 588 } 589 return (real s, c); 590} 591 592# 593# careful floating point 594# 595 596fmul(a, b: real): real 597{ 598 l: real; 599 600 if(a <= 0.0) { 601 if(a == 0.0) 602 return 0.0; 603 l = math->log(-a); 604 } else 605 l = math->log(a); 606 607 if(b <= 0.0) { 608 if(b == 0.0) 609 return 0.0; 610 l += math->log(-b); 611 } else 612 l += math->log(b); 613 614 if(l > Maxe) { 615 yyerror("overflow in multiply"); 616 return 1.0; 617 } 618 if(l < -Maxe) { 619 yyerror("underflow in multiply"); 620 return 0.0; 621 } 622 return a*b; 623} 624 625fdiv(a, b: real): real 626{ 627 l: real; 628 629 if(a <= 0.0) { 630 if(a == 0.0) 631 return 0.0; 632 l = math->log(-a); 633 } else 634 l = math->log(a); 635 636 if(b <= 0.0) { 637 if(b == 0.0) { 638 yyerror("division by zero"); 639 return 1.0; 640 } 641 l -= math->log(-b); 642 } else 643 l -= math->log(b); 644 645 if(l > Maxe) { 646 yyerror("overflow in divide"); 647 return 1.0; 648 } 649 if(l < -Maxe) { 650 yyerror("underflow in divide"); 651 return 0.0; 652 } 653 return a/b; 654} 655 656fadd(a, b: real): real 657{ 658 return a + b; 659} 660yyexca := array[] of {-1, 1, 661 1, -1, 662 -2, 0, 663}; 664YYNPROD: con 21; 665YYPRIVATE: con 57344; 666yytoknames: array of string; 667yystates: array of string; 668yydebug: con 0; 669YYLAST: con 41; 670yyact := array[] of { 671 8, 10, 7, 9, 16, 17, 12, 11, 20, 21, 672 15, 31, 23, 6, 4, 12, 11, 22, 13, 5, 673 1, 27, 28, 0, 14, 30, 29, 13, 20, 20, 674 25, 26, 0, 24, 18, 19, 16, 17, 2, 0, 675 3, 676}; 677yypact := array[] of { 678 31,-1000, 9, 11, 2, 26, 22, 11, 3, -3, 679-1000,-1000,-1000, 11, 26,-1000, 11, 11, 11, 11, 680 3,-1000, 11, 11, -6, 22, 22, 11, 11, -3, 681-1000,-1000, 682}; 683yypgo := array[] of { 684 0, 20, 19, 1, 3, 0, 2, 13, 685}; 686yyr1 := array[] of { 687 0, 1, 1, 1, 1, 2, 2, 2, 7, 7, 688 7, 6, 6, 5, 5, 5, 4, 4, 3, 3, 689 3, 690}; 691yyr2 := array[] of { 692 0, 3, 3, 2, 1, 1, 3, 3, 1, 3, 693 3, 1, 2, 1, 2, 3, 1, 3, 1, 1, 694 3, 695}; 696yychk := array[] of { 697-1000, -1, 7, 9, 5, -2, -7, -6, -5, -4, 698 -3, 5, 4, 16, -2, 8, 10, 11, 12, 13, 699 -5, 6, 14, 15, -2, -7, -7, -6, -6, -4, 700 -3, 17, 701}; 702yydef := array[] of { 703 0, -2, 0, 4, 0, 3, 5, 8, 11, 13, 704 16, 18, 19, 0, 1, 2, 0, 0, 0, 0, 705 12, 14, 0, 0, 0, 6, 7, 9, 10, 15, 706 17, 20, 707}; 708yytok1 := array[] of { 709 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 710 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 711 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 712 3, 3, 3, 3, 3, 8, 3, 3, 3, 3, 713 16, 17, 12, 10, 3, 11, 3, 13, 3, 3, 714 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 715 3, 3, 3, 9, 3, 3, 3, 3, 3, 3, 716 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 717 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 718 3, 3, 3, 3, 14, 3, 3, 3, 3, 3, 719 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 720 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 721 3, 3, 3, 3, 15, 722}; 723yytok2 := array[] of { 724 2, 3, 4, 5, 6, 725}; 726yytok3 := array[] of { 727 0 728}; 729 730YYSys: module 731{ 732 FD: adt 733 { 734 fd: int; 735 }; 736 fildes: fn(fd: int): ref FD; 737 fprint: fn(fd: ref FD, s: string, *): int; 738}; 739 740yysys: YYSys; 741yystderr: ref YYSys->FD; 742 743YYFLAG: con -1000; 744 745# parser for yacc output 746 747yytokname(yyc: int): string 748{ 749 if(yyc > 0 && yyc <= len yytoknames && yytoknames[yyc-1] != nil) 750 return yytoknames[yyc-1]; 751 return "<"+string yyc+">"; 752} 753 754yystatname(yys: int): string 755{ 756 if(yys >= 0 && yys < len yystates && yystates[yys] != nil) 757 return yystates[yys]; 758 return "<"+string yys+">\n"; 759} 760 761yylex1(yylex: ref YYLEX): int 762{ 763 c : int; 764 yychar := yylex.lex(); 765 if(yychar <= 0) 766 c = yytok1[0]; 767 else if(yychar < len yytok1) 768 c = yytok1[yychar]; 769 else if(yychar >= YYPRIVATE && yychar < YYPRIVATE+len yytok2) 770 c = yytok2[yychar-YYPRIVATE]; 771 else{ 772 n := len yytok3; 773 c = 0; 774 for(i := 0; i < n; i+=2) { 775 if(yytok3[i+0] == yychar) { 776 c = yytok3[i+1]; 777 break; 778 } 779 } 780 if(c == 0) 781 c = yytok2[1]; # unknown char 782 } 783 if(yydebug >= 3) 784 yysys->fprint(yystderr, "lex %.4ux %s\n", yychar, yytokname(c)); 785 return c; 786} 787 788YYS: adt 789{ 790 yyv: YYSTYPE; 791 yys: int; 792}; 793 794yyparse(yylex: ref YYLEX): int 795{ 796 if(yydebug >= 1 && yysys == nil) { 797 yysys = load YYSys "$Sys"; 798 yystderr = yysys->fildes(2); 799 } 800 801 yys := array[YYMAXDEPTH] of YYS; 802 803 yyval: YYSTYPE; 804 yystate := 0; 805 yychar := -1; 806 yynerrs := 0; # number of errors 807 yyerrflag := 0; # error recovery flag 808 yyp := -1; 809 yyn := 0; 810 811yystack: 812 for(;;){ 813 # put a state and value onto the stack 814 if(yydebug >= 4) 815 yysys->fprint(yystderr, "char %s in %s", yytokname(yychar), yystatname(yystate)); 816 817 yyp++; 818 if(yyp >= len yys) 819 yys = (array[len yys * 2] of YYS)[0:] = yys; 820 yys[yyp].yys = yystate; 821 yys[yyp].yyv = yyval; 822 823 for(;;){ 824 yyn = yypact[yystate]; 825 if(yyn > YYFLAG) { # simple state 826 if(yychar < 0) 827 yychar = yylex1(yylex); 828 yyn += yychar; 829 if(yyn >= 0 && yyn < YYLAST) { 830 yyn = yyact[yyn]; 831 if(yychk[yyn] == yychar) { # valid shift 832 yychar = -1; 833 yyp++; 834 if(yyp >= len yys) 835 yys = (array[len yys * 2] of YYS)[0:] = yys; 836 yystate = yyn; 837 yys[yyp].yys = yystate; 838 yys[yyp].yyv = yylex.lval; 839 if(yyerrflag > 0) 840 yyerrflag--; 841 if(yydebug >= 4) 842 yysys->fprint(yystderr, "char %s in %s", yytokname(yychar), yystatname(yystate)); 843 continue; 844 } 845 } 846 } 847 848 # default state action 849 yyn = yydef[yystate]; 850 if(yyn == -2) { 851 if(yychar < 0) 852 yychar = yylex1(yylex); 853 854 # look through exception table 855 for(yyxi:=0;; yyxi+=2) 856 if(yyexca[yyxi] == -1 && yyexca[yyxi+1] == yystate) 857 break; 858 for(yyxi += 2;; yyxi += 2) { 859 yyn = yyexca[yyxi]; 860 if(yyn < 0 || yyn == yychar) 861 break; 862 } 863 yyn = yyexca[yyxi+1]; 864 if(yyn < 0){ 865 yyn = 0; 866 break yystack; 867 } 868 } 869 870 if(yyn != 0) 871 break; 872 873 # error ... attempt to resume parsing 874 if(yyerrflag == 0) { # brand new error 875 yylex.error("syntax error"); 876 yynerrs++; 877 if(yydebug >= 1) { 878 yysys->fprint(yystderr, "%s", yystatname(yystate)); 879 yysys->fprint(yystderr, "saw %s\n", yytokname(yychar)); 880 } 881 } 882 883 if(yyerrflag != 3) { # incompletely recovered error ... try again 884 yyerrflag = 3; 885 886 # find a state where "error" is a legal shift action 887 while(yyp >= 0) { 888 yyn = yypact[yys[yyp].yys] + YYERRCODE; 889 if(yyn >= 0 && yyn < YYLAST) { 890 yystate = yyact[yyn]; # simulate a shift of "error" 891 if(yychk[yystate] == YYERRCODE) 892 continue yystack; 893 } 894 895 # the current yyp has no shift onn "error", pop stack 896 if(yydebug >= 2) 897 yysys->fprint(yystderr, "error recovery pops state %d, uncovers %d\n", 898 yys[yyp].yys, yys[yyp-1].yys ); 899 yyp--; 900 } 901 # there is no state on the stack with an error shift ... abort 902 yyn = 1; 903 break yystack; 904 } 905 906 # no shift yet; clobber input char 907 if(yydebug >= 2) 908 yysys->fprint(yystderr, "error recovery discards %s\n", yytokname(yychar)); 909 if(yychar == YYEOFCODE) { 910 yyn = 1; 911 break yystack; 912 } 913 yychar = -1; 914 # try again in the same state 915 } 916 917 # reduction by production yyn 918 if(yydebug >= 2) 919 yysys->fprint(yystderr, "reduce %d in:\n\t%s", yyn, yystatname(yystate)); 920 921 yypt := yyp; 922 yyp -= yyr2[yyn]; 923# yyval = yys[yyp+1].yyv; 924 yym := yyn; 925 926 # consult goto table to find next state 927 yyn = yyr1[yyn]; 928 yyg := yypgo[yyn]; 929 yyj := yyg + yys[yyp].yys + 1; 930 931 if(yyj >= YYLAST || yychk[yystate=yyact[yyj]] != -yyn) 932 yystate = yyact[yyg]; 933 case yym { 934 9351=> 936#line 90 "units.y" 937{ 938 f := yys[yypt-1].yyv.var.node.dim[0]; 939 yys[yypt-1].yyv.var.node = yys[yypt-0].yyv.node.copy(); 940 yys[yypt-1].yyv.var.node.dim[0] = 1; 941 if(f) 942 yyerror(sys->sprint("redefinition of %s", yys[yypt-1].yyv.var.name)); 943 else if(vflag) 944 sys->print("%s\t%s\n", yys[yypt-1].yyv.var.name, yys[yypt-1].yyv.var.node.text()); 945 } 9462=> 947#line 100 "units.y" 948{ 949 for(i:=1; i<Ndim; i++) 950 if(fund[i] == nil) 951 break; 952 if(i >= Ndim) { 953 yyerror("too many dimensions"); 954 i = Ndim-1; 955 } 956 fund[i] = yys[yypt-1].yyv.var; 957 958 f := yys[yypt-1].yyv.var.node.dim[0]; 959 yys[yypt-1].yyv.var.node = Node.mk(1.0); 960 yys[yypt-1].yyv.var.node.dim[0] = 1; 961 yys[yypt-1].yyv.var.node.dim[i] = 1; 962 if(f) 963 yyerror(sys->sprint("redefinition of %s", yys[yypt-1].yyv.var.name)); 964 else if(vflag) 965 sys->print("%s\t#\n", yys[yypt-1].yyv.var.name); 966 } 9673=> 968#line 120 "units.y" 969{ 970 retnode1 = yys[yypt-0].yyv.node.copy(); 971 } 9724=> 973#line 124 "units.y" 974{ 975 retnode1 = Node.mk(1.0); 976 } 9775=> 978yyval.node = yys[yyp+1].yyv.node; 9796=> 980#line 131 "units.y" 981{ 982 yyval.node = yys[yypt-2].yyv.node.add(yys[yypt-0].yyv.node); 983 } 9847=> 985#line 135 "units.y" 986{ 987 yyval.node = yys[yypt-2].yyv.node.sub(yys[yypt-0].yyv.node); 988 } 9898=> 990yyval.node = yys[yyp+1].yyv.node; 9919=> 992#line 142 "units.y" 993{ 994 yyval.node = yys[yypt-2].yyv.node.mul(yys[yypt-0].yyv.node); 995 } 99610=> 997#line 146 "units.y" 998{ 999 yyval.node = yys[yypt-2].yyv.node.div(yys[yypt-0].yyv.node); 1000 } 100111=> 1002yyval.node = yys[yyp+1].yyv.node; 100312=> 1004#line 153 "units.y" 1005{ 1006 yyval.node = yys[yypt-1].yyv.node.mul(yys[yypt-0].yyv.node); 1007 } 100813=> 1009yyval.node = yys[yyp+1].yyv.node; 101014=> 1011#line 160 "units.y" 1012{ 1013 yyval.node = yys[yypt-1].yyv.node.xpn(yys[yypt-0].yyv.numb); 1014 } 101515=> 1016#line 164 "units.y" 1017{ 1018 for(i:=1; i<Ndim; i++) 1019 if(yys[yypt-0].yyv.node.dim[i]) { 1020 yyerror("exponent has units"); 1021 yyval.node = yys[yypt-2].yyv.node; 1022 break; 1023 } 1024 if(i >= Ndim) { 1025 i = int yys[yypt-0].yyv.node.val; 1026 if(real i != yys[yypt-0].yyv.node.val) 1027 yyerror("exponent not integral"); 1028 yyval.node = yys[yypt-2].yyv.node.xpn(i); 1029 } 1030 } 103116=> 1032yyval.node = yys[yyp+1].yyv.node; 103317=> 1034#line 182 "units.y" 1035{ 1036 yyval.node = yys[yypt-2].yyv.node.div(yys[yypt-0].yyv.node); 1037 } 103818=> 1039#line 188 "units.y" 1040{ 1041 if(yys[yypt-0].yyv.var.node.dim[0] == 0) { 1042 yyerror(sys->sprint("undefined %s", yys[yypt-0].yyv.var.name)); 1043 yyval.node = Node.mk(1.0); 1044 } else 1045 yyval.node = yys[yypt-0].yyv.var.node.copy(); 1046 } 104719=> 1048#line 196 "units.y" 1049{ 1050 yyval.node = Node.mk(yys[yypt-0].yyv.val); 1051 } 105220=> 1053#line 200 "units.y" 1054{ 1055 yyval.node = yys[yypt-1].yyv.node; 1056 } 1057 } 1058 } 1059 1060 return yyn; 1061} 1062