Annotation of capa/capa51/pProj/capaUnit.c, revision 1.14

1.5       albertel    1: /* functions to handle the unit parser/comparison engine
                      2:    Copyright (C) 1992-2000 Michigan State University
                      3: 
                      4:    The CAPA system is free software; you can redistribute it and/or
1.7       albertel    5:    modify it under the terms of the GNU General Public License as
1.5       albertel    6:    published by the Free Software Foundation; either version 2 of the
                      7:    License, or (at your option) any later version.
                      8: 
                      9:    The CAPA system is distributed in the hope that it will be useful,
                     10:    but WITHOUT ANY WARRANTY; without even the implied warranty of
                     11:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1.7       albertel   12:    General Public License for more details.
1.5       albertel   13: 
1.7       albertel   14:    You should have received a copy of the GNU General Public
1.5       albertel   15:    License along with the CAPA system; see the file COPYING.  If not,
                     16:    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
1.6       albertel   17:    Boston, MA 02111-1307, USA.
                     18: 
                     19:    As a special exception, you have permission to link this program
                     20:    with the TtH/TtM library and distribute executables, as long as you
                     21:    follow the requirements of the GNU GPL in regard to all of the
                     22:    software in the executable aside from TtH/TtM.
                     23: */
1.1       albertel   24: 
                     25: /* =||>|===================== capaUnit.c   =====================|<||= */
                     26: /*   created by Isaac Tsai   1997                                    */
1.6       albertel   27: /*   by Isaac Tsai 1997, 1998, 1999                      */
1.1       albertel   28: /* =||>|========================================================|<||= */
                     29: #include <stdio.h>        /* fopen()  */
                     30: #include <stdlib.h>
                     31: #include <ctype.h>        /* isalnum()   */
                     32: #include <string.h>
                     33: #include <math.h>
