units.y 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785
  1. %{
  2. #include <u.h>
  3. #include <libc.h>
  4. #include <bio.h>
  5. enum
  6. {
  7. Ndim = 15, /* number of dimensions */
  8. Nsym = 40, /* size of a name */
  9. Nvar = 203, /* hash table size */
  10. Maxe = 695, /* log of largest number */
  11. };
  12. typedef struct Var Var;
  13. typedef struct Node Node;
  14. typedef struct Prefix Prefix;
  15. struct Node
  16. {
  17. double val;
  18. schar dim[Ndim];
  19. };
  20. struct Var
  21. {
  22. Rune name[Nsym];
  23. Node node;
  24. Var* link;
  25. };
  26. struct Prefix
  27. {
  28. double val;
  29. Rune* pname;
  30. };
  31. char buf[100];
  32. int digval;
  33. Biobuf* fi;
  34. Biobuf linebuf;
  35. Var* fund[Ndim];
  36. Rune line[1000];
  37. ulong lineno;
  38. int linep;
  39. int nerrors;
  40. Node one;
  41. int peekrune;
  42. Node retnode1;
  43. Node retnode2;
  44. Node retnode;
  45. Rune sym[Nsym];
  46. Var* vars[Nvar];
  47. int vflag;
  48. extern void add(Node*, Node*, Node*);
  49. extern void div(Node*, Node*, Node*);
  50. extern int specialcase(Node*, Node*, Node*);
  51. extern double fadd(double, double);
  52. extern double fdiv(double, double);
  53. extern double fmul(double, double);
  54. extern int gdigit(void*);
  55. extern Var* lookup(int);
  56. extern void main(int, char*[]);
  57. extern void mul(Node*, Node*, Node*);
  58. extern void ofile(void);
  59. extern double pname(void);
  60. extern void printdim(char*, int, int);
  61. extern int ralpha(int);
  62. extern int readline(void);
  63. extern void sub(Node*, Node*, Node*);
  64. extern int Ufmt(Fmt*);
  65. extern void xpn(Node*, Node*, int);
  66. extern void yyerror(char*, ...);
  67. extern int yylex(void);
  68. extern int yyparse(void);
  69. typedef Node* indnode;
  70. %}
  71. %union
  72. {
  73. Node node;
  74. Var* var;
  75. int numb;
  76. double val;
  77. }
  78. %type <node> prog expr expr0 expr1 expr2 expr3 expr4
  79. %token <val> VAL
  80. %token <var> VAR
  81. %token <numb> SUP
  82. %%
  83. prog:
  84. ':' VAR expr
  85. {
  86. int f;
  87. f = $2->node.dim[0];
  88. $2->node = $3;
  89. $2->node.dim[0] = 1;
  90. if(f)
  91. yyerror("redefinition of %S", $2->name);
  92. else
  93. if(vflag)
  94. print("%S\t%U\n", $2->name, &$2->node);
  95. }
  96. | ':' VAR '#'
  97. {
  98. int f, i;
  99. for(i=1; i<Ndim; i++)
  100. if(fund[i] == 0)
  101. break;
  102. if(i >= Ndim) {
  103. yyerror("too many dimensions");
  104. i = Ndim-1;
  105. }
  106. fund[i] = $2;
  107. f = $2->node.dim[0];
  108. $2->node = one;
  109. $2->node.dim[0] = 1;
  110. $2->node.dim[i] = 1;
  111. if(f)
  112. yyerror("redefinition of %S", $2->name);
  113. else
  114. if(vflag)
  115. print("%S\t#\n", $2->name);
  116. }
  117. | '?' expr
  118. {
  119. retnode1 = $2;
  120. }
  121. | '?'
  122. {
  123. retnode1 = one;
  124. }
  125. expr:
  126. expr4
  127. | expr '+' expr4
  128. {
  129. add(&$$, &$1, &$3);
  130. }
  131. | expr '-' expr4
  132. {
  133. sub(&$$, &$1, &$3);
  134. }
  135. expr4:
  136. expr3
  137. | expr4 '*' expr3
  138. {
  139. mul(&$$, &$1, &$3);
  140. }
  141. | expr4 '/' expr3
  142. {
  143. div(&$$, &$1, &$3);
  144. }
  145. expr3:
  146. expr2
  147. | expr3 expr2
  148. {
  149. mul(&$$, &$1, &$2);
  150. }
  151. expr2:
  152. expr1
  153. | expr2 SUP
  154. {
  155. xpn(&$$, &$1, $2);
  156. }
  157. | expr2 '^' expr1
  158. {
  159. int i;
  160. for(i=1; i<Ndim; i++)
  161. if($3.dim[i]) {
  162. yyerror("exponent has units");
  163. $$ = $1;
  164. break;
  165. }
  166. if(i >= Ndim) {
  167. i = $3.val;
  168. if(i != $3.val)
  169. yyerror("exponent not integral");
  170. xpn(&$$, &$1, i);
  171. }
  172. }
  173. expr1:
  174. expr0
  175. | expr1 '|' expr0
  176. {
  177. div(&$$, &$1, &$3);
  178. }
  179. expr0:
  180. VAR
  181. {
  182. if($1->node.dim[0] == 0) {
  183. yyerror("undefined %S", $1->name);
  184. $$ = one;
  185. } else
  186. $$ = $1->node;
  187. }
  188. | VAL
  189. {
  190. $$ = one;
  191. $$.val = $1;
  192. }
  193. | '(' expr ')'
  194. {
  195. $$ = $2;
  196. }
  197. %%
  198. int
  199. yylex(void)
  200. {
  201. int c, i;
  202. c = peekrune;
  203. peekrune = ' ';
  204. loop:
  205. if((c >= '0' && c <= '9') || c == '.')
  206. goto numb;
  207. if(ralpha(c))
  208. goto alpha;
  209. switch(c) {
  210. case ' ':
  211. case '\t':
  212. c = line[linep++];
  213. goto loop;
  214. case L'×':
  215. return '*';
  216. case L'÷':
  217. return '/';
  218. case L'¹':
  219. case L'ⁱ':
  220. yylval.numb = 1;
  221. return SUP;
  222. case L'²':
  223. case L'⁲':
  224. yylval.numb = 2;
  225. return SUP;
  226. case L'³':
  227. case L'⁳':
  228. yylval.numb = 3;
  229. return SUP;
  230. }
  231. return c;
  232. alpha:
  233. memset(sym, 0, sizeof(sym));
  234. for(i=0;; i++) {
  235. if(i < nelem(sym))
  236. sym[i] = c;
  237. c = line[linep++];
  238. if(!ralpha(c))
  239. break;
  240. }
  241. sym[nelem(sym)-1] = 0;
  242. peekrune = c;
  243. yylval.var = lookup(0);
  244. return VAR;
  245. numb:
  246. digval = c;
  247. yylval.val = charstod(gdigit, 0);
  248. return VAL;
  249. }
  250. void
  251. main(int argc, char *argv[])
  252. {
  253. char *file;
  254. ARGBEGIN {
  255. default:
  256. print("usage: units [-v] [file]\n");
  257. exits("usage");
  258. case 'v':
  259. vflag = 1;
  260. break;
  261. } ARGEND
  262. file = "/lib/units";
  263. if(argc > 0)
  264. file = argv[0];
  265. fi = Bopen(file, OREAD);
  266. if(fi == 0) {
  267. print("cant open: %s\n", file);
  268. exits("open");
  269. }
  270. fmtinstall('U', Ufmt);
  271. one.val = 1;
  272. /*
  273. * read the 'units' file to
  274. * develope a database
  275. */
  276. lineno = 0;
  277. for(;;) {
  278. lineno++;
  279. if(readline())
  280. break;
  281. if(line[0] == 0 || line[0] == '/')
  282. continue;
  283. peekrune = ':';
  284. yyparse();
  285. }
  286. /*
  287. * read the console to
  288. * print ratio of pairs
  289. */
  290. Bterm(fi);
  291. fi = &linebuf;
  292. Binit(fi, 0, OREAD);
  293. lineno = 0;
  294. for(;;) {
  295. if(lineno & 1)
  296. print("you want: ");
  297. else
  298. print("you have: ");
  299. if(readline())
  300. break;
  301. peekrune = '?';
  302. nerrors = 0;
  303. yyparse();
  304. if(nerrors)
  305. continue;
  306. if(lineno & 1) {
  307. if(specialcase(&retnode, &retnode2, &retnode1))
  308. print("\tis %U\n", &retnode);
  309. else {
  310. div(&retnode, &retnode2, &retnode1);
  311. print("\t* %U\n", &retnode);
  312. div(&retnode, &retnode1, &retnode2);
  313. print("\t/ %U\n", &retnode);
  314. }
  315. } else
  316. retnode2 = retnode1;
  317. lineno++;
  318. }
  319. print("\n");
  320. exits(0);
  321. }
  322. /*
  323. * all characters that have some
  324. * meaning. rest are usable as names
  325. */
  326. int
  327. ralpha(int c)
  328. {
  329. switch(c) {
  330. case 0:
  331. case '+':
  332. case '-':
  333. case '*':
  334. case '/':
  335. case '[':
  336. case ']':
  337. case '(':
  338. case ')':
  339. case '^':
  340. case ':':
  341. case '?':
  342. case ' ':
  343. case '\t':
  344. case '.':
  345. case '|':
  346. case '#':
  347. case L'¹':
  348. case L'ⁱ':
  349. case L'²':
  350. case L'⁲':
  351. case L'³':
  352. case L'⁳':
  353. case L'×':
  354. case L'÷':
  355. return 0;
  356. }
  357. return 1;
  358. }
  359. int
  360. gdigit(void*)
  361. {
  362. int c;
  363. c = digval;
  364. if(c) {
  365. digval = 0;
  366. return c;
  367. }
  368. c = line[linep++];
  369. peekrune = c;
  370. return c;
  371. }
  372. void
  373. yyerror(char *fmt, ...)
  374. {
  375. va_list arg;
  376. /*
  377. * hack to intercept message from yaccpar
  378. */
  379. if(strcmp(fmt, "syntax error") == 0) {
  380. yyerror("syntax error, last name: %S", sym);
  381. return;
  382. }
  383. va_start(arg, fmt);
  384. vseprint(buf, buf+sizeof(buf), fmt, arg);
  385. va_end(arg);
  386. print("%ld: %S\n\t%s\n", lineno, line, buf);
  387. nerrors++;
  388. if(nerrors > 5) {
  389. print("too many errors\n");
  390. exits("errors");
  391. }
  392. }
  393. void
  394. add(Node *c, Node *a, Node *b)
  395. {
  396. int i, d;
  397. for(i=0; i<Ndim; i++) {
  398. d = a->dim[i];
  399. c->dim[i] = d;
  400. if(d != b->dim[i])
  401. yyerror("add must be like units");
  402. }
  403. c->val = fadd(a->val, b->val);
  404. }
  405. void
  406. sub(Node *c, Node *a, Node *b)
  407. {
  408. int i, d;
  409. for(i=0; i<Ndim; i++) {
  410. d = a->dim[i];
  411. c->dim[i] = d;
  412. if(d != b->dim[i])
  413. yyerror("sub must be like units");
  414. }
  415. c->val = fadd(a->val, -b->val);
  416. }
  417. void
  418. mul(Node *c, Node *a, Node *b)
  419. {
  420. int i;
  421. for(i=0; i<Ndim; i++)
  422. c->dim[i] = a->dim[i] + b->dim[i];
  423. c->val = fmul(a->val, b->val);
  424. }
  425. void
  426. div(Node *c, Node *a, Node *b)
  427. {
  428. int i;
  429. for(i=0; i<Ndim; i++)
  430. c->dim[i] = a->dim[i] - b->dim[i];
  431. c->val = fdiv(a->val, b->val);
  432. }
  433. void
  434. xpn(Node *c, Node *a, int b)
  435. {
  436. int i;
  437. *c = one;
  438. if(b < 0) {
  439. b = -b;
  440. for(i=0; i<b; i++)
  441. div(c, c, a);
  442. } else
  443. for(i=0; i<b; i++)
  444. mul(c, c, a);
  445. }
  446. int
  447. specialcase(Node *c, Node *a, Node *b)
  448. {
  449. int i, d, d1, d2;
  450. d1 = 0;
  451. d2 = 0;
  452. for(i=1; i<Ndim; i++) {
  453. d = a->dim[i];
  454. if(d) {
  455. if(d != 1 || d1)
  456. return 0;
  457. d1 = i;
  458. }
  459. d = b->dim[i];
  460. if(d) {
  461. if(d != 1 || d2)
  462. return 0;
  463. d2 = i;
  464. }
  465. }
  466. if(d1 == 0 || d2 == 0)
  467. return 0;
  468. if(memcmp(fund[d1]->name, L"°C", 3*sizeof(Rune)) == 0 &&
  469. memcmp(fund[d2]->name, L"°F", 3*sizeof(Rune)) == 0 &&
  470. b->val == 1) {
  471. memcpy(c->dim, b->dim, sizeof(c->dim));
  472. c->val = a->val * 9. / 5. + 32.;
  473. return 1;
  474. }
  475. if(memcmp(fund[d1]->name, L"°F", 3*sizeof(Rune)) == 0 &&
  476. memcmp(fund[d2]->name, L"°C", 3*sizeof(Rune)) == 0 &&
  477. b->val == 1) {
  478. memcpy(c->dim, b->dim, sizeof(c->dim));
  479. c->val = (a->val - 32.) * 5. / 9.;
  480. return 1;
  481. }
  482. return 0;
  483. }
  484. void
  485. printdim(char *str, int d, int n)
  486. {
  487. Var *v;
  488. if(n) {
  489. v = fund[d];
  490. if(v)
  491. sprint(strchr(str, 0), " %S", v->name);
  492. else
  493. sprint(strchr(str, 0), " [%d]", d);
  494. switch(n) {
  495. case 1:
  496. break;
  497. case 2:
  498. strcat(str, "²");
  499. break;
  500. case 3:
  501. strcat(str, "³");
  502. break;
  503. default:
  504. sprint(strchr(str, 0), "^%d", n);
  505. }
  506. }
  507. }
  508. int
  509. Ufmt(Fmt *fp)
  510. {
  511. char str[200];
  512. Node *n;
  513. int f, i, d;
  514. n = va_arg(fp->args, Node*);
  515. sprint(str, "%g", n->val);
  516. f = 0;
  517. for(i=1; i<Ndim; i++) {
  518. d = n->dim[i];
  519. if(d > 0)
  520. printdim(str, i, d);
  521. else
  522. if(d < 0)
  523. f = 1;
  524. }
  525. if(f) {
  526. strcat(str, " /");
  527. for(i=1; i<Ndim; i++) {
  528. d = n->dim[i];
  529. if(d < 0)
  530. printdim(str, i, -d);
  531. }
  532. }
  533. return fmtstrcpy(fp, str);
  534. }
  535. int
  536. readline(void)
  537. {
  538. int i, c;
  539. linep = 0;
  540. for(i=0;; i++) {
  541. c = Bgetrune(fi);
  542. if(c < 0)
  543. return 1;
  544. if(c == '\n')
  545. break;
  546. if(i < nelem(line))
  547. line[i] = c;
  548. }
  549. if(i >= nelem(line))
  550. i = nelem(line)-1;
  551. line[i] = 0;
  552. return 0;
  553. }
  554. Var*
  555. lookup(int f)
  556. {
  557. int i;
  558. Var *v, *w;
  559. double p;
  560. ulong h;
  561. h = 0;
  562. for(i=0; sym[i]; i++)
  563. h = h*13 + sym[i];
  564. h %= nelem(vars);
  565. for(v=vars[h]; v; v=v->link)
  566. if(memcmp(sym, v->name, sizeof(sym)) == 0)
  567. return v;
  568. if(f)
  569. return 0;
  570. v = malloc(sizeof(*v));
  571. if(v == nil) {
  572. fprint(2, "out of memory\n");
  573. exits("mem");
  574. }
  575. memset(v, 0, sizeof(*v));
  576. memcpy(v->name, sym, sizeof(sym));
  577. v->link = vars[h];
  578. vars[h] = v;
  579. p = 1;
  580. for(;;) {
  581. p = fmul(p, pname());
  582. if(p == 0)
  583. break;
  584. w = lookup(1);
  585. if(w) {
  586. v->node = w->node;
  587. v->node.val = fmul(v->node.val, p);
  588. break;
  589. }
  590. }
  591. return v;
  592. }
  593. Prefix prefix[] =
  594. {
  595. 1e-24, L"yocto",
  596. 1e-21, L"zepto",
  597. 1e-18, L"atto",
  598. 1e-15, L"femto",
  599. 1e-12, L"pico",
  600. 1e-9, L"nano",
  601. 1e-6, L"micro",
  602. 1e-6, L"μ",
  603. 1e-3, L"milli",
  604. 1e-2, L"centi",
  605. 1e-1, L"deci",
  606. 1e1, L"deka",
  607. 1e2, L"hecta",
  608. 1e2, L"hecto",
  609. 1e3, L"kilo",
  610. 1e6, L"mega",
  611. 1e6, L"meg",
  612. 1e9, L"giga",
  613. 1e12, L"tera",
  614. 1e15, L"peta",
  615. 1e18, L"exa",
  616. 1e21, L"zetta",
  617. 1e24, L"yotta",
  618. 0, 0
  619. };
  620. double
  621. pname(void)
  622. {
  623. Rune *p;
  624. int i, j, c;
  625. /*
  626. * rip off normal prefixs
  627. */
  628. for(i=0; p=prefix[i].pname; i++) {
  629. for(j=0; c=p[j]; j++)
  630. if(c != sym[j])
  631. goto no;
  632. memmove(sym, sym+j, (Nsym-j)*sizeof(*sym));
  633. memset(sym+(Nsym-j), 0, j*sizeof(*sym));
  634. return prefix[i].val;
  635. no:;
  636. }
  637. /*
  638. * rip off 's' suffixes
  639. */
  640. for(j=0; sym[j]; j++)
  641. ;
  642. j--;
  643. /* j>1 is special hack to disallow ms finding m */
  644. if(j > 1 && sym[j] == 's') {
  645. sym[j] = 0;
  646. return 1;
  647. }
  648. return 0;
  649. }
  650. /*
  651. * careful floating point
  652. */
  653. double
  654. fmul(double a, double b)
  655. {
  656. double l;
  657. if(a <= 0) {
  658. if(a == 0)
  659. return 0;
  660. l = log(-a);
  661. } else
  662. l = log(a);
  663. if(b <= 0) {
  664. if(b == 0)
  665. return 0;
  666. l += log(-b);
  667. } else
  668. l += log(b);
  669. if(l > Maxe) {
  670. yyerror("overflow in multiply");
  671. return 1;
  672. }
  673. if(l < -Maxe) {
  674. yyerror("underflow in multiply");
  675. return 0;
  676. }
  677. return a*b;
  678. }
  679. double
  680. fdiv(double a, double b)
  681. {
  682. double l;
  683. if(a <= 0) {
  684. if(a == 0)
  685. return 0;
  686. l = log(-a);
  687. } else
  688. l = log(a);
  689. if(b <= 0) {
  690. if(b == 0) {
  691. yyerror("division by zero");
  692. return 1;
  693. }
  694. l -= log(-b);
  695. } else
  696. l -= log(b);
  697. if(l > Maxe) {
  698. yyerror("overflow in divide");
  699. return 1;
  700. }
  701. if(l < -Maxe) {
  702. yyerror("underflow in divide");
  703. return 0;
  704. }
  705. return a/b;
  706. }
  707. double
  708. fadd(double a, double b)
  709. {
  710. return a + b;
  711. }