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, 8 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_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
/* 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 <stdio.h> /* fopen() */
#include <stdlib.h>
#include <ctype.h> /* isalnum() */
#include <string.h>
#include <math.h>
#include <float.h>
#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;ii<BaseUnitcnt;ii++) {
TmpAexp[ii] = 0.0;
}
if( t->u_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;ii<EquivUnitCnt;ii++) {
tmp_p = EquivUnit[ii];
if( MinSquared == MinValue[ii] ) {
if( tmp_p->u_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<EquivUnitCnt;ii++) {
tmp_p = EquivUnit[ii];
if( MinSquared == MinValue[ii] ) {
printf(" <<%s>> ", 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;ii<BaseUnitcnt;ii++) {
TmpAexp[ii] = 0.0;
TmpBexp[ii] = 0.0;
}
if( a->u_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;ii<BaseUnitcnt;ii++) {
result = TmpAexp[ii] - TmpBexp[ii];
squared_diff = squared_diff + result*result;
}
return (squared_diff);
}
double
u_sq_diff(Unit_t *b)
{
double result;
double squared_diff = 0.0;
int ii;
Unit_E *eu_p;
for(ii=0;ii<BaseUnitcnt;ii++) {
TmpBexp[ii] = 0.0;
}
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"); */
} else if( b->u_type == U_BASE ) {
TmpBexp[b->u_index] = 1.0;
}
for(ii=0;ii<BaseUnitcnt;ii++) {
result = TmpAexp[ii] - TmpBexp[ii];
squared_diff = squared_diff + result*result;
}
return (squared_diff);
}
/* ------------------------------------ */
int
inorder_diff(node_p) Unit_t *node_p;
{
int result;
double sq_diff=0.0;
if( node_p == NULL ) return (1);
result = inorder_diff(U_LEFT(node_p));
if( result ) {
sq_diff = u_sq_diff(node_p);
/*
printf("DIFF [%s,%s,%d] - [%s,%s,%d] = %g\n",
U_SYMB(InqueryUnit_p), U_NAME(InqueryUnit_p),U_COUNT(InqueryUnit_p),
U_SYMB(node_p), U_NAME(node_p),U_COUNT(node_p),sq_diff);
*/
if( MinSquared > 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;ii<b_p->u_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;ii<len;ii++) {
tmp_str[ii-1] = symb_str[ii];
}
tmp_str[len-1]=0;
au_p = u_find_symb(tmp_str, UnitTree_p, &c_result);
if( c_result == 1 ) {
/* printf("[%s] ", tmp_str); */
u_copy_unit(cu_p, au_p, exp);
d_exp = (double)PrefixTbl[ (int)symb_str[0] ] * exp;
cu_p->u_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;ii<BaseUnitcnt;ii++) {
CScale[ii] = 0.0;
CExp[ii] = 0.0;
}
/*
printf("Before Simplify:: \n");
print_unit_t(u_p);
*/
if( u_p->u_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;ii<BaseUnitcnt;ii++) {
if( CScale[ii] != 0.0 ) {
printf("(%d)%s,S=%g,E=%g\n",ii,CSymb[ii],CScale[ii], CExp[ii]);
}
if( CExp[ii] == 0.0 ) {
printf("(%d)%s,S=%g,Exp=%g\n",ii,CSymb[ii],CScale[ii], CExp[ii]);
}
}
*/
freelist_unit_e(u_p->u_list);
prev_p = u_p->u_list = NULL;
u_p->u_count = 0;
for(ii=0;ii<BaseUnitcnt;ii++) {
if( CScale[ii] != 0.0 && CExp[ii] != 0) {
eu_p = (Unit_E *)capa_malloc(1,sizeof(Unit_E)); /* ***************** */
eu_p->ue_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()<sp>*
--> '-' scan_num_item()<sp>*
--> '(' scan_num_expr() ')'
--> '{' scan_num_expr() '}'
scan_unit_item() --> UNIT<sp>*
--> UNIT<sp>* '^' <sp>* scan_num_term()
scan_num_item() --> FLOAT<sp>*
--> FLOAT<sp>* '^' <sp>* 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("<U %s>", 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;ii<len;ii++) {
tmp_str[ii-1] = symb_str[ii];
}
tmp_str[len-1]=0;
au_p = u_find_symb(tmp_str, UnitTree_p, &c_result);
if( c_result == 1 ) {
/* printf("[%s] ", tmp_str); */
u_copy_unit(cu_p, au_p, 1);
d_exp = (double)PrefixTbl[ (int)symb_str[0] ];
cu_p->u_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 <prefix><units> 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("<N %s %g>",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("<B.term>"); 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("<B.block>(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("<B.block>(/ *)"); 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("<U.expr>"); 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("<U.expr>(+-)"); 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<len;ii++) {
printf("%c",Sbuf[ii]);
}
printf("]]");
}
/* =================================================================== */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>