From 476da015f0431d264702215758f2453287e39ef2 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 19 May 2021 16:27:52 -0400 Subject: [PATCH] Added support for expression parameters to be added to a device class during setup, for the purpose of generating some derived value that is used for merging and sorting, such as area = l*w. Note that this likely needs adjusting so that the expression is evaluated but not replaced for the purpose of sorting, since the values to the parameter may change after parallel and series merging. --- base/netcmp.c | 14 +- base/netgen.c | 1059 +++++++++++++++++++++++---------------------- base/netgen.h | 3 +- tcltk/tclnetgen.c | 9 +- 4 files changed, 556 insertions(+), 529 deletions(-) diff --git a/base/netcmp.c b/base/netcmp.c index f984f05..24740d2 100644 --- a/base/netcmp.c +++ b/base/netcmp.c @@ -4298,7 +4298,7 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run) else if (kl->merge & (MERGE_P_ADD | MERGE_P_PAR)) { if ((vl->type == PROP_STRING || vl->type == PROP_EXPRESSION) && (kl->type != vl->type)) - PromoteProperty(kl, vl); + PromoteProperty(kl, vl, obp, tp1); if (vl->type == PROP_INTEGER) { tval = (double)vl->value.ival; tslop = (double)kl->slop.ival; @@ -4827,12 +4827,12 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series, else if (vl == NULL || vl2 == NULL) { if (vl == NULL) { if (kl->type != vlist[p][j]->type) - PromoteProperty(kl, vl2); + PromoteProperty(kl, vl2, ob2, tp); vl = &dfltvl; } else { if (kl->type != vlist[p][i]->type) - PromoteProperty(kl, vl); + PromoteProperty(kl, vl, ob2, tp); vl2 = &dfltvl; } dfltvl.type = kl->type; @@ -5307,8 +5307,8 @@ PropertyCheckMismatch(struct objlist *tp1, struct nlist *tc1, } /* Promote properties as necessary to make sure they all match */ - if (kl1->type != vl1->type) PromoteProperty(kl1, vl1); - if (kl2->type != vl2->type) PromoteProperty(kl2, vl2); + if (kl1->type != vl1->type) PromoteProperty(kl1, vl1, tc1, tp1); + if (kl2->type != vl2->type) PromoteProperty(kl2, vl2, tc2, tp2); /* If kl1 and kl2 types differ, choose one type to target. Prefer */ /* double if either type is double, otherwise string. */ @@ -5328,8 +5328,8 @@ PropertyCheckMismatch(struct objlist *tp1, struct nlist *tc1, else klt = kl1; - if (vl2->type != klt->type) PromoteProperty(klt, vl2); - if (vl1->type != klt->type) PromoteProperty(klt, vl1); + if (vl2->type != klt->type) PromoteProperty(klt, vl2, tc2, tp2); + if (vl1->type != klt->type) PromoteProperty(klt, vl1, tc1, tp1); if (vl1->type != vl2->type) { if (do_print && (vl1->type != vl2->type)) { diff --git a/base/netgen.c b/base/netgen.c index 590db5d..ae57791 100644 --- a/base/netgen.c +++ b/base/netgen.c @@ -239,7 +239,8 @@ int TokGetValue(char *estr, struct nlist *parent, struct objlist *parprops, if (kl != NULL) { switch(kl->type) { case PROP_STRING: - result = ConvertStringToFloat(kl->pdefault.string, dval); + if (kl->pdefault.string != NULL) + result = ConvertStringToFloat(kl->pdefault.string, dval); break; case PROP_DOUBLE: case PROP_VALUE: @@ -268,529 +269,514 @@ int TokGetValue(char *estr, struct nlist *parent, struct objlist *parprops, /* single value, then replace the property type. */ /*--------------------------------------------------------------*/ -int ReduceExpressions(struct objlist *instprop, struct objlist *parprops, +int ReduceOneExpression(struct valuelist *kv, struct objlist *parprops, struct nlist *parent, int glob) { struct tokstack *expstack, *stackptr, *lptr, *nptr; - struct valuelist *kv; struct property *kl = NULL; char *estr, *tstr, *sstr; - int toktype, functype, i, result, modified, numlast, savetok; + int toktype, functype, result, modified, numlast, savetok; double dval; - if (instprop == NULL) return 0; // Nothing to do - if (instprop->type != PROPERTY) return -1; // Shouldn't happen + if (kv->type == PROP_EXPRESSION) + expstack = kv->value.stack; - for (i = 0;; i++) { + else if (kv->type == PROP_STRING) { - kv = &(instprop->instance.props[i]); - switch (kv->type) { - case PROP_ENDLIST: - break; + /* Compile the string into an expression stack */ + expstack = NULL; + estr = kv->value.string; + tstr = estr; - case PROP_INTEGER: - case PROP_DOUBLE: - case PROP_VALUE: - continue; - - case PROP_EXPRESSION: - expstack = kv->value.stack; - break; - - case PROP_STRING: - - expstack = NULL; - estr = kv->value.string; - tstr = estr; - - numlast = 0; - while (*tstr != '\0') { - switch(*tstr) { + numlast = 0; + while (*tstr != '\0') { + switch(*tstr) { - case '+': - if (numlast == 0) { - /* This is part of a number */ - dval = strtod(estr, &sstr); - if (sstr > estr && sstr > tstr) { - tstr = sstr - 1; - numlast = 1; - } - break; - } - /* Not a number, so must be arithmetic */ - *tstr = '\0'; - result = TokGetValue(estr, parent, parprops, glob, &dval); - if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); - else if (result == -1) PushTok(TOK_STRING, estr, &expstack); - PushTok(TOK_PLUS, NULL, &expstack); - estr = tstr + 1; - numlast = 0; - break; + case '+': + if (numlast == 0) { + /* This is part of a number */ + dval = strtod(estr, &sstr); + if (sstr > estr && sstr > tstr) { + tstr = sstr - 1; + numlast = 1; + } + break; + } + /* Not a number, so must be arithmetic */ + *tstr = '\0'; + result = TokGetValue(estr, parent, parprops, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + PushTok(TOK_PLUS, NULL, &expstack); + estr = tstr + 1; + numlast = 0; + break; - case '-': - if (numlast == 0) { - /* This is part of a number */ - dval = strtod(estr, &sstr); - if (sstr > estr && sstr > tstr) { - tstr = sstr - 1; - numlast = 1; - } - break; - } - /* Not a number, so must be arithmetic */ - *tstr = '\0'; - result = TokGetValue(estr, parent, parprops, glob, &dval); - if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); - else if (result == -1) PushTok(TOK_STRING, estr, &expstack); - PushTok(TOK_MINUS, NULL, &expstack); - estr = tstr + 1; - numlast = 0; - break; - - case '1': case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': case '0': - /* Numerical value. Use strtod() to capture */ - if (numlast == 1) break; - dval = strtod(estr, &sstr); - if (sstr > estr && sstr > tstr) { - tstr = sstr - 1; - numlast = 1; - } - break; - - case '/': - *tstr = '\0'; - result = TokGetValue(estr, parent, parprops, glob, &dval); - if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); - else if (result == -1) PushTok(TOK_STRING, estr, &expstack); - PushTok(TOK_DIVIDE, NULL, &expstack); - estr = tstr + 1; - numlast = 0; - break; - - case '*': - *tstr = '\0'; - result = TokGetValue(estr, parent, parprops, glob, &dval); - if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); - else if (result == -1) PushTok(TOK_STRING, estr, &expstack); - PushTok(TOK_MULTIPLY, NULL, &expstack); - estr = tstr + 1; - numlast = 0; - break; - - case '(': - *tstr = '\0'; - - /* Check for predefined function keywords */ - - if (!strcmp(estr, "IF")) { - PushTok(TOK_FUNC_IF, NULL, &expstack); - } - else { - /* Treat as a parenthetical grouping */ - - result = TokGetValue(estr, parent, parprops, - glob, &dval); - if (result == 1) - PushTok(TOK_DOUBLE, &dval, &expstack); - else if (result == -1) - PushTok(TOK_STRING, estr, &expstack); - PushTok(TOK_FUNC_OPEN, NULL, &expstack); - } - estr = tstr + 1; - numlast = 0; - break; - - case ')': - *tstr = '\0'; - - if (expstack == NULL) break; - savetok = expstack->toktype; - - result = TokGetValue(estr, parent, parprops, glob, &dval); - if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); - else if (result == -1) PushTok(TOK_STRING, estr, &expstack); - - switch (savetok) { - case TOK_FUNC_THEN: - PushTok(TOK_FUNC_ELSE, NULL, &expstack); - break; - default: - PushTok(TOK_FUNC_CLOSE, NULL, &expstack); - break; - } + case '-': + if (numlast == 0) { + /* This is part of a number */ + dval = strtod(estr, &sstr); + if (sstr > estr && sstr > tstr) { + tstr = sstr - 1; numlast = 1; - estr = tstr + 1; + } + break; + } + /* Not a number, so must be arithmetic */ + *tstr = '\0'; + result = TokGetValue(estr, parent, parprops, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + PushTok(TOK_MINUS, NULL, &expstack); + estr = tstr + 1; + numlast = 0; + break; + + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': case '0': + /* Numerical value. Use strtod() to capture */ + if (numlast == 1) break; + dval = strtod(estr, &sstr); + if (sstr > estr && sstr > tstr) { + tstr = sstr - 1; + numlast = 1; + } + break; + + case '/': + *tstr = '\0'; + result = TokGetValue(estr, parent, parprops, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + PushTok(TOK_DIVIDE, NULL, &expstack); + estr = tstr + 1; + numlast = 0; + break; + + case '*': + *tstr = '\0'; + result = TokGetValue(estr, parent, parprops, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + PushTok(TOK_MULTIPLY, NULL, &expstack); + estr = tstr + 1; + numlast = 0; + break; + + case '(': + *tstr = '\0'; + + /* Check for predefined function keywords */ + + if (!strcmp(estr, "IF")) { + PushTok(TOK_FUNC_IF, NULL, &expstack); + } + else { + /* Treat as a parenthetical grouping */ + + result = TokGetValue(estr, parent, parprops, + glob, &dval); + if (result == 1) + PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) + PushTok(TOK_STRING, estr, &expstack); + PushTok(TOK_FUNC_OPEN, NULL, &expstack); + } + estr = tstr + 1; + numlast = 0; + break; + + case ')': + *tstr = '\0'; + + if (expstack == NULL) break; + savetok = expstack->toktype; + + result = TokGetValue(estr, parent, parprops, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + + switch (savetok) { + case TOK_FUNC_THEN: + PushTok(TOK_FUNC_ELSE, NULL, &expstack); break; - - case '\'': - *tstr = '\0'; - result = TokGetValue(estr, parent, parprops, glob, &dval); - if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); - else if (result == -1) PushTok(TOK_STRING, estr, &expstack); - PushTok(TOK_SGL_QUOTE, NULL, &expstack); - estr = tstr + 1; - numlast = 0; - break; - - case '"': - *tstr = '\0'; - result = TokGetValue(estr, parent, parprops, glob, &dval); - if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); - else if (result == -1) PushTok(TOK_STRING, estr, &expstack); - PushTok(TOK_DBL_QUOTE, NULL, &expstack); - estr = tstr + 1; - numlast = 0; - break; - - case '{': - *tstr = '\0'; - result = TokGetValue(estr, parent, parprops, glob, &dval); - if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); - else if (result == -1) PushTok(TOK_STRING, estr, &expstack); - PushTok(TOK_GROUP_OPEN, NULL, &expstack); - estr = tstr + 1; - numlast = 0; - break; - - case '}': - *tstr = '\0'; - result = TokGetValue(estr, parent, parprops, glob, &dval); - if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); - PushTok(TOK_GROUP_CLOSE, NULL, &expstack); - estr = tstr + 1; - numlast = 1; - break; - - case '!': - if (*(tstr + 1) == '=') { - *tstr = '\0'; - result = TokGetValue(estr, parent, parprops, - glob, &dval); - if (result == 1) - PushTok(TOK_DOUBLE, &dval, &expstack); - else if (result == -1) - PushTok(TOK_STRING, estr, &expstack); - PushTok(TOK_NE, NULL, &expstack); - } - numlast = 0; - break; - - case '=': - if (*(tstr + 1) == '=') { - *tstr = '\0'; - result = TokGetValue(estr, parent, parprops, - glob, &dval); - if (result == 1) - PushTok(TOK_DOUBLE, &dval, &expstack); - else if (result == -1) - PushTok(TOK_STRING, estr, &expstack); - PushTok(TOK_EQ, NULL, &expstack); - numlast = 0; - } - break; - - case '>': - *tstr = '\0'; - result = TokGetValue(estr, parent, parprops, glob, &dval); - if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); - else if (result == -1) PushTok(TOK_STRING, estr, &expstack); - - if (*(tstr + 1) == '=') { - PushTok(TOK_GE, NULL, &expstack); - tstr++; - } - else - PushTok(TOK_GT, NULL, &expstack); - estr = tstr + 1; - numlast = 0; - break; - - case '<': - *tstr = '\0'; - result = TokGetValue(estr, parent, parprops, glob, &dval); - if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); - else if (result == -1) PushTok(TOK_STRING, estr, &expstack); - - if (*(tstr + 1) == '=') { - PushTok(TOK_LE, NULL, &expstack); - tstr++; - } - else - PushTok(TOK_LT, NULL, &expstack); - estr = tstr + 1; - numlast = 0; - break; - - case ',': - *tstr = '\0'; - result = TokGetValue(estr, parent, parprops, glob, &dval); - if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); - else if (result == -1) PushTok(TOK_STRING, estr, &expstack); - if (expstack == NULL) break; - lptr = expstack; - while (lptr->next) { - lptr = lptr->next; - if (lptr->toktype == TOK_FUNC_THEN) { - PushTok(TOK_FUNC_ELSE, NULL, &expstack); - break; - } - else if (lptr->toktype == TOK_FUNC_IF) { - PushTok(TOK_FUNC_THEN, NULL, &expstack); - break; - } - } - estr = tstr + 1; - numlast = 0; - break; - default: + PushTok(TOK_FUNC_CLOSE, NULL, &expstack); break; } - tstr++; - } - result = TokGetValue(estr, parent, parprops, glob, &dval); - if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); - else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + numlast = 1; + estr = tstr + 1; + break; - FREE(kv->value.string); - kv->value.stack = expstack; - kv->type = PROP_EXPRESSION; - break; + case '\'': + *tstr = '\0'; + result = TokGetValue(estr, parent, parprops, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + PushTok(TOK_SGL_QUOTE, NULL, &expstack); + estr = tstr + 1; + numlast = 0; + break; + + case '"': + *tstr = '\0'; + result = TokGetValue(estr, parent, parprops, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + PushTok(TOK_DBL_QUOTE, NULL, &expstack); + estr = tstr + 1; + numlast = 0; + break; + + case '{': + *tstr = '\0'; + result = TokGetValue(estr, parent, parprops, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + PushTok(TOK_GROUP_OPEN, NULL, &expstack); + estr = tstr + 1; + numlast = 0; + break; + + case '}': + *tstr = '\0'; + result = TokGetValue(estr, parent, parprops, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + PushTok(TOK_GROUP_CLOSE, NULL, &expstack); + estr = tstr + 1; + numlast = 1; + break; + + case '!': + if (*(tstr + 1) == '=') { + *tstr = '\0'; + result = TokGetValue(estr, parent, parprops, + glob, &dval); + if (result == 1) + PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) + PushTok(TOK_STRING, estr, &expstack); + PushTok(TOK_NE, NULL, &expstack); + } + numlast = 0; + break; + + case '=': + if (*(tstr + 1) == '=') { + *tstr = '\0'; + result = TokGetValue(estr, parent, parprops, + glob, &dval); + if (result == 1) + PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) + PushTok(TOK_STRING, estr, &expstack); + PushTok(TOK_EQ, NULL, &expstack); + numlast = 0; + } + break; + + case '>': + *tstr = '\0'; + result = TokGetValue(estr, parent, parprops, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + + if (*(tstr + 1) == '=') { + PushTok(TOK_GE, NULL, &expstack); + tstr++; + } + else + PushTok(TOK_GT, NULL, &expstack); + estr = tstr + 1; + numlast = 0; + break; + + case '<': + *tstr = '\0'; + result = TokGetValue(estr, parent, parprops, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + + if (*(tstr + 1) == '=') { + PushTok(TOK_LE, NULL, &expstack); + tstr++; + } + else + PushTok(TOK_LT, NULL, &expstack); + estr = tstr + 1; + numlast = 0; + break; + + case ',': + *tstr = '\0'; + result = TokGetValue(estr, parent, parprops, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); + if (expstack == NULL) break; + lptr = expstack; + while (lptr->next) { + lptr = lptr->next; + if (lptr->toktype == TOK_FUNC_THEN) { + PushTok(TOK_FUNC_ELSE, NULL, &expstack); + break; + } + else if (lptr->toktype == TOK_FUNC_IF) { + PushTok(TOK_FUNC_THEN, NULL, &expstack); + break; + } + } + estr = tstr + 1; + numlast = 0; + break; + + default: + break; + } + tstr++; } + result = TokGetValue(estr, parent, parprops, glob, &dval); + if (result == 1) PushTok(TOK_DOUBLE, &dval, &expstack); + else if (result == -1) PushTok(TOK_STRING, estr, &expstack); - // Find the beginning of the expression, which is the bottom of - // the stack. - for (stackptr = kv->value.stack; stackptr != NULL && + FREE(kv->value.string); + kv->value.stack = expstack; + kv->type = PROP_EXPRESSION; + } + + /* Find the beginning of the expression, which is the bottom of + * the stack. + */ + + for (stackptr = kv->value.stack; stackptr != NULL && stackptr->next != NULL; stackptr = stackptr->next); - // For each pass, start at the bottom and work forward - expstack = stackptr; + /* For each pass, start at the bottom and work forward. */ + expstack = stackptr; - modified = 1; - while (modified) { - double dval1, dval2; + modified = 1; + while (modified) { + double dval1, dval2; - modified = 0; + modified = 0; - // Reduce conditionals + // Reduce conditionals - for (stackptr = expstack; stackptr != NULL; stackptr = stackptr->last) { - switch (stackptr->toktype) { - case TOK_LE: - case TOK_LT: - case TOK_GE: - case TOK_GT: - case TOK_EQ: - case TOK_NE: - lptr = stackptr->last; - nptr = stackptr->next; - if (lptr && nptr && (lptr->toktype == TOK_DOUBLE) && + for (stackptr = expstack; stackptr != NULL; stackptr = stackptr->last) { + switch (stackptr->toktype) { + case TOK_LE: + case TOK_LT: + case TOK_GE: + case TOK_GT: + case TOK_EQ: + case TOK_NE: + lptr = stackptr->last; + nptr = stackptr->next; + if (lptr && nptr && (lptr->toktype == TOK_DOUBLE) && (nptr->toktype == TOK_DOUBLE)) { - switch (stackptr->toktype) { - case TOK_LE: - if (nptr->data.dvalue <= lptr->data.dvalue) { - stackptr->data.dvalue = 1.0; - } - else { - stackptr->data.dvalue = 0.0; - } - break; - case TOK_LT: - if (nptr->data.dvalue < lptr->data.dvalue) { - stackptr->data.dvalue = 1.0; - } - else { - stackptr->data.dvalue = 0.0; - } - break; - case TOK_GE: - if (nptr->data.dvalue >= lptr->data.dvalue) { - stackptr->data.dvalue = 1.0; - } - else { - stackptr->data.dvalue = 0.0; - } - break; - case TOK_GT: - if (nptr->data.dvalue > lptr->data.dvalue) { - stackptr->data.dvalue = 1.0; - } - else { - stackptr->data.dvalue = 0.0; - } - break; - case TOK_EQ: - if (nptr->data.dvalue == lptr->data.dvalue) { - stackptr->data.dvalue = 1.0; - } - else { - stackptr->data.dvalue = 0.0; - } - break; - case TOK_NE: - if (nptr->data.dvalue != lptr->data.dvalue) { - stackptr->data.dvalue = 1.0; - } - else { - stackptr->data.dvalue = 0.0; - } - break; - } - modified = 1; - stackptr->toktype = TOK_DOUBLE; - stackptr->last = lptr->last; - if (lptr->last) lptr->last->next = stackptr; - else kv->value.stack = stackptr; - stackptr->next = nptr->next; - if (nptr->next) nptr->next->last = stackptr; - if (expstack == nptr) expstack = stackptr; - - FREE(nptr); - FREE(lptr); + switch (stackptr->toktype) { + case TOK_LE: + if (nptr->data.dvalue <= lptr->data.dvalue) { + stackptr->data.dvalue = 1.0; + } + else { + stackptr->data.dvalue = 0.0; + } + break; + case TOK_LT: + if (nptr->data.dvalue < lptr->data.dvalue) { + stackptr->data.dvalue = 1.0; + } + else { + stackptr->data.dvalue = 0.0; + } + break; + case TOK_GE: + if (nptr->data.dvalue >= lptr->data.dvalue) { + stackptr->data.dvalue = 1.0; + } + else { + stackptr->data.dvalue = 0.0; + } + break; + case TOK_GT: + if (nptr->data.dvalue > lptr->data.dvalue) { + stackptr->data.dvalue = 1.0; + } + else { + stackptr->data.dvalue = 0.0; + } + break; + case TOK_EQ: + if (nptr->data.dvalue == lptr->data.dvalue) { + stackptr->data.dvalue = 1.0; + } + else { + stackptr->data.dvalue = 0.0; + } + break; + case TOK_NE: + if (nptr->data.dvalue != lptr->data.dvalue) { + stackptr->data.dvalue = 1.0; + } + else { + stackptr->data.dvalue = 0.0; + } + break; } - } + modified = 1; + stackptr->toktype = TOK_DOUBLE; + stackptr->last = lptr->last; + if (lptr->last) lptr->last->next = stackptr; + else kv->value.stack = stackptr; + stackptr->next = nptr->next; + if (nptr->next) nptr->next->last = stackptr; + if (expstack == nptr) expstack = stackptr; + + FREE(nptr); + FREE(lptr); + } } + } - // Reduce IF(a,b,c) + // Reduce IF(a,b,c) - for (stackptr = expstack; stackptr != NULL; stackptr = stackptr->last) { - struct tokstack *ifptr, *thenptr; - if (stackptr->toktype == TOK_FUNC_IF) { - ifptr = stackptr->last; - if (ifptr->toktype == TOK_DOUBLE) { - stackptr->toktype = TOK_FUNC_OPEN; - if (ifptr->data.dvalue == 0.0) { - /* Keep ELSE value, remove IF and THEN */ - for (thenptr = ifptr; thenptr->toktype != + for (stackptr = expstack; stackptr != NULL; stackptr = stackptr->last) { + struct tokstack *ifptr, *thenptr; + if (stackptr->toktype == TOK_FUNC_IF) { + ifptr = stackptr->last; + if (ifptr->toktype == TOK_DOUBLE) { + stackptr->toktype = TOK_FUNC_OPEN; + if (ifptr->data.dvalue == 0.0) { + /* Keep ELSE value, remove IF and THEN */ + for (thenptr = ifptr; thenptr->toktype != TOK_FUNC_ELSE; ) { - lptr = thenptr->last; - nptr = thenptr->next; - lptr->next = nptr; - nptr->last = lptr; - if (thenptr->toktype == TOK_STRING) - FREE(thenptr->data.string); - FREE(thenptr); - thenptr = lptr; - } - /* Free the TOK_FUNC_ELSE record */ lptr = thenptr->last; nptr = thenptr->next; lptr->next = nptr; nptr->last = lptr; + if (thenptr->toktype == TOK_STRING) + FREE(thenptr->data.string); FREE(thenptr); - modified = 1; + thenptr = lptr; } - else { - /* Keep THEN value, remove IF and ELSE */ - /* Free the conditional result value record */ - lptr = ifptr->last; - nptr = ifptr->next; - lptr->next = nptr; - nptr->last = lptr; - FREE(ifptr); - thenptr = nptr; + /* Free the TOK_FUNC_ELSE record */ + lptr = thenptr->last; + nptr = thenptr->next; + lptr->next = nptr; + nptr->last = lptr; + FREE(thenptr); + modified = 1; + } + else { + /* Keep THEN value, remove IF and ELSE */ + /* Free the conditional result value record */ + lptr = ifptr->last; + nptr = ifptr->next; + lptr->next = nptr; + nptr->last = lptr; + FREE(ifptr); + thenptr = nptr; - /* Free the TOK_FUNC_THEN record */ - lptr = thenptr->last; - nptr = thenptr->next; - lptr->next = nptr; - nptr->last = lptr; - FREE(thenptr); + /* Free the TOK_FUNC_THEN record */ + lptr = thenptr->last; + nptr = thenptr->next; + lptr->next = nptr; + nptr->last = lptr; + FREE(thenptr); - /* Free to end of IF block */ - for (thenptr = nptr->last; thenptr->toktype != + /* Free to end of IF block */ + for (thenptr = nptr->last; thenptr->toktype != TOK_FUNC_CLOSE; ) { - lptr = thenptr->last; - nptr = thenptr->next; - lptr->next = nptr; - nptr->last = lptr; - if (thenptr->toktype == TOK_STRING) - FREE(thenptr->data.string); - FREE(thenptr); - thenptr = lptr; - } - modified = 1; + lptr = thenptr->last; + nptr = thenptr->next; + lptr->next = nptr; + nptr->last = lptr; + if (thenptr->toktype == TOK_STRING) + FREE(thenptr->data.string); + FREE(thenptr); + thenptr = lptr; } + modified = 1; } } } + } - // Reduce (value) * (value) and (value) / (value) + // Reduce (value) * (value) and (value) / (value) - for (stackptr = expstack; stackptr != NULL; stackptr = stackptr->last) { - switch (stackptr->toktype) { - case TOK_MULTIPLY: - case TOK_DIVIDE: - lptr = stackptr->last; - nptr = stackptr->next; - if (lptr && nptr && (lptr->toktype == TOK_DOUBLE) && + for (stackptr = expstack; stackptr != NULL; stackptr = stackptr->last) { + switch (stackptr->toktype) { + case TOK_MULTIPLY: + case TOK_DIVIDE: + lptr = stackptr->last; + nptr = stackptr->next; + if (lptr && nptr && (lptr->toktype == TOK_DOUBLE) && (nptr->toktype == TOK_DOUBLE)) { - if (stackptr->toktype == TOK_MULTIPLY) - stackptr->data.dvalue = nptr->data.dvalue * + if (stackptr->toktype == TOK_MULTIPLY) + stackptr->data.dvalue = nptr->data.dvalue * lptr->data.dvalue; - else - stackptr->data.dvalue = nptr->data.dvalue / + else + stackptr->data.dvalue = nptr->data.dvalue / lptr->data.dvalue; - modified = 1; - stackptr->toktype = TOK_DOUBLE; - stackptr->last = lptr->last; - if (lptr->last) lptr->last->next = stackptr; - else kv->value.stack = stackptr; - stackptr->next = nptr->next; - if (nptr->next) nptr->next->last = stackptr; - if (expstack == nptr) expstack = stackptr; + modified = 1; + stackptr->toktype = TOK_DOUBLE; + stackptr->last = lptr->last; + if (lptr->last) lptr->last->next = stackptr; + else kv->value.stack = stackptr; + stackptr->next = nptr->next; + if (nptr->next) nptr->next->last = stackptr; + if (expstack == nptr) expstack = stackptr; - FREE(nptr); - FREE(lptr); - } - } + FREE(nptr); + FREE(lptr); + } } + } - // Reduce (value) + (value) and (value) - (value) + // Reduce (value) + (value) and (value) - (value) - for (stackptr = expstack; stackptr != NULL; stackptr = stackptr->last) { - switch (stackptr->toktype) { - case TOK_PLUS: - case TOK_MINUS: - lptr = stackptr->last; - nptr = stackptr->next; - if (lptr && nptr && (lptr->toktype == TOK_DOUBLE) && + for (stackptr = expstack; stackptr != NULL; stackptr = stackptr->last) { + switch (stackptr->toktype) { + case TOK_PLUS: + case TOK_MINUS: + lptr = stackptr->last; + nptr = stackptr->next; + if (lptr && nptr && (lptr->toktype == TOK_DOUBLE) && (nptr->toktype == TOK_DOUBLE)) { - if (stackptr->toktype == TOK_PLUS) - stackptr->data.dvalue = nptr->data.dvalue + + if (stackptr->toktype == TOK_PLUS) + stackptr->data.dvalue = nptr->data.dvalue + lptr->data.dvalue; - else - stackptr->data.dvalue = nptr->data.dvalue - + else + stackptr->data.dvalue = nptr->data.dvalue - lptr->data.dvalue; - modified = 1; - stackptr->toktype = TOK_DOUBLE; - stackptr->last = lptr->last; - if (lptr->last) lptr->last->next = stackptr; - else kv->value.stack = stackptr; - stackptr->next = nptr->next; - if (nptr->next) nptr->next->last = stackptr; - if (expstack == nptr) expstack = stackptr; + modified = 1; + stackptr->toktype = TOK_DOUBLE; + stackptr->last = lptr->last; + if (lptr->last) lptr->last->next = stackptr; + else kv->value.stack = stackptr; + stackptr->next = nptr->next; + if (nptr->next) nptr->next->last = stackptr; + if (expstack == nptr) expstack = stackptr; - FREE(nptr); - FREE(lptr); - } - } + FREE(nptr); + FREE(lptr); + } } + } - // Reduce {value}, (value), and 'value' + // Reduce {value}, (value), and 'value' - for (stackptr = expstack; stackptr != NULL; stackptr = stackptr->last) { - switch (stackptr->toktype) { - case TOK_DOUBLE: - lptr = stackptr->last; - nptr = stackptr->next; - if (lptr && nptr && + for (stackptr = expstack; stackptr != NULL; stackptr = stackptr->last) { + switch (stackptr->toktype) { + case TOK_DOUBLE: + lptr = stackptr->last; + nptr = stackptr->next; + if (lptr && nptr && (((nptr->toktype == TOK_FUNC_OPEN) && (lptr->toktype == TOK_FUNC_CLOSE)) || ((nptr->toktype == TOK_GROUP_OPEN) && @@ -800,75 +786,103 @@ int ReduceExpressions(struct objlist *instprop, struct objlist *parprops, ((nptr->toktype == TOK_SGL_QUOTE) && (lptr->toktype == TOK_SGL_QUOTE)))) { - modified = 1; - stackptr->last = lptr->last; - if (lptr->last) lptr->last->next = stackptr; - else kv->value.stack = stackptr; - stackptr->next = nptr->next; - if (nptr->next) nptr->next->last = stackptr; - if (expstack == nptr) expstack = stackptr; + modified = 1; + stackptr->last = lptr->last; + if (lptr->last) lptr->last->next = stackptr; + else kv->value.stack = stackptr; + stackptr->next = nptr->next; + if (nptr->next) nptr->next->last = stackptr; + if (expstack == nptr) expstack = stackptr; - FREE(nptr); - FREE(lptr); - } - break; - } + FREE(nptr); + FREE(lptr); + } + break; } + } - // Replace value if string can be substituted with a number + // Replace value if string can be substituted with a number - for (stackptr = expstack; stackptr != NULL; stackptr = stackptr->last) { - switch (stackptr->toktype) { - case TOK_STRING: - result = TokGetValue(stackptr->data.string, parent, + for (stackptr = expstack; stackptr != NULL; stackptr = stackptr->last) { + switch (stackptr->toktype) { + case TOK_STRING: + result = TokGetValue(stackptr->data.string, parent, parprops, glob, &dval); - if (result == 1) { - stackptr->toktype = TOK_DOUBLE; - FREE(stackptr->data.string); - stackptr->data.dvalue = dval; - modified = 1; - } - break; - } + if (result == 1) { + stackptr->toktype = TOK_DOUBLE; + FREE(stackptr->data.string); + stackptr->data.dvalue = dval; + modified = 1; + } + break; } } - - // Replace the expression with the reduced expression or - // value. - - expstack = kv->value.stack; // Now pointing at the end - - if (expstack && expstack->next == NULL) { - if (expstack->toktype == TOK_DOUBLE) { - kv->type = PROP_DOUBLE; - kv->value.dval = expstack->data.dvalue; - } - else if (expstack->toktype == TOK_STRING) { - kv->type = PROP_STRING; - kv->value.string = strsave(expstack->data.string); - } - } - else { - // Still an expression; do nothing - } - - // Free up the stack if it's not being used - - if (kv->type != PROP_EXPRESSION) - { - while (expstack != NULL) { - nptr = expstack->next; - if (expstack->toktype == TOK_STRING) - FREE(expstack->data.string); - FREE(expstack); - expstack = nptr; - } - } - - if (kv->type == PROP_ENDLIST) - break; } + // Replace the expression with the reduced expression or + // value. + + expstack = kv->value.stack; // Now pointing at the end + + if (expstack && expstack->next == NULL) { + if (expstack->toktype == TOK_DOUBLE) { + kv->type = PROP_DOUBLE; + kv->value.dval = expstack->data.dvalue; + } + else if (expstack->toktype == TOK_STRING) { + kv->type = PROP_STRING; + kv->value.string = strsave(expstack->data.string); + } + } + else { + // Still an expression; do nothing + } + + // Free up the stack if it's not being used + + if (kv->type != PROP_EXPRESSION) + { + while (expstack != NULL) { + nptr = expstack->next; + if (expstack->toktype == TOK_STRING) + FREE(expstack->data.string); + FREE(expstack); + expstack = nptr; + } + } + + return 0; +} + +/*----------------------------------------------------------------------*/ +/* Wrapper around the above routine, to reduce all expressions in a */ +/* property list. */ +/*----------------------------------------------------------------------*/ + +int ReduceExpressions(struct objlist *instprop, struct objlist *parprops, + struct nlist *parent, int glob) { + + struct valuelist *kv; + int i; + + if (instprop == NULL) return 0; // Nothing to do + if (instprop->type != PROPERTY) return -1; // Shouldn't happen + + for (i = 0;; i++) { + kv = &(instprop->instance.props[i]); + if (kv->type == PROP_ENDLIST) break; + switch (kv->type) + { + case PROP_INTEGER: + case PROP_DOUBLE: + case PROP_VALUE: + continue; + + default: + ReduceOneExpression(kv, parprops, parent, glob); + break; + } + } return 0; } @@ -2163,9 +2177,13 @@ int SetPropertyDefault(struct property *prop, struct valuelist *vl) /* to integers, and strings that are not numbers must be left as */ /* strings. Return 1 if the property was promoted successfully, and 0 */ /* if no promotion was possible, and -1 if passed a bad argument. */ +/* */ +/* NOTE: Arguments ob and tc are only used in the case of evaluating */ +/* an expression, used to generate a derived property. */ /*----------------------------------------------------------------------*/ -int PromoteProperty(struct property *prop, struct valuelist *vl) +int PromoteProperty(struct property *prop, struct valuelist *vl, + struct objlist *ob, struct nlist *tc) { char tstr[256]; int ival, result; @@ -2174,6 +2192,9 @@ int PromoteProperty(struct property *prop, struct valuelist *vl) if (prop == NULL || vl == NULL) return -1; if (prop->type == vl->type) return 1; /* Nothing to do */ result = 0; + if (prop->type == PROP_EXPRESSION) { + ReduceOneExpression(vl, ob, tc, FALSE); + } switch (prop->type) { case PROP_STRING: switch (vl->type) { diff --git a/base/netgen.h b/base/netgen.h index 20e55f3..b60893c 100644 --- a/base/netgen.h +++ b/base/netgen.h @@ -43,7 +43,8 @@ extern int PropertyMerge(char *name, int fnum, char *key, int merge_type, int merge_mask); extern void ResolveProperties(char *name1, int file1, char *name2, int file2); extern void CopyProperties(struct objlist *obj_to, struct objlist *obj_from); -extern int PromoteProperty(struct property *, struct valuelist *); +extern int PromoteProperty(struct property *, struct valuelist *, + struct objlist *, struct nlist *); extern int SetPropertyDefault(struct property *, struct valuelist *); extern struct objlist *LinkProperties(char *model, struct keyvalue *topptr); extern int ReduceExpressions(struct objlist *instprop, struct objlist *parprops, diff --git a/tcltk/tclnetgen.c b/tcltk/tclnetgen.c index 79f005a..cd6b262 100644 --- a/tcltk/tclnetgen.c +++ b/tcltk/tclnetgen.c @@ -3343,10 +3343,10 @@ _netcmp_property(ClientData clientData, int result, index, idx2; char *suboptions[] = { - "integer", "double", "value", "string", NULL + "integer", "double", "value", "string", "expression", NULL }; enum SubOptionIdx { - INTEGER_IDX, DOUBLE_IDX, VALUE_IDX, STRING_IDX + INTEGER_IDX, DOUBLE_IDX, VALUE_IDX, STRING_IDX, EXPRESSION_IDX }; /* Note: "merge" has been deprecated, but kept for backwards compatibility. */ @@ -3735,6 +3735,11 @@ _netcmp_property(ClientData clientData, PropertyString(tp->name, fnum, Tcl_GetString(tobj1), ival, NULL); break; + case EXPRESSION_IDX: + PropertyString(tp->name, fnum, + Tcl_GetString(tobj1), 0, + Tcl_GetString(tobj3)); + break; } break; }