/* functions to handle the unit parser/comparison engine Copyright (C) 1992-2000 Michigan State University The CAPA system is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The CAPA system is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the CAPA system; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception, you have permission to link this program with the TtH/TtM library and distribute executables, as long as you follow the requirements of the GNU GPL in regard to all of the software in the executable aside from TtH/TtM. */ /* =||>|===================== capaUnit.c =====================|<||= */ /* created by Isaac Tsai 1997 */ /* by Isaac Tsai 1997, 1998, 1999 */ /* =||>|========================================================|<||= */ #include /* fopen() */ #include #include /* isalnum() */ #include #include #include #include "capaParser.h" int PrefixTbl[QUARTER_K]; int BaseUnitcnt; double CScale[BASEUNIT_LIMIT]; double CExp[BASEUNIT_LIMIT]; char CSymb[BASEUNIT_LIMIT][SYMBOL_MAXLEN]; Unit_t *UnitTree_p; double MinSquared; Unit_t *MinSquaredUnit_p; Unit_t *InqueryUnit_p; double *TmpAexp, *TmpBexp; Unit_t *EquivUnit[BASEUNIT_LIMIT]; double MinValue[BASEUNIT_LIMIT]; int EquivUnitCnt; char Sbuf[ONE_K_SIZE]; int Sidx; Unit_t *Pstack[ONE_K_SIZE]; int Ptopidx; int gUnitError; FILE *ufp; /* ==================================================================== */ void c_ignorewhite(FILE *f) /* ignore white spaces from a file stream */ { register int c; register int ok; ok = 0; do { do { c = getc(f); } while ( isspace(c) ); ungetc(c,f); if (c == '#') { while (getc(f) != '\n'); } else ok = 1; } while( ! ok); } int c_getint(FILE *f) /* returns an integer from the file stream */ { int c; int value; c_ignorewhite(f); c = fgetc(f); if (!isdigit(c)) { fprintf(stderr,"Error: Expected digit, got %c\n", c); exit(-1); } ungetc(c,f); fscanf(f,"%d", &value); return(value); } int c_getsec_range(FILE *f,int *low,int *high) { int c; int tmp, result; c_ignorewhite(f); c = fgetc(f); if( c == '[' ) { /* specify a range of sections */ do { c = getc(f); } while ( isspace(c) ); if (!isdigit(c)) { fprintf(stderr,"Error in section range format, expecting a number.\n"); result = -1; return (result); } ungetc(c,f); fscanf(f,"%d", low); do { c = getc(f); } while ( isspace(c) ); if( c == ',' ) { do { c = getc(f); } while ( isspace(c) ); if (!isdigit(c)) { fprintf(stderr,"Error in section range format, expecting a number.\n"); result = -1; return (result); } ungetc(c,f); fscanf(f,"%d", high); do { c = getc(f); } while ( isspace(c) ); if( c == ']' ) { if( *high < *low ) { tmp= *high; *high = *low; *low =tmp; } if(*low <=0) { *low = 1; } if(*high <=0) { *high =1; } /* printf("Section range=>[%d,%d]\n",*low,*high); */ result = 2; } } else { /* no , specified */ result = -1; return (result); } } else { /* specify a section only */ if (!isdigit(c)) { fprintf(stderr,"Error: Expected digit, got %c\n", c); result = -1; return (result); } ungetc(c,f); fscanf(f,"%d", low); result = 1; } return (result); } double c_getdouble(FILE *f) { int c; double value; c_ignorewhite(f); c = fgetc(f); if (!isdigit(c)) { fprintf(stderr,"Error: Expected digit, got %c\n", c); exit(-1); } ungetc(c,f); fscanf(f,"%lf", &value); return(value); } /* read until encountered an unrecognizable char */ /* space, #, anything other than alphanum, {}-^_ */ char *c_getword(FILE *f) { register int c; register int idx; char tmp_string[ONE_K]; char *new_string; idx = 0; c_ignorewhite(f); do { c = getc(f); tmp_string[idx] = c; idx++; } while (isalnum(c) || c == '{' || c == '}' || c == '-' || c == '^' || c == '_' ); ungetc(c,f); idx--; tmp_string[idx] = 0; new_string = (char *)malloc( (idx+1)*sizeof(char) ); strncpy(new_string,tmp_string, (idx+1) ); return (new_string); } /* read until encountered a newline, # */ char *c_getstring(FILE *f) { register int c; register int idx; char tmp_string[1024]; char *new_string; idx = 0; c_ignorewhite(f); do { c = getc(f); tmp_string[idx] = c; idx++; } while (isalnum(c) || c == '{' || c == '}' || c == '-' || c == '^' || c == ' ' || c == ',' || c == ';' || c == '.' || c == '(' || c == ')' || c == '=' || c == '+' || c == '*' || c == '/' ); ungetc(c,f); idx--; tmp_string[idx] = 0; c = tmp_string[idx-1]; while( c == ' ') { /* get rid of trailing white space */ idx--; c = tmp_string[idx-1]; } tmp_string[idx] = 0; new_string = (char *)malloc( (idx+1)*sizeof(char) ); strncpy(new_string,tmp_string, (idx+1) ); return (new_string); } char *c_getcomment(FILE *f) { register int c; register int idx; char tmp_string[ONE_K]; char *new_string; idx = 0; while (getc(f) != '#'); while ((c = getc(f)) == ' '); ungetc(c,f); do { c = getc(f); tmp_string[idx] = c; idx++; } while ( isprint(c) ); /* } while (isalnum(c) || c == '{' || c == '}' || c == '-' || c == '^' || c == ' ' || c == ',' || c == ';' || c == '.' || c == '(' || c == ')' || c == '=' ); */ ungetc(c,f); idx--; tmp_string[idx] = 0; c = tmp_string[idx-1]; while( c == ' ') { /* get rid of trailing white space */ idx--; c = tmp_string[idx-1]; } tmp_string[idx] = 0; new_string = (char *)malloc( (idx+1)*sizeof(char) ); strncpy(new_string,tmp_string, (idx+1) ); return (new_string); } void c_moveto_unit(FILE *f) { register int c; register int ok; ok = 0; do { do { c = getc(f); } while (c != '<' ); c = getc(f); if (c == '<') { ungetc(c,f); ungetc(c,f); ok=1; } } while( ! ok); } int c_gettype(FILE *f) { register int c; register int idx; char tmp_string[ONE_K]; char new_string[ONE_K]; idx = 0; PRESTART: c_ignorewhite(f); while ((c=getc(f)) != '<') { if ( (char)c==(char)EOF ) return U_UNKNOWN; } c = getc(f); if( c == '<' ) { c_ignorewhite(f); PREEND: do { c = getc(f); tmp_string[idx] = toupper(c); idx++; } while ( c != '>' ); c = getc(f); if( c == '>' ) { idx--; tmp_string[idx] = 0; c = tmp_string[idx-1]; while( c == ' ') { /* get rid of trailing white space */ idx--; c = tmp_string[idx-1]; } tmp_string[idx] = 0; strncpy(new_string,tmp_string, (idx+1) ); } else { ungetc(c,f); goto PREEND; } } else { goto PRESTART; } if( !strcmp(new_string,"BASE UNIT") ) { return (U_BASE); } if( strcmp(new_string, "DERIVED UNIT") == 0 ) { return (U_DERIVED); } if( strcmp(new_string, "PREFIX") == 0 ) { return (U_PREFIX); } if( strcmp(new_string, "CONSTANTS") == 0 ) { return (U_CONSTANT); } if( strcasecmp(new_string, "DEFAULTS") == 0 ) { return (U_DEFAULT); } return (U_UNKNOWN); } /* =================================================================== */ /* =================================================================== */ /* returns: 0 success */ /* 1 the first units string u1_str could not be reduce to a valid unit */ /* 2 the second units string could not be reduced to a valid unit */ int u_convert_unit(char *u1_str,char *u2_str,double *ratio) { Unit_t *ap, *bp; int result=0; while( isspace(*u1_str) ) u1_str++; while( isspace(*u2_str) ) u2_str++; bp = parse_unit_expr(u2_str); Ptopidx=0; postwalk_utree(bp); if( Ptopidx == 1 ) { simplify_unit(Pstack[Ptopidx]); bp = Pstack[Ptopidx]; /* print_unit_t(bp); */ ap = parse_unit_expr(u1_str); Ptopidx=0; postwalk_utree(ap); if( Ptopidx == 1 ) { simplify_unit(Pstack[Ptopidx]); /* print_unit_t(Pstack[Ptopidx]); */ if( (Pstack[Ptopidx]->u_count != 0) || (Pstack[Ptopidx]->u_count == bp->u_count) ) { /* has unit */ *ratio = units_ratio(Pstack[Ptopidx], bp); } else { result = 1; } } free_utree(ap); } else { result = 2; } free_utree(bp); return (result); } /* =================================================================== */ Unit_t * u_find_symb (char *name, Unit_t *t, int *result) { if (t == NULL) return t; for (;;) { if ( comp_unit_symb(name,t->u_symbol) < 0 ) { if (t->u_left == NULL) { /* printf("L not found\n"); */ *result = 0; break; } t = t->u_left; } else if ( comp_unit_symb(name,t->u_symbol) > 0 ) { if (t->u_right == NULL) { /* printf("R not found\n"); */ *result = 0; break; } t = t->u_right; } else { *result = 1; break; } } return t; } /* ------------------------------------------------------------- */ /* use the input unit_t's element list to locate the min squared */ /* error fit of the unit tree */ /* report either exact fit or approx */ void u_find_name(Unit_t *t) { int ii; Unit_E *eu_p; MinSquared = FLT_MAX; EquivUnitCnt=0; InqueryUnit_p = t; /* printf("INQ[[%s,%s,%d]]\n", U_SYMB(t), U_NAME(t),U_COUNT(t)); */ TmpAexp = (double *)capa_malloc(BaseUnitcnt,sizeof(double)); TmpBexp = (double *)capa_malloc(BaseUnitcnt,sizeof(double)); for(ii=0;iiu_count > 0 ) { for(eu_p = t->u_list; eu_p; eu_p = eu_p->ue_nextp) { TmpAexp[eu_p->ue_index] = eu_p->ue_exp; /* printf("(%d)^(%g) ",eu_p->ue_index,TmpAexp[eu_p->ue_exp]); */ } /* printf("\n"); */ } inorder_diff(UnitTree_p); /*capa_mfree((char *)TmpAexp); capa_mfree((char *)TmpBexp);*/ } void print_matches(Unit_t *t) { double scale, factor; Unit_t *tmp_p; int ii; scale = t->u_scale; if( MinSquared == 0.0 ) { /* exact match */ if( EquivUnitCnt > 0 ) { printf(" Entered unit is equivalent to:\n"); for(ii=0;iiu_type == U_BASE ) { /* if there is a base unit */ MinSquaredUnit_p = tmp_p; } factor = scale / tmp_p->u_scale; printf(" <<%g %s>>", factor,U_SYMB(tmp_p)); } } printf("\n"); } } else { /* no exact match */ if( EquivUnitCnt > 0 ) { printf(" Entered unit is approximated by:\n"); for(ii=0;ii> ", U_SYMB(tmp_p) ); } } printf("\n"); } } } /* ------------------------------------ */ double u_squared_diff(Unit_t *a, Unit_t *b) { double result; double squared_diff = 0.0; int ii; Unit_E *eu_p; for(ii=0;iiu_count > 0 ) { for(eu_p= a->u_list; eu_p; eu_p = eu_p->ue_nextp) { TmpAexp[eu_p->ue_index] = eu_p->ue_exp; } } if( b->u_count > 0 ) { for(eu_p= b->u_list; eu_p; eu_p = eu_p->ue_nextp) { TmpBexp[eu_p->ue_index] = eu_p->ue_exp; /* printf("Exp[%d]=%g ",ii,TmpBexp[ii]); */ } /* printf("\n"); */ } for(ii=0;iiu_count > 0 ) { for(eu_p= b->u_list; eu_p; eu_p = eu_p->ue_nextp) { TmpBexp[eu_p->ue_index] = eu_p->ue_exp; /* printf("Exp[%d]=%g ",ii,TmpBexp[ii]); */ } /* printf("\n"); */ } else if( b->u_type == U_BASE ) { TmpBexp[b->u_index] = 1.0; } for(ii=0;ii sq_diff) { MinSquaredUnit_p = node_p; MinSquared = sq_diff; } else if ( MinSquared == sq_diff) { EquivUnit[EquivUnitCnt] = node_p; MinValue[EquivUnitCnt] = sq_diff; EquivUnitCnt++; } } result = inorder_diff(U_RIGHT(node_p)); return (result); } int alphaorder_utree(node_p) Unit_t *node_p; { int result; if( node_p == NULL ) return (1); result = alphaorder_utree(U_LEFT(node_p)); if( result ) printf(" (%s,%s)\n", U_SYMB(node_p), U_NAME(node_p) ); result = alphaorder_utree(U_RIGHT(node_p)); return (result); } int w_alphaorder_utree(node_p) Unit_t *node_p; { int result; if( node_p == NULL ) return (1); result = alphaorder_utree(U_LEFT(node_p)); if( result ) { printf(" (%s,%s)\n", U_SYMB(node_p), U_NAME(node_p) ); } result = alphaorder_utree(U_RIGHT(node_p)); return (result); } /* --------------------------------------------------------------------- */ void print_unit_tree(int mode) { if( mode == 1 ) { alphaorder_utree(UnitTree_p); } else { w_alphaorder_utree(UnitTree_p); } } int preorder_utree(node_p) Unit_t *node_p; { int result; if( node_p == NULL ) return (1); printf("Preorder=[[%s,%s,%d]]\n", U_SYMB(node_p), U_NAME(node_p),U_COUNT(node_p)); result = preorder_utree(U_LEFT(node_p)); if( result ) result = preorder_utree(U_RIGHT(node_p)); return (result); } int inorder_utree(node_p) Unit_t *node_p; { int result; if( node_p == NULL ) return (1); result = inorder_utree(U_LEFT(node_p)); if( result ) printf("INorder=[[%s,%s,%d]]\n", U_SYMB(node_p), U_NAME(node_p),U_COUNT(node_p)); result = inorder_utree(U_RIGHT(node_p)); return (result); } int postorder_utree(node_p) Unit_t *node_p; { int result; if( node_p == NULL ) return (1); result = postorder_utree(U_LEFT(node_p)); if( result ) result = postorder_utree(U_RIGHT(node_p)); if( result ) { switch(U_TYPE(node_p)) { case U_DERIVED: print_unit_t(node_p); break; case U_CONSTANT: printf("(%g)",U_SCALE(node_p)); break; case U_OP_POWER: printf("^"); break; case U_OP_TIMES: printf("*"); break; case U_OP_PLUS: printf("+"); break; case U_OP_MINUS: printf("-"); break; case U_OP_DIVIDE: printf("/"); break; default: printf("()"); break; } } return (result); } /* returns 1 on okay, 2 on error*/ int postwalk_utree(Unit_t *n_p) { int result; if( n_p == NULL ) return (1); result = postwalk_utree(U_LEFT(n_p)); if (result !=2) { if( result ) result = postwalk_utree(U_RIGHT(n_p)); if (result !=2) { if( result ) { switch(U_TYPE(n_p)) { case U_DERIVED: Ptopidx++; Pstack[Ptopidx] = n_p; /* push into stack */ break; case U_CONSTANT: Ptopidx++; Pstack[Ptopidx] = n_p; /* push into stack */ break; case U_UNKNOWN: result=2; /*push into stack anyway, try to parse rest of tree */ break; case U_OP_POWER: printf("^"); result=2; break; case U_OP_TIMES: process_op(U_OP_TIMES); /* process operator */ break; case U_OP_PLUS: printf("+"); result=2; break; case U_OP_MINUS: printf("-"); result=2; break; case U_OP_DIVIDE: process_op(U_OP_DIVIDE); /* process operator */ break; default: printf("()"); result=2; break; } } } } return (result); } void process_op(int op) { Unit_t *ap, *bp; double exp_scale; int no_error=1; bp = Pstack[Ptopidx--]; ap = Pstack[Ptopidx--]; switch(op) { case U_OP_TIMES: exp_scale = 1.0; break; case U_OP_DIVIDE: exp_scale = -1.0; break; case U_OP_PLUS: case U_OP_MINUS: no_error = u_pm_op(ap,bp,op); if(no_error) { Ptopidx++; Pstack[Ptopidx] = ap; } break; default: no_error=0; printf("No such op on the parse tree!\n"); break; } if(no_error) { u_copy_unit(ap, bp, exp_scale); Ptopidx++; Pstack[Ptopidx] = ap; } } Unit_t* process_utree(Unit_t *t) { Ptopidx=0; postwalk_utree(t); if( Ptopidx == 1 ) { //fprintf(stderr,"Correctly parsed!\n"); //fprintf(stderr,"Unit:%s\n",Sbuf); simplify_unit(Pstack[Ptopidx]); //Pstack[Ptopidx]->u_symbol[0]='\0'; //fprintf(stderr,Pstack[Ptopidx]->u_symbol,""); print_unit_t(Pstack[Ptopidx]); //u_find_name(Pstack[Ptopidx]); //print_matches(Pstack[Ptopidx]); return(Pstack[Ptopidx]); //free_utree(t); } return(t); } /* ============================================================== */ /* called from capaCommon.c */ /* */ /* UNIT_FAIL */ /* NO_UNIT */ /* result: UNIT_OK correct */ /* */ /* -------------------------------------------------------------- */ int check_correct_unit(char *u_symb,Unit_t *t,double *scale) { Unit_t *ap; int result=UNIT_OK; #ifdef UNIT_DBUG if ((ufp=fopen("unit.DBUG","a"))==NULL) { fprintf(stderr,"Error: can't open login debug\n"); return UNIT_FAIL; } #endif while( isspace(*u_symb) ) u_symb++; /* <= change this to search from the end of string */ /* or to get rid of all the white spaces */ ap = parse_unit_expr(u_symb); Ptopidx=0; if (postwalk_utree(ap)==1) { #ifdef UNIT_DBUG fprintf(ufp,"Ptopidx %d\n",Ptopidx); #endif if( Ptopidx == 1 ) { simplify_unit(Pstack[Ptopidx]); if( (Pstack[Ptopidx]->u_count != 0) || (Pstack[Ptopidx]->u_count == t->u_count) ) { /* has unit */ *scale = units_ratio(Pstack[Ptopidx], t); if( *scale == 0.0 ) { result = UNIT_IRRECONCIBLE; } free_utree(ap); } else { result = UNIT_INVALID_STUDENT3; } } else { /* invalid unit representation */ result = UNIT_INVALID_STUDENT2; } } else { result = UNIT_INVALID_STUDENT1; } #ifdef UNIT_DBUG fclose(ufp); #endif return (result); } /* ============================================================= */ int free_units() { free_utree(UnitTree_p); UnitTree_p=NULL; return 0; } int free_utree(Unit_t *t) { int result=1; if( t == NULL ) return (1); u_postfree(t); t=NULL; return (result); } int u_postfree(Unit_t *t) { int result; if( t == NULL ) return (1); result = u_postfree(U_LEFT(t)); if( result ) result = u_postfree(U_RIGHT(t)); if( result ) { if( t->u_comment ) { capa_mfree((char *)t->u_comment); } freelist_unit_e(t->u_list); capa_mfree((char *)t); } return (result); } void print_unit_t(Unit_t *t) { Unit_E *ue_p; /* printf(" Unit::[%s,%d]= %g * ", t->u_symbol,t->u_count,t->u_scale); */ printf(" Unit::[%s] = %g * ", t->u_symbol, t->u_scale); for(ue_p=t->u_list; ue_p ; ue_p = ue_p->ue_nextp) { /* printf("<%s,%d,%g,%g> ",ue_p->ue_symbol,ue_p->ue_index,ue_p->ue_scale,ue_p->ue_exp); */ printf("(%g*%s^%g) ",ue_p->ue_scale,ue_p->ue_symbol,ue_p->ue_exp); } printf("\n"); } /* ----------------------------------------------------------- */ /* copy the Unit_E linked list from b_p->u_list to a_p->u_list */ /* create some Unit_E nodes in a_p->u_list if needed and */ /* leave b_p->u_list intact */ /* a_p->u_scale is multiplied by pow(b_p->u_scale,exp_scale) */ /* ----------------------------------------------------------- */ void u_copy_unit(Unit_t *a_p, Unit_t *b_p, double exp_scale) { Unit_E *oe_p, *ne_p, *last_p; int ii; double scale; if( a_p->u_count > 0 ) { for(last_p = a_p->u_list; last_p->ue_nextp; last_p = last_p->ue_nextp) { } } else { a_p->u_list = last_p = NULL; } if( b_p->u_count > 0 ) { oe_p = b_p->u_list; for(ii=0;iiu_count;ii++) { ne_p = (Unit_E *) capa_malloc(1, sizeof(Unit_E)); /* *** */ ne_p->ue_scale = oe_p->ue_scale; ne_p->ue_exp = oe_p->ue_exp * exp_scale; ne_p->ue_index = oe_p->ue_index; strcpy(ne_p->ue_symbol, oe_p->ue_symbol); oe_p = oe_p->ue_nextp; if( last_p == NULL ) { a_p->u_list = ne_p; } else { last_p->ue_nextp = ne_p; } last_p = ne_p; a_p->u_count++; } scale = pow(b_p->u_scale, exp_scale); a_p->u_scale = a_p->u_scale * scale; /* printf("Found scale=%g=%g\n",a_p->u_scale,b_p->u_scale); */ } else { if( b_p->u_type == U_BASE ) { /* *b_p is a base unit, so create a one element unit */ ne_p = (Unit_E *) capa_malloc(1, sizeof(Unit_E)); /* *** */ ne_p->ue_scale = b_p->u_scale; ne_p->ue_exp = exp_scale; ne_p->ue_index = b_p->u_index; strcpy(ne_p->ue_symbol, b_p->u_symbol); if( last_p == NULL ) { a_p->u_list = ne_p; } else { last_p->ue_nextp = ne_p; } last_p = ne_p; a_p->u_count++; } else if( b_p->u_type == U_DERIVED) { /* derived units but without any units elements (scalar) */ /*a_p->u_count++;*/ scale = pow(b_p->u_scale, exp_scale); a_p->u_scale = a_p->u_scale * scale; } else if( b_p->u_type == U_CONSTANT ) { scale = pow(b_p->u_scale, exp_scale); a_p->u_scale = a_p->u_scale * scale; } else { printf("This node has no u_e list and Type unknown\n"); } } } int u_pm_op(Unit_t *a_p, Unit_t *b_p, int op) { int result=0; if( a_p->u_count > 0 || b_p->u_count > 0 ) { printf(" cannot add or sub units at this moment\n"); return result; } if( op == U_OP_PLUS ) { a_p->u_scale = a_p->u_scale + b_p->u_scale; } else { a_p->u_scale = a_p->u_scale - b_p->u_scale; } return 1; } int u_parsepower(char *unit_str) { int exp, ii; char *ch_p, exp_str[16]; ch_p = unit_str; while( isspace(*ch_p) ) { ch_p++; } ii=0; while( isdigit(*ch_p) ) { ch_p++; } while( isspace(*ch_p) ) { ch_p++; } if( *ch_p == '^' ) { ch_p++; } while( isspace(*ch_p) ) { ch_p++; } if( *ch_p == '{' ) { ch_p++; } while( isspace(*ch_p) ) { ch_p++; } ii=0; while( isdigit(*ch_p) || *ch_p == '-' || *ch_p == '+' ) { exp_str[ii++] = *ch_p; ch_p++; } exp_str[ii]=0; sscanf(exp_str,"%d", &exp); return (exp); } /* ------------------------------------------- */ /* scan a number of the form indicated below from the input buffer */ /* 1.234^{2.3} */ /* 1e */ double s_scan_number(char *buf, int idx, int *r_idx) { double num; float exp; double result; int ii=0; char num_str[QUARTER_K]; num_str[ii]=0; if( buf[idx] == '-' ) { num_str[ii++] = '-'; idx++; } while( isdigit(buf[idx]) || buf[idx] == '.' ) { num_str[ii++] = buf[idx]; idx++; } if( buf[idx] == 'E' || buf[idx] == 'e' ) { if( buf[idx+1] == '-' || isdigit(buf[idx+1]) ) { num_str[ii++] = buf[idx++]; num_str[ii++] = buf[idx++]; while( isdigit(buf[idx]) ) { num_str[ii++] = buf[idx]; idx++; } } } num_str[ii] = 0; /* terminate the str */ sscanf(num_str,"%lg", &num); /* printf("Scan number %s got %g\n",num_str, num); fflush(stdout); */ result = num; if( buf[idx] == '^' ) { idx++; while( isspace(buf[idx]) ) { idx++; } if( buf[idx] == '{' ) { /* need to scan for a matching right bracket */ idx++; } while( isspace(buf[idx]) ) { idx++; } num_str[0]=0; if( isdigit(buf[idx]) || buf[idx] == '+' || buf[idx] == '-' ) { ii=0; while( isdigit(buf[idx]) || buf[idx] == '.' || buf[idx] == '+' || buf[idx] == '-' ) { num_str[ii++] = buf[idx]; idx++; } num_str[ii]=0; } while( isspace(buf[idx]) ) { idx++; } if( buf[idx] == '}' ) { idx++; } sscanf(num_str,"%f", &exp); /* printf("Scan exp number %s got %g\n",num_str, exp); fflush(stdout); */ result = pow(num, (double)exp); /* printf("{%d^%d}=%g\n",num, exp,result); */ } *r_idx = idx; return (result); } double s_scan_symbol(char *buf,char *symb_p,int idx, int *r_idx) { char num_str[QUARTER_K]; int ii=0; double r_exp=1.0; symb_p[0]=0; while( isalnum(buf[idx]) || buf[idx] == '_' ) { symb_p[ii++] = buf[idx]; idx++; } symb_p[ii]=0; if( buf[idx] == '^' ) { /* look for either left bracket or a number */ idx++; while( isspace(buf[idx]) ) { idx++; } if( buf[idx] == '{' ) { /* need to scan for a matching right bracket */ idx++; } while( isspace(buf[idx]) ) { idx++; } if( isdigit(buf[idx]) || buf[idx] == '.' || buf[idx] == '+' || buf[idx] == '-' ) { ii=0; num_str[ii] = 0; while( isdigit(buf[idx]) || buf[idx] == '.' || buf[idx] == '+' || buf[idx] == '-' ) { num_str[ii++] = buf[idx]; idx++; } num_str[ii]=0; } while( isspace(buf[idx]) ) { idx++; } if( buf[idx] == '}' ) { idx++; } sscanf(num_str,"%lg", &r_exp); /* power could be of type float */ /* printf("[scan symb with power %s ^ %lg] ",symb_p, r_exp); fflush(stdout); */ } *r_idx = idx; return (r_exp); } /* return: err_code 0 parsed ok */ /* 1 symbol is of length 1, not found in the tree */ /* 2 symbol not found in the tree */ /* 3 symbol parsed as prefix symb, but symb not found */ /* 4 symbol length is 0 or negative */ int s_process_symb(char *symb_str,Unit_t *cu_p,double exp) { int len; Unit_t *au_p; int c_result; int ii; char tmp_str[ANSWER_STRING_LENG]; int err_code = 0; double d_exp; len = strlen(symb_str); if( len > 0 ) { au_p = u_find_symb(symb_str, UnitTree_p, &c_result); if( c_result == 1 ) { /* if found, copy the definition over */ u_copy_unit(cu_p, au_p, exp); } else { if( len > 1 ) { if( PrefixTbl[ (int)symb_str[0] ] != 0 ) { /* prefix is defined */ for(ii=1;iiu_scale = cu_p->u_scale * pow((double)10.0,d_exp); } else { /* unit *tmp_str not found */ /*printf("The unit: %s, not defined\n",tmp_str);*/ err_code = 3; } } else { /*printf("<<%s>>", symb_str);*/ err_code = 2; } } else {/* len == 1 */ /*printf("The unit: %s, not defined\n",symb_str);*/ err_code = 1; } } } else { err_code = 4; } return (err_code); } Unit_t * u_parse_unit(char *unit_str) { char *ch; char symb_str[QUARTER_K]; int idx; double exp_sign; int s_result; int not_done; double s_number, offset; double tmp_scale, symb_exp, exp; Unit_t *cu_p; gUnitError=0; ch = unit_str; cu_p = (Unit_t *) capa_malloc(1, sizeof(Unit_t)); /* *** */ cu_p->u_scale = 1.0; idx = 0; not_done = 1; exp_sign = 1.0; exp = 1; symb_str[0] = 0; while( isspace(*ch) ) { ch++; } /* trim leading white spaces */ /* fprintf(stdout,"PARSE |%s|\n", unit_str); */ while( not_done ) { if( isdigit(ch[idx]) || ch[idx] == '-' ) { /* rule 1: number */ s_number = s_scan_number(ch,idx,&idx); tmp_scale = pow(s_number,exp_sign); /* printf("S=%g,Power(%g,%d)=%g\n", cu_p->u_scale, s_number,exp_sign, tmp_scale); */ cu_p->u_scale = cu_p->u_scale * tmp_scale; /* printf("[Scale %g=%g^%g] ",tmp_scale,s_number,exp_sign); */ while( isspace(ch[idx]) ) { idx++; } } else { if( isalpha(ch[idx]) ) { /* rule 2: unit_symbol ^ exp */ symb_str[0] = 0; symb_exp = s_scan_symbol(ch,symb_str,idx,&idx); exp = (double)exp_sign * symb_exp; /* printf("[scanned %s ^ (%g * %g)] ", symb_str,symb_exp,exp_sign); fflush(stdout); */ s_result = s_process_symb(symb_str,cu_p,exp); if( s_result > 0 ) { /* printf("Error processing symbol [%s]\n", symb_str); */ gUnitError = 1; } while( isspace(ch[idx]) ) { idx++; } } else { if( ch[idx] == '*' || ch[idx] == '/' ) { if( ch[idx] == '/' ) { /* printf("[/] "); */ exp_sign = -1.0; } idx++; while( isspace(ch[idx]) ) { idx++; } } else { if( ch[idx] == '+' || ch[idx] == '-' ) { idx++; while( isspace(ch[idx]) ) { idx++; } offset = s_scan_number(ch,idx,&idx); /* printf("[Offset %g] ",offset); */ } else { if( ch[idx] == 0 ) { /* end of input string */ not_done = 0; /* printf("\n"); */ } else { /* garbage in unit string */ gUnitError = 1; not_done=0; } } } } } } simplify_unit(cu_p); return (cu_p); } void u_getunit(FILE *f) { register int unit_type; register int c; int power, result; char *name_p, *symbol_p, *comment_p, *unit_p; BaseUnitcnt = 0; free_utree(UnitTree_p); UnitTree_p = NULL; c_moveto_unit(f); /* move the file position to << */ do { c_ignorewhite(f); c = getc(f); ungetc(c,f); if( c == '<' ) { unit_type = c_gettype(f); } if( c != EOF ) { switch(unit_type) { case U_BASE: name_p = c_getword(f); symbol_p = c_getword(f); comment_p = c_getcomment(f); /* printf("B Unit: N=%s,S=%s,C=%s\n",name_p,symbol_p,comment_p); */ result = u_insert_baseunit(name_p,symbol_p,comment_p); if( result == 1 ) { printf("The entry %s is duplicated\n",symbol_p); } free(name_p); free(symbol_p); free(comment_p); break; case U_DERIVED: name_p = c_getword(f); symbol_p = c_getword(f); unit_p = c_getstring(f); comment_p = c_getcomment(f); /* printf("D Unit: N=%s,S=%s,C=%s,U=%s\n", name_p,symbol_p,comment_p,unit_p); */ result = u_insert_derived(name_p,symbol_p,comment_p,unit_p); if( result == 1 ) { printf("The entry %s is duplicated\n",symbol_p); } /* preorder_utree(UnitTree_p); */ free(name_p); free(symbol_p); free(comment_p); free(unit_p); break; case U_PREFIX: name_p = c_getword(f); symbol_p = c_getword(f); unit_p = c_getstring(f); /* printf("Prefix: N=%s,S=%s,U=%s\n", name_p,symbol_p,unit_p); */ power = u_parsepower(unit_p); PrefixTbl[ (int)(*symbol_p) ] = power; /* printf(" P[%c]=%d\n",*symbol_p,power); */ free(name_p); free(symbol_p); free(unit_p); break; case U_CONSTANT: symbol_p = c_getword(f); unit_p = c_getstring(f); comment_p = c_getcomment(f); /* printf("Const.: S=%s,C=%s,U=%s\n", symbol_p,comment_p,unit_p); */ break; case U_UNKNOWN: /* printf("Unknown\n"); */ break; } } } while ( c != EOF ); } /* ----------------------------------------------------------------- */ /* comparing unit symbol names should be case sensitive */ int comp_unit_symb(a, b) char *a; char *b; { return strncmp(a,b,SYMBOL_MAXLEN); } Unit_t * u_splay (char *name, Unit_t *t) { Unit_t N; Unit_t *l, *r, *y; if (t == NULL) return t; N.u_left = (Unit_t *)NULL; N.u_right = (Unit_t *)NULL; l = r = &N; for (;;) { if ( comp_unit_symb(name,t->u_symbol) < 0 ) { if (t->u_left == NULL) break; if ( comp_unit_symb(name, (t->u_left)->u_symbol ) < 0 ) { y = t->u_left; t->u_left = y->u_right; y->u_right = t; t = y; if (t->u_left == NULL) break; } r->u_left = t; r = t; t = t->u_left; } else if ( comp_unit_symb(name,t->u_symbol) > 0 ) { if (t->u_right == NULL) break; if ( comp_unit_symb(name, (t->u_right)->u_symbol ) > 0 ) { y = t->u_right; t->u_right = y->u_left; y->u_left = t; t = y; if (t->u_right == NULL) break; } l->u_right = t; l = t; t = t->u_right; } else { break; } } l->u_right = t->u_left; r->u_left = t->u_right; t->u_left = N.u_right; t->u_right = N.u_left; return t; } /* returns: 0 correctly inserted */ /* -1 error */ /* 1 duplicate entry */ int u_insert_baseunit(n_p,s_p,c_p) char *n_p, *s_p, *c_p; { Unit_t *new_p, *t; int len; new_p = (Unit_t *) capa_malloc(1, sizeof(Unit_t)); /* *** */ if (new_p == NULL) { printf("Ran out of space\n"); return(-1); } strcpy(new_p->u_symbol, s_p); strcpy(new_p->u_name, n_p); len = strlen(c_p); new_p->u_comment = (char *) capa_malloc((len+1), sizeof(char)); /* *** */ strcpy(new_p->u_comment,c_p); BaseUnitcnt++; new_p->u_index = BaseUnitcnt; new_p->u_type = U_BASE; new_p->u_scale = 1.0; new_p->u_offset = 0.0; new_p->u_count = 0; new_p->u_list = NULL; if (UnitTree_p == NULL) { /* a new unit tree */ UnitTree_p = new_p; return (0); } t = u_splay(s_p, UnitTree_p); if ( comp_unit_symb(s_p,t->u_symbol) < 0 ) { new_p->u_left = t->u_left; new_p->u_right = t; t->u_left = NULL; /* Splay_cnt++; */ UnitTree_p = new_p; return (0); } else if ( comp_unit_symb(s_p,t->u_symbol) > 0 ) { new_p->u_right = t->u_right; new_p->u_left = t; t->u_right = NULL; /* Splay_cnt++; */ UnitTree_p = new_p; return (0); } else { /* name and t->u_symbol is the same, which means found it */ capa_mfree( (char *)new_p ); UnitTree_p = t; return (1); } } int u_insert_derived(n_p,s_p,c_p,u_p)char *n_p, *s_p, *c_p, *u_p; { Unit_t *new_p, *t; int c_result, len; /* inorder_utree(UnitTree_p); */ t = u_splay(s_p, UnitTree_p); UnitTree_p = t; c_result = comp_unit_symb(s_p,t->u_symbol); if ( c_result == 0 ) { UnitTree_p = t; return (1); } /* prepare a new Unit_t */ new_p = u_parse_unit(u_p); strcpy(new_p->u_symbol,s_p); strcpy(new_p->u_name, n_p); new_p->u_type = U_DERIVED; len = strlen(c_p); new_p->u_comment = (char *) capa_malloc((len+1), sizeof(char)); /* *** */ strcpy(new_p->u_comment,c_p); simplify_unit(new_p); #ifdef UNIT_DBUG printf("Derived Unit:%s\n",new_p->u_name); print_unit_t(new_p); #endif if (c_result < 0 ) { new_p->u_left = t->u_left; new_p->u_right = t; t->u_left = NULL; } else { /* c_result > 0 */ new_p->u_right = t->u_right; new_p->u_left = t; t->u_right = NULL; } UnitTree_p = new_p; return (0); } void freelist_unit_e(Unit_E *ue_p) { Unit_E *curr_p, *next_p; if( ue_p != NULL ) { next_p = ue_p->ue_nextp; curr_p = ue_p; if( next_p == NULL ) { capa_mfree((char *)curr_p); } else { for( curr_p = ue_p; next_p; curr_p = next_p, next_p = next_p->ue_nextp) { capa_mfree((char *)curr_p); } capa_mfree((char *)curr_p); } } } void simplify_unit(u_p) Unit_t *u_p; { Unit_E *eu_p, *prev_p; int ii, idx; /* walk through u_list and replace those u_index = -1 with */ /* a linked list of basic unit. */ /* u_msort_main() the whole u_list */ /* combine those units with same u_index */ for(ii=0;iiu_count > 0 ) { for(eu_p=u_p->u_list; eu_p; eu_p = eu_p->ue_nextp) { idx = eu_p->ue_index; if( CScale[idx] == 0.0 ) { CScale[idx] = 1.0; strcpy(CSymb[idx],eu_p->ue_symbol); } CScale[idx] = CScale[idx] * eu_p->ue_scale; CExp[idx] = CExp[idx] + eu_p->ue_exp; } /* debugging for(ii=0;iiu_list); prev_p = u_p->u_list = NULL; u_p->u_count = 0; for(ii=0;iiue_scale = 1.0; eu_p->ue_exp = CExp[ii]; eu_p->ue_index = ii; strcpy(eu_p->ue_symbol,CSymb[ii]); if( prev_p == NULL) { u_p->u_list = prev_p = eu_p; } else { prev_p->ue_nextp = eu_p; prev_p = eu_p; } u_p->u_count++; } } } /* printf("After Simplify:: \n"); print_unit_t(u_p); */ } /* before comparing two units, make sure they are of basic form */ /* compares if two units are equal */ /* equality returns 1 */ int is_units_equal(Unit_t *u1_p, Unit_t *u2_p) { int result=1; Unit_E *a_p, *b_p; if( (u1_p->u_count == u2_p->u_count) && (u1_p->u_scale == u2_p->u_scale) ) { for(a_p=u1_p->u_list, b_p=u2_p->u_list; a_p; a_p=a_p->ue_nextp, b_p=b_p->ue_nextp) { if(a_p->ue_index != b_p->ue_index || a_p->ue_scale != b_p->ue_scale || a_p->ue_exp != b_p->ue_exp ) { result=0; break; } } } else { result=0; } return (result); } /* input : both are the simplest units */ /* result: 0.0 means they are not of euquvalent units */ /* the ratio of u1 / u2 */ double units_ratio(Unit_t *u1_p, Unit_t *u2_p) { double ratio=1.0; Unit_E *a_p, *b_p; if( (u1_p->u_count == u2_p->u_count) ) { for(a_p=u1_p->u_list, b_p=u2_p->u_list; a_p; a_p=a_p->ue_nextp, b_p=b_p->ue_nextp) { if(a_p->ue_index != b_p->ue_index || a_p->ue_scale != b_p->ue_scale || a_p->ue_exp != b_p->ue_exp ) { ratio=0.0; break; } } } else { ratio=0.0; } if( (ratio != 0.0) && (u2_p->u_scale != 0.0 ) ) { ratio = u1_p->u_scale / u2_p->u_scale; } return (ratio); } /* ------------- The Grammar of Units Parser -------------------- scan_unit_expr() --> scan_basic_block() --> scan_basic_block() '+' scan_basic_block() --> scan_basic_block() '-' scan_basic_block() scan_num_expr() --> scan_num_block() --> scan_num_block() '+' scan_num_block() --> scan_num_block() '-' scan_num_block() scan_basic_block()--> scan_basic_term() --> scan_basic_term() '*' scan_basic_term() --> scan_basic_term() ' ' scan_basic_term() --> scan_basic_term() '/' scan_basic_term() scan_num_block() --> scan_num_term() --> scan_num_term() '*' scan_num_term() --> scan_num_term() ' ' scan_num_term() --> scan_num_term() '/' scan_num_term() scan_basic_term() --> scan_unit_item() --> scan_num_item() --> '(' scan_basic_block() ')' --> '{' scan_basic_block() '}' scan_num_term() --> scan_num_item()* --> '-' scan_num_item()* --> '(' scan_num_expr() ')' --> '{' scan_num_expr() '}' scan_unit_item() --> UNIT* --> UNIT* '^' * scan_num_term() scan_num_item() --> FLOAT* --> FLOAT* '^' * scan_num_term() scan_FLOAT() --> [0-9]+([eE][+-]?[0-9]+)* p_new_unit() --> [a-Z]+[a-Z0-9_]* ----------------------------------------- U.expr := B.block | B.block '+' B.block | B.block '-' B.block N.expr := N.block | N.block '+' N.block | N.block '-' N.block To allow for operations like (J/N)^2 or {N/m}^2 (N/J)^3 B.block := B.term | B.term ' ' B.term | B.term '*' B.term | B.term '/' B.term N.block := N.term | N.term ' ' N.term | N.term '*' N.term | N.term '/' N.term B.term := U.item | N.item | '(' B.block ')' | '{' B.block '}' | '(' B.block ')' ^ N.term | '{' B.block '}' ^ N.term N.term := N.item | '-' N.item | '(' N.expr ')' | '{' N.expr '}' U.item := UNIT | UNIT '^' N.term N.item := FLOAT | FLOAT '^' N.term UNIT := [a-Z]+[a-Z0-9_]* FLOAT := [0-9]+([eE][+-]?[0-9]+)* ------------------------------------------------------------------- */ Unit_t * p_new_op(Unit_t *left_p, int op, Unit_t *right_p) { Unit_t *new_p; new_p = (Unit_t *) capa_malloc(1, sizeof(Unit_t)); if (new_p == NULL) { printf("Ran out of space\n"); return(NULL); } new_p->u_left = left_p; new_p->u_right = right_p; new_p->u_scale = 0.0; new_p->u_type = op; new_p->u_offset = 0.0; new_p->u_count = 0; new_p->u_list = NULL; return (new_p); } Unit_t * p_new_num(Unit_t *left_p, double num, Unit_t *right_p) { Unit_t *new_p; new_p = (Unit_t *) capa_malloc(1, sizeof(Unit_t)); if (new_p == NULL) { printf("Ran out of space\n"); return(NULL); } new_p->u_left = left_p; new_p->u_right = right_p; new_p->u_scale = num; new_p->u_type = U_CONSTANT; new_p->u_offset = 0.0; new_p->u_count = 0; new_p->u_list = NULL; return (new_p); } Unit_t * p_new_unit(Unit_t *left_p, Unit_t *right_p) { char symb_str[ANSWER_STRING_LENG]; int ii=0; int len; Unit_t *au_p, *cu_p; int c_result; char tmp_str[ANSWER_STRING_LENG]; int err_code = 0; double d_exp; symb_str[ii]=0; while( isspace(Sbuf[Sidx]) ) { Sidx++; } while( isalnum(Sbuf[Sidx]) || Sbuf[Sidx] == '_' ) { symb_str[ii++] = Sbuf[Sidx]; Sidx++; } symb_str[ii]=0; /* printf("", symb_str); */ cu_p = (Unit_t *) capa_malloc(1, sizeof(Unit_t)); strcpy(cu_p->u_symbol,symb_str); cu_p->u_left = left_p; cu_p->u_right = right_p; cu_p->u_scale = 1.0; cu_p->u_type = U_DERIVED; cu_p->u_offset = 0.0; cu_p->u_count = 0; cu_p->u_list = NULL; len = strlen(symb_str); if( len > 0 ) { au_p = u_find_symb(symb_str, UnitTree_p, &c_result); if( c_result == 1 ) { /* if found, copy the definition over */ u_copy_unit(cu_p, au_p, 1); } else { if( len > 1 ) { if( PrefixTbl[ (int)symb_str[0] ] != 0 ) { /* prefix is defined */ for(ii=1;iiu_scale = cu_p->u_scale * pow((double)10.0,d_exp); } else { /* unit *tmp_str not found */ /* printf(" not found\n"); */ err_code = 3; cu_p->u_type = U_UNKNOWN; } } else { /* symb_str is not in form */ /* printf("<<%s>>", symb_str); */ err_code = 2; cu_p->u_type = U_UNKNOWN; } } else {/* len == 1 */ /* printf(" not found in symbol tree \n"); */ err_code = 1; cu_p->u_type = U_UNKNOWN; } } } else { /* why would we have a length less than zero symb_str ? */ err_code = 4; } return (cu_p); } int s_peeknext_op() { char *ch; int sp=0; ch = (char *)&Sbuf[Sidx]; while( isspace(*ch) ) { ch++; sp=1; } if( (*ch == '*') || (*ch == '/') || (*ch == '+') || (*ch == '-') || (*ch == '^')) { return (*ch); } /* what if space is the last thing on the line?*/ if( sp && (*ch != '\0')) return '*'; return (*ch); } int s_getnext_op() { char *ch; int inc = 0, sp=0; /* printf("\n((op"); print_remains(); printf("\n"); */ ch = (char *)&Sbuf[Sidx]; while( isspace(*ch) ) { ch++; inc++; sp=1; } Sidx = Sidx + inc; if( (*ch == '*') || (*ch == '/') || (*ch == '+') || (*ch == '-') || (*ch == '^') ) { Sidx++; /* print_remains(); printf(" op))"); printf("\n"); */ return (*ch); } /* print_remains(); printf(" op))"); printf("\n"); */ /* what if space is the last thing on the line?*/ if( sp && (*ch != '\0')) return '*'; return (*ch); } int s_getnext() { char ch; ch = Sbuf[Sidx]; Sidx++; return (ch); } int s_peeknext() { char ch; ch = Sbuf[Sidx]; return (ch); } int s_peeknextNW() /* peek into the next non-whitespaces character */ { char *ch; ch = (char *)&Sbuf[Sidx]; while( isspace(*ch) ) { ch++; } return (*ch); } int s_getnextNW() /* get the next non-whitespaces character */ { char *ch; ch = (char *)&Sbuf[Sidx]; Sidx++; while( isspace(*ch) ) { ch++; Sidx++; } return (*ch); } /* peek into the next non-whitespaces character which should be either a multiply or division */ int s_peekMDWS() { char *ch; int sp=0; ch = (char *)&Sbuf[Sidx]; while( isspace(*ch) ) { ch++; sp=1;} if( (*ch == '*') || (*ch == '/') ) { return (*ch); } if( sp ) return ' '; ch = (char *)&Sbuf[Sidx]; while( isspace(*ch) ) { ch++; } return (*ch); } int s_getnextMDWS() { char *ch; int inc=0, sp=0; ch = (char *)&Sbuf[Sidx]; Sidx++; while( isspace(*ch) ) { ch++; inc++; sp=1; } Sidx += inc; if( (*ch == '*') || (*ch == '/') ) { return (*ch); } if( sp ) return ' '; return (*ch); } double scan_FLOAT() { double num; int ii=0, len; char num_str[QUARTER_K]; num_str[ii]=0; while( isspace(Sbuf[Sidx]) ) { Sidx++; } if( Sbuf[Sidx] == '-' ) { num_str[ii++] = Sbuf[Sidx++]; } while( isdigit(Sbuf[Sidx]) || Sbuf[Sidx] == '.' ) { num_str[ii++] = Sbuf[Sidx++]; } if( Sbuf[Sidx] == 'E' || Sbuf[Sidx] == 'e' ) { if( Sbuf[Sidx+1] == '-' || isdigit(Sbuf[Sidx+1]) ) { num_str[ii++] = Sbuf[Sidx++]; num_str[ii++] = Sbuf[Sidx++]; while( isdigit(Sbuf[Sidx]) ) { num_str[ii++] = Sbuf[Sidx++]; } } } num_str[ii] = 0; /* terminate the str */ len = strlen(num_str); if(len > 0 ) { sscanf(num_str,"%lg", &num); /* printf("",num_str,num); fflush(stdout); print_remains(); */ } else { num = 1.0; } return (num); } /* ----------------------------------------------- N.item := FLOAT | FLOAT '^' N.term ----------------------------------------------- */ Unit_t * scan_num_item() { Unit_t *node_p, *exp_p; double num_const; char ch; num_const = scan_FLOAT(); node_p = p_new_num(NULL, num_const, NULL); ch = s_peeknext_op(); if( ch == '^' ) { ch = s_getnext_op(); exp_p = scan_num_term(); num_const = node_p->u_scale; if( node_p->u_scale > 0.0 ) { num_const = pow(node_p->u_scale,exp_p->u_scale); } node_p->u_scale = num_const; capa_mfree((char *)exp_p); } return node_p; } /* ----------------------------------------------- U.item := UNIT | UNIT '^' N.term ----------------------------------------------- */ Unit_t * scan_unit_item() { Unit_t *node_p, *exp_p; char ch; double num_const; Unit_E *oe_p; node_p = p_new_unit(NULL,NULL); ch = s_peeknext_op(); if( ch == '^' ) { ch = s_getnext_op(); exp_p = scan_num_term(); num_const = exp_p->u_scale; if( node_p->u_count > 0 ) { oe_p = node_p->u_list; for(oe_p = node_p->u_list; oe_p; oe_p = oe_p->ue_nextp ) { oe_p->ue_exp = oe_p->ue_exp * num_const; } } num_const = node_p->u_scale; if( node_p->u_scale > 0.0 ) { num_const = pow(node_p->u_scale,exp_p->u_scale); } node_p->u_scale = num_const; capa_mfree((char *)exp_p); } return node_p; } void distribute_exp(Unit_t* node_p,Unit_t* exp_p) { Unit_E* oe_p; double num_const; num_const = exp_p->u_scale; /* should we check if num_const too large or small ? */ if( node_p->u_count > 0 ) { oe_p = node_p->u_list; for(oe_p = node_p->u_list; oe_p; oe_p = oe_p->ue_nextp ) { oe_p->ue_exp = oe_p->ue_exp * num_const; } } num_const = node_p->u_scale; if( node_p->u_scale > 0.0 ) { /* what if u_scale <= 0.0 ? */ num_const = pow(node_p->u_scale,exp_p->u_scale); } node_p->u_scale = num_const; if (node_p->u_left) distribute_exp(node_p->u_left,exp_p); if (node_p->u_right) distribute_exp(node_p->u_right,exp_p); } /* --------------------------------------------------------------- B.term := U.item | N.item | '(' B.block ')' | '{' B.block '}' | '(' B.block ')' '^' N.term <== July 6 1998 | '{' B.block '}' '^' N.term --------------------------------------------------------------- */ Unit_t * scan_basic_term() { Unit_t *node_p, *exp_p; int ch, nch; ch = s_peeknextNW(); if( ch == '(' || ch == '{' ) { ch = s_getnextNW(); /* get rid of '(' or '{' */ node_p = scan_basic_block(); nch = s_peeknextNW(); if( nch == ')' || nch == '}' ) { /* should be either ')' or '}' */ if( ((ch == '(' ) && (nch == ')' )) || ((ch == '{' ) && (nch == '}' )) ) { /* matching left paren with right paren */ } else { /* printf(" WARN: %c matched by %c\n", ch, nch); */ } nch = s_getnextNW(); /* ====== Added Jul 6, 1998 ====> */ ch = s_peeknext_op(); if( ch == '^' ) { ch = s_getnext_op(); /* get rid of '^' char */ exp_p = scan_num_term(); distribute_exp(node_p,exp_p); capa_mfree((char *)exp_p); } /* <== added Jul 6, 1998 == */ } else { /* printf(" WARN: %c is not matched by %c\n", ch, nch); */ } } else if( ch >= '0' && ch <= '9' ) { node_p = scan_num_item(); } else { /* assume a unit symbol */ /* printf(""); print_remains(); */ node_p = scan_unit_item(); /* print_remains(); */ } return node_p; } /* -------------------------------------------------- N.term := N.item | '-' N.item | '(' N.expr ')' | '{' N.expr '}' -------------------------------------------------- */ Unit_t * scan_num_term() { Unit_t *node_p; char ch, nch; ch = s_peeknextNW(); if( ch == '(' || ch == '{' ) { ch = s_getnextNW(); node_p = scan_num_expr(); nch = s_peeknextNW(); if( nch == ')' || nch == '}' ) { /* should be either ')' or '}' */ if( ((ch == '(' ) && (nch == ')' )) || ((ch == '{' ) && (nch == '}' )) ) { } else { /* printf(" WARN: %c matched by %c\n", ch, nch); */ } nch = s_getnextNW(); } else { /* printf(" WARN: %c is not matched by %c\n", ch, ch); */ } } else if( ch == '-' ) { ch = s_getnextNW(); node_p = scan_num_item(); node_p->u_scale = (-1)*node_p->u_scale; } else { if( isdigit(ch) ) { node_p = scan_num_item(); } else { /* something other than a number */ /* printf(" ERROR: expect a number: "); print_remains(); */ node_p = p_new_num(NULL, 0.0, NULL); /* make the unknown item */ } } return node_p; } /* -------------------------------------------------- B.block := B.term | B.term ' ' B.term | B.term '*' B.term | B.term '/' B.term -------------------------------------------------- */ Unit_t * scan_basic_block() { Unit_t *node_p; char ch; int op; /* printf("(before B.term)"); print_remains(); */ node_p = scan_basic_term(); ch = s_peeknext_op(); while ( ch == '*' || ch == '/' ) { op = ( ch == '/' ? U_OP_DIVIDE : U_OP_TIMES); ch = s_getnext_op(); /* printf("(/ *)"); print_remains(); */ node_p = p_new_op(node_p,op,scan_basic_term()); ch = s_peeknext_op(); } return node_p; } /* -------------------------------------------------- N.block := N.term | N.term ' ' N.term | N.term '*' N.term | N.term '/' N.term -------------------------------------------------- */ Unit_t * scan_num_block() { Unit_t *node_p, *opand_p; char ch; double result; node_p = scan_num_term(); ch = s_peeknext_op(); while ( ch == '*' || ch == '/' ) { s_getnext_op(); opand_p = scan_num_term(); if( ch == '*' ) { result = node_p->u_scale * opand_p->u_scale; } else { result = node_p->u_scale / opand_p->u_scale; } node_p->u_scale = result; capa_mfree((char *)opand_p); ch = s_peeknext_op(); } return node_p; } /* --------------------------------------- U.expr := B.block | B.block '+' B.block | B.block '-' B.block --------------------------------------- */ Unit_t * scan_unit_expr() { Unit_t *node_p; char ch; int op; /* printf(""); print_remains(); */ node_p = scan_basic_block(); ch = s_peeknext_op(); while ( ch == '+' || ch == '-' ) { op = ( ch == '+' ? U_OP_PLUS : U_OP_MINUS); ch = s_getnext_op(); /* printf("(+-)"); print_remains(); */ node_p = p_new_op(node_p,op,scan_basic_block()); ch = s_peeknext_op(); } return node_p; } /* ----------------------------------------- N.expr := N.block | N.block '+' N.block | N.block '-' N.block ----------------------------------------- */ Unit_t * scan_num_expr() { Unit_t *node_p, *opand_p; char ch; double result; node_p = scan_num_block(); ch = s_peeknext_op(); while ( ch == '+' || ch == '-' ) { ch = s_getnext_op(); opand_p = scan_num_block(); if( ch == '+' ) { result = node_p->u_scale + opand_p->u_scale; } else { result = node_p->u_scale - opand_p->u_scale; } node_p->u_scale = result; capa_mfree((char *)opand_p); ch = s_peeknext_op(); } return node_p; } /* ----------------------------------------------------------------------- */ /* <-- This is the major entry point to parse an units expression ------> */ Unit_t * parse_unit_expr(char *symb_str) { Unit_t *root_p; int len; len = strlen(symb_str); strcpy(Sbuf,symb_str); /* copy it into the global Sbuf */ Sidx=0; root_p = scan_unit_expr(); if(Sidx < len-1 ) { /* printf(" WARN: NOT PARSED:"); print_remains(); */ } return (root_p); } void print_remains() { int len, ii; len = strlen(Sbuf); printf("[["); for(ii=Sidx;ii