From 4aa8a72769106e22864ba7bbc3de11025b3c55a7 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 19 May 2021 14:56:38 -0400 Subject: [PATCH 1/3] Corrected an error found in ResolveAutomorphsByProperty which would cause inexplicable output in case of a property error by showing a netlist topography error instead of a property error (but the output shows that the netlists match, and there is no reporting of any property errors). This error was discovered while implementing a better sorting method for parallel combination. The improved method sorts on two properties rather than one, and so should not fall into the error where, say, devices are sorted on W but have different L for a device like a capacitor where no "critical" property is specified (and other similar cases, although that is a common one). --- VERSION | 2 +- base/netcmp.c | 148 +++++++++++++++++++++++++--------------------- tcltk/tclnetgen.c | 14 +++-- 3 files changed, 88 insertions(+), 76 deletions(-) diff --git a/VERSION b/VERSION index 8232290..56dd60e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.5.176 +1.5.177 diff --git a/base/netcmp.c b/base/netcmp.c index 3a29ae4..f984f05 100644 --- a/base/netcmp.c +++ b/base/netcmp.c @@ -4058,24 +4058,33 @@ int series_optimize(struct objlist *ob1, struct nlist *tp1, int idx1, } typedef struct _propsort { - double value; + double value; /* Primary sorting value */ + double avalue; /* Secondary sorting value */ + double slop; /* Delta for accepting equality */ int idx; unsigned char flags; struct objlist *ob; } propsort; /*--------------------------------------------------------------*/ -/* Property sorting routine used by qsort() */ +/* Property sorting routine used by qsort(). Sorts on "value" */ +/* unless the "value" for the two entries differs by less than */ +/* "slop", in which case the entries are sorted on "avalue". */ /*--------------------------------------------------------------*/ static int compsort(const void *p1, const void *p2) { propsort *s1, *s2; + double smax; s1 = (propsort *)p1; s2 = (propsort *)p2; - return (s1->value > s2->value) ? 1 : 0; + smax = fmax(s1->slop, s2->slop); + if (fabs(s1->value - s2->value) <= smax) + return (s1->avalue > s2->avalue) ? 1 : 0; + else + return (s1->value > s2->value) ? 1 : 0; } /*--------------------------------------------------------------*/ @@ -4094,7 +4103,7 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run) struct property *kl; struct valuelist *vl, *sl; int i, p, sval, merge_type; - double cval; + double cval, slop; obn = ob1->next; for (i = 0; i < idx1; i++) obn = obn->next; @@ -4107,7 +4116,7 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run) obp = obn; sval = 1; - cval = 0.0; + cval = slop = 0.0; for (i = 0; i < run; i++) { merge_type = MERGE_NONE; for (p = 0;; p++) { @@ -4121,24 +4130,35 @@ void series_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run) else { kl = (struct property *)HashLookup(vl->key, &(tp1->propdict)); if (kl && (kl->merge & (MERGE_S_ADD | MERGE_S_PAR))) { - if (vl->type == PROP_INTEGER) + if (vl->type == PROP_INTEGER) { cval = (double)vl->value.ival; - else + slop = (double)kl->slop.ival; + } + else { cval = vl->value.dval; + slop = kl->slop.dval; + } merge_type = kl->merge & (MERGE_S_ADD | MERGE_S_PAR); } } } if (merge_type == MERGE_S_ADD) { proplist[i].value = cval * (double)sval; + proplist[i].slop = slop; + proplist[i].avalue = 0; sl->value.ival = 1; } else if (merge_type == MERGE_S_PAR) { proplist[i].value = cval / (double)sval; + proplist[i].slop = slop; + proplist[i].avalue = 0; sl->value.ival = 1; } else { + /* Components which declare no series addition method stay unsorted */ proplist[i].value = (double)0; + proplist[i].avalue = (double)0; + proplist[i].slop = (double)1E-6; } proplist[i].idx = i; proplist[i].ob = obp; @@ -4236,8 +4256,8 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run) struct property *kl; struct valuelist *vl, *ml; int i, p, mval, merge_type, has_crit = FALSE; - char *subs_crit = NULL; - double cval; + char c, *subs_crit = NULL; + double cval, tval, aval, slop, tslop; obn = ob1->next; for (i = 0; i < idx1; i++) obn = obn->next; @@ -4258,10 +4278,11 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run) obp = obn; mval = 1; - cval = 0.0; + cval = aval = slop = 0.0; for (i = 0; i < run; i++) { merge_type = MERGE_NONE; ml = NULL; + c = (char)0; for (p = 0;; p++) { vl = &(obp->instance.props[p]); if (vl->type == PROP_ENDLIST) break; @@ -4278,84 +4299,71 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run) if ((vl->type == PROP_STRING || vl->type == PROP_EXPRESSION) && (kl->type != vl->type)) PromoteProperty(kl, vl); - if (vl->type == PROP_INTEGER) - cval = (double)vl->value.ival; - else if (vl->type == PROP_STRING) + if (vl->type == PROP_INTEGER) { + tval = (double)vl->value.ival; + tslop = (double)kl->slop.ival; + } + else if (vl->type == PROP_STRING) { /* This is unlikely---no method to merge string properties! */ - cval = (double)vl->value.string[0] + tval = (double)vl->value.string[0] + (double)vl->value.string[1] / 10.0; - else - cval = vl->value.dval; + tslop = (double)0; + } + else { + tval = vl->value.dval; + tslop = kl->slop.dval; + } - merge_type = kl->merge & (MERGE_P_ADD | MERGE_P_PAR); + if (merge_type == MERGE_NONE) + { + merge_type = kl->merge & (MERGE_P_ADD | MERGE_P_PAR); + cval = tval; + slop = tslop; + } + else { + if ((c == (char)0) || (toupper(vl->key[0]) > c)) { + c = toupper(vl->key[0]); + aval = tval; + } + } } + else { + if ((c == (char)0) || (toupper(vl->key[0]) > c)) { + if (vl->type == PROP_INTEGER) { + aval = (double)vl->value.ival; + c = toupper(vl->key[0]); + } + else if (vl->type == PROP_DOUBLE) { + aval = vl->value.dval; + c = toupper(vl->key[0]); + } + } + } } if (merge_type == MERGE_P_ADD) { proplist[i].value = cval * (double)mval; + proplist[i].avalue = aval; + proplist[i].slop = tslop; if (ml) ml->value.ival = 1; } else if (merge_type == MERGE_P_PAR) { proplist[i].value = cval / (double)mval; + proplist[i].avalue = aval; + proplist[i].slop = tslop; if (ml) ml->value.ival = 1; } else { - proplist[i].value = (double)0; + /* If there are no additive values, then sort first by M */ + /* and second by aval */ + proplist[i].value = (double)mval; + proplist[i].avalue = aval; + proplist[i].slop = (double)0; } proplist[i].idx = i; proplist[i].ob = obp; obp = obp->next; } - if (has_crit == FALSE) { - /* If no critical property was specified, then choose the first one found */ - /* and recalculate all the proplist values. */ - mval = 1; - obp = obn; - ml = NULL; - merge_type = MERGE_NONE; - for (i = 0; i < run; i++) { - for (p = 0;; p++) { - vl = &(obp->instance.props[p]); - if (vl->type == PROP_ENDLIST) break; - if (vl->key == NULL) continue; - if ((*matchfunc)(vl->key, "M")) { - mval = vl->value.ival; - ml = vl; - } - kl = (struct property *)HashLookup(vl->key, &(tp1->propdict)); - if (kl == NULL) continue; /* Ignored property */ - if (subs_crit == NULL) - subs_crit = vl->key; - if ((subs_crit != NULL) && (*matchfunc)(vl->key, subs_crit)) { - if ((vl->type == PROP_STRING || vl->type == PROP_EXPRESSION) && - (kl->type != vl->type)) - PromoteProperty(kl, vl); - if (vl->type == PROP_INTEGER) - cval = (double)vl->value.ival; - else if (vl->type == PROP_STRING) - /* In case property is non-numeric, sort by dictionary order */ - cval = (double)vl->value.string[0] - + (double)vl->value.string[1] / 10.0; - else - cval = vl->value.dval; - merge_type = kl->merge & (MERGE_P_ADD | MERGE_P_PAR); - } - } - if (merge_type == MERGE_P_ADD) { - proplist[i].value = cval * (double)mval; - if (ml) ml->value.ival = 1; - } - else if (merge_type == MERGE_P_PAR) { - proplist[i].value = cval / (double)mval; - if (ml) ml->value.ival = 1; - } - else { - proplist[i].value = 0; - } - obp = obp->next; - } - } - obn = obp; /* Link from last property */ qsort(&proplist[0], run, sizeof(propsort), compsort); @@ -4846,7 +4854,7 @@ int PropertyOptimize(struct objlist *ob, struct nlist *tp, int run, int series, } // Additive properties do not need to be matched, since - // they can be combined. Critical paroperties must be + // they can be combined. Critical properties must be // matched. Properties with no merge behavior must match. ctype = clist[p][i]; @@ -6207,6 +6215,7 @@ int ResolveAutomorphsByProperty() if ((E2->graph != E1->graph) && (E2->hashval == newhash)) { E2->hashval = orighash; C2--; + if (C2 == C1) break; } } } @@ -6215,6 +6224,7 @@ int ResolveAutomorphsByProperty() if ((E2->graph == E1->graph) && (E2->hashval == newhash)) { E2->hashval = orighash; C1--; + if (C1 == C2) break; } } } diff --git a/tcltk/tclnetgen.c b/tcltk/tclnetgen.c index ccab280..79f005a 100644 --- a/tcltk/tclnetgen.c +++ b/tcltk/tclnetgen.c @@ -2457,8 +2457,7 @@ _netcmp_run(ClientData clientData, automorphisms = ResolveAutomorphsByProperty(); if (automorphisms == 0) Fprintf(stdout, "Netlists match uniquely.\n"); - else { - + else if (automorphisms > 0) { // Next, attempt to resolve automorphisms uniquely by // using the pin names automorphisms = ResolveAutomorphsByPin(); @@ -2466,14 +2465,17 @@ _netcmp_run(ClientData clientData, if (automorphisms == 0) Fprintf(stdout, "Netlists match uniquely.\n"); - else + else if (automorphisms > 0) { // Anything left is truly indistinguishable Fprintf(stdout, "Netlists match with %d symmetr%s.\n", automorphisms, (automorphisms == 1) ? "y" : "ies"); - while ((automorphisms = ResolveAutomorphisms()) > 0); - if (automorphisms == -1) Fprintf(stdout, "Netlists do not match.\n"); - else Fprintf(stdout, "Circuits match correctly.\n"); + while ((automorphisms = ResolveAutomorphisms()) > 0); + } + if (automorphisms == -1) + Fprintf(stdout, "Netlists do not match.\n"); + else + Fprintf(stdout, "Circuits match correctly.\n"); } if (PropertyErrorDetected) { Fprintf(stdout, "There were property errors.\n"); From 476da015f0431d264702215758f2453287e39ef2 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 19 May 2021 16:27:52 -0400 Subject: [PATCH 2/3] 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; } From 759d63cea9958b2cfd6c6d471b23e73472f2c9fe Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Wed, 19 May 2021 16:42:03 -0400 Subject: [PATCH 3/3] Changed a comment in the code that no longer applies after the last modification. --- base/netcmp.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/base/netcmp.c b/base/netcmp.c index 24740d2..3a99e0c 100644 --- a/base/netcmp.c +++ b/base/netcmp.c @@ -4262,17 +4262,15 @@ void parallel_sort(struct objlist *ob1, struct nlist *tp1, int idx1, int run) obn = ob1->next; for (i = 0; i < idx1; i++) obn = obn->next; - // Create a structure of length (run) to hold critical property - // value and index. Then sort that list, then use the sorted - // indexes to sort the actual property linked list. - - // If there is no critical property listed, then it is still better - // to sort on any random property than on no properties. Note that - // this can (and should!) be made better by sorting on *all* - // properties, not just the first. Otherwise, circuit 1 can have, e.g., - // parallel transistors with W=1, L=1 and W=1, L=2 while circuit two - // has W=1, L=2 and W=1, L=1 and property matching will fail because - // sorting was done on W only. + /* Create a structure of length (run) to hold critical property + * value and index. Then sort that list, then use the sorted + * indexes to sort the actual property linked list. + * + * If there is no critical property listed, then it will sort on + * M first, and any additive property second, or any property at + * all if no additive property was found. It is doubtful that any + * use case requires more than two properties for sorting. + */ proplist = (propsort *)MALLOC(run * sizeof(propsort));