File:  [LON-CAPA] / capa / capa51 / pProj / capaUnit.c
Revision 1.5: download - view: text, annotated - select for diffs
Fri Jun 30 21:36:16 2000 UTC (24 years ago) by albertel
Branches: MAIN
CVS tags: HEAD
- gave everyone the GPL header

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

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