1.8       albertel   34: #include <float.h>
1.1       albertel   35: 
                     36: #include "capaParser.h"
                     37: 
                     38: int      PrefixTbl[QUARTER_K];
                     39: int      BaseUnitcnt;
                     40: double   CScale[BASEUNIT_LIMIT];
                     41: double   CExp[BASEUNIT_LIMIT];
                     42: char     CSymb[BASEUNIT_LIMIT][SYMBOL_MAXLEN];
                     43: Unit_t  *UnitTree_p;
                     44: double   MinSquared;
                     45: Unit_t  *MinSquaredUnit_p;
                     46: Unit_t  *InqueryUnit_p;
                     47: double  *TmpAexp, *TmpBexp;
                     48: Unit_t  *EquivUnit[BASEUNIT_LIMIT];
                     49: double   MinValue[BASEUNIT_LIMIT];
                     50: int      EquivUnitCnt;
                     51: char     Sbuf[ONE_K_SIZE];
                     52: int      Sidx;
                     53: Unit_t  *Pstack[ONE_K_SIZE];
                     54: int      Ptopidx;
                     55: int      gUnitError;
                     56: 
                     57: FILE    *ufp;
                     58: 
                     59: /* ==================================================================== */
                     60: void c_ignorewhite(FILE *f) /* ignore white spaces from a file stream */
                     61: {
                     62:   register int c;
                     63:   register int ok;
                     64:  
                     65:   ok = 0;
                     66:   do {
                     67:     do {  c = getc(f);
                     68:     } while ( isspace(c) );
                     69:     ungetc(c,f);
                     70:     if (c == '#') {
                     71:       while (getc(f) != '\n');
                     72:     } else ok = 1;
                     73:   } while( ! ok);
                     74: }
                     75: 
                     76: int c_getint(FILE *f)  /* returns an integer from the file stream */
                     77: {
                     78:     int c;
                     79:     int value;
                     80:  
                     81:     c_ignorewhite(f);
                     82:     c = fgetc(f);
                     83:     if (!isdigit(c)) {
                     84:         fprintf(stderr,"Error: Expected digit, got %c\n", c);
                     85:         exit(-1);
                     86:     }
                     87:     ungetc(c,f);
                     88:     fscanf(f,"%d", &value);
                     89:     return(value);
                     90: }
                     91: int c_getsec_range(FILE *f,int *low,int *high)
                     92: {
                     93:     int c;
                     94:     int tmp, result;
                     95:  
                     96:     c_ignorewhite(f);
                     97:     c = fgetc(f);
                     98:     if( c == '[' ) { /* specify a range of sections */
                     99:       do {  c = getc(f); } while ( isspace(c) );
                    100:       if (!isdigit(c)) {
                    101:         fprintf(stderr,"Error in section range format, expecting a number.\n");
                    102:         result = -1;
                    103:         return (result);
                    104:       }
                    105:       ungetc(c,f);
                    106:       fscanf(f,"%d", low);
                    107:       do {  c = getc(f); } while ( isspace(c) );
                    108:       if( c == ',' ) {
                    109:         do {  c = getc(f); } while ( isspace(c) );
                    110:         if (!isdigit(c)) {
                    111:           fprintf(stderr,"Error in section range format, expecting a number.\n");
                    112:           result = -1;
                    113:           return (result);
                    114:         }
                    115:         ungetc(c,f);
                    116:         fscanf(f,"%d", high);
                    117:         do {  c = getc(f); } while ( isspace(c) );
                    118:         if( c == ']' ) {
                    119:           if( *high < *low ) {
                    120:             tmp= *high; *high = *low; *low =tmp;
                    121:           }
                    122:           if(*low <=0) {
                    123:             *low = 1;
                    124:           }
                    125:           if(*high <=0) {
                    126:             *high =1;
                    127:           }
                    128:           /* printf("Section range=>[%d,%d]\n",*low,*high); */
                    129:           result = 2;
                    130:         }
                    131:       } else { /* no , specified */
                    132:         result = -1;
                    133:         return (result);
                    134:       }
                    135:     } else { /* specify a section only */
                    136:       if (!isdigit(c)) {
                    137:         fprintf(stderr,"Error: Expected digit, got %c\n", c);
                    138:         result = -1;
                    139:         return (result);
                    140:       }
                    141:       ungetc(c,f);
                    142:       fscanf(f,"%d", low);
                    143:       result = 1;
                    144:     }
                    145:     return (result);
                    146: }
                    147: 
                    148: double c_getdouble(FILE *f)
                    149: {
                    150:     int c;
                    151:     double value;
                    152:  
                    153:     c_ignorewhite(f);
                    154:     c = fgetc(f);
                    155:     if (!isdigit(c)) {
                    156:         fprintf(stderr,"Error: Expected digit, got %c\n", c);
                    157:         exit(-1);
                    158:     }
                    159:     ungetc(c,f);
                    160:     fscanf(f,"%lf", &value);
                    161:     return(value);
                    162: }
                    163: 
                    164: /*   read until encountered an unrecognizable char */
                    165: /*      space, #, anything other than alphanum, {}-^_ */
                    166: char *c_getword(FILE *f) 
                    167: {
                    168:   register int c;
                    169:   register int idx;
                    170:   char     tmp_string[ONE_K];
                    171:   char     *new_string;
                    172: 
                    173:   idx = 0;
                    174:   c_ignorewhite(f);
                    175:     do {  c = getc(f);
                    176:       tmp_string[idx] = c;
                    177:       idx++;
                    178:     } while (isalnum(c) || c == '{' || c == '}' || c == '-' || 
                    179:              c == '^'   || c == '_' );
                    180:     ungetc(c,f); idx--;
                    181:     tmp_string[idx] = 0;
                    182:     new_string = (char *)malloc( (idx+1)*sizeof(char) );
                    183:     strncpy(new_string,tmp_string, (idx+1) );
                    184:   
                    185:   return (new_string);
                    186: }
                    187: /*   read until encountered a newline, # */
                    188: char *c_getstring(FILE *f) 
                    189: {
                    190:   register int c;
                    191:   register int idx;
                    192:   char     tmp_string[1024];
                    193:   char     *new_string;
                    194: 
                    195:   idx = 0;
                    196:   c_ignorewhite(f);
                    197:     do {  c = getc(f);
                    198:       tmp_string[idx] = c;
                    199:       idx++;
                    200:     } while (isalnum(c) || c == '{' || c == '}' || c == '-' || 
                    201:              c == '^'   || c == ' ' || c == ',' || c == ';' ||
                    202:              c == '.'   || c == '(' || c == ')' || c == '=' ||
                    203:              c == '+'   || c == '*' || c == '/' );
                    204:     ungetc(c,f); idx--;
                    205:     tmp_string[idx] = 0;
                    206:     c = tmp_string[idx-1];
                    207:     while( c == ' ') {   /* get rid of trailing white space */
                    208:        idx--;
                    209:        c = tmp_string[idx-1];
                    210:     }
                    211:     tmp_string[idx] = 0;
                    212:     new_string = (char *)malloc( (idx+1)*sizeof(char) );
                    213:     strncpy(new_string,tmp_string, (idx+1) );
                    214:   
                    215:   return (new_string);
                    216: }
                    217: char *c_getcomment(FILE *f) 
                    218: {
                    219:   register int c;
                    220:   register int idx;
                    221:   char     tmp_string[ONE_K];
                    222:   char     *new_string;
                    223: 
                    224:   idx = 0;
                    225:   while (getc(f) != '#');
                    226:   while ((c = getc(f)) == ' ');  ungetc(c,f);
                    227:     do {  c = getc(f);
                    228:       tmp_string[idx] = c;
                    229:       idx++;
                    230:     } while ( isprint(c) );
                    231: /*
                    232:     } while (isalnum(c) || c == '{' || c == '}' || c == '-' || 
                    233:              c == '^'   || c == ' ' || c == ',' || c == ';' ||
                    234:              c == '.'   || c == '(' || c == ')' || c == '=' );
                    235: */
                    236:     ungetc(c,f); idx--;
                    237:     tmp_string[idx] = 0;
                    238:     c = tmp_string[idx-1];
                    239:     while( c == ' ') {   /* get rid of trailing white space */
                    240:        idx--;
                    241:        c = tmp_string[idx-1];
                    242:     }
                    243:     tmp_string[idx] = 0;
                    244:     new_string = (char *)malloc( (idx+1)*sizeof(char) );
                    245:     strncpy(new_string,tmp_string, (idx+1) );
                    246:   
                    247:   return (new_string);
                    248: }
                    249: void  c_moveto_unit(FILE *f)
                    250: {
                    251:   register int c;
                    252:   register int ok;
                    253:  
                    254:   ok = 0;
                    255:   do {
                    256:     do {  c = getc(f);
                    257:     } while (c != '<' );
                    258:     c = getc(f);
                    259:     if (c == '<') {
                    260:       ungetc(c,f); ungetc(c,f); ok=1;
                    261:     }
                    262:   } while( ! ok);
                    263: }
                    264: 
                    265: int  c_gettype(FILE *f)
                    266: {
                    267:   register int c;
                    268:   register int idx;
                    269:   char     tmp_string[ONE_K];
                    270:   char     new_string[ONE_K];
                    271:   
                    272:   idx = 0;
                    273: PRESTART:
                    274:   c_ignorewhite(f);
                    275:   while ((c=getc(f)) != '<') { if ( (char)c==(char)EOF ) return U_UNKNOWN; }
                    276:   c = getc(f);
                    277:   if( c == '<' ) {
                    278:     c_ignorewhite(f);
                    279: PREEND:
                    280:     do {  c = getc(f);
                    281:       tmp_string[idx] = toupper(c);
                    282:       idx++;
                    283:     } while ( c != '>' );
                    284:     c = getc(f); 
                    285:     if( c == '>' ) {
                    286:       idx--;
                    287:       tmp_string[idx] = 0;
                    288:       c = tmp_string[idx-1];
                    289:       while( c == ' ') {   /* get rid of trailing white space */
                    290:         idx--;
                    291:         c = tmp_string[idx-1];
                    292:       }
                    293:       tmp_string[idx] = 0;
                    294:       strncpy(new_string,tmp_string, (idx+1) );
                    295:     } else {
                    296:       ungetc(c,f);
                    297:       goto PREEND;
                    298:     }
                    299:   } else {
                    300:     goto PRESTART;
                    301:   }
                    302:   if( !strcmp(new_string,"BASE UNIT") ) {
                    303:     return (U_BASE);
                    304:   }  
                    305:   if( strcmp(new_string, "DERIVED UNIT") == 0 ) {
                    306:     return (U_DERIVED);
                    307:   }
                    308:   if( strcmp(new_string, "PREFIX") == 0 ) {
                    309:     return (U_PREFIX);
                    310:   }
                    311:   if( strcmp(new_string, "CONSTANTS") == 0 ) {
                    312:     return (U_CONSTANT);
                    313:   }
                    314:   if( strcasecmp(new_string, "DEFAULTS") == 0 ) {
                    315:     return (U_DEFAULT);
                    316:   }
                    317:   return (U_UNKNOWN);
                    318:   
                    319: }
                    320: 
                    321: /* =================================================================== */
                    322: /* =================================================================== */
                    323: /* returns: 0 success */
                    324: /*          1 the first units string u1_str could not be reduce to a valid unit */
                    325: /*          2 the second units string could not be reduced to a valid unit */
                    326: int
                    327: u_convert_unit(char *u1_str,char *u2_str,double *ratio)
                    328: {
                    329:   Unit_t   *ap, *bp;
                    330:   int       result=0;
                    331:   
                    332:   while( isspace(*u1_str) )  u1_str++;
                    333:   while( isspace(*u2_str) )  u2_str++;
                    334:   bp = parse_unit_expr(u2_str);
                    335:   Ptopidx=0;
                    336:   postwalk_utree(bp);
                    337:   if( Ptopidx == 1 ) {
                    338:     simplify_unit(Pstack[Ptopidx]);
                    339:     bp = Pstack[Ptopidx];
                    340:     /* print_unit_t(bp); */
                    341:     ap = parse_unit_expr(u1_str);
                    342:     Ptopidx=0;
                    343:     postwalk_utree(ap);
                    344:     if( Ptopidx == 1 ) {
                    345:       simplify_unit(Pstack[Ptopidx]);
                    346:       /* print_unit_t(Pstack[Ptopidx]); */
                    347:       if( (Pstack[Ptopidx]->u_count != 0) ||
                    348:           (Pstack[Ptopidx]->u_count == bp->u_count) ) { /* has unit */
                    349:         *ratio = units_ratio(Pstack[Ptopidx], bp);
                    350:       } else {
                    351:         result = 1;
                    352:       }
                    353:     }
                    354:     free_utree(ap);
                    355:   } else {
                    356:     result = 2;
                    357:   }
                    358:   free_utree(bp);
                    359:   return (result);
                    360: }
                    361: 
                    362: /* =================================================================== */
                    363: 
                    364: 
                    365: 
                    366: Unit_t *
                    367: u_find_symb (char *name, Unit_t *t, int *result) 
                    368: {
                    369:   
                    370:   if (t == NULL)  return t;
                    371: 
                    372:   for (;;) {
                    373:     if ( comp_unit_symb(name,t->u_symbol) < 0 ) {
                    374:       if (t->u_left == NULL)  {
                    375:         /* printf("L not found\n"); */
                    376:         *result = 0;
                    377:         break;
                    378:       }
                    379:       t = t->u_left;
                    380:     } else if ( comp_unit_symb(name,t->u_symbol) > 0 ) {
                    381:       if (t->u_right == NULL) {
                    382:         /* printf("R not found\n"); */
                    383:         *result = 0;
                    384:         break;
                    385:       }
                    386:       t = t->u_right;
                    387:     } else {
                    388:      *result = 1;
                    389:       break;
                    390:     }
                    391:   }
                    392:   return t;
                    393: }
                    394: /* ------------------------------------------------------------- */
                    395: /*   use the input unit_t's element list to locate the min squared */
                    396: /*   error fit of the unit tree        */
                    397: /*   report either exact fit or approx */
                    398: 
                    399: void
                    400: u_find_name(Unit_t *t)
                    401: {
                    402:   int      ii;
                    403:   Unit_E  *eu_p;
                    404:   
                    405:   MinSquared = FLT_MAX;
                    406:   EquivUnitCnt=0;
                    407:   InqueryUnit_p = t;
                    408:   /* printf("INQ[[%s,%s,%d]]\n", U_SYMB(t), U_NAME(t),U_COUNT(t)); */
                    409:   TmpAexp = (double *)capa_malloc(BaseUnitcnt,sizeof(double));
                    410:   TmpBexp = (double *)capa_malloc(BaseUnitcnt,sizeof(double));
                    411:   for(ii=0;ii<BaseUnitcnt;ii++) {
                    412:      TmpAexp[ii] = 0.0;
                    413:   }
                    414:   if( t->u_count > 0 ) {
                    415:     for(eu_p = t->u_list; eu_p; eu_p = eu_p->ue_nextp) {
                    416:       TmpAexp[eu_p->ue_index] = eu_p->ue_exp;
                    417:       /* printf("(%d)^(%g) ",eu_p->ue_index,TmpAexp[eu_p->ue_exp]); */
                    418:     }
                    419:     /* printf("\n"); */
                    420:   }
                    421:   inorder_diff(UnitTree_p);
                    422:   /*capa_mfree((char *)TmpAexp); capa_mfree((char *)TmpBexp);*/
                    423:   
                    424: }
                    425: 
                    426: void
                    427: print_matches(Unit_t *t)
                    428: {
                    429:   double   scale, factor;
                    430:   Unit_t  *tmp_p;
                    431:   int      ii;
                    432:   
                    433:   scale = t->u_scale;
                    434:   if( MinSquared == 0.0 ) {  /* exact match */
                    435:     if( EquivUnitCnt > 0 ) {
                    436:       printf(" Entered unit is equivalent to:\n");
                    437:       for(ii=0;ii<EquivUnitCnt;ii++) {
                    438:         tmp_p = EquivUnit[ii];
                    439:         if( MinSquared ==  MinValue[ii] ) {
                    440:           if( tmp_p->u_type == U_BASE ) {    /* if there is a base unit */
                    441:             MinSquaredUnit_p = tmp_p;
                    442:           }
                    443:           factor = scale / tmp_p->u_scale;
                    444:           printf(" <<%g %s>>", factor,U_SYMB(tmp_p));
                    445:         }
                    446:       }
                    447:       printf("\n");
                    448:       
                    449:     }
                    450:   } else {  /* no exact match */
                    451:     if( EquivUnitCnt > 0 ) {
                    452:       printf(" Entered unit is approximated by:\n");
                    453:       for(ii=0;ii<EquivUnitCnt;ii++) {
                    454:         tmp_p = EquivUnit[ii];
                    455:         if( MinSquared ==  MinValue[ii] ) {
                    456:           printf(" <<%s>> ", U_SYMB(tmp_p) );
                    457:         }
                    458:       }
                    459:       printf("\n");
                    460:     }
                    461:   }
                    462: }
                    463: 
                    464: /* ------------------------------------ */
                    465: double
                    466: u_squared_diff(Unit_t  *a, Unit_t *b)
                    467: {
                    468:   double   result;
                    469:   double   squared_diff = 0.0;
                    470:   int      ii;
                    471:   Unit_E  *eu_p;
                    472:   
                    473:   
                    474:   for(ii=0;ii<BaseUnitcnt;ii++) {
                    475:     TmpAexp[ii] = 0.0;
                    476:     TmpBexp[ii] = 0.0;
                    477:   }
                    478:   if( a->u_count > 0 ) {
                    479:     for(eu_p= a->u_list; eu_p; eu_p = eu_p->ue_nextp) {
                    480:       TmpAexp[eu_p->ue_index] = eu_p->ue_exp;
                    481:     }
                    482:   }
                    483:   if( b->u_count > 0 ) {
                    484:     for(eu_p= b->u_list; eu_p; eu_p = eu_p->ue_nextp) {
                    485:       TmpBexp[eu_p->ue_index] = eu_p->ue_exp;
                    486:       /* printf("Exp[%d]=%g ",ii,TmpBexp[ii]); */
                    487:     }
                    488:     /* printf("\n"); */
                    489:   }
                    490:   for(ii=0;ii<BaseUnitcnt;ii++) {
                    491:     result = TmpAexp[ii] - TmpBexp[ii];
                    492:     squared_diff = squared_diff + result*result;
                    493:   }
                    494:   
                    495:   return (squared_diff);
                    496: }
                    497: 
                    498: double
                    499: u_sq_diff(Unit_t *b)
                    500: {
                    501:   double   result;
                    502:   double   squared_diff = 0.0;
                    503:   int      ii;
                    504:   Unit_E  *eu_p;
                    505:   
                    506:   
                    507:   for(ii=0;ii<BaseUnitcnt;ii++) {
                    508:     TmpBexp[ii] = 0.0;
                    509:   }
                    510:   if( b->u_count > 0 ) {
                    511:     for(eu_p= b->u_list; eu_p; eu_p = eu_p->ue_nextp) {
                    512:       TmpBexp[eu_p->ue_index] = eu_p->ue_exp;
                    513:       /* printf("Exp[%d]=%g ",ii,TmpBexp[ii]); */
                    514:     }
                    515:     /* printf("\n"); */
                    516:   } else if( b->u_type == U_BASE  ) {
                    517:     TmpBexp[b->u_index] = 1.0;
                    518:   }
                    519:   for(ii=0;ii<BaseUnitcnt;ii++) {
                    520:     result = TmpAexp[ii] - TmpBexp[ii];
                    521:     squared_diff = squared_diff + result*result;
                    522:   }
                    523:   
                    524:   return (squared_diff);
                    525: 
                    526: }
                    527: /* ------------------------------------ */
                    528: 
                    529: int
                    530: inorder_diff(node_p) Unit_t  *node_p;
                    531: {
                    532:   int      result;
                    533:   double   sq_diff=0.0;
                    534:   
                    535:   if( node_p == NULL )  return (1);
                    536:   
                    537:   result = inorder_diff(U_LEFT(node_p));
                    538:   if( result ) {
                    539:      sq_diff = u_sq_diff(node_p);
                    540:      /*
                    541:      printf("DIFF [%s,%s,%d] - [%s,%s,%d] = %g\n", 
                    542:       U_SYMB(InqueryUnit_p), U_NAME(InqueryUnit_p),U_COUNT(InqueryUnit_p),
                    543:       U_SYMB(node_p), U_NAME(node_p),U_COUNT(node_p),sq_diff);
                    544:      */
                    545:      if( MinSquared > sq_diff) {
                    546:        MinSquaredUnit_p = node_p;
                    547:        MinSquared = sq_diff;
                    548:      } else if ( MinSquared == sq_diff) {
                    549:        EquivUnit[EquivUnitCnt] = node_p;
                    550:        MinValue[EquivUnitCnt] = sq_diff;
                    551:        EquivUnitCnt++;
                    552:      }
                    553:   }
                    554:   result = inorder_diff(U_RIGHT(node_p));
                    555:   
                    556:   return (result);
                    557: }
                    558: 
                    559: 
                    560: int
                    561: alphaorder_utree(node_p) Unit_t  *node_p;
                    562: {
                    563:   int  result;
                    564:   
                    565:   if( node_p == NULL )  return (1);
                    566:   
                    567:   result = alphaorder_utree(U_LEFT(node_p));
                    568:   if( result ) printf(" (%s,%s)\n", U_SYMB(node_p), U_NAME(node_p) );
                    569:   result = alphaorder_utree(U_RIGHT(node_p));
                    570:   
                    571:   return (result);
                    572: }
                    573: 
                    574: int
                    575: w_alphaorder_utree(node_p) Unit_t  *node_p;
                    576: {
                    577:   int  result;
                    578:   
                    579:   if( node_p == NULL )  return (1);
                    580:   
                    581:   result = alphaorder_utree(U_LEFT(node_p));
                    582:   if( result ) { 
                    583:      printf(" (%s,%s)\n", U_SYMB(node_p), U_NAME(node_p) );
                    584:   }
                    585:   result = alphaorder_utree(U_RIGHT(node_p));
                    586:   
                    587:   return (result);
                    588: }
                    589: 
                    590: /* --------------------------------------------------------------------- */
                    591: void
                    592: print_unit_tree(int mode)
                    593: {
                    594:   if( mode == 1 ) {
                    595:     alphaorder_utree(UnitTree_p);
                    596:   } else {
                    597:     w_alphaorder_utree(UnitTree_p);
                    598:   }
                    599: }
                    600: 
                    601: 
                    602: int
                    603: preorder_utree(node_p) Unit_t  *node_p;
                    604: {
                    605:   int  result;
                    606:   
                    607:   if( node_p == NULL )  return (1);
                    608:   printf("Preorder=[[%s,%s,%d]]\n", U_SYMB(node_p), U_NAME(node_p),U_COUNT(node_p));
                    609:   result = preorder_utree(U_LEFT(node_p));
                    610:   if( result ) result = preorder_utree(U_RIGHT(node_p));
                    611:   return (result);
                    612: }
                    613: int
                    614: inorder_utree(node_p) Unit_t  *node_p;
                    615: {
                    616:   int  result;
                    617:   
                    618:   if( node_p == NULL )  return (1);
                    619:   
                    620:   result = inorder_utree(U_LEFT(node_p));
                    621:   if( result ) printf("INorder=[[%s,%s,%d]]\n", 
                    622:     U_SYMB(node_p), U_NAME(node_p),U_COUNT(node_p));
                    623:   result = inorder_utree(U_RIGHT(node_p));
                    624:   
                    625:   return (result);
                    626: }
                    627: int
                    628: postorder_utree(node_p) Unit_t  *node_p;
                    629: {
                    630:   int  result;
                    631:   
                    632:   if( node_p == NULL )  return (1);
                    633:   
                    634:   result = postorder_utree(U_LEFT(node_p));
                    635:   if( result ) result = postorder_utree(U_RIGHT(node_p));
                    636:   if( result ) {
                    637:     switch(U_TYPE(node_p)) {
                    638:       case U_DERIVED:   print_unit_t(node_p);
                    639:             break;
                    640:       case U_CONSTANT:  printf("(%g)",U_SCALE(node_p));
                    641:             break;
                    642:       case U_OP_POWER:  printf("^");
                    643:             break;
                    644:       case U_OP_TIMES:  printf("*");
                    645:             break;
                    646:       case U_OP_PLUS:   printf("+");
                    647:             break;
                    648:       case U_OP_MINUS:  printf("-");
                    649:             break;
                    650:       case U_OP_DIVIDE: printf("/");
                    651:             break;
                    652:       default:          printf("()");
                    653:             break;  
                    654:     }
                    655:   }
                    656:   return (result);
                    657: }
                    658: 
