File:  [LON-CAPA] / capa / capa51 / pProj / capaUnit.c
Revision 1.6: download - view: text, annotated - select for diffs
Fri Jul 7 18:33:03 2000 UTC (24 years ago) by albertel
Branches: MAIN
CVS tags: version5-1-2-first_release, HEAD
- updating GPL notices

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

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