File:  [LON-CAPA] / capa / capa51 / pProj / capaUnit.c
Revision 1.13: download - view: text, annotated - select for diffs
Tue Feb 15 22:15:05 2005 UTC (19 years, 4 months ago) by albertel
Branches: MAIN
CVS tags: version_2_9_X, version_2_9_99_0, version_2_9_1, version_2_9_0, version_2_8_X, version_2_8_99_1, version_2_8_99_0, version_2_8_2, version_2_8_1, version_2_8_0, version_2_7_X, version_2_7_99_1, version_2_7_99_0, version_2_7_1, version_2_7_0, version_2_6_X, version_2_6_99_1, version_2_6_99_0, version_2_6_3, version_2_6_2, version_2_6_1, version_2_6_0, version_2_5_X, version_2_5_99_1, version_2_5_99_0, version_2_5_2, version_2_5_1, version_2_5_0, version_2_4_X, version_2_4_99_0, version_2_4_2, version_2_4_1, version_2_4_0, version_2_3_X, version_2_3_99_0, version_2_3_2, version_2_3_1, version_2_3_0, version_2_2_X, version_2_2_99_1, version_2_2_99_0, version_2_2_2, version_2_2_1, version_2_2_0, version_2_1_X, version_2_1_99_3, version_2_1_99_2, version_2_1_99_1, version_2_1_99_0, version_2_1_3, version_2_1_2, version_2_1_1, version_2_1_0, version_2_11_X, version_2_11_4_uiuc, version_2_11_4, version_2_11_3_uiuc, version_2_11_3_msu, version_2_11_3, version_2_11_2_uiuc, version_2_11_2_msu, version_2_11_2_educog, version_2_11_2, version_2_11_1, version_2_11_0_RC3, version_2_11_0_RC2, version_2_11_0_RC1, version_2_11_0, version_2_10_X, version_2_10_1, version_2_10_0_RC2, version_2_10_0_RC1, version_2_10_0, version_2_0_X, version_2_0_99_1, version_2_0_2, version_2_0_1, version_2_0_0, version_1_99_3, version_1_99_2, version_1_99_1_tmcc, version_1_99_1, version_1_99_0_tmcc, version_1_99_0, loncapaMITrelate_1, language_hyphenation_merge, language_hyphenation, bz6209-base, bz6209, HEAD, GCI_3, GCI_2, GCI_1, BZ4492-merge, BZ4492-feature_horizontal_radioresponse, BZ4492-feature_Support_horizontal_radioresponse, BZ4492-Support_horizontal_radioresponse
- BUG#3952, the instructor's unit was being parsed by the stupid, but fast unit parser, swapping it out so that the instructor's parser is the same as the one used to parse the students's answer

    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>