1.4       albertel  659: /* returns 1 on okay, 2 on error*/
1.1       albertel  660: int
                    661: postwalk_utree(Unit_t  *n_p)
                    662: {
                    663:   int  result;
                    664:   
                    665:   if( n_p == NULL )  return (1);
                    666:   
                    667:   result = postwalk_utree(U_LEFT(n_p));
1.4       albertel  668:   if (result !=2) {
                    669:     if( result ) result = postwalk_utree(U_RIGHT(n_p));
                    670:     if (result !=2) {
                    671:       if( result ) {
                    672: 	switch(U_TYPE(n_p)) {
                    673: 	case U_DERIVED:   Ptopidx++; Pstack[Ptopidx] = n_p;  /* push into stack */
                    674: 	  break;
                    675: 	case U_CONSTANT:  Ptopidx++; Pstack[Ptopidx] = n_p;  /* push into stack */
                    676: 	  break;
                    677: 	case U_UNKNOWN:   result=2; 
                    678: 	  /*push into stack anyway, try to parse rest of tree */
                    679: 	  break;
                    680: 	case U_OP_POWER:  printf("^"); result=2;
                    681: 	  break;
                    682: 	case U_OP_TIMES:  process_op(U_OP_TIMES);        /* process operator */
                    683: 	  break;
                    684: 	case U_OP_PLUS:   printf("+"); result=2;
                    685: 	  break;
                    686: 	case U_OP_MINUS:  printf("-"); result=2;
                    687: 	  break;
                    688: 	case U_OP_DIVIDE: process_op(U_OP_DIVIDE);       /* process operator */
                    689: 	  break;
                    690: 	default:          printf("()"); result=2;
                    691: 	  break;  
                    692: 	}
                    693:       }
1.1       albertel  694:     }
                    695:   }
                    696:   return (result);
                    697: }
                    698: 
                    699: void
                    700: process_op(int op)
                    701: {
                    702:   Unit_t  *ap, *bp;
                    703:   double   exp_scale;
                    704:   int      no_error=1;
                    705:   
                    706:   bp = Pstack[Ptopidx--]; 
                    707:   ap = Pstack[Ptopidx--]; 
                    708:   
                    709:   switch(op) {
                    710:     case U_OP_TIMES:  exp_scale = 1.0;  break;
                    711:     case U_OP_DIVIDE: exp_scale = -1.0; break;
                    712:     case U_OP_PLUS:   
                    713:     case U_OP_MINUS:  no_error = u_pm_op(ap,bp,op);
                    714:                       if(no_error) {
                    715:                         Ptopidx++;
                    716:                         Pstack[Ptopidx] = ap;
                    717:                       }
                    718:                       break;
                    719:     default:          no_error=0; 
                    720:                       printf("No such op on the parse tree!\n");
                    721:           break;
                    722:   }
                    723:   if(no_error) {
                    724:     u_copy_unit(ap, bp, exp_scale);
                    725:     Ptopidx++;
                    726:     Pstack[Ptopidx] = ap;
                    727:   }
                    728: }
                    729: 
