|
|
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.