From 6b476e99af9158d6b2b07d8feaaac813f70ff696 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 18 Jan 2020 16:49:04 +0100 Subject: [PATCH] update to the .measure and meas error messages: remove crash uipon buggy inputs add buggy example input file unify fcn returns: 0 is OK, 1 is bad Improve on error message for bad syntax --- examples/measure/buggy-meas-tran.sp | 86 +++++++++++++++++ src/frontend/com_measure2.c | 145 +++++++++++++++++----------- 2 files changed, 175 insertions(+), 56 deletions(-) create mode 100644 examples/measure/buggy-meas-tran.sp diff --git a/examples/measure/buggy-meas-tran.sp b/examples/measure/buggy-meas-tran.sp new file mode 100644 index 000000000..4ff1f46d6 --- /dev/null +++ b/examples/measure/buggy-meas-tran.sp @@ -0,0 +1,86 @@ +File: buggy-meas-tran.sp +* Simple .measurement examples +* transient simulation of two sine signals with different frequencies +vac1 1 0 DC 0 sin(0 1 1k 0 0) +R1 1 0 100k +vac2 2 0 DC 0 sin(0 1.2 0.9k 0 0) +.tran 10u 5m +* +.measure tra tdiff TRIG v(1) VAL=0.5 RISE=1 TARG v(1) VAL=0.5 RISE=2 +.measure tran tdiff RIG v(1) VAL=0.5 RISE=1 TARG v(1) VAL=0.5 RISE=3 +.measure tran tdiff TRIG v(1 VAL=0.5 RISE=1 TARG v(1) VAL=0.5 FALL=1 +.measure tran tdiff TRIG v(1) VAL FALL=3 TARG v(2) VAL=0 FALL=3 +.measure tran tdiff TRIG v(1) VAL=-0.6 CROS=1 TARG v(2) VAL=-0.8 CROSS=1 +.measure tran tdiff TRIG AT=1m TARG v(2) VAL -0.8 CROSS=3 +.measure tran teval WHE v(2)=0.7 CROSS=LAST +.measure tran teval WHEN v(2)==v(1) FALL=LAST +.measure tran teval WHEN v(1)!=v(2) CROSS=LAST +.measure tran yeval FIND v(2) WHEN v(1)=0.2 FALL=2 +.measure tran yeval FIND v(2) AT=2 m +.measure tran ymax MAX v(2) fro m=2m to=3m +.measure tran tymax MAX_AT v(2) from=2m to=3m +.measure tran ypp PP v(1) from=2m to=4m +.measure tran yrms RMS v() from=2m to=3.5m +.measure tran yavg AVG v(1) from 2m to=4m +.measure tran yint INTER v(2) from=2m to=3m +.param fval=5 +.measure tran yadd param='fval + 7' +.param vout_diff=50k +.meas tran bw_chk param='(vout_diff < 100k) ? 1 : 0' +.measure tran vtest find par('v(2)*v(1)') AT=2.3m +* +.control +run +plot v(1) v(2) +plot i(vac1) + +echo +echo good meas lines +meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 TARG v(1) VAL=0.5 RISE=2 +meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 TARG v(1) VAL=0.5 RISE=3 +meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 TARG v(1) VAL=0.5 FALL=1 +meas tran tdiff TRIG v(1) VAL=0 FALL=3 TARG v(2) VAL=0 FALL=3 +meas tran tdiff TRIG v(1) VAL=-0.6 CROSS=1 TARG v(2) VAL=-0.8 CROSS=1 +meas tran tdiff TRIG AT=1m TARG v(2) VAL=-0.8 CROSS=3 +meas tran teval WHEN v(2)=0.7 CROSS=LAST +meas tran teval WHEN v(2)=v(1) FALL=LAST +meas tran teval WHEN v(1)=v(2) CROSS=LAST +meas tran yeval FIND v(2) WHEN v(1)=0.2 FALL=2 +meas tran yeval FIND v(2) AT=2m +meas tran ymax MAX v(2) from=2m to=3m +meas tran tymax MAX_AT v(2) from=2m to=3m +meas tran ypp PP v(1) from=2m to=4m +meas tran yrms RMS v(1) from=2m to=3.5m +meas tran yavg AVG v(1) from=2m to=4m +meas tran yint INTEG v(2) from=2m to=3m +meas tran ymax MAX v(2) from=2m to=3m +meas tran tmax WHEN v(2)=YMAX from=1m to=2m + +echo +echo buggy input lines +meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 TARG v(1) VAL=0.5 RISE=2 +meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 TARG v(1) VAL=0.5 +meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 TARG v(1) +meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 TARG +meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 +meas tran tdiff TRIG v(1) VAL=0.5 +meas tran tdiff TRIG v(1) +meas tran tdiff TRIG +meas tran tdiff +meas tran +meas +echo +echo more buggy lines +meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 TARG v(1) VAL=0.5 RISE=2 +meas tran TRIG v(1) VAL=0.5 RISE=1 TARG v(1) VAL=0.5 RISE=2 +meas tran tdiff v(1) VAL=0.5 RISE=1 TARG v(1) VAL=0.5 RISE=2 +meas tran tdiff TRIG VAL=0.5 RISE=1 TARG v(1) VAL=0.5 RISE=2 +meas tran tdiff TRIG v(1) RISE=1 TARG v(1) VAL=0.5 RISE=2 +meas tran tdiff TRIG v(1) VAL=0.5 TARG v(1) VAL=0.5 RISE=2 +meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 v(1) VAL=0.5 RISE=2 +meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 TARG VAL=0.5 RISE=2 +meas tran tdiff TRIG v(1) VAL=0.5 RISE=1 TARG v(1) RISE=2 +meas tran tdiff TRIG v(1) VAL= RISE=1 TARG v(1) VAL=0.5 RISE=2 +meas tran tdiff TRIG v(1) VAL=0.5 RISE= TARG v(1) VAL=0.5 RISE=2 +.endc +.end diff --git a/src/frontend/com_measure2.c b/src/frontend/com_measure2.c index e4c3d4418..9cf19ab6a 100644 --- a/src/frontend/com_measure2.c +++ b/src/frontend/com_measure2.c @@ -350,7 +350,7 @@ measure_extract_variables(char *line) * Function: process a WHEN measurement statement which has been * parsed into a measurement structure. * ----------------------------------------------------------------- */ -static void +static int com_measure_when( MEASUREPTR meas /* in : parsed measurement structure */ ) @@ -385,16 +385,16 @@ com_measure_when( if (d == NULL) { fprintf(cp_err, "Error: no such vector as %s.\n", meas->m_vec); - return; + return MEASUREMENT_FAILURE; } if (has_d2 && (d2 == NULL)) { fprintf(cp_err, "Error: no such vector as %s.\n", meas->m_vec2); - return; + return MEASUREMENT_FAILURE; } if (dScale == NULL) { fprintf(cp_err, "Error: no scale vector.\n"); - return; + return MEASUREMENT_FAILURE; } prevValue = 0.; @@ -537,13 +537,13 @@ com_measure_when( * exit when we meet condition */ // meas->m_measured = prevScaleValue + (value2 - prevValue) * (scaleValue - prevScaleValue) / (value - prevValue); meas->m_measured = prevScaleValue + (prevValue2 - prevValue) * (scaleValue - prevScaleValue) / (value - prevValue - value2 + prevValue2); - return; + return MEASUREMENT_OK; } if (measurement_pending) { if ((meas->m_cross == MEASURE_DEFAULT) && (meas->m_rise == MEASURE_DEFAULT) && (meas->m_fall == MEASURE_DEFAULT)) { /* user didn't request any option, return the first possible case */ meas->m_measured = prevScaleValue + (prevValue2 - prevValue) * (scaleValue - prevScaleValue) / (value - prevValue - value2 + prevValue2); - return; + return MEASUREMENT_OK; } else if ((meas->m_cross == MEASURE_LAST_TRANSITION) || (meas->m_rise == MEASURE_LAST_TRANSITION) || (meas->m_fall == MEASURE_LAST_TRANSITION)) { meas->m_measured = prevScaleValue + (prevValue2 - prevValue) * (scaleValue - prevScaleValue) / (value - prevValue - value2 + prevValue2); /* no return - look for last */ @@ -577,13 +577,13 @@ com_measure_when( /* user requested an exact match of cross, rise, or fall * exit when we meet condition */ meas->m_measured = prevScaleValue + (meas->m_val - prevValue) * (scaleValue - prevScaleValue) / (value - prevValue); - return; + return MEASUREMENT_OK; } if (measurement_pending) { if ((meas->m_cross == MEASURE_DEFAULT) && (meas->m_rise == MEASURE_DEFAULT) && (meas->m_fall == MEASURE_DEFAULT)) { /* user didn't request any option, return the first possible case */ meas->m_measured = prevScaleValue + (meas->m_val - prevValue) * (scaleValue - prevScaleValue) / (value - prevValue); - return; + return MEASUREMENT_OK; } else if ((meas->m_cross == MEASURE_LAST_TRANSITION) || (meas->m_rise == MEASURE_LAST_TRANSITION) || (meas->m_fall == MEASURE_LAST_TRANSITION)) { meas->m_measured = prevScaleValue + (meas->m_val - prevValue) * (scaleValue - prevScaleValue) / (value - prevValue); /* no return - look for last */ @@ -603,6 +603,8 @@ com_measure_when( if (init_measured_value) meas->m_measured = NAN; + + return MEASUREMENT_OK; } @@ -611,7 +613,7 @@ com_measure_when( * parsed into a measurement structure. We make sure to interpolate * the value when appropriate. * ----------------------------------------------------------------- */ -static void +static int measure_at( MEASUREPTR meas, /* in : parsed "at" data */ double at /* in: time to perform measurement */ @@ -623,17 +625,23 @@ measure_at( struct dvec *d, *dScale; psvalue = pvalue = 0; + + if (meas->m_vec == NULL) { + fprintf(stderr, "Error: Syntax error in meas line, missing vector\n"); + return MEASUREMENT_FAILURE; + } + d = vec_get(meas->m_vec); dScale = plot_cur->pl_scale; if (d == NULL) { fprintf(cp_err, "Error: no such vector as %s.\n", meas->m_vec); - return; + return MEASUREMENT_FAILURE; } if (dScale == NULL) { fprintf(cp_err, "Error: no such vector time, frequency or dc.\n"); - return; + return MEASUREMENT_FAILURE; } /* ----------------------------------------------------------------- @@ -670,10 +678,10 @@ measure_at( if ((i > 0) && (psvalue <= at) && (svalue >= at)) { meas->m_measured = pvalue + (at - psvalue) * (value - pvalue) / (svalue - psvalue); - return; + return MEASUREMENT_OK; } else if (dc_check && (i > 0) && (psvalue >= at) && (svalue <= at)) { meas->m_measured = pvalue + (at - psvalue) * (value - pvalue) / (svalue - psvalue); - return; + return MEASUREMENT_OK; } psvalue = svalue; @@ -681,6 +689,7 @@ measure_at( } meas->m_measured = NAN; + return MEASUREMENT_OK; } @@ -690,7 +699,7 @@ measure_at( * the value here when we have m_from and m_to constraints * so this * function is slightly wrong. Need to fix in future rev. * ----------------------------------------------------------------- */ -static void +static int measure_minMaxAvg( MEASUREPTR meas, /* in : parsed measurement data request */ ANALYSIS_TYPE_T mFunctionType /* in: one of AT_AVG, AT_MIN, AT_MAX, AT_MIN_AT, AT_MAX_AT */ @@ -709,10 +718,15 @@ measure_minMaxAvg( meas->m_measured_at = NAN; first = 0; + if (meas->m_vec == NULL) { + fprintf(cp_err, "Syntax error in meas line\n"); + return MEASUREMENT_FAILURE; + } + d = vec_get(meas->m_vec); if (d == NULL) { fprintf(cp_err, "Error: no such vector as %s.\n", meas->m_vec); - return; + return MEASUREMENT_FAILURE; } @@ -736,12 +750,12 @@ measure_minMaxAvg( dScale = vec_get("v-sweep"); } else { /* error */ fprintf(cp_err, "Error: no such analysis type as %s.\n", meas->m_analysis); - return; + return MEASUREMENT_FAILURE; } if (dScale == NULL) { fprintf(cp_err, "Error: no such vector as time, frquency or v-sweep.\n"); - return; + return MEASUREMENT_FAILURE; } for (i = 0; i < d->v_length; i++) { @@ -801,6 +815,7 @@ measure_minMaxAvg( break; default: fprintf(cp_err, "Error: improper min/max/avg call.\n"); + return MEASUREMENT_FAILURE; } } else { switch (mFunctionType) { @@ -829,6 +844,7 @@ measure_minMaxAvg( } default : fprintf(cp_err, "Error: improper min/max/avg call.\n"); + return MEASUREMENT_FAILURE; } } @@ -851,7 +867,9 @@ measure_minMaxAvg( } default : fprintf(cp_err, "Error: improper min/max/avg call.\n"); + return MEASUREMENT_FAILURE; } + return MEASUREMENT_OK; } @@ -860,7 +878,7 @@ measure_minMaxAvg( * parsed into a measurement structure. Here we do interpolate * the starting and stopping time window so the answer is correct. * ----------------------------------------------------------------- */ -static void +static int measure_rms_integral( MEASUREPTR meas, /* in : parsed measurement data request */ ANALYSIS_TYPE_T mFunctionType /* in: one of AT_RMS, or AT_INTEG */ @@ -897,7 +915,7 @@ measure_rms_integral( d = vec_get(meas->m_vec); if (d == NULL) { fprintf(cp_err, "Error: no such vector as %s.\n", meas->m_vec); - return; + return MEASUREMENT_FAILURE; } if (ac_check || sp_check) { @@ -908,12 +926,12 @@ measure_rms_integral( xScale = vec_get("v-sweep"); } else { /* error */ fprintf(cp_err, "Error: no such analysis type as %s.\n", meas->m_analysis); - return; + return MEASUREMENT_FAILURE; } if (xScale == NULL) { fprintf(cp_err, "Error: no such vector as time.\n"); - return; + return MEASUREMENT_FAILURE; } /* Allocate buffers for calculation. */ @@ -1033,6 +1051,7 @@ measure_rms_integral( txfree(x); txfree(y); txfree(width); + return MEASUREMENT_OK; } @@ -1170,7 +1189,7 @@ measure_parse_stdParams( continue; } else { sprintf(errbuf, "bad syntax. equal sign missing ?\n"); - return 0; + return MEASUREMENT_FAILURE; } } @@ -1180,7 +1199,7 @@ measure_parse_stdParams( else { if (ft_numparse(&pValue, FALSE, &engVal1) < 0) { sprintf(errbuf, "bad syntax, cannot evaluate right hand side of %s=%s\n", pName, pValue); - return 0; + return MEASUREMENT_FAILURE; } } @@ -1208,7 +1227,7 @@ measure_parse_stdParams( meas->m_at = engVal1; } else { sprintf(errbuf, "no such parameter as '%s'\n", pName); - return 0; + return MEASUREMENT_FAILURE; } pCnt ++; @@ -1220,20 +1239,20 @@ measure_parse_stdParams( sprintf(errbuf, "bad syntax of %s\n", pName); else sprintf(errbuf, "bad syntax of\n"); - return 0; + return MEASUREMENT_FAILURE; } // valid vector if (measure_valid_vector(meas->m_vec) == 0) { sprintf(errbuf, "no such vector as '%s'\n", meas->m_vec); - return 0; + return MEASUREMENT_FAILURE; } // valid vector2 if (meas->m_vec2 != NULL) if (measure_valid_vector(meas->m_vec2) == 0) { sprintf(errbuf, "no such vector as '%s'\n", meas->m_vec2); - return 0; + return MEASUREMENT_FAILURE; } /* dc: make m_from always less than m_to */ @@ -1242,7 +1261,7 @@ measure_parse_stdParams( SWAP(double, meas->m_from, meas->m_to); } - return 1; + return MEASUREMENT_OK; } @@ -1294,29 +1313,30 @@ measure_parse_find( if (pVal == NULL) { sprintf(errbuf, "bad syntax of WHEN\n"); - return 0; + return MEASUREMENT_FAILURE; } if (strcasecmp(pName, "AT") == 0) { if (ft_numparse((char **) &pVal, FALSE, &meas->m_at) < 0) { sprintf(errbuf, "bad syntax of WHEN\n"); - return 0; + return MEASUREMENT_FAILURE; } } else { sprintf(errbuf, "bad syntax of WHEN\n"); - return 0; + return MEASUREMENT_FAILURE; } } else { - if (measure_parse_stdParams(meas, wl, NULL, errbuf) == 0) - return 0; + if (measure_parse_stdParams(meas, wl, NULL, errbuf) == + MEASUREMENT_FAILURE) + return MEASUREMENT_FAILURE; } wl = wl->wl_next; pCnt ++; } - return 1; + return MEASUREMENT_OK; } @@ -1363,7 +1383,7 @@ measure_parse_when( if (pVar2 == NULL) { sprintf(errBuf, "bad syntax\n"); - return 0; + return MEASUREMENT_FAILURE; } meas->m_vec = copy(pVar1); @@ -1379,15 +1399,15 @@ measure_parse_when( meas->m_val = INPevaluate(&pVar2, &err, 1); } } else { - if (measure_parse_stdParams(meas, wl, NULL, errBuf) == 0) - return 0; + if (measure_parse_stdParams(meas, wl, NULL, errBuf) == MEASUREMENT_FAILURE) + return MEASUREMENT_FAILURE; break; } wl = wl->wl_next; pCnt ++; } - return 1; + return MEASUREMENT_OK; } @@ -1436,11 +1456,13 @@ measure_parse_trigtarg( if (cieq("ac", meas->m_analysis) || cieq("sp", meas->m_analysis)) correct_vec(meas); } else if (ciprefix("at", p)) { - if (measure_parse_stdParams(meas, words, wlTarg, errbuf) == 0) - return 0; + if (measure_parse_stdParams(meas, words, wlTarg, errbuf) == + MEASUREMENT_FAILURE) + return MEASUREMENT_FAILURE; } else { - if (measure_parse_stdParams(meas, words, wlTarg, errbuf) == 0) - return 0; + if (measure_parse_stdParams(meas, words, wlTarg, errbuf) == + MEASUREMENT_FAILURE) + return MEASUREMENT_FAILURE; break; } @@ -1450,16 +1472,16 @@ measure_parse_trigtarg( if (pcnt == 0) { sprintf(errbuf, "bad syntax of '%s'\n", trigTarg); - return 0; + return MEASUREMENT_FAILURE; } // valid vector if (measure_valid_vector(meas->m_vec) == 0) { sprintf(errbuf, "no such vector as '%s'\n", meas->m_vec); - return 0; + return MEASUREMENT_FAILURE; } - return 1; + return MEASUREMENT_OK; } @@ -1594,7 +1616,8 @@ get_measure2( measTrig->m_analysis = measTarg->m_analysis = mAnalysis; - if (measure_parse_trigtarg(measTrig, words , wlTarg, "trig", errbuf) == 0) { + if (measure_parse_trigtarg(measTrig, words, wlTarg, "trig", errbuf) == + MEASUREMENT_FAILURE) { measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck); goto err_ret1; } @@ -1612,7 +1635,8 @@ get_measure2( if (words) words = words->wl_next; // skip targ - if (measure_parse_trigtarg(measTarg, words , NULL, "targ", errbuf) == 0) { + if (measure_parse_trigtarg(measTarg, words, NULL, "targ", errbuf) == + MEASUREMENT_FAILURE) { measure_errMessage(mName, mFunction, "TARG", errbuf, autocheck); goto err_ret1; } @@ -1673,7 +1697,7 @@ err_ret1: meas->m_analysis = measFind->m_analysis = mAnalysis; - if (measure_parse_find(meas, words, wlWhen, errbuf) == 0) { + if (measure_parse_find(meas, words, wlWhen, errbuf) == MEASUREMENT_FAILURE) { measure_errMessage(mName, mFunction, "FIND", errbuf, autocheck); goto err_ret2; } @@ -1686,7 +1710,7 @@ err_ret1: if (words) words = words->wl_next; // skip targ - if (measure_parse_when(measFind, words, errbuf) == 0) { + if (measure_parse_when(measFind, words, errbuf) == MEASUREMENT_FAILURE) { measure_errMessage(mName, mFunction, "WHEN", errbuf, autocheck); goto err_ret2; } @@ -1699,11 +1723,16 @@ err_ret1: goto err_ret2; } - measure_at(meas, measFind->m_measured); + if(measure_at(meas, measFind->m_measured) == MEASUREMENT_FAILURE){ + goto err_ret2; + } + meas->m_at = measFind->m_measured; } else { - measure_at(meas, meas->m_at); + if (measure_at(meas, meas->m_at) == MEASUREMENT_FAILURE) { + goto err_ret2; + } } if (isnan(meas->m_measured)) { @@ -1737,7 +1766,7 @@ err_ret2: MEASUREPTR meas; meas = TMALLOC(struct measure, 1); meas->m_analysis = mAnalysis; - if (measure_parse_when(meas, words, errbuf) == 0) { + if (measure_parse_when(meas, words, errbuf) == MEASUREMENT_FAILURE) { measure_errMessage(mName, mFunction, "WHEN", errbuf, autocheck); goto err_ret3; } @@ -1776,7 +1805,8 @@ err_ret3: MEASUREPTR meas; meas = TMALLOC(struct measure, 1); meas->m_analysis = mAnalysis; - if (measure_parse_trigtarg(meas, words , NULL, "trig", errbuf) == 0) { + if (measure_parse_trigtarg(meas, words, NULL, "trig", errbuf) == + MEASUREMENT_FAILURE) { measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck); goto err_ret4; } @@ -1820,7 +1850,8 @@ err_ret4: meas->m_analysis = mAnalysis; - if (measure_parse_trigtarg(meas, words , NULL, "trig", errbuf) == 0) { + if (measure_parse_trigtarg(meas, words, NULL, "trig", errbuf) == + MEASUREMENT_FAILURE) { measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck); goto err_ret5; } @@ -1863,7 +1894,8 @@ err_ret5: MEASUREPTR measTrig; measTrig = TMALLOC(struct measure, 1); measTrig->m_analysis = mAnalysis; - if (measure_parse_trigtarg(measTrig, words , NULL, "trig", errbuf) == 0) { + if (measure_parse_trigtarg(measTrig, words, NULL, "trig", errbuf) == + MEASUREMENT_FAILURE) { measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck); goto err_ret6; } @@ -1914,7 +1946,8 @@ err_ret6: MEASUREPTR measTrig; measTrig = TMALLOC(struct measure, 1); measTrig->m_analysis = mAnalysis; - if (measure_parse_trigtarg(measTrig, words , NULL, "trig", errbuf) == 0) { + if (measure_parse_trigtarg(measTrig, words, NULL, "trig", errbuf) == + MEASUREMENT_FAILURE) { measure_errMessage(mName, mFunction, "TRIG", errbuf, autocheck); goto err_ret7; }