1.13      albertel  730: Unit_t*
1.1       albertel  731: process_utree(Unit_t *t)
                    732: {
                    733:   Ptopidx=0;
                    734:   postwalk_utree(t);
                    735:   if( Ptopidx == 1 ) {
1.13      albertel  736:     //fprintf(stderr,"Correctly parsed!\n");
                    737:     //fprintf(stderr,"Unit:%s\n",Sbuf);
1.1       albertel  738:     simplify_unit(Pstack[Ptopidx]);
1.13      albertel  739:     //Pstack[Ptopidx]->u_symbol[0]='\0';
                    740:     //fprintf(stderr,Pstack[Ptopidx]->u_symbol,"");
1.14    ! raeburn   741:     //print_unit_t(Pstack[Ptopidx]);
1.13      albertel  742:     //u_find_name(Pstack[Ptopidx]);
                    743:     //print_matches(Pstack[Ptopidx]);
                    744:     return(Pstack[Ptopidx]);
                    745:     //free_utree(t);
1.1       albertel  746:   }
1.13      albertel  747:   return(t);
1.1       albertel  748: }
                    749: 
                    750: /* ============================================================== */
                    751: /*  called from capaCommon.c */
                    752: /*                      */
                    753: /*  UNIT_FAIL           */
                    754: /*  NO_UNIT             */
                    755: /*  result: UNIT_OK correct   */
                    756: /*                            */
                    757: /* -------------------------------------------------------------- */
                    758: int  check_correct_unit(char *u_symb,Unit_t *t,double *scale)
                    759: {
                    760:   Unit_t   *ap;
                    761:   int       result=UNIT_OK;
                    762: 
                    763: #ifdef UNIT_DBUG
1.4       albertel  764:    if ((ufp=fopen("unit.DBUG","a"))==NULL) { fprintf(stderr,"Error: can't open login debug\n"); return UNIT_FAIL; }
1.1       albertel  765: #endif 
                    766: 
1.3       albertel  767:   while( isspace(*u_symb) )  u_symb++; 
                    768:   /* <= change this to search from the end of string */
                    769:   /* or to get rid of all the white spaces */
                    770: 
                    771: 
1.1       albertel  772:   ap = parse_unit_expr(u_symb);
                    773:   Ptopidx=0;
1.4       albertel  774: 
                    775:   if (postwalk_utree(ap)==1) {
1.1       albertel  776: #ifdef UNIT_DBUG
1.4       albertel  777:     fprintf(ufp,"Ptopidx %d\n",Ptopidx);
1.1       albertel  778: #endif
1.4       albertel  779:     if( Ptopidx == 1 ) {
                    780:       simplify_unit(Pstack[Ptopidx]);
                    781:       
                    782:       if( (Pstack[Ptopidx]->u_count != 0) ||
                    783: 	  (Pstack[Ptopidx]->u_count == t->u_count) ) { /* has unit */
                    784: 	*scale = units_ratio(Pstack[Ptopidx], t);
                    785: 	if( *scale == 0.0 ) {
1.12      albertel  786: 	  result = UNIT_IRRECONCIBLE;
1.4       albertel  787: 	}
                    788: 	free_utree(ap);
                    789:       } else {
1.12      albertel  790: 	result = UNIT_INVALID_STUDENT3;
1.1       albertel  791:       }
1.4       albertel  792:     } else { /* invalid unit representation */
1.12      albertel  793:       result = UNIT_INVALID_STUDENT2;
1.1       albertel  794:     }
1.4       albertel  795:   } else {
1.12      albertel  796:     result = UNIT_INVALID_STUDENT1;
1.1       albertel  797:   }
                    798: #ifdef UNIT_DBUG
                    799:   fclose(ufp);
                    800: #endif 
                    801:   return (result);
                    802: }
                    803: 
                    804: /* ============================================================= */
                    805: int
                    806: free_units()
                    807: {
                    808:   free_utree(UnitTree_p);
                    809:   UnitTree_p=NULL;
                    810:   return 0;
                    811: }
                    812: 
                    813: int
                    814: free_utree(Unit_t  *t)
                    815: {
                    816:   int  result=1;
                    817:   
                    818:   if( t == NULL )  return (1);
                    819:   u_postfree(t);
                    820:   t=NULL;
                    821:   
                    822:   return (result);
                    823: }
                    824: 
                    825: 
                    826: int
                    827: u_postfree(Unit_t  *t)
                    828: {
                    829:   int  result;
                    830:   
                    831:   if( t == NULL )  return (1);
                    832:   
                    833:   result = u_postfree(U_LEFT(t));
                    834:   if( result ) result = u_postfree(U_RIGHT(t));
                    835:   if( result ) {
                    836:     if( t->u_comment ) {
                    837:       capa_mfree((char *)t->u_comment);
                    838:     }
                    839:     freelist_unit_e(t->u_list);
                    840:     capa_mfree((char *)t);
                    841:   }
                    842:   return (result);
                    843: }
                    844: 
                    845: 
                    846: void
                    847: print_unit_t(Unit_t *t) 
                    848: {
                    849:   Unit_E  *ue_p;
                    850: 
                    851:   /* printf("  Unit::[%s,%d]= %g * ", t->u_symbol,t->u_count,t->u_scale); */
                    852:   printf("  Unit::[%s] = %g * ", t->u_symbol, t->u_scale);
                    853:   for(ue_p=t->u_list; ue_p ; ue_p = ue_p->ue_nextp) {
                    854:     /*
                    855:     printf("<%s,%d,%g,%g> ",ue_p->ue_symbol,ue_p->ue_index,ue_p->ue_scale,ue_p->ue_exp);
                    856:     */
                    857:     printf("(%g*%s^%g) ",ue_p->ue_scale,ue_p->ue_symbol,ue_p->ue_exp);
                    858:   }
                    859:   printf("\n");
                    860: 
                    861: }
                    862: /*  ----------------------------------------------------------- */
                    863: /*  copy the Unit_E linked list from b_p->u_list to a_p->u_list */
                    864: /*   create some Unit_E nodes in a_p->u_list if needed and      */
                    865: /*   leave b_p->u_list intact                                   */
                    866: /*   a_p->u_scale is multiplied by pow(b_p->u_scale,exp_scale)  */
                    867: /*  ----------------------------------------------------------- */
                    868: void
                    869: u_copy_unit(Unit_t *a_p, Unit_t *b_p, double exp_scale) 
                    870: {
                    871:   Unit_E  *oe_p, *ne_p, *last_p;
                    872:   int      ii;
                    873:   double   scale;
                    874:   
                    875:   if( a_p->u_count > 0 ) {
                    876:     for(last_p = a_p->u_list; last_p->ue_nextp; last_p = last_p->ue_nextp) {  }
                    877:   } else {
                    878:     a_p->u_list = last_p = NULL;
                    879:   }
                    880:   if( b_p->u_count > 0 ) {
                    881:     oe_p = b_p->u_list;
                    882:     for(ii=0;ii<b_p->u_count;ii++) {
                    883:       ne_p = (Unit_E *) capa_malloc(1, sizeof(Unit_E)); /* *** */
                    884:       ne_p->ue_scale = oe_p->ue_scale;
                    885:       ne_p->ue_exp   = oe_p->ue_exp * exp_scale;
                    886:       ne_p->ue_index = oe_p->ue_index;
                    887:       strcpy(ne_p->ue_symbol, oe_p->ue_symbol);
                    888:       oe_p = oe_p->ue_nextp;
                    889:       if( last_p == NULL ) {
                    890:         a_p->u_list = ne_p;
                    891:       } else {
                    892:         last_p->ue_nextp = ne_p;
                    893:       }
                    894:       last_p = ne_p;
                    895:       a_p->u_count++;
                    896:     }
                    897:     scale = pow(b_p->u_scale, exp_scale);
                    898:     a_p->u_scale = a_p->u_scale * scale;
                    899:     /* printf("Found scale=%g=%g\n",a_p->u_scale,b_p->u_scale); */
                    900:   } else {  
1.2       albertel  901:     if( b_p->u_type == U_BASE ) { 
1.1       albertel  902:       /* *b_p is a base unit, so create a one element unit */
                    903:       ne_p = (Unit_E *) capa_malloc(1, sizeof(Unit_E));   /* *** */
                    904:       ne_p->ue_scale = b_p->u_scale;
                    905:       ne_p->ue_exp   = exp_scale;
                    906:       ne_p->ue_index = b_p->u_index;
                    907:       strcpy(ne_p->ue_symbol, b_p->u_symbol);
                    908:       if( last_p == NULL ) {
                    909:         a_p->u_list = ne_p;
                    910:       } else {
                    911:         last_p->ue_nextp = ne_p;
                    912:       }
                    913:       last_p = ne_p;
                    914:       a_p->u_count++;
1.2       albertel  915:     } else if( b_p->u_type == U_DERIVED) {
                    916:       /* derived units but without any units elements (scalar) */
1.4       albertel  917:       /*a_p->u_count++;*/
1.10      albertel  918:       scale = pow(b_p->u_scale, exp_scale);
                    919:       a_p->u_scale = a_p->u_scale * scale;
1.1       albertel  920:     } else if( b_p->u_type == U_CONSTANT ) {
                    921:       scale = pow(b_p->u_scale, exp_scale);
                    922:       a_p->u_scale = a_p->u_scale * scale;
                    923:     } else {
                    924:       printf("This node has no u_e list and Type unknown\n");
                    925:     }
                    926:   }
                    927: }
                    928: int
                    929: u_pm_op(Unit_t *a_p, Unit_t *b_p, int op)
                    930: {
                    931:   int    result=0;
                    932:   
                    933:   if( a_p->u_count > 0 || b_p->u_count > 0 ) {
                    934:      printf(" cannot add or sub units at this moment\n");
                    935:      return  result;
                    936:   }
                    937:   if( op == U_OP_PLUS ) {
                    938:     a_p->u_scale = a_p->u_scale + b_p->u_scale;
                    939:   } else {
                    940:     a_p->u_scale = a_p->u_scale - b_p->u_scale;
                    941:   }
                    942:   return 1;
                    943: }
                    944: 
                    945: int
                    946: u_parsepower(char *unit_str)
                    947: {
                    948:   int   exp, ii;
                    949:   char  *ch_p, exp_str[16];
                    950: 
                    951:   ch_p = unit_str;
                    952:   while( isspace(*ch_p) ) { ch_p++; }
                    953:   ii=0;
                    954:   while( isdigit(*ch_p) ) {
                    955:     ch_p++;
                    956:   }
                    957:   while( isspace(*ch_p) ) { ch_p++; }
                    958:   if( *ch_p == '^' ) {
                    959:     ch_p++;
                    960:   }
                    961:   while( isspace(*ch_p) ) { ch_p++; }
                    962:   if( *ch_p == '{' ) {
                    963:     ch_p++;
                    964:   }
                    965:   while( isspace(*ch_p) ) { ch_p++; }
                    966:   ii=0;
                    967:   while( isdigit(*ch_p) || *ch_p == '-' || *ch_p == '+' ) {
                    968:     exp_str[ii++] = *ch_p;
                    969:     ch_p++;
                    970:   }
                    971:   exp_str[ii]=0;
                    972:   sscanf(exp_str,"%d", &exp);
                    973:   return (exp);
                    974: }
                    975: 
                    976: /* ------------------------------------------- */
                    977: /* scan a number of the form indicated below from the input buffer */
                    978: /* 1.234^{2.3} */
                    979: /*  1e */
                    980: double
                    981: s_scan_number(char *buf, int idx, int *r_idx)
                    982: {
                    983:   double   num; 
                    984:   float    exp; 
                    985:   double   result;
                    986:   int      ii=0;
                    987:   char     num_str[QUARTER_K];
                    988:   
                    989:   num_str[ii]=0;
                    990:   
                    991:   if( buf[idx] == '-' ) {
                    992:     num_str[ii++] = '-';
                    993:     idx++;
                    994:   }
                    995:   while( isdigit(buf[idx]) || buf[idx] == '.' ) { 
                    996:       num_str[ii++] = buf[idx];
                    997:       idx++;
                    998:   }
                    999:   if( buf[idx] == 'E' || buf[idx] == 'e' ) {
                   1000:     if( buf[idx+1] == '-' || isdigit(buf[idx+1]) ) {
                   1001:       num_str[ii++] = buf[idx++];
                   1002:       num_str[ii++] = buf[idx++];
                   1003:       while( isdigit(buf[idx]) ) {
                   1004:         num_str[ii++] = buf[idx];
                   1005:         idx++;
                   1006:       }
                   1007:     }
                   1008:   }
                   1009:   num_str[ii] = 0; /* terminate the str */
                   1010:   sscanf(num_str,"%lg", &num);
                   1011:   /* printf("Scan number %s got %g\n",num_str, num); fflush(stdout); */
                   1012:   result = num;
                   1013:   if( buf[idx] == '^' ) {
                   1014:     idx++;
                   1015:     while( isspace(buf[idx]) ) { idx++; }
                   1016:     if( buf[idx] == '{' ) {  /* need to scan for a matching right bracket */
                   1017:         idx++;
                   1018:     }
                   1019:     while( isspace(buf[idx]) ) { idx++; }
                   1020:     num_str[0]=0;
                   1021:     if( isdigit(buf[idx]) || buf[idx] == '+' || buf[idx] == '-' )  {
                   1022:        ii=0;
                   1023:        while( isdigit(buf[idx]) || buf[idx] == '.' || buf[idx] == '+' || buf[idx] == '-' ) {
                   1024:          num_str[ii++] = buf[idx];
                   1025:          idx++;
                   1026:        }
                   1027:        num_str[ii]=0;
                   1028:     }
                   1029:     while( isspace(buf[idx]) ) { idx++; }
                   1030:     if( buf[idx] == '}' ) {
                   1031:       idx++;
                   1032:     }
                   1033:     sscanf(num_str,"%f", &exp);
                   1034:     /* printf("Scan exp number %s got %g\n",num_str, exp); fflush(stdout); */
                   1035:     
                   1036:     result = pow(num, (double)exp);
                   1037:     /* printf("{%d^%d}=%g\n",num, exp,result); */
                   1038:   }
                   1039:   *r_idx = idx;
                   1040:   return (result);
                   1041: }
                   1042: 
                   1043: 
                   1044: double
                   1045: s_scan_symbol(char *buf,char *symb_p,int idx, int *r_idx)
                   1046: {
                   1047:   char     num_str[QUARTER_K];
                   1048:   int      ii=0;
                   1049:   double   r_exp=1.0;
                   1050:   
                   1051:   symb_p[0]=0;
                   1052:   while( isalnum(buf[idx]) || buf[idx] == '_' ) {
                   1053:     symb_p[ii++] = buf[idx];
                   1054:     idx++;
                   1055:   }
                   1056:   symb_p[ii]=0;
                   1057:   
                   1058:   if( buf[idx] == '^' ) {  /* look for either left bracket or a number */
                   1059:     idx++;
                   1060:     while( isspace(buf[idx]) ) { idx++; } 
                   1061:     if( buf[idx] == '{' ) {  /* need to scan for a matching right bracket */
                   1062:       idx++;
                   1063:     }
                   1064:     while( isspace(buf[idx]) ) { idx++; }
                   1065:     if( isdigit(buf[idx]) || buf[idx] == '.' || buf[idx] == '+' || buf[idx] == '-'  )  {
                   1066:       ii=0; num_str[ii] = 0;
                   1067:       while( isdigit(buf[idx]) || buf[idx] == '.' || buf[idx] == '+' || buf[idx] == '-' ) {
                   1068:         num_str[ii++] = buf[idx];
                   1069:         idx++;
                   1070:       }
                   1071:       num_str[ii]=0;
                   1072:     }
                   1073:     while( isspace(buf[idx]) ) { idx++; }
                   1074:     if( buf[idx] == '}' ) {
                   1075:       idx++;
                   1076:     }
                   1077:     sscanf(num_str,"%lg", &r_exp);  /* power could be of type float */
                   1078:     /* printf("[scan symb with power %s ^ %lg] ",symb_p, r_exp); fflush(stdout);  */
                   1079:   }
                   1080:   *r_idx = idx;
                   1081:   return (r_exp);
                   1082: }
                   1083: 
                   1084: /*  return: err_code    0    parsed ok */
                   1085: /*                      1    symbol is of length 1, not found in the tree */
                   1086: /*                      2    symbol not found in the tree  */
                   1087: /*                      3    symbol parsed as prefix symb, but symb not found */
                   1088: /*                      4    symbol length is 0 or negative */
                   1089: int
                   1090: s_process_symb(char *symb_str,Unit_t  *cu_p,double exp)
                   1091: {
                   1092:   int      len;
                   1093:   Unit_t  *au_p;
                   1094:   int      c_result;
                   1095:   int      ii;
                   1096:   char     tmp_str[ANSWER_STRING_LENG];
                   1097:   int      err_code = 0;
                   1098:   double   d_exp;
                   1099:   
                   1100:   len = strlen(symb_str);
                   1101:   if( len > 0 ) {
                   1102:     au_p = u_find_symb(symb_str, UnitTree_p, &c_result);
                   1103:     if( c_result == 1 ) {  /* if found, copy the definition over */
                   1104:       u_copy_unit(cu_p, au_p, exp);
                   1105:     } else {
                   1106:       if( len > 1 ) {
                   1107:         if( PrefixTbl[ (int)symb_str[0] ] != 0 ) {  /* prefix is defined */
                   1108:           for(ii=1;ii<len;ii++) {
                   1109:              tmp_str[ii-1] = symb_str[ii];
                   1110:           }
                   1111:           tmp_str[len-1]=0;
                   1112:           au_p = u_find_symb(tmp_str, UnitTree_p, &c_result);
                   1113:           if( c_result == 1 ) {
                   1114:               /* printf("[%s] ", tmp_str); */
                   1115:             u_copy_unit(cu_p, au_p, exp);
                   1116:             d_exp = (double)PrefixTbl[ (int)symb_str[0] ] * exp;
                   1117:             cu_p->u_scale = cu_p->u_scale * pow((double)10.0,d_exp);
                   1118:           } else { /* unit *tmp_str not found */
                   1119:             /*printf("The unit: %s, not defined\n",tmp_str);*/
                   1120:             err_code = 3;
                   1121:           }
                   1122:         } else {
                   1123:           /*printf("<<%s>>", symb_str);*/
                   1124:           err_code = 2;
                   1125:         }
                   1126:       } else {/* len == 1 */
                   1127: 	/*printf("The unit: %s, not defined\n",symb_str);*/
                   1128:         err_code = 1;
                   1129:       }
                   1130:     }
                   1131:   } else {
                   1132:     err_code = 4;
                   1133:   }
                   1134:   return (err_code);
                   1135: }
                   1136: 
                   1137: Unit_t *
                   1138: u_parse_unit(char *unit_str)
                   1139: {
                   1140:   char      *ch;
                   1141:   char       symb_str[QUARTER_K];
                   1142:   int        idx;
                   1143:   double     exp_sign;
                   1144:   int        s_result;
                   1145:   int        not_done;
                   1146:   double     s_number,  offset;
                   1147:   double     tmp_scale, symb_exp, exp;
                   1148:   Unit_t    *cu_p;
                   1149: 
                   1150:   gUnitError=0;
                   1151:   ch   = unit_str;
                   1152:   cu_p = (Unit_t *) capa_malloc(1, sizeof(Unit_t)); /* *** */
                   1153:   cu_p->u_scale = 1.0;
                   1154:   idx = 0;  not_done = 1;
                   1155:   exp_sign = 1.0; exp = 1;
                   1156:   symb_str[0] = 0;
                   1157: 
                   1158:   while( isspace(*ch) ) { ch++; }    /* trim leading white spaces */
                   1159:   /* fprintf(stdout,"PARSE |%s|\n", unit_str); */
                   1160:   while( not_done ) {
                   1161:     if( isdigit(ch[idx]) || ch[idx] == '-' ) {  /* rule 1: number */
                   1162:        s_number = s_scan_number(ch,idx,&idx);
                   1163:        
                   1164:        tmp_scale = pow(s_number,exp_sign);
                   1165:        /* printf("S=%g,Power(%g,%d)=%g\n", 
                   1166:           cu_p->u_scale, s_number,exp_sign, tmp_scale);
                   1167:        */
                   1168:        cu_p->u_scale = cu_p->u_scale * tmp_scale;
                   1169:        
                   1170:        /* printf("[Scale %g=%g^%g] ",tmp_scale,s_number,exp_sign); */
                   1171:        while( isspace(ch[idx]) ) { idx++; }
                   1172:     } else {
                   1173:       if( isalpha(ch[idx]) ) { /* rule 2: unit_symbol ^ exp */
                   1174: 	symb_str[0] = 0;
                   1175: 	symb_exp = s_scan_symbol(ch,symb_str,idx,&idx);
                   1176: 	exp = (double)exp_sign * symb_exp;
                   1177: 	/* printf("[scanned %s ^ (%g * %g)] ", symb_str,symb_exp,exp_sign); fflush(stdout); */
                   1178: 	s_result = s_process_symb(symb_str,cu_p,exp);
                   1179: 	if( s_result > 0 ) {
                   1180: 	  /* printf("Error processing symbol [%s]\n", symb_str); */
                   1181: 	  gUnitError = 1;
                   1182: 	}
                   1183: 	while( isspace(ch[idx]) ) { idx++; }
                   1184:       } else {
                   1185: 	if( ch[idx] == '*' || ch[idx] == '/' ) {
                   1186: 	  if( ch[idx] == '/' ) { /* printf("[/] "); */ exp_sign = -1.0; }
                   1187: 	  idx++;
                   1188: 	  while( isspace(ch[idx]) ) { idx++; }
                   1189: 	} else {
                   1190: 	  if( ch[idx] == '+' || ch[idx] == '-' ) {
                   1191: 	    idx++;
                   1192: 	    while( isspace(ch[idx]) ) { idx++; }
                   1193: 	    offset = s_scan_number(ch,idx,&idx);
                   1194: 	    /* printf("[Offset %g] ",offset); */
                   1195: 	  } else {
                   1196: 	    if( ch[idx] == 0 ) {  /* end of input string */
                   1197: 	      not_done = 0;
                   1198: 	      /* printf("\n"); */
                   1199: 	    } else {
                   1200: 	      /* garbage in unit string */
                   1201: 	      gUnitError = 1;
                   1202: 	      not_done=0;
                   1203: 	    }
                   1204: 	  }
                   1205: 	}
                   1206:       }
                   1207:     }
                   1208:   }
                   1209:   simplify_unit(cu_p);
                   1210:   return (cu_p);
                   1211: 
                   1212: }
                   1213: 
                   1214: void
                   1215: u_getunit(FILE *f)
                   1216: {
                   1217:   register int  unit_type;
                   1218:   register int  c;
                   1219:   int      power, result;
                   1220:   char   *name_p, *symbol_p, *comment_p, *unit_p;
                   1221:   
                   1222:   BaseUnitcnt = 0;
                   1223:   free_utree(UnitTree_p);
                   1224:   UnitTree_p = NULL;
                   1225:   c_moveto_unit(f);  /* move the file position to << */
                   1226:   do {
                   1227:     c_ignorewhite(f);
                   1228:     c = getc(f); ungetc(c,f);
                   1229:     if( c == '<' ) {
                   1230:       unit_type = c_gettype(f);
                   1231:     }
                   1232:     if( c != EOF ) {
                   1233:       switch(unit_type) {
                   1234:         case U_BASE:
                   1235:                name_p    = c_getword(f);    symbol_p = c_getword(f); 
                   1236:                comment_p = c_getcomment(f);
                   1237:                /*
                   1238:                printf("B Unit: N=%s,S=%s,C=%s\n",name_p,symbol_p,comment_p);
                   1239:                */
                   1240:                result = u_insert_baseunit(name_p,symbol_p,comment_p);
                   1241:                if( result == 1 ) {
                   1242:                  printf("The entry %s is duplicated\n",symbol_p);
                   1243:                }
                   1244:                free(name_p); free(symbol_p); free(comment_p);
                   1245:                break;
                   1246:         case U_DERIVED:
                   1247:                name_p    = c_getword(f);    symbol_p = c_getword(f);
                   1248:                unit_p    = c_getstring(f);  comment_p = c_getcomment(f);
                   1249:                /*
                   1250:                printf("D Unit: N=%s,S=%s,C=%s,U=%s\n",
                   1251:                        name_p,symbol_p,comment_p,unit_p);
                   1252:                */
                   1253:                result = u_insert_derived(name_p,symbol_p,comment_p,unit_p);
                   1254:                if( result == 1 ) {
                   1255:                  printf("The entry %s is duplicated\n",symbol_p);
                   1256:                }
                   1257:                /* preorder_utree(UnitTree_p); */ 
                   1258:                free(name_p); free(symbol_p); free(comment_p); free(unit_p);
                   1259:                break;
                   1260:         case U_PREFIX:
                   1261:                name_p    = c_getword(f);    symbol_p = c_getword(f);
                   1262:                unit_p    = c_getstring(f);
                   1263:                /*
                   1264:                printf("Prefix: N=%s,S=%s,U=%s\n",
                   1265:                        name_p,symbol_p,unit_p);
                   1266:                */
                   1267:                power = u_parsepower(unit_p);
                   1268:                PrefixTbl[ (int)(*symbol_p) ] = power;
                   1269:                /* printf("    P[%c]=%d\n",*symbol_p,power);  */
                   1270:                free(name_p); free(symbol_p); free(unit_p);
                   1271:                break;
                   1272:         case U_CONSTANT:
                   1273:                symbol_p = c_getword(f);  unit_p    = c_getstring(f);
                   1274:                comment_p = c_getcomment(f);
                   1275:                /*
                   1276:                printf("Const.: S=%s,C=%s,U=%s\n",
                   1277:                        symbol_p,comment_p,unit_p);
                   1278:                */
                   1279:                break;
                   1280:         case U_UNKNOWN:
                   1281:                /* printf("Unknown\n"); */
                   1282:                break;
                   1283:       }
                   1284:     }
                   1285:   } while ( c != EOF );
                   1286: 
                   1287: }
                   1288: 
                   1289: /* ----------------------------------------------------------------- */
                   1290: /* comparing unit symbol names should be case sensitive */
                   1291: int
                   1292: comp_unit_symb(a, b) char *a; char *b;
                   1293: {
                   1294:   return strncmp(a,b,SYMBOL_MAXLEN);
                   1295: }
                   1296: 
                   1297: 
                   1298: Unit_t *
                   1299: u_splay (char *name, Unit_t *t) 
                   1300: {
                   1301:   Unit_t     N;
                   1302:   Unit_t    *l, *r, *y;
                   1303: 
                   1304:   if (t == NULL)  return t;
                   1305:   N.u_left  = (Unit_t *)NULL;
                   1306:   N.u_right = (Unit_t *)NULL;
                   1307:   l = r = &N;
                   1308: 
                   1309:   for (;;) {
                   1310:     if ( comp_unit_symb(name,t->u_symbol) < 0 ) {
                   1311:       if (t->u_left == NULL)  break;
                   1312:       if ( comp_unit_symb(name, (t->u_left)->u_symbol ) < 0 ) {
                   1313:         y = t->u_left; t->u_left = y->u_right; y->u_right = t; t = y;
                   1314:         if (t->u_left == NULL) break;
                   1315:       }
                   1316:       r->u_left = t; r = t; t = t->u_left;
                   1317:     } else if ( comp_unit_symb(name,t->u_symbol) > 0 ) {
                   1318:         if (t->u_right == NULL) break;
                   1319:         if ( comp_unit_symb(name, (t->u_right)->u_symbol ) > 0 ) {
                   1320:           y = t->u_right; t->u_right = y->u_left; y->u_left = t; t = y;
                   1321:           if (t->u_right == NULL) break;
                   1322:         }
                   1323:         l->u_right = t; l = t; t = t->u_right;
                   1324:     } else {
                   1325:       break;
                   1326:     }
                   1327:   }
                   1328:   l->u_right = t->u_left; r->u_left = t->u_right; t->u_left = N.u_right;
                   1329:   t->u_right = N.u_left;
                   1330:   return t;
                   1331: }
                   1332: 
                   1333: 
                   1334: 
                   1335: /* returns: 0  correctly inserted */
                   1336: /*          -1 error */
                   1337: /*          1  duplicate entry    */
                   1338: 
                   1339: int
                   1340: u_insert_baseunit(n_p,s_p,c_p) char  *n_p, *s_p, *c_p;
                   1341: {
                   1342:   Unit_t   *new_p, *t;
                   1343:   int       len;
                   1344:  
                   1345:   new_p = (Unit_t *) capa_malloc(1, sizeof(Unit_t)); /* *** */
                   1346:   if (new_p == NULL) {
                   1347:       printf("Ran out of space\n");
                   1348:       return(-1);
                   1349:   }
                   1350:   strcpy(new_p->u_symbol, s_p);
                   1351:   strcpy(new_p->u_name, n_p);
                   1352:   len = strlen(c_p);
                   1353:   new_p->u_comment = (char *) capa_malloc((len+1), sizeof(char)); /* *** */
                   1354:   strcpy(new_p->u_comment,c_p);
                   1355:   BaseUnitcnt++;
                   1356:   new_p->u_index  = BaseUnitcnt;
                   1357:   new_p->u_type   = U_BASE;
                   1358:   new_p->u_scale  = 1.0;
                   1359:   new_p->u_offset = 0.0;
                   1360:   new_p->u_count  = 0;
                   1361:   new_p->u_list   = NULL;
                   1362:  
                   1363:   if (UnitTree_p == NULL) {  /* a new unit tree */
                   1364:       UnitTree_p = new_p;
                   1365:       return (0);
                   1366:   }
                   1367:   t = u_splay(s_p, UnitTree_p);
                   1368:   if ( comp_unit_symb(s_p,t->u_symbol) < 0 ) {
                   1369:         new_p->u_left = t->u_left; new_p->u_right = t;
                   1370:         t->u_left = NULL;
                   1371:         /* Splay_cnt++;  */
                   1372:         UnitTree_p = new_p;
                   1373:         return (0);
                   1374:   } else if ( comp_unit_symb(s_p,t->u_symbol) > 0 ) {
                   1375:         new_p->u_right = t->u_right; new_p->u_left = t;
                   1376:         t->u_right = NULL;
                   1377:         /* Splay_cnt++; */
                   1378:         UnitTree_p = new_p;
                   1379:         return (0);
                   1380:   } else {    /* name and t->u_symbol is the same, which means found it */
                   1381:         capa_mfree( (char *)new_p );
                   1382:         UnitTree_p = t;
                   1383:         return (1);
                   1384:   }
                   1385: }
                   1386: 
                   1387: 
                   1388: int
                   1389: u_insert_derived(n_p,s_p,c_p,u_p)char  *n_p, *s_p, *c_p, *u_p;
                   1390: {
                   1391:   Unit_t  *new_p, *t;
                   1392:   int      c_result, len;
                   1393:   
                   1394:   /* inorder_utree(UnitTree_p); */
                   1395:   t = u_splay(s_p, UnitTree_p);
                   1396:   UnitTree_p = t;
                   1397:   c_result = comp_unit_symb(s_p,t->u_symbol);
                   1398:   if ( c_result == 0 ) {
                   1399:     UnitTree_p = t;
                   1400:     return (1);
                   1401:   }
                   1402:   
                   1403:   /* prepare a new Unit_t */
                   1404:   new_p = u_parse_unit(u_p);
                   1405:   strcpy(new_p->u_symbol,s_p);
                   1406:   strcpy(new_p->u_name, n_p);
                   1407:   new_p->u_type = U_DERIVED;
                   1408:   len = strlen(c_p);
                   1409:   new_p->u_comment = (char *) capa_malloc((len+1), sizeof(char)); /* *** */
                   1410:   strcpy(new_p->u_comment,c_p);
                   1411:   
                   1412:   simplify_unit(new_p);
1.10      albertel 1413: #ifdef UNIT_DBUG
1.2       albertel 1414:   printf("Derived Unit:%s\n",new_p->u_name);
                   1415:   print_unit_t(new_p); 
1.10      albertel 1416: #endif
1.1       albertel 1417:   if (c_result < 0 ) {
                   1418:     new_p->u_left = t->u_left; new_p->u_right = t;
                   1419:     t->u_left = NULL;
                   1420:   } else {  /* c_result > 0 */
                   1421:     new_p->u_right = t->u_right; new_p->u_left = t;
                   1422:     t->u_right = NULL;
                   1423:   }
                   1424:   UnitTree_p = new_p;
                   1425:   
                   1426:   return (0);
                   1427:   
                   1428: }
                   1429: 
                   1430: void
                   1431: freelist_unit_e(Unit_E *ue_p) 
                   1432: {
                   1433:   Unit_E  *curr_p, *next_p;
                   1434:   
                   1435:   if( ue_p != NULL ) {
                   1436:     next_p = ue_p->ue_nextp;
                   1437:     curr_p = ue_p;
                   1438:     if( next_p == NULL ) {
                   1439:       capa_mfree((char *)curr_p);
                   1440:     } else {
                   1441:       for( curr_p = ue_p; next_p; curr_p = next_p, next_p = next_p->ue_nextp) {
                   1442:         capa_mfree((char *)curr_p);
                   1443:       }
                   1444:       capa_mfree((char *)curr_p);
                   1445:     }
                   1446:   }
                   1447: }
                   1448: void
                   1449: simplify_unit(u_p) Unit_t *u_p;
                   1450: {
                   1451:   Unit_E   *eu_p, *prev_p;
                   1452:   int       ii, idx;
                   1453:   
                   1454:   /* walk through u_list and replace those u_index = -1 with */
                   1455:   /* a linked list of basic unit. */
                   1456:   /* u_msort_main() the whole u_list */
                   1457:   /* combine those units with same u_index */
                   1458:   for(ii=0;ii<BaseUnitcnt;ii++) {
                   1459:     CScale[ii] = 0.0;
                   1460:     CExp[ii] = 0.0;
                   1461:   }
1.2       albertel 1462:   /*
                   1463:   printf("Before Simplify:: \n");
                   1464:   print_unit_t(u_p);
                   1465:   */
1.1       albertel 1466:   if( u_p->u_count > 0 ) {
                   1467:     
                   1468:     for(eu_p=u_p->u_list; eu_p; eu_p = eu_p->ue_nextp) {
                   1469:       idx = eu_p->ue_index;
                   1470:       if( CScale[idx] == 0.0 ) {
                   1471:         CScale[idx] = 1.0;
                   1472:         strcpy(CSymb[idx],eu_p->ue_symbol);
                   1473:       }
                   1474:       CScale[idx] = CScale[idx] * eu_p->ue_scale;
                   1475:       CExp[idx] = CExp[idx] + eu_p->ue_exp;
                   1476:     }
1.2       albertel 1477:     /* debugging 
1.1       albertel 1478:     for(ii=0;ii<BaseUnitcnt;ii++) {
                   1479:       if( CScale[ii] != 0.0 ) {
                   1480:         printf("(%d)%s,S=%g,E=%g\n",ii,CSymb[ii],CScale[ii], CExp[ii]);
                   1481:       }
1.2       albertel 1482:       if( CExp[ii] == 0.0 ) {
                   1483:         printf("(%d)%s,S=%g,Exp=%g\n",ii,CSymb[ii],CScale[ii], CExp[ii]);
                   1484:       }
1.1       albertel 1485:     }
                   1486:     */
                   1487:     freelist_unit_e(u_p->u_list);
                   1488:     prev_p = u_p->u_list = NULL;
                   1489:     u_p->u_count = 0;
                   1490:     for(ii=0;ii<BaseUnitcnt;ii++) {
                   1491:       if( CScale[ii] != 0.0 && CExp[ii] != 0) {
                   1492:         eu_p = (Unit_E *)capa_malloc(1,sizeof(Unit_E)); /* ***************** */
                   1493:         eu_p->ue_scale = 1.0;
                   1494:         eu_p->ue_exp = CExp[ii];
                   1495:         eu_p->ue_index = ii;
                   1496:         strcpy(eu_p->ue_symbol,CSymb[ii]);
                   1497:         if( prev_p == NULL) {
                   1498:           u_p->u_list = prev_p = eu_p;
                   1499:         } else {
                   1500:           prev_p->ue_nextp = eu_p;
                   1501:           prev_p = eu_p;
                   1502:         }
                   1503:         u_p->u_count++;
                   1504:       }
                   1505:     }
                   1506:   }
1.2       albertel 1507:   /* 
                   1508:   printf("After Simplify:: \n");
                   1509:   print_unit_t(u_p);
                   1510:   */
1.1       albertel 1511: }
                   1512: 
                   1513: /* before comparing two units, make sure they are of  basic form */
                   1514: /* compares if two units are equal */
                   1515: /* equality returns 1 */
                   1516: 
                   1517: int  is_units_equal(Unit_t *u1_p, Unit_t *u2_p)
                   1518: {
                   1519:   int      result=1;
                   1520:   Unit_E  *a_p, *b_p;
                   1521:   
                   1522:   if( (u1_p->u_count == u2_p->u_count) && 
                   1523:       (u1_p->u_scale == u2_p->u_scale) ) {
                   1524:     for(a_p=u1_p->u_list, b_p=u2_p->u_list;
                   1525:         a_p; a_p=a_p->ue_nextp, b_p=b_p->ue_nextp) {
                   1526:       if(a_p->ue_index != b_p->ue_index ||
                   1527:          a_p->ue_scale != b_p->ue_scale ||
                   1528:          a_p->ue_exp   != b_p->ue_exp ) {
                   1529:         result=0;
                   1530:         break;
                   1531:       }
                   1532:     }
                   1533:   } else {
                   1534:     result=0;
                   1535:   }
                   1536:   return (result);
                   1537: }
                   1538: /*     input : both are the simplest units */
                   1539: /*     result: 0.0 means they are not of euquvalent units */
                   1540: /*             the ratio of u1 / u2   */
                   1541: double  units_ratio(Unit_t *u1_p, Unit_t *u2_p)
                   1542: {
                   1543:   double   ratio=1.0;
                   1544:   Unit_E  *a_p, *b_p;
                   1545:   
                   1546:   if( (u1_p->u_count == u2_p->u_count) ) {
                   1547:     for(a_p=u1_p->u_list, b_p=u2_p->u_list;
                   1548:         a_p; a_p=a_p->ue_nextp, b_p=b_p->ue_nextp) {
                   1549:       if(a_p->ue_index != b_p->ue_index ||
                   1550:          a_p->ue_scale != b_p->ue_scale ||
                   1551:          a_p->ue_exp   != b_p->ue_exp ) {
                   1552:         ratio=0.0;
                   1553:         break;
                   1554:       }
                   1555:     }
                   1556:   } else {
                   1557:     ratio=0.0;
                   1558:   }
                   1559:   if( (ratio != 0.0) && (u2_p->u_scale != 0.0 )  ) {
                   1560:     ratio = u1_p->u_scale / u2_p->u_scale;
                   1561:   }
                   1562:   return (ratio);
                   1563: }
                   1564: 
                   1565: /* ------------- The Grammar of Units Parser --------------------
                   1566: 
                   1567:   scan_unit_expr()  -->  scan_basic_block()
                   1568:                     -->  scan_basic_block() '+' scan_basic_block() 
                   1569:                     -->  scan_basic_block() '-' scan_basic_block()
                   1570:  
                   1571:   scan_num_expr()   -->  scan_num_block()
                   1572:                     -->  scan_num_block() '+' scan_num_block()
                   1573:                     -->  scan_num_block() '-' scan_num_block()
                   1574:                     
                   1575:   scan_basic_block()-->  scan_basic_term()
                   1576:                     -->  scan_basic_term()  '*' scan_basic_term()
                   1577:                     -->  scan_basic_term()  ' ' scan_basic_term()
                   1578:                     -->  scan_basic_term()  '/' scan_basic_term()
                   1579: 
                   1580:   scan_num_block()  -->  scan_num_term()
                   1581:                     -->  scan_num_term()  '*' scan_num_term()
                   1582:                     -->  scan_num_term()  ' ' scan_num_term()
                   1583:                     -->  scan_num_term()  '/' scan_num_term()
                   1584:   
                   1585:   
                   1586:   scan_basic_term() -->  scan_unit_item()          
                   1587:                     -->  scan_num_item()
                   1588:                     -->  '(' scan_basic_block() ')'
                   1589:                     -->  '{' scan_basic_block() '}'
                   1590: 
                   1591:   scan_num_term()   -->  scan_num_item()<sp>*
                   1592:                     --> '-' scan_num_item()<sp>*
                   1593:                     --> '(' scan_num_expr() ')'
                   1594:                     --> '{' scan_num_expr() '}'
                   1595: 
                   1596:   scan_unit_item()  -->  UNIT<sp>*
                   1597:                     -->  UNIT<sp>*  '^' <sp>* scan_num_term()
                   1598:                     
                   1599:   scan_num_item()   -->  FLOAT<sp>*
                   1600:                     -->  FLOAT<sp>* '^' <sp>* scan_num_term()
                   1601:   
                   1602:   scan_FLOAT()      -->  [0-9]+([eE][+-]?[0-9]+)*
                   1603:   
                   1604:   p_new_unit()      -->  [a-Z]+[a-Z0-9_]*
                   1605:   
                   1606:   -----------------------------------------
                   1607:   U.expr  := B.block
                   1608:            | B.block '+' B.block
                   1609:            | B.block '-' B.block
                   1610:            
                   1611:   N.expr  := N.block 
                   1612:            | N.block '+' N.block
                   1613:            | N.block '-' N.block
                   1614:  
                   1615:  To allow for operations like (J/N)^2 or {N/m}^2 (N/J)^3 
                   1616:  
                   1617:  
                   1618:   B.block := B.term
                   1619:            | B.term ' ' B.term
                   1620:            | B.term '*' B.term
                   1621:            | B.term '/' B.term
                   1622:            
                   1623:   N.block := N.term 
                   1624:            | N.term ' ' N.term
                   1625:            | N.term '*' N.term
                   1626:            | N.term '/' N.term
                   1627:            
                   1628:   B.term  := U.item
                   1629:            | N.item
                   1630:            | '(' B.block ')'
                   1631:            | '{' B.block '}'
                   1632:            
                   1633:            | '(' B.block ')' ^ N.term
                   1634:            | '{' B.block '}' ^ N.term
                   1635:            
                   1636:   N.term  := N.item
                   1637:            | '-' N.item
                   1638:            | '(' N.expr ')'
                   1639:            | '{' N.expr '}'
                   1640:            
                   1641:   U.item  := UNIT
                   1642:            | UNIT '^' N.term
                   1643:            
                   1644:   N.item  := FLOAT
                   1645:            | FLOAT '^' N.term
                   1646:            
                   1647:   UNIT    := [a-Z]+[a-Z0-9_]*
                   1648:   
                   1649:   FLOAT   := [0-9]+([eE][+-]?[0-9]+)*
                   1650:   
                   1651:  ------------------------------------------------------------------- */
                   1652:  
                   1653: Unit_t *
                   1654: p_new_op(Unit_t *left_p, int op, Unit_t *right_p)
                   1655: {
                   1656:   Unit_t  *new_p;
                   1657:   
                   1658:   new_p = (Unit_t *) capa_malloc(1, sizeof(Unit_t));
                   1659:   if (new_p == NULL) {
                   1660:       printf("Ran out of space\n");
                   1661:       return(NULL);
                   1662:   }
                   1663:   new_p->u_left   = left_p;
                   1664:   new_p->u_right  = right_p;
                   1665:   new_p->u_scale  = 0.0;
                   1666:   new_p->u_type   = op;
                   1667:   new_p->u_offset = 0.0;
                   1668:   new_p->u_count  = 0;
                   1669:   new_p->u_list   = NULL;
                   1670:   
                   1671:   return (new_p);
                   1672: }
                   1673: 
                   1674: Unit_t *
                   1675: p_new_num(Unit_t *left_p, double num, Unit_t *right_p)
                   1676: {
                   1677:   Unit_t  *new_p;
                   1678:   
                   1679:   new_p = (Unit_t *) capa_malloc(1, sizeof(Unit_t));
                   1680:   if (new_p == NULL) {
                   1681:       printf("Ran out of space\n");
                   1682:       return(NULL);
                   1683:   }
                   1684:   
                   1685:   new_p->u_left   = left_p;
                   1686:   new_p->u_right  = right_p;
                   1687:   new_p->u_scale  = num;
                   1688:   new_p->u_type   = U_CONSTANT;
                   1689:   new_p->u_offset = 0.0;
                   1690:   new_p->u_count  = 0;
                   1691:   new_p->u_list   = NULL;
                   1692:   
                   1693:   return (new_p);
                   1694: }
                   1695: 
                   1696: Unit_t *
                   1697: p_new_unit(Unit_t *left_p, Unit_t *right_p)
                   1698: {
                   1699:   char     symb_str[ANSWER_STRING_LENG];
                   1700:   int      ii=0;
                   1701:   int      len;
                   1702:   Unit_t  *au_p, *cu_p;
                   1703:   int      c_result;
                   1704:   char     tmp_str[ANSWER_STRING_LENG];
                   1705:   int      err_code = 0;
                   1706:   double   d_exp;
                   1707:   
                   1708:   symb_str[ii]=0;
                   1709:   while( isspace(Sbuf[Sidx]) ) { Sidx++; }
                   1710:   while( isalnum(Sbuf[Sidx]) || Sbuf[Sidx] == '_' ) {
                   1711:     symb_str[ii++] = Sbuf[Sidx];
                   1712:     Sidx++;
                   1713:   }
                   1714:   symb_str[ii]=0;
                   1715:   /* printf("<U %s>", symb_str); */
                   1716:   cu_p = (Unit_t *) capa_malloc(1, sizeof(Unit_t));
                   1717:   strcpy(cu_p->u_symbol,symb_str);
                   1718:   cu_p->u_left   = left_p;
                   1719:   cu_p->u_right  = right_p;
                   1720:   cu_p->u_scale  = 1.0;
                   1721:   cu_p->u_type   = U_DERIVED;
                   1722:   cu_p->u_offset = 0.0;
                   1723:   cu_p->u_count  = 0;
                   1724:   cu_p->u_list   = NULL;
                   1725:   
                   1726:   len = strlen(symb_str);
                   1727:   if( len > 0 ) {
                   1728:     au_p = u_find_symb(symb_str, UnitTree_p, &c_result);
                   1729:     if( c_result == 1 ) {  /* if found, copy the definition over */
                   1730:       u_copy_unit(cu_p, au_p, 1);
                   1731:     } else {
                   1732:       if( len > 1 ) {
                   1733:         if( PrefixTbl[ (int)symb_str[0] ] != 0 ) {  /* prefix is defined */
                   1734:           for(ii=1;ii<len;ii++) {
                   1735:              tmp_str[ii-1] = symb_str[ii];
                   1736:           }
                   1737:           tmp_str[len-1]=0;
                   1738:           au_p = u_find_symb(tmp_str, UnitTree_p, &c_result);
                   1739:           if( c_result == 1 ) {
                   1740:               /* printf("[%s] ", tmp_str); */
                   1741:             u_copy_unit(cu_p, au_p, 1);
                   1742:             d_exp = (double)PrefixTbl[ (int)symb_str[0] ];
                   1743:             cu_p->u_scale = cu_p->u_scale * pow((double)10.0,d_exp);
                   1744:           } else { /* unit *tmp_str not found */
                   1745:             /* printf(" not found\n"); */
                   1746:             err_code = 3;
1.4       albertel 1747: 	    cu_p->u_type   = U_UNKNOWN;
1.1       albertel 1748:           }
1.9       albertel 1749:         } else { /* symb_str is not in <prefix><units> form */
1.1       albertel 1750:           /* printf("<<%s>>", symb_str); */
                   1751:           err_code = 2;
1.4       albertel 1752: 	  cu_p->u_type   = U_UNKNOWN;
1.1       albertel 1753:         }
                   1754:       } else {/* len == 1 */
1.9       albertel 1755:         /* printf(" not found in symbol tree \n"); */
1.1       albertel 1756:         err_code = 1;
1.4       albertel 1757: 	cu_p->u_type   = U_UNKNOWN;
1.1       albertel 1758:       }
                   1759:     }
1.9       albertel 1760:   } else { /* why would we have a length less than zero symb_str ? */
1.1       albertel 1761:     err_code = 4;
                   1762:   }
                   1763:   
                   1764:   return (cu_p);
                   1765: }
                   1766: 
                   1767: int  s_peeknext_op()
                   1768: {
                   1769:   char  *ch;
                   1770:   int    sp=0;
                   1771:   
                   1772:   ch = (char *)&Sbuf[Sidx];
                   1773:   while( isspace(*ch) ) { ch++; sp=1; }
                   1774:   if( (*ch == '*')  || (*ch == '/') || (*ch == '+')  || (*ch == '-') || (*ch == '^')) {
                   1775:     return (*ch);
                   1776:   }
                   1777:   /* what if space is the last thing on the line?*/
                   1778:   if( sp && (*ch != '\0')) return '*';
                   1779:   return (*ch);
                   1780: }
                   1781: 
                   1782: int  s_getnext_op()
                   1783: {
                   1784:   char  *ch;
                   1785:   int    inc = 0, sp=0;
                   1786:   
                   1787:   
                   1788:   /* printf("\n((op"); print_remains(); printf("\n");  */
                   1789:   ch = (char *)&Sbuf[Sidx];
                   1790:   while( isspace(*ch) ) { ch++; inc++; sp=1; }
                   1791:   Sidx = Sidx + inc;
                   1792:   if( (*ch == '*')  || (*ch == '/') || (*ch == '+')  || (*ch == '-') || (*ch == '^') ) {
                   1793:     Sidx++;
                   1794:     /* print_remains();  printf(" op))"); printf("\n"); */
                   1795:     return (*ch);
                   1796:   }
                   1797:   /* print_remains();  printf(" op))"); printf("\n"); */
                   1798:   /* what if space is the last thing on the line?*/
                   1799:   if( sp  && (*ch != '\0')) return '*';
                   1800:   return (*ch);
                   1801: }
                   1802: 
                   1803: int
                   1804: s_getnext()
                   1805: {
                   1806:   char  ch;
                   1807:   
                   1808:   ch = Sbuf[Sidx];
                   1809:   Sidx++;
                   1810:   return (ch);
                   1811: }
                   1812: 
                   1813: int
                   1814: s_peeknext()
                   1815: {
                   1816:   char  ch;
                   1817:   
                   1818:   ch = Sbuf[Sidx];
                   1819:   return (ch);
                   1820: }
                   1821: 
                   1822: int
                   1823: s_peeknextNW()  /* peek into the next non-whitespaces character */
                   1824: {
                   1825:   char  *ch;
                   1826: 
                   1827:   ch = (char *)&Sbuf[Sidx];
                   1828:   while( isspace(*ch) ) { ch++; }
                   1829:   return (*ch);
                   1830: }
                   1831: 
                   1832: int
                   1833: s_getnextNW()  /* get the next non-whitespaces character */
                   1834: {
                   1835:   char  *ch;
                   1836: 
                   1837:   ch = (char *)&Sbuf[Sidx]; Sidx++;
                   1838:   while( isspace(*ch) ) { ch++; Sidx++; }
                   1839:   return (*ch);
                   1840: }
                   1841: /* peek into the next non-whitespaces character 
                   1842:    which should be either a multiply or division */
                   1843: int
                   1844: s_peekMDWS()  
                   1845: {
                   1846:   char  *ch;
                   1847:   int    sp=0;
                   1848:   
                   1849:   ch = (char *)&Sbuf[Sidx];
                   1850:   while( isspace(*ch) ) { ch++; sp=1;}
                   1851:   if( (*ch == '*')  || (*ch == '/') ) {
                   1852:     return (*ch);
                   1853:   }
                   1854:   if( sp ) return ' ';
                   1855:   ch = (char *)&Sbuf[Sidx];
                   1856:   while( isspace(*ch) ) { ch++; }
                   1857:   return (*ch);
                   1858: }
                   1859: 
                   1860: int
                   1861: s_getnextMDWS()
                   1862: {
                   1863:   char  *ch;
                   1864:   int    inc=0, sp=0;
                   1865:   
                   1866:   ch = (char *)&Sbuf[Sidx]; Sidx++;
                   1867:   while( isspace(*ch) ) { ch++; inc++; sp=1; }
                   1868:   Sidx += inc;
                   1869:   if( (*ch == '*')  || (*ch == '/') ) {
                   1870:     return (*ch);
                   1871:   }
                   1872:   if( sp ) return ' ';
                   1873:   return (*ch);
                   1874: }
                   1875: 
                   1876: double
                   1877: scan_FLOAT()
                   1878: {
                   1879:   double   num; 
                   1880:   int      ii=0, len;
                   1881:   char     num_str[QUARTER_K];
                   1882:   
                   1883:   num_str[ii]=0;
                   1884:   while( isspace(Sbuf[Sidx]) ) { Sidx++; }
                   1885:   if( Sbuf[Sidx] == '-' ) {
                   1886:     num_str[ii++] = Sbuf[Sidx++];
                   1887:   }
                   1888:   while( isdigit(Sbuf[Sidx]) || Sbuf[Sidx] == '.' ) {
                   1889:       num_str[ii++] = Sbuf[Sidx++];
                   1890:   }
                   1891:   if( Sbuf[Sidx] == 'E' || Sbuf[Sidx] == 'e' ) {
                   1892:     if( Sbuf[Sidx+1] == '-' || isdigit(Sbuf[Sidx+1]) ) {
                   1893:       num_str[ii++] = Sbuf[Sidx++];
                   1894:       num_str[ii++] = Sbuf[Sidx++];
                   1895:       while( isdigit(Sbuf[Sidx]) ) {
                   1896:         num_str[ii++] = Sbuf[Sidx++];
                   1897:       }
                   1898:     }
                   1899:   }
                   1900:   num_str[ii] = 0; /* terminate the str */
                   1901:   len = strlen(num_str);
                   1902:   if(len > 0 ) {
                   1903:     sscanf(num_str,"%lg", &num);
                   1904:     /* printf("<N %s %g>",num_str,num); fflush(stdout);  print_remains(); */
                   1905:   } else {
                   1906:     num = 1.0;
                   1907:   }
                   1908:   return (num);
                   1909: }
                   1910: /* -----------------------------------------------
                   1911:   N.item  := FLOAT
                   1912:            | FLOAT '^' N.term
                   1913:    ----------------------------------------------- */
                   1914: Unit_t  *
                   1915: scan_num_item()
                   1916: {
                   1917:   Unit_t  *node_p, *exp_p;
                   1918:   double   num_const;
                   1919:   char     ch;
                   1920:   
                   1921:   num_const = scan_FLOAT();
                   1922:   node_p = p_new_num(NULL, num_const, NULL);
                   1923:   ch = s_peeknext_op();
                   1924:   if( ch == '^' ) {
                   1925:     ch = s_getnext_op();
                   1926:     
                   1927:     exp_p = scan_num_term();
                   1928:     num_const = node_p->u_scale;
                   1929:     if( node_p->u_scale > 0.0 ) {
                   1930:       num_const = pow(node_p->u_scale,exp_p->u_scale);
                   1931:     }
                   1932:     node_p->u_scale = num_const;
                   1933:     capa_mfree((char *)exp_p);
                   1934:   }
                   1935:   return node_p;
                   1936: }
                   1937: 
                   1938: /* -----------------------------------------------
                   1939:   U.item  := UNIT
                   1940:            | UNIT '^' N.term
                   1941:    ----------------------------------------------- */
                   1942:    
                   1943: Unit_t *
                   1944: scan_unit_item()
                   1945: {
                   1946:   Unit_t   *node_p, *exp_p;
                   1947:   char      ch;
                   1948:   double   num_const;
                   1949:   Unit_E   *oe_p;
                   1950:   
                   1951:   node_p = p_new_unit(NULL,NULL);
                   1952:   ch = s_peeknext_op();
                   1953:   if( ch == '^' ) {
                   1954:     ch = s_getnext_op();
                   1955:     exp_p = scan_num_term();
                   1956:     num_const = exp_p->u_scale;
                   1957:     if( node_p->u_count > 0 ) {
                   1958:       oe_p = node_p->u_list;
                   1959:       for(oe_p = node_p->u_list; oe_p; oe_p = oe_p->ue_nextp ) {
                   1960:         oe_p->ue_exp   = oe_p->ue_exp * num_const;
                   1961:       }
                   1962:     }
                   1963:     num_const = node_p->u_scale;
                   1964:     if( node_p->u_scale > 0.0 ) {
                   1965:       num_const = pow(node_p->u_scale,exp_p->u_scale);
                   1966:     }
                   1967:     node_p->u_scale = num_const;
                   1968:     capa_mfree((char *)exp_p);
                   1969:   }
                   1970:   return node_p;
                   1971: }
                   1972: 
                   1973: void distribute_exp(Unit_t* node_p,Unit_t* exp_p) 
                   1974: {
                   1975:   Unit_E* oe_p;
                   1976:   double num_const;
                   1977:   num_const = exp_p->u_scale;  /* should we check if num_const too large or small ? */
                   1978:   if( node_p->u_count > 0 ) {
                   1979:     oe_p = node_p->u_list;
                   1980:     for(oe_p = node_p->u_list; oe_p; oe_p = oe_p->ue_nextp ) {
                   1981:       oe_p->ue_exp   = oe_p->ue_exp * num_const;
                   1982:     }
                   1983:   }
                   1984:   num_const = node_p->u_scale;
                   1985:   if( node_p->u_scale > 0.0 ) {  /* what if u_scale <= 0.0 ? */
                   1986:     num_const = pow(node_p->u_scale,exp_p->u_scale);
                   1987:   }
                   1988:   node_p->u_scale = num_const;
                   1989:   if (node_p->u_left) distribute_exp(node_p->u_left,exp_p);
                   1990:   if (node_p->u_right) distribute_exp(node_p->u_right,exp_p);
                   1991: }
                   1992: 
                   1993: /* ---------------------------------------------------------------
                   1994:    B.term  := U.item
                   1995:            | N.item
                   1996:            | '(' B.block ')'
                   1997:            | '{' B.block '}'
                   1998:            
                   1999:            | '(' B.block ')' '^' N.term  <== July 6 1998
                   2000:            | '{' B.block '}' '^' N.term
                   2001:            
                   2002:    --------------------------------------------------------------- */
                   2003: Unit_t *
                   2004: scan_basic_term()
                   2005: {
                   2006:   Unit_t   *node_p, *exp_p;
                   2007:   int       ch, nch;
                   2008:   
                   2009:   ch = s_peeknextNW();
                   2010:   if( ch == '(' || ch == '{' ) {
                   2011:     ch = s_getnextNW();  /* get rid of '(' or '{' */
                   2012:     node_p = scan_basic_block();
                   2013:     nch = s_peeknextNW();
                   2014:     if( nch == ')' || nch == '}' ) {  /* should be either ')' or '}' */
                   2015:       if( ((ch == '(' ) && (nch == ')' )) ||
                   2016:           ((ch == '{' ) && (nch == '}' )) ) { /* matching left paren with right paren */
                   2017:           
                   2018:            
                   2019:       } else {
                   2020:         /* printf(" WARN: %c matched by %c\n", ch, nch); */
                   2021:       }
                   2022:       nch = s_getnextNW();
                   2023:       /* ====== Added Jul 6, 1998 ====> */
                   2024:       ch = s_peeknext_op();
                   2025:       if( ch == '^' ) {
                   2026:         ch = s_getnext_op();  /* get rid of '^' char */
                   2027:         exp_p = scan_num_term();
                   2028: 	distribute_exp(node_p,exp_p);
                   2029:         capa_mfree((char *)exp_p);
                   2030:       } 
                   2031:       /* <== added Jul 6, 1998 == */
                   2032:     } else {
                   2033:       /* printf(" WARN: %c is not matched by %c\n", ch, nch); */
                   2034:     }
                   2035:   } else if( ch >= '0' && ch <= '9' ) {
                   2036:     node_p = scan_num_item();
                   2037:   } else { /* assume a unit symbol */
                   2038:     /* printf("<B.term>"); print_remains(); */
                   2039:     node_p = scan_unit_item();
                   2040:     /* print_remains(); */
                   2041:   }
                   2042:   return node_p;
                   2043: }
                   2044: /* --------------------------------------------------
                   2045:    N.term  := N.item
                   2046:            | '-' N.item
                   2047:            | '(' N.expr ')'
                   2048:            | '{' N.expr '}'
                   2049:  -------------------------------------------------- */
                   2050: Unit_t *
                   2051: scan_num_term()
                   2052: {
                   2053:   Unit_t   *node_p;
                   2054:   char      ch, nch;
                   2055: 
                   2056:   ch = s_peeknextNW();
                   2057:   if( ch == '(' || ch == '{' ) {
                   2058:     ch = s_getnextNW();
                   2059:     node_p = scan_num_expr();
                   2060:     nch = s_peeknextNW();
                   2061:     if( nch == ')' || nch == '}' ) {  /* should be either ')' or '}' */
                   2062:       if( ((ch == '(' ) && (nch == ')' )) ||
                   2063:           ((ch == '{' ) && (nch == '}' )) ) { 
                   2064:         
                   2065:       } else {
                   2066:         /* printf(" WARN: %c matched by %c\n", ch, nch); */
                   2067:       }
                   2068:       nch = s_getnextNW();
                   2069:     } else {
                   2070:       /* printf(" WARN: %c is not matched by %c\n", ch, ch); */
                   2071:     }
                   2072:   } else if( ch == '-' ) {
                   2073:     ch = s_getnextNW();
                   2074:     node_p = scan_num_item();
                   2075:     node_p->u_scale = (-1)*node_p->u_scale;
                   2076:   } else {
                   2077:     if( isdigit(ch) ) {
                   2078:        node_p = scan_num_item();
                   2079:     } else { /* something other than a number */
                   2080:        /*
                   2081:           printf(" ERROR: expect a number: ");
                   2082:           print_remains();
                   2083:        */
                   2084:        node_p = p_new_num(NULL, 0.0, NULL); /* make the unknown item */
                   2085:     }
                   2086:   }
                   2087:   return node_p;
                   2088: }
                   2089: 
                   2090: /* --------------------------------------------------
                   2091:    B.block := B.term
                   2092:            | B.term ' ' B.term
                   2093:            | B.term '*' B.term
                   2094:            | B.term '/' B.term
                   2095:    -------------------------------------------------- */
                   2096: Unit_t  *
                   2097: scan_basic_block()
                   2098: {
                   2099:   Unit_t   *node_p;
                   2100:   char      ch;
                   2101:   int       op;
                   2102:   
                   2103:   /* printf("<B.block>(before B.term)"); print_remains(); */
                   2104:   node_p = scan_basic_term();
                   2105:   ch = s_peeknext_op();
                   2106:   while ( ch == '*' || ch == '/' ) {
                   2107:     op = ( ch == '/' ? U_OP_DIVIDE : U_OP_TIMES);
                   2108:     ch = s_getnext_op();
                   2109:     /* printf("<B.block>(/ *)"); print_remains();  */
                   2110:     node_p = p_new_op(node_p,op,scan_basic_term());
                   2111:     ch = s_peeknext_op();
                   2112:   }
                   2113:   return node_p;
                   2114: }
                   2115: /* --------------------------------------------------
                   2116:    N.block := N.term 
                   2117:            | N.term ' ' N.term
                   2118:            | N.term '*' N.term
                   2119:            | N.term '/' N.term
                   2120:    -------------------------------------------------- */
                   2121: Unit_t  *
                   2122: scan_num_block()
                   2123: {
                   2124:   Unit_t   *node_p, *opand_p;
                   2125:   char      ch;
                   2126:   double    result;
                   2127:   
                   2128:   node_p = scan_num_term();
                   2129:   ch = s_peeknext_op();
                   2130:   while ( ch == '*' || ch == '/' ) {
                   2131:     s_getnext_op();
                   2132:     opand_p = scan_num_term();
                   2133:     if( ch == '*' ) {
                   2134:       result = node_p->u_scale * opand_p->u_scale;
                   2135:     } else {
                   2136:       result = node_p->u_scale / opand_p->u_scale;
                   2137:     }
                   2138:     node_p->u_scale = result;
                   2139:     capa_mfree((char *)opand_p);
                   2140:     ch = s_peeknext_op();
                   2141:   }
                   2142:   return node_p;
                   2143: }
                   2144: 
                   2145: /* ---------------------------------------
                   2146:    U.expr  := B.block
                   2147:            | B.block '+' B.block
                   2148:            | B.block '-' B.block
                   2149:    --------------------------------------- */
                   2150: Unit_t  *
                   2151: scan_unit_expr()
                   2152: {
                   2153:   Unit_t   *node_p;
                   2154:   char      ch;
                   2155:   int       op;
                   2156:   
                   2157:   /* printf("<U.expr>"); print_remains();  */
                   2158:   node_p = scan_basic_block();
                   2159:   ch = s_peeknext_op();
                   2160:   while ( ch == '+' || ch == '-' ) {
                   2161:     op = ( ch == '+' ? U_OP_PLUS : U_OP_MINUS);
                   2162:     ch = s_getnext_op();
                   2163:     /* printf("<U.expr>(+-)"); print_remains(); */
                   2164:     node_p = p_new_op(node_p,op,scan_basic_block());
                   2165:     ch = s_peeknext_op();
                   2166:   }
                   2167:   return node_p;
                   2168: }
                   2169: /* -----------------------------------------
                   2170:    N.expr  := N.block 
                   2171:            | N.block '+' N.block
                   2172:            | N.block '-' N.block
                   2173:    ----------------------------------------- */
                   2174: Unit_t  *
                   2175: scan_num_expr()
                   2176: {
                   2177:   Unit_t   *node_p, *opand_p;
                   2178:   char      ch;
                   2179:   double    result;
                   2180:   
                   2181:   node_p = scan_num_block();
                   2182:   ch = s_peeknext_op();
                   2183:   while ( ch == '+' || ch == '-' ) {
                   2184:     ch = s_getnext_op();
                   2185:     opand_p = scan_num_block();
                   2186:     if( ch == '+' ) {
                   2187:       result = node_p->u_scale + opand_p->u_scale;
                   2188:     } else {
                   2189:       result = node_p->u_scale - opand_p->u_scale;
                   2190:     }
                   2191:     node_p->u_scale = result;
                   2192:     capa_mfree((char *)opand_p);
                   2193:     ch = s_peeknext_op();
                   2194:   }
                   2195:   return node_p;
                   2196: }
                   2197: 
                   2198: /* ----------------------------------------------------------------------- */
                   2199: /* <--  This is the major entry point to parse an units expression ------> */
                   2200: Unit_t  *
                   2201: parse_unit_expr(char *symb_str)
                   2202: {
                   2203:   Unit_t   *root_p;
                   2204:   int       len;
                   2205:   
                   2206:   len = strlen(symb_str);
                   2207:   strcpy(Sbuf,symb_str);  /* copy it into the global Sbuf */
                   2208:   Sidx=0;
                   2209:   root_p = scan_unit_expr();
                   2210:   if(Sidx < len-1 ) {
                   2211:     /* printf(" WARN: NOT PARSED:");  print_remains(); */
                   2212:   }
                   2213:   return (root_p);
                   2214: 
                   2215: }
                   2216: 
                   2217: void
                   2218: print_remains()
                   2219: {
                   2220:   int       len, ii;
                   2221:   
                   2222:   len = strlen(Sbuf);
                   2223:   printf("[[");
                   2224:   for(ii=Sidx;ii<len;ii++) {
                   2225:       printf("%c",Sbuf[ii]);
                   2226:   }
                   2227:   printf("]]");
                   2228:   
                   2229: }
                   2230: 
                   2231: 
                   2232: 
                   2233: /* =================================================================== */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>