Annotation of researchv10no/cmd/units/units.y, 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 <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: }

unix.superglobalmegacorp.com

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