|
|
1.1 root 1: /*% mkcdate >cdate.h && yacc % && cyntax y.tab.c && cc -go # y.tab.c
2: * New units
3: */
4: %{
5: #define NDIM 11
6: #define NUNIT 700
7: #define NSTRBUF 8192
8: struct unit{
9: char *name;
10: double coef;
11: int dim[NDIM];
12: }unit[NUNIT];
13: struct unit *dim[NDIM];
14: char strbuf[NSTRBUF];
15: char *strp=strbuf;
16: struct unit mul(), div(), pwr(), prim();
17: %}
18: %term NUMBER NAME SQUARE CUBE
19: %type<u> u unit NUMBER NAME
20: %union{
21: struct unit u;
22: }
23: %left SQUARE CUBE
24: %left '^'
25: %%
26: unit: {static struct unit u={0,1}; $$=u;}
27: | unit u {$$=mul($1, $2);}
28: | unit '/' u {$$=div($1, $3);}
29: u: NUMBER
30: | NAME
31: | '@' NUMBER {$$=prim($2);}
32: | '(' unit ')' {$$=$2;}
33: | SQUARE u {$$=pwr($2, 2.);}
34: | CUBE u {$$=pwr($2, 3.);}
35: | u '^' NUMBER {$$=pwr($1, $3.coef);}
36: %%
37: #include <stdio.h>
38: #include <math.h>
39: #include <errno.h>
40: #include <sys/types.h>
41: #include <sys/stat.h>
42: #include "cdate.h"
43: char *strchr();
44: char *lp, *line;
45: digit(c){ return '0'<=c && c<='9'; }
46: char idchar[256];
47: int nerror;
48: idcharfn(c){
49: switch(c){
50: case '\0':
51: case '*':
52: case '/':
53: case '@':
54: case '(':
55: case ')':
56: case '^':
57: case ' ':
58: case '\t':
59: case '\n':
60: return 0;
61: default:
62: return 1;
63: }
64: }
65: struct prefix{
66: int len;
67: double coef;
68: char *name;
69: }prefix[]={
70: 0, 1e18, "exa",
71: 0, 1e15, "peta",
72: 0, 1e12, "tera",
73: 0, 1e9, "giga",
74: 0, 1e6, "mega",
75: 0, 1e6, "meg",
76: 0, 1e4, "myria",
77: 0, 1e3, "kilo",
78: 0, 1e2, "hekta",
79: 0, 1e2, "hekto",
80: 0, 1e1, "deka",
81: 0, 1.5, "sesqui",
82: 0, .5, "hemi",
83: 0, .5, "demi",
84: 0, .5, "semi",
85: 0, 1e-1, "deci",
86: 0, 1e-2, "centi",
87: 0, 1e-3, "milli",
88: 0, 1e-6, "micro",
89: 0, 1e-9, "nano",
90: 0, 1e-12, "pico",
91: 0, 1e-15, "femto",
92: 0, 1e-18, "atto",
93: /* Are these a good idea? */
94: 0, 1e9, "G",
95: 0, 1e6, "M",
96: 0, 1e3, "k",
97: 0, 1e-3, "m",
98: 0, 1e-6, "u",
99: 0, 1e-9, "n",
100: 0, 1e-12, "p",
101: 0, 0, 0
102: };
103: hash(s)
104: register char *s;
105: {
106: register i, j;
107: i=0;
108: for(j=0;*s;j++)
109: i+=*s++*j;
110: i%=NUNIT;
111: return i<0?i+NUNIT:i;
112: }
113: /*
114: * symbol table lookup subroutine: look for the name. If not found,
115: * try stripping prefixes.
116: */
117: struct unit *look2(name)
118: char *name;
119: {
120: register char *s=name;
121: register i, j;
122: register struct prefix *p;
123: double coef=1;
124: static struct unit mul;
125: do{
126: i=j=hash(s);
127: do{
128: if(unit[j].name==0)
129: break;
130: if(strcmp(s, unit[j].name)==0){
131: if(coef==1)
132: return unit+j;
133: mul=unit[j];
134: mul.coef*=coef;
135: return &mul;
136: }
137: if(++j==NUNIT)
138: j=0;
139: }while(j!=i);
140: for(p=prefix;p->name;p++)
141: if(strncmp(s, p->name, p->len)==0){
142: coef*=p->coef;
143: s+=p->len;
144: if(*s=='\0'){ /* no unit, just prefixes */
145: mul.coef=coef;
146: for(i=0;i!=NDIM;i++)
147: mul.dim[i]=0;
148: return &mul;
149: }
150: break;
151: }
152: }while(p->name);
153: return 0;
154: }
155: /*
156: * Look for the unit with the given name.
157: * Perhaps deleting a trailing `s' will help.
158: */
159: struct unit *lookup(name)
160: char *name;
161: {
162: register struct unit *u=look2(name);
163: if(u==0 && name[strlen(name)-1]=='s'){
164: name[strlen(name)-1]=0;
165: u=look2(name);
166: }
167: if(u==0){
168: fprintf(stderr, "Unknown unit %s\n", name);
169: nerror++;
170: }
171: return u;
172: }
173: char *copy(s)
174: register char *s;
175: {
176: char *strcpy();
177: register l=strlen(s)+1;
178: if(strp+l>&strbuf[NSTRBUF]){
179: fprintf(stderr, "Units: out of space (copy)\n");
180: exit(1);
181: }
182: strcpy(strp, s);
183: strp+=l;
184: return strp-l;
185: }
186: yylex(){
187: register char *s;
188: char token[512];
189: register digits, dot, i;
190: register struct unit *up;
191: while(*lp==' ' || *lp=='\t')
192: lp++;
193: if(*lp=='\0')
194: return EOF;
195: if(digit(*lp) || *lp=='-' || *lp=='.'){
196: s=token;
197: digits=0;
198: dot=0;
199: do{
200: if(digit(*lp))
201: digits++;
202: else if(*lp=='.')
203: dot++;
204: *s++=*lp++;
205: }while(digit(*lp) || *lp=='.');
206: if(!digits || dot>1)
207: yyerror("Bad number");
208: else if(*lp=='e' || *lp=='E'){
209: *s++=*lp++;
210: if(*lp=='+' || *lp=='-')
211: *s++=*lp++;
212: if(!digit(*lp))
213: yyerror("Bad number");
214: else{
215: do
216: *s++=*lp++;
217: while(digit(*lp));
218: }
219: }
220: *s='\0';
221: yylval.u.coef=atof(token);
222: for(i=0;i!=NDIM;i++)
223: yylval.u.dim[i]=0;
224: return NUMBER;
225: }
226: if(idchar[*lp]){
227: for(s=token;idchar[*s=*lp];s++,lp++);
228: *s='\0';
229: if(strcmp(token, "square")==0) return SQUARE;
230: if(strcmp(token, "sq")==0) return SQUARE;
231: if(strcmp(token, "cubic")==0) return CUBE;
232: if(strcmp(token, "cu")==0) return CUBE;
233: if(up=lookup(token))
234: yylval.u=*up;
235: else
236: yylval.u.coef=5551212.;
237: return NAME;
238: }
239: switch(*lp){
240: case '*':
241: case '/':
242: case '(':
243: case ')':
244: case '^':
245: case '@':
246: return *lp++;
247: case '\0':
248: return EOF;
249: default:
250: yyerror("Bad char");
251: return EOF;
252: }
253: }
254: conformable(u, v)
255: register struct unit *u, *v;
256: {
257: register i;
258: for(i=0;i!=NDIM;i++)
259: if(u->dim[i]!=v->dim[i])
260: return 0;
261: return 1;
262: }
263: char *dname(i){
264: static char v[]="%000";
265: if(dim[i])
266: return dim[i]->name;
267: sprintf(v, "%%%d", i);
268: return v;
269: }
270: punit(u)
271: register struct unit *u;
272: {
273: register i;
274: printf("\t%g", u->coef);
275: for(i=0;i!=NDIM;i++)
276: switch(u->dim[i]){
277: case 0: break;
278: case 1: printf(" %s", dname(i)); break;
279: default: printf(" %s^%d", dname(i), u->dim[i]); break;
280: }
281: putchar('\n');
282: }
283: yyerror(m)
284: char *m;
285: {
286: register char *s;
287: printf("%s\n", line);
288: for(s=line;s!=lp;s++)
289: putchar(*s=='\t'?'\t':' ');
290: printf("^\n%s\n", m);
291: nerror++;
292: }
293: struct unit mul(u, v)
294: struct unit u, v;
295: {
296: register i;
297: u.coef*=v.coef;
298: for(i=0;i!=NDIM;i++)
299: u.dim[i]+=v.dim[i];
300: return u;
301: }
302: struct unit div(u, v)
303: struct unit u, v;
304: {
305: register i;
306: u.coef/=v.coef;
307: for(i=0;i!=NDIM;i++)
308: u.dim[i]-=v.dim[i];
309: return u;
310: }
311: double huge = HUGE;
312: double zero = 0.;
313: struct unit pwr(u, f)
314: struct unit u;
315: double f;
316: {
317: register i;
318: if(f!=(int)f)
319: yyerror("Sorry, only integer powers");
320: errno = 0;
321: u.coef=pow(u.coef, f);
322: if(errno == EDOM)
323: zero/zero;
324: if(errno == ERANGE)
325: huge*huge;
326: for(i=0;i!=NDIM;i++)
327: u.dim[i]*=f;
328: return u;
329: }
330: struct unit prim(u)
331: struct unit u;
332: {
333: register d=u.coef;
334: if(d!=u.coef)
335: yyerror("Primitive unit must be integral");
336: else if(d<0 || NDIM<=u.coef)
337: yyerror("Primitive unit out of range");
338: else{
339: u.coef=1;
340: u.dim[d]=1;
341: }
342: return u;
343: }
344: /*
345: * readunits sucks, since it knows too many details about the
346: * difference between file1 and file2
347: */
348: readunits(file1, file2)
349: char *file1, *file2;
350: {
351: register FILE *f;
352: char buf[512];
353: register char *s, *name;
354: register i, j, k, nunit;
355: int n;
356: struct stat ascii1, ascii2, bin;
357: sprintf(buf, "%s.bin", file1);
358: if(stat(file1, &ascii1)>=0 && stat(file2, &ascii2)>=0
359: && stat(buf, &bin)>=0 && cdate<bin.st_mtime
360: && ascii1.st_mtime<bin.st_mtime && ascii2.st_mtime<bin.st_mtime){
361: if((i=open(buf, 0))>=0
362: && read(i, (char *)unit, sizeof unit)==sizeof unit
363: && read(i, (char *)strbuf, sizeof strbuf)==sizeof strbuf
364: && read(i, (char *)&n, sizeof n)==sizeof n
365: && read(i, (char *)dim, sizeof dim)==sizeof dim){
366: strp=strbuf+n;
367: close(i);
368: return;
369: }
370: close(i);
371: for(i=0;i!=NUNIT;i++)
372: unit[i].name=0;
373: }
374: for(k=0;k!=2;k++){
375: f=fopen(k==0?file1:file2, "r");
376: if(f==0){
377: perror(k==0?file1:file2);
378: if(k==1)
379: break;
380: exit(1);
381: }
382: while(fgets(buf, sizeof buf, f)){
383: if((s=strchr(buf, '#')) || (s=strchr(buf, '\n')))
384: *s='\0';
385: for(name=buf;*name==' ' || *name=='\t';name++);
386: if(*name=='\0')
387: continue;
388: for(s=name;idchar[*s];s++);
389: if(*s!=' ' && *s!='\t'){
390: fprintf(stderr, "Bad unit `%s'\n", name);
391: nerror++;
392: continue;
393: }
394: *s++='\0';
395: line=lp=s;
396: if(yyparse())
397: continue;
398: i=j=hash(name);
399: do{
400: if(unit[j].name==0){
401: unit[j]=yyval.u;
402: unit[j].name=copy(name);
403: if(unit[j].coef==1){
404: nunit=0;
405: for(i=0;i!=NDIM;i++)
406: switch(unit[j].dim[i]){
407: case 1: nunit++; n=i; break;
408: case 0: break;
409: default: nunit=2; break;
410: }
411: if(nunit==1 && dim[n]==0)
412: dim[n]=unit+j;
413: }
414: goto Ok;
415: }
416: if(++j==NUNIT)
417: j=0;
418: }while(j!=i);
419: fprintf(stderr, "Units: out of space (NUNIT)\n");
420: exit(1);
421: Ok: ;
422: }
423: fclose(f);
424: }
425: sprintf(buf, "%s.bin", file1);
426: umask(0);
427: if((i=creat(buf, 0666))>=0){
428: n=strp-strbuf;
429: write(i, (char *)unit, sizeof unit);
430: write(i, (char *)strbuf, sizeof strbuf);
431: write(i, (char *)&n, sizeof n);
432: write(i, (char *)dim, sizeof dim);
433: close(i);
434: }
435: }
436: getunit(u, prompt, match)
437: struct unit *u;
438: char *prompt;
439: {
440: char buf[512];
441: register char *s;
442: Again:
443: do{
444: nerror=0;
445: printf("%s: ", prompt);
446: if(fgets(buf, sizeof buf, stdin)==0)
447: return 0;
448: if((s=strchr(buf, '#')) || (s=strchr(buf, '\n')))
449: *s='\0';
450: for(s=buf;*s==' ' || *s=='\t';s++);
451: if(match && *s=='?'){
452: matchunit();
453: goto Again;
454: }
455: line=lp=s;
456: }while(yyparse() || nerror);
457: *u=yyval.u;
458: return 1;
459: }
460: #include <setjmp.h>
461: jmp_buf jmp;
462: err(){
463: signal(8, err);
464: printf("Floating point error\n");
465: nerror++;
466: errno = 0;
467: longjmp(jmp, 0);
468: }
469: struct unit have, want;
470: matchunit(){
471: register struct unit *u;
472: for(u=unit;u!=&unit[NUNIT];u++)
473: if(u->name && conformable(&have, u))
474: printf("%g %s\n", have.coef/u->coef, u->name);
475: }
476: main(){
477: register i;
478: for(i=0;prefix[i].name;i++)
479: prefix[i].len=strlen(prefix[i].name);
480: for(i=0;i!=256;i++)
481: idchar[i]=idcharfn(i);
482: setjmp(jmp);
483: signal(8, err);
484: readunits("/usr/lib/Units", "/usr/lib/Monetary.Units");
485: while(getunit(&have, "You have", 0) && getunit(&want, "You want", 1)){
486: if(conformable(&have, &want))
487: printf("* %g\n/ %g\n",
488: have.coef/want.coef, want.coef/have.coef);
489: else{
490: printf("conformability\n");
491: punit(&have);
492: punit(&want);
493: }
494: }
495: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.