Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/planix-v0/sys/src/cmd/units.y – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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