File:  [LON-CAPA] / capa / capa51 / pProj / capaUnit.c
Revision 1.14: download - view: text, annotated - select for diffs
Fri Aug 4 18:09:55 2023 UTC (12 months, 2 weeks ago) by raeburn
Branches: MAIN
CVS tags: version_2_12_X, version_2_11_X, version_2_11_5_msu, version_2_11_5, version_2_11_4_msu, HEAD
- Bug 6976.  Reduce logfile spew in /var/log/messages for Apache 2.4.

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

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