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