Annotation of researchv10dc/cmd/units/units.y-1, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.