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