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