units.y 11 KB

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