2012-09-20 20:30:53 +02:00
|
|
|
/* xpressn.c Copyright (C) 2002 Georg Post
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2009-11-15 22:22:04 +01:00
|
|
|
This file is part of Numparam, see: readme.txt
|
|
|
|
|
Free software under the terms of the GNU Lesser General Public License
|
2012-09-20 20:30:53 +02:00
|
|
|
*/
|
2003-09-25 19:19:44 +02:00
|
|
|
|
2012-09-29 20:44:12 +02:00
|
|
|
#include "ngspice/ngspice.h"
|
2003-09-25 19:19:44 +02:00
|
|
|
|
|
|
|
|
#include "general.h"
|
|
|
|
|
#include "numparam.h"
|
2011-12-11 19:05:00 +01:00
|
|
|
#include "ngspice/cpdefs.h"
|
|
|
|
|
#include "ngspice/ftedefs.h"
|
|
|
|
|
#include "ngspice/dvec.h"
|
2009-08-23 16:45:23 +02:00
|
|
|
#include "../frontend/variable.h"
|
2011-12-11 19:05:00 +01:00
|
|
|
#include "ngspice/compatmode.h"
|
2017-11-18 18:37:05 +01:00
|
|
|
#include "ngspice/stringskip.h"
|
2009-08-08 22:12:46 +02:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2008-11-29 21:21:56 +01:00
|
|
|
/* random numbers in /maths/misc/randnumb.c */
|
2016-08-05 16:03:56 +02:00
|
|
|
#include "ngspice/randnumb.h"
|
2009-08-23 16:45:23 +02:00
|
|
|
|
2003-09-25 19:19:44 +02:00
|
|
|
/************ keywords ************/
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
extern long dynsubst; /* see inpcom.c */
|
2008-11-26 21:31:50 +01:00
|
|
|
|
2013-11-09 14:45:26 +01:00
|
|
|
#define ACT_CHARACTS 25 /* actual string length to be inserted and replaced */
|
2010-01-29 23:33:59 +01:00
|
|
|
|
2013-10-07 18:21:02 +02:00
|
|
|
#define S_init 0
|
|
|
|
|
#define S_atom 1
|
|
|
|
|
#define S_binop 2
|
|
|
|
|
#define S_unop 3
|
|
|
|
|
#define S_stop 4
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2007-10-08 16:52:25 +02:00
|
|
|
static double
|
2013-11-01 20:15:21 +01:00
|
|
|
ternary_fcn(double conditional, double if_value, double else_value)
|
2007-10-08 16:52:25 +02:00
|
|
|
{
|
2013-11-01 20:15:21 +01:00
|
|
|
if (conditional != 0.0)
|
2011-02-13 20:19:02 +01:00
|
|
|
return if_value;
|
|
|
|
|
else
|
|
|
|
|
return else_value;
|
2007-10-08 16:52:25 +02:00
|
|
|
}
|
|
|
|
|
|
2008-11-26 21:31:50 +01:00
|
|
|
|
2007-12-09 22:07:14 +01:00
|
|
|
static double
|
2012-09-20 20:30:53 +02:00
|
|
|
agauss(double nominal_val, double abs_variation, double sigma)
|
2007-12-09 22:07:14 +01:00
|
|
|
{
|
2011-02-13 20:19:02 +01:00
|
|
|
double stdvar;
|
2012-09-20 20:30:53 +02:00
|
|
|
stdvar = abs_variation / sigma;
|
|
|
|
|
return (nominal_val + stdvar * gauss0());
|
2010-12-28 20:01:30 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2010-12-28 20:01:30 +01:00
|
|
|
static double
|
2012-09-20 20:30:53 +02:00
|
|
|
gauss(double nominal_val, double rel_variation, double sigma)
|
2010-12-28 20:01:30 +01:00
|
|
|
{
|
2011-02-13 20:19:02 +01:00
|
|
|
double stdvar;
|
2012-09-20 20:30:53 +02:00
|
|
|
stdvar = nominal_val * rel_variation / sigma;
|
2011-02-13 20:19:02 +01:00
|
|
|
return (nominal_val + stdvar * gauss0());
|
2010-12-28 20:01:30 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2010-12-28 20:01:30 +01:00
|
|
|
static double
|
2012-09-20 20:30:53 +02:00
|
|
|
unif(double nominal_val, double rel_variation)
|
2010-12-28 20:01:30 +01:00
|
|
|
{
|
2011-02-13 20:19:02 +01:00
|
|
|
return (nominal_val + nominal_val * rel_variation * drand());
|
2010-12-28 20:01:30 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2010-12-28 20:01:30 +01:00
|
|
|
static double
|
2012-09-20 20:30:53 +02:00
|
|
|
aunif(double nominal_val, double abs_variation)
|
2010-12-28 20:01:30 +01:00
|
|
|
{
|
2011-02-13 20:19:02 +01:00
|
|
|
return (nominal_val + abs_variation * drand());
|
2010-12-28 20:01:30 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2010-12-28 20:01:30 +01:00
|
|
|
static double
|
2012-09-20 20:30:53 +02:00
|
|
|
limit(double nominal_val, double abs_variation)
|
2010-12-28 20:01:30 +01:00
|
|
|
{
|
|
|
|
|
return (nominal_val + (drand() > 0 ? abs_variation : -1. * abs_variation));
|
2007-12-09 22:07:14 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2013-11-07 21:42:02 +01:00
|
|
|
static const char *fmathS = /* all math functions */
|
2014-09-12 19:06:43 +02:00
|
|
|
"SQR SQRT SIN COS EXP LN ARCTAN ABS POW PWR MAX MIN INT LOG LOG10 SINH COSH"
|
2013-11-07 21:42:02 +01:00
|
|
|
" TANH TERNARY_FCN AGAUSS SGN GAUSS UNIF AUNIF LIMIT CEIL FLOOR"
|
2013-12-16 21:28:40 +01:00
|
|
|
" ASIN ACOS ATAN ASINH ACOSH ATANH TAN NINT";
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2013-12-01 12:01:00 +01:00
|
|
|
enum {
|
2014-09-12 19:06:43 +02:00
|
|
|
XFU_SQR = 1, XFU_SQRT, XFU_SIN, XFU_COS, XFU_EXP, XFU_LN, XFU_ARCTAN, XFU_ABS, XFU_POW, XFU_PWR, XFU_MAX, XFU_MIN, XFU_INT, XFU_LOG, XFU_LOG10, XFU_SINH, XFU_COSH,
|
2013-12-01 12:01:00 +01:00
|
|
|
XFU_TANH, XFU_TERNARY_FCN, XFU_AGAUSS, XFU_SGN, XFU_GAUSS, XFU_UNIF, XFU_AUNIF, XFU_LIMIT, XFU_CEIL, XFU_FLOOR,
|
2013-12-16 21:28:40 +01:00
|
|
|
XFU_ASIN, XFU_ACOS, XFU_ATAN, XFU_ASINH, XFU_ACOSH, XFU_ATANH, XFU_TAN, XFU_NINT
|
2013-12-01 12:01:00 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2007-12-26 17:55:27 +01:00
|
|
|
static double
|
2012-09-20 20:30:53 +02:00
|
|
|
mathfunction(int f, double z, double x)
|
2007-12-09 22:07:14 +01:00
|
|
|
/* the list of built-in functions. Patch 'fmath', here and near line 888 to get more ...*/
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2011-02-13 20:19:02 +01:00
|
|
|
double y;
|
|
|
|
|
switch (f)
|
|
|
|
|
{
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_SQR:
|
2008-01-19 22:35:44 +01:00
|
|
|
y = x * x;
|
|
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_SQRT:
|
2012-09-20 20:30:53 +02:00
|
|
|
y = sqrt(x);
|
2008-01-19 22:35:44 +01:00
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_SIN:
|
2012-09-20 20:30:53 +02:00
|
|
|
y = sin(x);
|
2008-01-19 22:35:44 +01:00
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_COS:
|
2012-09-20 20:30:53 +02:00
|
|
|
y = cos(x);
|
2008-01-19 22:35:44 +01:00
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_EXP:
|
2012-09-20 20:30:53 +02:00
|
|
|
y = exp(x);
|
2008-01-19 22:35:44 +01:00
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_LN:
|
2013-11-24 14:16:24 +01:00
|
|
|
y = log(x);
|
2008-01-19 22:35:44 +01:00
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_ARCTAN:
|
2012-09-20 20:30:53 +02:00
|
|
|
y = atan(x);
|
2008-01-19 22:35:44 +01:00
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_ABS:
|
2012-09-20 20:30:53 +02:00
|
|
|
y = fabs(x);
|
2008-01-19 22:35:44 +01:00
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_POW:
|
2012-09-20 20:30:53 +02:00
|
|
|
y = pow(z, x);
|
2008-01-19 22:35:44 +01:00
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_PWR:
|
2013-10-04 21:09:04 +02:00
|
|
|
y = pow(fabs(z), x);
|
2008-01-19 22:35:44 +01:00
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_MAX:
|
2012-09-20 20:30:53 +02:00
|
|
|
y = MAX(x, z);
|
2008-01-19 22:35:44 +01:00
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_MIN:
|
2012-09-20 20:30:53 +02:00
|
|
|
y = MIN(x, z);
|
2008-01-19 22:35:44 +01:00
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_INT:
|
2012-09-20 20:30:53 +02:00
|
|
|
y = trunc(x);
|
2008-01-19 22:35:44 +01:00
|
|
|
break;
|
2013-12-16 21:28:40 +01:00
|
|
|
case XFU_NINT:
|
|
|
|
|
/* round to "nearest integer",
|
|
|
|
|
* round half-integers to the nearest even integer
|
|
|
|
|
* rely on default rounding mode of IEEE 754 to do so
|
|
|
|
|
*/
|
|
|
|
|
y = nearbyint(x);
|
|
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_LOG:
|
2012-09-20 20:30:53 +02:00
|
|
|
y = log(x);
|
2008-01-19 22:35:44 +01:00
|
|
|
break;
|
2014-09-12 19:06:43 +02:00
|
|
|
case XFU_LOG10:
|
|
|
|
|
y = log10(x);
|
|
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_SINH:
|
2012-09-20 20:30:53 +02:00
|
|
|
y = sinh(x);
|
2008-11-26 21:31:50 +01:00
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_COSH:
|
2012-09-20 20:30:53 +02:00
|
|
|
y = cosh(x);
|
2008-11-26 21:31:50 +01:00
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_TANH:
|
2013-10-04 21:09:04 +02:00
|
|
|
y = tanh(x);
|
2008-11-26 21:31:50 +01:00
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_SGN:
|
2012-09-20 20:30:53 +02:00
|
|
|
if (x > 0)
|
|
|
|
|
y = 1.;
|
|
|
|
|
else if (x == 0)
|
|
|
|
|
y = 0.;
|
|
|
|
|
else
|
|
|
|
|
y = -1.;
|
2010-03-07 16:59:08 +01:00
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_CEIL:
|
2012-09-20 20:30:53 +02:00
|
|
|
y = ceil(x);
|
2011-12-26 12:34:21 +01:00
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_FLOOR:
|
2012-09-20 20:30:53 +02:00
|
|
|
y = floor(x);
|
2011-12-26 12:34:21 +01:00
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_ASIN:
|
2013-10-04 21:09:04 +02:00
|
|
|
y = asin(x);
|
|
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_ACOS:
|
2013-10-04 21:09:04 +02:00
|
|
|
y = acos(x);
|
|
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_ATAN:
|
2013-10-04 21:09:04 +02:00
|
|
|
y = atan(x);
|
|
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_ASINH:
|
2013-10-04 21:09:04 +02:00
|
|
|
y = asinh(x);
|
|
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_ACOSH:
|
2013-10-04 21:09:04 +02:00
|
|
|
y = acosh(x);
|
|
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_ATANH:
|
2013-10-04 21:09:04 +02:00
|
|
|
y = atanh(x);
|
|
|
|
|
break;
|
2013-12-01 12:01:00 +01:00
|
|
|
case XFU_TAN:
|
2013-10-04 21:09:04 +02:00
|
|
|
y = tan(x);
|
|
|
|
|
break;
|
2007-12-26 17:55:27 +01:00
|
|
|
default:
|
2008-01-19 22:35:44 +01:00
|
|
|
y = x;
|
|
|
|
|
break;
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2011-02-13 20:19:02 +01:00
|
|
|
return y;
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
2003-09-25 19:19:44 +02:00
|
|
|
|
2011-02-19 15:45:42 +01:00
|
|
|
|
|
|
|
|
#ifdef __GNUC__
|
2014-08-10 20:21:39 +02:00
|
|
|
static bool message(dico_t *dico, const char *fmt, ...)
|
2011-02-19 15:45:42 +01:00
|
|
|
__attribute__ ((format (__printf__, 2, 3)));
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
2010-11-02 18:55:32 +01:00
|
|
|
static bool
|
2014-08-10 20:21:39 +02:00
|
|
|
message(dico_t *dico, const char *fmt, ...)
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2011-02-19 15:45:42 +01:00
|
|
|
va_list ap;
|
|
|
|
|
|
2014-08-10 20:21:39 +02:00
|
|
|
if (dico->srcline >= 0)
|
2011-02-19 15:45:42 +01:00
|
|
|
fprintf
|
2012-09-20 20:30:53 +02:00
|
|
|
(stderr,
|
|
|
|
|
"Original line no.: %d, new internal line no.: %d:\n",
|
2014-08-10 20:21:39 +02:00
|
|
|
dico->oldline, dico->srcline);
|
2011-02-19 15:45:42 +01:00
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
|
vfprintf(stderr, fmt, ap);
|
|
|
|
|
va_end(ap);
|
|
|
|
|
|
2014-08-10 20:21:39 +02:00
|
|
|
dico->errcount++;
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
return 1; /* error! */
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
|
|
|
|
|
2011-02-19 15:45:42 +01:00
|
|
|
|
2003-09-25 19:19:44 +02:00
|
|
|
/************ the input text symbol table (dictionary) *************/
|
|
|
|
|
|
2007-12-26 17:55:27 +01:00
|
|
|
void
|
2014-08-10 20:21:34 +02:00
|
|
|
initdico(dico_t *dico)
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2014-08-09 20:51:02 +02:00
|
|
|
int asize = 10; /* default allocation depth of the synbol stack */
|
2011-02-13 20:19:02 +01:00
|
|
|
COMPATMODE_T compat_mode;
|
|
|
|
|
|
|
|
|
|
dico->srcline = -1;
|
|
|
|
|
dico->errcount = 0;
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
spice_dstring_init(&(dico->lookup_buf));
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2014-08-09 20:49:25 +02:00
|
|
|
dico->symbols = TMALLOC(NGHASHPTR, asize);
|
2012-09-20 20:30:53 +02:00
|
|
|
dico->inst_name = TMALLOC(char*, asize);
|
2014-08-09 20:51:02 +02:00
|
|
|
dico->max_stack_depth = asize;
|
2014-08-09 20:48:56 +02:00
|
|
|
dico->stack_depth = 0; /* top of the stack */
|
|
|
|
|
|
2014-08-09 20:49:25 +02:00
|
|
|
dico->symbols[0] = nghash_init(NGHASH_MIN_SIZE);
|
|
|
|
|
nghash_unique(dico->symbols[0], TRUE); /* no rewrite of global symbols */
|
2014-08-09 20:48:56 +02:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
dico->inst_symbols = NULL; /* instance qualified are lazily allocated */
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
compat_mode = ngspice_compat_mode();
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
if (compat_mode == COMPATMODE_HS)
|
|
|
|
|
dico->hs_compatibility = 1;
|
2011-02-13 20:19:02 +01:00
|
|
|
else
|
2012-09-20 20:30:53 +02:00
|
|
|
dico->hs_compatibility = 0;
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
2003-09-25 19:19:44 +02:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
|
|
|
|
void
|
2014-08-10 20:21:43 +02:00
|
|
|
dico_free_entry(entry_t *entry)
|
2010-02-25 22:43:03 +01:00
|
|
|
{
|
2014-08-10 20:21:43 +02:00
|
|
|
if (entry->symbol)
|
|
|
|
|
txfree(entry->symbol);
|
2011-02-19 16:04:09 +01:00
|
|
|
|
2014-08-10 20:21:43 +02:00
|
|
|
txfree(entry);
|
2012-09-20 20:30:53 +02:00
|
|
|
}
|
2010-02-25 22:43:03 +01:00
|
|
|
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
/* local semantics for parameters inside a subckt */
|
|
|
|
|
/* arguments as wll as .param expressions */
|
2003-09-25 19:19:44 +02:00
|
|
|
/* to do: scope semantics ?
|
|
|
|
|
"params:" and all new symbols should have local scope inside subcircuits.
|
|
|
|
|
redefinition of old symbols gives a warning message.
|
|
|
|
|
*/
|
|
|
|
|
|
2009-03-15 16:08:04 +01:00
|
|
|
static void
|
2016-04-27 18:41:38 +02:00
|
|
|
dicostack_push(dico_t *dico, char *inst_name)
|
2014-08-09 19:38:18 +02:00
|
|
|
/* push operation for nested subcircuit locals */
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2014-08-09 19:38:29 +02:00
|
|
|
dico->stack_depth++;
|
2014-08-09 20:51:02 +02:00
|
|
|
|
|
|
|
|
if (dico->stack_depth >= dico->max_stack_depth) {
|
|
|
|
|
int asize = (dico->max_stack_depth *= 2);
|
2014-08-09 20:49:25 +02:00
|
|
|
dico->symbols = TREALLOC(NGHASHPTR, dico->symbols, asize);
|
2014-08-09 19:38:29 +02:00
|
|
|
dico->inst_name = TREALLOC(char*, dico->inst_name, asize);
|
|
|
|
|
}
|
2014-08-09 20:51:02 +02:00
|
|
|
|
2014-08-09 19:38:29 +02:00
|
|
|
/* lazy allocation - don't allocate space if we can help it */
|
2014-08-09 20:49:25 +02:00
|
|
|
dico->symbols[dico->stack_depth] = NULL;
|
2016-04-27 18:41:38 +02:00
|
|
|
dico->inst_name[dico->stack_depth] = inst_name;
|
2014-08-09 19:38:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2014-08-10 20:21:34 +02:00
|
|
|
dicostack_pop(dico_t *dico)
|
2014-08-09 19:38:18 +02:00
|
|
|
/* pop operation for nested subcircuit locals */
|
|
|
|
|
{
|
|
|
|
|
char *inst_name; /* name of subcircuit instance */
|
|
|
|
|
char *param_p; /* qualified inst parameter name */
|
2014-08-10 20:21:43 +02:00
|
|
|
entry_t *entry; /* current entry */
|
2014-08-09 19:38:18 +02:00
|
|
|
NGHASHPTR htable_p; /* current hash table */
|
|
|
|
|
NGHASHITER iter; /* hash iterator - thread safe */
|
|
|
|
|
|
2014-08-09 19:38:29 +02:00
|
|
|
if (dico->stack_depth <= 0) {
|
|
|
|
|
message(dico, " Subckt Stack underflow.\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* -----------------------------------------------------------------
|
|
|
|
|
* Keep instance parameters around by transferring current local
|
|
|
|
|
* scope variables to an instance qualified hash table.
|
|
|
|
|
* ----------------------------------------------------------------- */
|
|
|
|
|
inst_name = dico->inst_name[dico->stack_depth];
|
2014-08-09 20:49:25 +02:00
|
|
|
htable_p = dico->symbols[dico->stack_depth];
|
2014-08-09 19:38:29 +02:00
|
|
|
if (htable_p) {
|
|
|
|
|
SPICE_DSTRING param_name; /* build a qualified name */
|
|
|
|
|
spice_dstring_init(¶m_name);
|
|
|
|
|
|
|
|
|
|
NGHASH_FIRST(&iter);
|
2014-08-10 20:21:43 +02:00
|
|
|
for (entry = (entry_t *) nghash_enumerateRE(htable_p, &iter);
|
|
|
|
|
entry;
|
|
|
|
|
entry = (entry_t *) nghash_enumerateRE(htable_p, &iter))
|
2014-08-09 19:38:29 +02:00
|
|
|
{
|
|
|
|
|
spice_dstring_reinit(¶m_name);
|
|
|
|
|
param_p = spice_dstring_print(¶m_name, "%s.%s",
|
2014-08-10 20:21:43 +02:00
|
|
|
inst_name, entry->symbol);
|
|
|
|
|
nupa_add_inst_param(param_p, entry->vl);
|
|
|
|
|
dico_free_entry(entry);
|
2014-08-09 19:38:25 +02:00
|
|
|
}
|
2014-08-09 19:38:29 +02:00
|
|
|
nghash_free(htable_p, NULL, NULL);
|
|
|
|
|
spice_dstring_free(¶m_name);
|
|
|
|
|
}
|
|
|
|
|
tfree(inst_name);
|
2014-08-09 19:38:25 +02:00
|
|
|
|
2014-08-09 19:38:29 +02:00
|
|
|
dico->inst_name[dico->stack_depth] = NULL;
|
2014-08-09 20:49:25 +02:00
|
|
|
dico->symbols[dico->stack_depth] = NULL;
|
2014-08-09 19:38:29 +02:00
|
|
|
dico->stack_depth--;
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2007-12-26 17:55:27 +01:00
|
|
|
int
|
2014-08-10 20:21:34 +02:00
|
|
|
donedico(dico_t *dico)
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2014-08-09 20:49:25 +02:00
|
|
|
int sze = nghash_get_size(dico->symbols[0]);
|
2011-02-13 20:19:02 +01:00
|
|
|
return sze;
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
2003-09-25 19:19:44 +02:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2010-03-25 23:44:37 +01:00
|
|
|
/* -----------------------------------------------------------------
|
|
|
|
|
* Now entryb works on the given hash table hierarchy. First
|
|
|
|
|
* look thru the stack of local symbols and then look at the global
|
|
|
|
|
* symbols in that order.
|
|
|
|
|
* ----------------------------------------------------------------- */
|
2016-04-29 17:51:50 +02:00
|
|
|
entry_t *
|
2014-08-10 20:21:39 +02:00
|
|
|
entrynb(dico_t *dico, char *s)
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2012-09-20 20:30:53 +02:00
|
|
|
int depth; /* stack depth */
|
2014-08-10 20:21:43 +02:00
|
|
|
entry_t *entry; /* search hash table */
|
2012-09-20 20:30:53 +02:00
|
|
|
NGHASHPTR htable_p; /* hash table */
|
2011-02-13 20:19:02 +01:00
|
|
|
|
|
|
|
|
/* look at the current scope and then backup the stack */
|
2014-08-10 20:21:39 +02:00
|
|
|
for (depth = dico->stack_depth; depth >= 0; depth--) {
|
|
|
|
|
htable_p = dico->symbols[depth];
|
2012-09-20 20:30:53 +02:00
|
|
|
if (htable_p) {
|
2014-08-10 20:21:43 +02:00
|
|
|
entry = (entry_t *) nghash_find(htable_p, s);
|
|
|
|
|
if (entry)
|
|
|
|
|
return (entry);
|
2011-02-13 20:19:02 +01:00
|
|
|
}
|
|
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2014-08-09 20:49:46 +02:00
|
|
|
return NULL;
|
2012-09-20 20:30:53 +02:00
|
|
|
}
|
2007-12-26 17:55:27 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
static double
|
2015-10-11 14:02:45 +02:00
|
|
|
fetchnumentry(dico_t *dico, char *s, bool *perr)
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2015-10-11 14:02:45 +02:00
|
|
|
entry_t *entry = entrynb(dico, s);
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2017-10-31 10:45:48 +01:00
|
|
|
if (entry && (entry->tp == NUPA_REAL))
|
2015-10-11 14:02:45 +02:00
|
|
|
return entry->vl;
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2015-10-11 14:02:45 +02:00
|
|
|
*perr = message(dico, "Undefined number [%s]\n", s);
|
|
|
|
|
return 0.0;
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
2003-09-25 19:19:44 +02:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2003-09-25 19:19:44 +02:00
|
|
|
/******* writing dictionary entries *********/
|
|
|
|
|
|
2014-08-10 20:21:29 +02:00
|
|
|
entry_t *
|
2014-08-10 20:21:39 +02:00
|
|
|
attrib(dico_t *dico, NGHASHPTR htable_p, char *t, char op)
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2011-02-13 20:19:02 +01:00
|
|
|
/* seek or attribute dico entry number for string t.
|
|
|
|
|
Option op='N' : force a new entry, if tos>level and old is valid.
|
|
|
|
|
*/
|
2014-08-10 20:21:43 +02:00
|
|
|
entry_t *entry; /* symbol table entry */
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2014-08-10 20:21:43 +02:00
|
|
|
entry = (entry_t *) nghash_find(htable_p, t);
|
|
|
|
|
if (entry && (op == 'N') &&
|
2017-10-31 10:45:48 +01:00
|
|
|
(entry->level < dico->stack_depth) && (entry->tp != NUPA_UNKNOWN))
|
2011-02-13 20:19:02 +01:00
|
|
|
{
|
2014-08-10 20:21:43 +02:00
|
|
|
entry = NULL;
|
2011-02-13 20:19:02 +01:00
|
|
|
}
|
|
|
|
|
|
2014-08-10 20:21:43 +02:00
|
|
|
if (!entry) {
|
|
|
|
|
entry = TMALLOC(entry_t, 1);
|
|
|
|
|
entry->symbol = strdup(t);
|
2017-10-31 10:45:48 +01:00
|
|
|
entry->tp = NUPA_UNKNOWN; /* signal Unknown */
|
2014-08-10 20:21:43 +02:00
|
|
|
entry->level = dico->stack_depth;
|
|
|
|
|
nghash_insert(htable_p, t, entry);
|
2011-02-13 20:19:02 +01:00
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2014-08-10 20:21:43 +02:00
|
|
|
return entry;
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2013-08-21 20:52:05 +02:00
|
|
|
/* user defined delete function:
|
|
|
|
|
* free the dictionary entries malloc'ed above
|
|
|
|
|
* will be called by nghash_free() in nupa_del_dicoS()
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void
|
2014-08-10 20:21:43 +02:00
|
|
|
del_attrib(void *entry_p)
|
2013-08-21 20:52:05 +02:00
|
|
|
{
|
2014-08-10 20:21:43 +02:00
|
|
|
entry_t *entry = (entry_t*) entry_p;
|
|
|
|
|
if(entry) {
|
|
|
|
|
tfree(entry->symbol);
|
|
|
|
|
tfree(entry);
|
2013-08-21 20:52:05 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-11-02 18:55:32 +01:00
|
|
|
static bool
|
2014-08-10 20:21:34 +02:00
|
|
|
nupa_define(dico_t *dico,
|
2012-09-20 20:30:53 +02:00
|
|
|
char *t, /* identifier to define */
|
|
|
|
|
char op, /* option */
|
2017-10-31 10:45:48 +01:00
|
|
|
nupa_type tpe, /* type marker */
|
2012-09-20 20:30:53 +02:00
|
|
|
double z, /* float value if any */
|
|
|
|
|
int w, /* integer value if any */
|
|
|
|
|
char *base) /* string pointer if any */
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2011-02-13 20:19:02 +01:00
|
|
|
/*define t as real or integer,
|
|
|
|
|
opcode= 'N' impose a new item under local conditions.
|
|
|
|
|
check for pointers, too, in full macrolanguage version:
|
2012-09-20 20:30:53 +02:00
|
|
|
Call with 'N','P',0.0, ksymbol ... for VAR parameter passing.
|
2011-02-13 20:19:02 +01:00
|
|
|
Overwrite warning, beware: During 1st pass (macro definition),
|
2012-09-20 20:30:53 +02:00
|
|
|
we already make symbol entries which are dummy globals !
|
|
|
|
|
we mark each id with its subckt level, and warn if write at higher one.
|
2011-02-13 20:19:02 +01:00
|
|
|
*/
|
2017-10-31 10:45:48 +01:00
|
|
|
nupa_type c;
|
2017-10-25 21:37:36 +02:00
|
|
|
bool warn;
|
2014-08-10 20:21:43 +02:00
|
|
|
entry_t *entry; /* spice table entry */
|
2012-09-20 20:30:53 +02:00
|
|
|
NGHASHPTR htable_p; /* hash table */
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2014-08-09 20:49:46 +02:00
|
|
|
/* can't be lazy anymore */
|
|
|
|
|
if (!(dico->symbols[dico->stack_depth]))
|
|
|
|
|
dico->symbols[dico->stack_depth] = nghash_init(NGHASH_MIN_SIZE);
|
2011-02-19 16:04:09 +01:00
|
|
|
|
2014-08-09 20:49:46 +02:00
|
|
|
htable_p = dico->symbols[dico->stack_depth];
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2014-08-10 20:21:43 +02:00
|
|
|
entry = attrib(dico, htable_p, t, op);
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2017-10-25 21:37:36 +02:00
|
|
|
if (!entry)
|
|
|
|
|
return message(dico, " Symbol table overflow\n");
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2017-10-25 22:08:53 +02:00
|
|
|
c = entry->tp;
|
2017-10-25 21:33:13 +02:00
|
|
|
|
2017-10-31 10:45:48 +01:00
|
|
|
if ((c == NUPA_REAL) || (c == NUPA_STRING) || (c == NUPA_UNKNOWN)) {
|
2017-10-25 21:33:13 +02:00
|
|
|
|
|
|
|
|
entry->vl = z;
|
|
|
|
|
entry->tp = tpe;
|
|
|
|
|
entry->ivl = w;
|
|
|
|
|
entry->sbbase = base;
|
|
|
|
|
/* if ((c != '?') && (i <= dico->stack[dico->tos])) { */
|
2017-10-31 10:45:48 +01:00
|
|
|
if (c == NUPA_UNKNOWN)
|
2017-10-25 21:33:13 +02:00
|
|
|
entry->level = dico->stack_depth; /* promote! */
|
|
|
|
|
|
|
|
|
|
/* warn about re-write to a global scope! */
|
|
|
|
|
if (entry->level < dico->stack_depth)
|
|
|
|
|
warn = message(dico, "%s:%d overwritten.\n", t, entry->level);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
/* suppress error message, resulting from multiple definition of
|
|
|
|
|
symbols (devices) in .model lines with same name, but in different subcircuits.
|
|
|
|
|
Subcircuit expansion is o.k., we have to deal with this numparam
|
|
|
|
|
behaviour later. (H. Vogt 090426)
|
|
|
|
|
*/
|
|
|
|
|
if (0)
|
|
|
|
|
message(dico, "%s: cannot redefine\n", t);
|
|
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2017-10-25 21:37:36 +02:00
|
|
|
return 0;
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
2003-09-25 19:19:44 +02:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2010-11-02 18:55:32 +01:00
|
|
|
bool
|
2017-10-31 10:45:48 +01:00
|
|
|
defsubckt(dico_t *dico, struct card *card, nupa_type categ)
|
2008-01-19 22:35:44 +01:00
|
|
|
/* called on 1st pass of spice source code,
|
|
|
|
|
to enter subcircuit (categ=U) and model (categ=O) names
|
2003-09-25 19:19:44 +02:00
|
|
|
*/
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2016-05-08 19:02:34 +02:00
|
|
|
const char *s = card->line;
|
2017-10-31 20:02:37 +01:00
|
|
|
int w = card->linenum;
|
|
|
|
|
|
2011-02-13 20:19:02 +01:00
|
|
|
bool err;
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2016-05-08 19:03:41 +02:00
|
|
|
const char *s_end;
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2016-05-08 19:02:34 +02:00
|
|
|
while (*s && (*s != '.'))
|
|
|
|
|
s++; /* skip 1st dotword */
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2016-05-08 19:02:34 +02:00
|
|
|
while (*s && (*s > ' '))
|
|
|
|
|
s++;
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2016-05-08 19:02:34 +02:00
|
|
|
while (*s && (*s <= ' '))
|
|
|
|
|
s++; /* skip blank */
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2016-05-08 19:03:41 +02:00
|
|
|
s_end = s;
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2016-05-08 19:03:41 +02:00
|
|
|
while (*s_end && (*s_end > ' '))
|
|
|
|
|
s_end++;
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2016-05-08 19:03:41 +02:00
|
|
|
if (s_end > s) {
|
2012-09-20 20:30:53 +02:00
|
|
|
SPICE_DSTRING ustr; /* temp user string */
|
|
|
|
|
spice_dstring_init(&ustr);
|
2016-05-08 19:03:41 +02:00
|
|
|
pscopy_up(&ustr, s, 0, (int) (s_end - s));
|
2014-08-10 20:21:48 +02:00
|
|
|
err = nupa_define(dico, spice_dstring_value(&ustr), ' ', categ, 0.0, w, NULL);
|
2012-09-20 20:30:53 +02:00
|
|
|
spice_dstring_free(&ustr);
|
|
|
|
|
} else {
|
2014-05-18 20:39:17 +02:00
|
|
|
err = message(dico, "Subcircuit or Model without name.\n");
|
2011-02-13 20:19:02 +01:00
|
|
|
}
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2011-02-13 20:19:02 +01:00
|
|
|
return err;
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2007-12-26 17:55:27 +01:00
|
|
|
int
|
2016-05-08 19:08:15 +02:00
|
|
|
findsubckt(dico_t *dico, const char * const s)
|
2003-09-25 19:19:44 +02:00
|
|
|
/* input: s is a subcircuit invocation line.
|
2016-04-27 18:38:19 +02:00
|
|
|
returns 0 if not found, else the stored definition line number value */
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2017-11-18 19:05:51 +01:00
|
|
|
const char *name_e = skip_back_ws(s + strlen(s), s);
|
|
|
|
|
const char *name_b = skip_back_non_ws(name_e, s);
|
2016-05-08 19:10:49 +02:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
SPICE_DSTRING ustr; /* u= subckt name is last token in string s */
|
2017-11-18 17:51:49 +01:00
|
|
|
entry_t *entry; /* symbol table entry */
|
2012-09-20 20:30:53 +02:00
|
|
|
|
|
|
|
|
spice_dstring_init(&ustr);
|
|
|
|
|
|
2017-11-18 18:28:28 +01:00
|
|
|
pscopy_up(&ustr, name_b, 0, (int) (name_e - name_b));
|
2014-08-10 20:21:43 +02:00
|
|
|
entry = entrynb(dico, spice_dstring_value(&ustr));
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2017-10-31 10:45:48 +01:00
|
|
|
if (entry && (entry->tp == NUPA_SUBCKT)) {
|
2017-11-18 17:51:49 +01:00
|
|
|
return entry->ivl;
|
2012-09-20 20:30:53 +02:00
|
|
|
} else {
|
2014-05-18 20:39:17 +02:00
|
|
|
message(dico, "Cannot find subcircuit.\n");
|
2017-11-18 17:51:49 +01:00
|
|
|
return 0;
|
2011-02-13 20:19:02 +01:00
|
|
|
}
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2003-09-25 19:19:44 +02:00
|
|
|
/************ input scanner stuff **************/
|
|
|
|
|
|
2007-12-26 17:55:27 +01:00
|
|
|
static unsigned char
|
2015-10-11 14:39:05 +02:00
|
|
|
keyword(const char *keys, const char *s, const char *s_end)
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2015-10-11 11:56:35 +02:00
|
|
|
/* return 0 if s not found in list keys, else the ordinal number */
|
|
|
|
|
unsigned char j = 1;
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2015-10-11 11:56:35 +02:00
|
|
|
if (!*s)
|
|
|
|
|
return 0;
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2015-10-11 11:56:35 +02:00
|
|
|
for (;;) {
|
|
|
|
|
const char *p = s;
|
2016-04-30 20:29:13 +02:00
|
|
|
while ((p < s_end) && (toupper_c(*p) == *keys))
|
2015-10-11 11:56:35 +02:00
|
|
|
p++, keys++;
|
2015-10-11 14:39:05 +02:00
|
|
|
if ((p >= s_end) && (*keys <= ' '))
|
2015-10-11 11:56:35 +02:00
|
|
|
return j;
|
|
|
|
|
keys = strchr(keys, ' ');
|
|
|
|
|
if (!keys)
|
|
|
|
|
return 0;
|
|
|
|
|
keys++;
|
2011-02-13 20:19:02 +01:00
|
|
|
j++;
|
2015-10-11 11:56:35 +02:00
|
|
|
}
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2007-12-26 17:55:27 +01:00
|
|
|
static double
|
2013-10-08 18:57:37 +02:00
|
|
|
parseunit(const char *s)
|
2003-09-25 19:19:44 +02:00
|
|
|
/* the Spice suffixes */
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2016-03-08 21:24:40 +01:00
|
|
|
switch (toupper_c(s[0]))
|
2011-02-19 15:37:40 +01:00
|
|
|
{
|
2014-01-09 18:36:42 +01:00
|
|
|
case 'T': return 1e12;
|
2012-09-20 20:30:53 +02:00
|
|
|
case 'G': return 1e9;
|
|
|
|
|
case 'K': return 1e3;
|
|
|
|
|
case 'M': return ci_prefix("MEG", s) ? 1e6 : 1e-3;
|
|
|
|
|
case 'U': return 1e-6;
|
|
|
|
|
case 'N': return 1e-9;
|
|
|
|
|
case 'P': return 1e-12;
|
|
|
|
|
case 'F': return 1e-15;
|
|
|
|
|
default : return 1;
|
2011-02-19 15:37:40 +01:00
|
|
|
}
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2013-10-08 18:38:43 +02:00
|
|
|
static const char *
|
2015-10-11 14:39:05 +02:00
|
|
|
fetchid(const char *s, const char *s_end)
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2015-11-07 19:11:54 +01:00
|
|
|
for (; s < s_end; s++)
|
|
|
|
|
if (!(alfanum(*s) || *s == '.'))
|
2015-10-10 17:11:04 +02:00
|
|
|
return s;
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2015-10-10 16:33:10 +02:00
|
|
|
return s;
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2007-12-26 17:55:27 +01:00
|
|
|
static double
|
2014-08-10 20:21:34 +02:00
|
|
|
fetchnumber(dico_t *dico, const char **pi, bool *perror)
|
2003-09-25 19:19:44 +02:00
|
|
|
/* parse a Spice number in string s */
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2011-02-13 20:19:02 +01:00
|
|
|
double u;
|
2011-02-19 15:37:40 +01:00
|
|
|
int n = 0;
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2013-10-08 18:38:43 +02:00
|
|
|
const char *s = *pi;
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
if (1 != sscanf(s, "%lG%n", &u, &n)) {
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2014-05-18 20:39:17 +02:00
|
|
|
*perror = message(dico, "Number format error: \"%s\"\n", s);
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2011-02-19 15:37:40 +01:00
|
|
|
return 0.0; /* FIXME return NaN */
|
2007-12-26 17:55:27 +01:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
u *= parseunit(s + n);
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2011-02-19 15:37:40 +01:00
|
|
|
/* swallow unit
|
|
|
|
|
* FIXME `100MegBaz42' should emit an error message
|
|
|
|
|
* FIXME should we allow whitespace ? `100 MEG' ?
|
|
|
|
|
*/
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2011-02-19 15:37:40 +01:00
|
|
|
while (s[n] && alfa(s[n]))
|
|
|
|
|
n++;
|
|
|
|
|
|
2013-10-08 19:06:12 +02:00
|
|
|
*pi += n;
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2011-02-13 20:19:02 +01:00
|
|
|
return u;
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2007-12-26 17:55:27 +01:00
|
|
|
static char
|
2014-08-10 20:21:34 +02:00
|
|
|
fetchoperator(dico_t *dico,
|
2013-10-08 18:38:43 +02:00
|
|
|
const char *s_end,
|
|
|
|
|
const char **pi,
|
2012-09-20 20:30:53 +02:00
|
|
|
unsigned char *pstate, unsigned char *plevel,
|
|
|
|
|
bool *perror)
|
2003-09-25 19:19:44 +02:00
|
|
|
/* grab an operator from string s and advance scan index pi.
|
|
|
|
|
each operator has: one-char alias, precedence level, new interpreter state.
|
|
|
|
|
*/
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2013-10-08 18:38:43 +02:00
|
|
|
const char *iptr = *pi;
|
2011-02-13 20:19:02 +01:00
|
|
|
unsigned char state = *pstate;
|
|
|
|
|
unsigned char level = *plevel;
|
|
|
|
|
bool error = *perror;
|
|
|
|
|
char c, d;
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2013-10-08 18:38:43 +02:00
|
|
|
c = *iptr++;
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2013-10-08 18:38:43 +02:00
|
|
|
d = *iptr;
|
|
|
|
|
if (iptr >= s_end)
|
2011-02-19 15:56:40 +01:00
|
|
|
d = '\0';
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
if ((c == '!') && (d == '=')) {
|
2011-02-13 20:19:02 +01:00
|
|
|
c = '#';
|
2013-10-08 18:38:43 +02:00
|
|
|
iptr++;
|
2012-09-20 20:30:53 +02:00
|
|
|
} else if ((c == '<') && (d == '>')) {
|
2011-02-13 20:19:02 +01:00
|
|
|
c = '#';
|
2013-10-08 18:38:43 +02:00
|
|
|
iptr++;
|
2012-09-20 20:30:53 +02:00
|
|
|
} else if ((c == '<') && (d == '=')) {
|
2011-02-13 20:19:02 +01:00
|
|
|
c = 'L';
|
2013-10-08 18:38:43 +02:00
|
|
|
iptr++;
|
2012-09-20 20:30:53 +02:00
|
|
|
} else if ((c == '>') && (d == '=')) {
|
2011-02-13 20:19:02 +01:00
|
|
|
c = 'G';
|
2013-10-08 18:38:43 +02:00
|
|
|
iptr++;
|
2012-09-20 20:30:53 +02:00
|
|
|
} else if ((c == '*') && (d == '*')) {
|
2011-02-13 20:19:02 +01:00
|
|
|
c = '^';
|
2013-10-08 18:38:43 +02:00
|
|
|
iptr++;
|
2012-09-20 20:30:53 +02:00
|
|
|
} else if ((c == '=') && (d == '=')) {
|
2013-10-08 18:38:43 +02:00
|
|
|
iptr++;
|
2012-09-20 20:30:53 +02:00
|
|
|
} else if ((c == '&') && (d == '&')) {
|
2013-11-01 20:15:21 +01:00
|
|
|
c = 'A';
|
2013-10-08 18:38:43 +02:00
|
|
|
iptr++;
|
2012-09-20 20:30:53 +02:00
|
|
|
} else if ((c == '|') && (d == '|')) {
|
2013-11-01 20:15:21 +01:00
|
|
|
c = 'O';
|
2013-10-08 18:38:43 +02:00
|
|
|
iptr++;
|
2013-11-01 20:15:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((c == '+') || (c == '-')) {
|
2013-10-07 18:21:02 +02:00
|
|
|
state = S_binop; /* pending operator */
|
2011-02-13 20:19:02 +01:00
|
|
|
level = 4;
|
2012-09-20 20:30:53 +02:00
|
|
|
} else if ((c == '*') || (c == '/') || (c == '%') || (c == '\\')) {
|
2013-10-07 18:21:02 +02:00
|
|
|
state = S_binop;
|
2011-02-13 20:19:02 +01:00
|
|
|
level = 3;
|
2012-09-20 20:30:53 +02:00
|
|
|
} else if (c == '^') {
|
2013-10-07 18:21:02 +02:00
|
|
|
state = S_binop;
|
2011-02-13 20:19:02 +01:00
|
|
|
level = 2;
|
2016-04-30 12:20:35 +02:00
|
|
|
} else if (strchr("=<>#GL", c)) {
|
2013-10-07 18:21:02 +02:00
|
|
|
state = S_binop;
|
2011-02-13 20:19:02 +01:00
|
|
|
level = 5;
|
2013-11-07 21:42:02 +01:00
|
|
|
} else if (c == 'A') {
|
2013-10-07 18:21:02 +02:00
|
|
|
state = S_binop;
|
2011-02-13 20:19:02 +01:00
|
|
|
level = 6;
|
2013-11-07 21:42:02 +01:00
|
|
|
} else if (c == 'O') {
|
2013-10-07 18:21:02 +02:00
|
|
|
state = S_binop;
|
2011-02-13 20:19:02 +01:00
|
|
|
level = 7;
|
2012-09-20 20:30:53 +02:00
|
|
|
} else if (c == '!') {
|
2013-10-07 18:21:02 +02:00
|
|
|
state = S_unop;
|
2013-10-15 19:20:52 +02:00
|
|
|
} else if (c == '?') {
|
|
|
|
|
state = S_binop;
|
|
|
|
|
level = 9;
|
|
|
|
|
} else if (c == ':') {
|
|
|
|
|
state = S_binop;
|
|
|
|
|
level = 8;
|
2012-09-20 20:30:53 +02:00
|
|
|
} else {
|
2013-10-07 18:21:02 +02:00
|
|
|
state = S_init;
|
2011-02-13 20:19:02 +01:00
|
|
|
if (c > ' ')
|
2014-05-18 20:39:17 +02:00
|
|
|
error = message(dico, "Syntax error: letter [%c]\n", c);
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2013-10-08 18:38:43 +02:00
|
|
|
*pi = iptr;
|
2011-02-13 20:19:02 +01:00
|
|
|
*pstate = state;
|
|
|
|
|
*plevel = level;
|
|
|
|
|
*perror = error;
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2011-02-13 20:19:02 +01:00
|
|
|
return c;
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
2003-09-25 19:19:44 +02:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2007-12-26 17:55:27 +01:00
|
|
|
static double
|
2012-09-20 20:30:53 +02:00
|
|
|
operate(char op, double x, double y)
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2011-02-13 20:19:02 +01:00
|
|
|
/* execute operator op on a pair of reals */
|
|
|
|
|
/* bug: x:=x op y or simply x:=y for empty op? No error signalling! */
|
|
|
|
|
double u = 1.0;
|
|
|
|
|
double z = 0.0;
|
|
|
|
|
double t;
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2011-02-13 20:19:02 +01:00
|
|
|
switch (op)
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
|
|
|
|
case ' ':
|
2012-09-20 20:30:53 +02:00
|
|
|
x = y; /* problem here: do type conversions ?! */
|
2011-02-13 20:19:02 +01:00
|
|
|
break;
|
2007-12-26 17:55:27 +01:00
|
|
|
case '+':
|
2011-02-13 20:19:02 +01:00
|
|
|
x = x + y;
|
|
|
|
|
break;
|
2007-12-26 17:55:27 +01:00
|
|
|
case '-':
|
2011-02-13 20:19:02 +01:00
|
|
|
x = x - y;
|
|
|
|
|
break;
|
2007-12-26 17:55:27 +01:00
|
|
|
case '*':
|
2011-02-13 20:19:02 +01:00
|
|
|
x = x * y;
|
|
|
|
|
break;
|
2007-12-26 17:55:27 +01:00
|
|
|
case '/':
|
2008-01-19 22:35:44 +01:00
|
|
|
x = x / y;
|
2011-02-13 20:19:02 +01:00
|
|
|
break;
|
2012-09-20 20:30:53 +02:00
|
|
|
case '^': /* power */
|
2013-10-08 18:38:43 +02:00
|
|
|
x = pow(fabs(x), y);
|
2011-02-13 20:19:02 +01:00
|
|
|
break;
|
2013-11-01 20:15:21 +01:00
|
|
|
case 'A': /* && */
|
|
|
|
|
x = ((x != 0.0) && (y != 0.0)) ? 1.0 : 0.0;
|
|
|
|
|
break;
|
|
|
|
|
case 'O': /* || */
|
|
|
|
|
x = ((x != 0.0) || (y != 0.0)) ? 1.0 : 0.0;
|
|
|
|
|
break;
|
2007-12-26 17:55:27 +01:00
|
|
|
case '=':
|
2011-02-13 20:19:02 +01:00
|
|
|
if (x == y)
|
|
|
|
|
x = u;
|
|
|
|
|
else
|
|
|
|
|
x = z;
|
|
|
|
|
break;
|
2012-09-20 20:30:53 +02:00
|
|
|
case '#': /* <> */
|
2011-02-13 20:19:02 +01:00
|
|
|
if (x != y)
|
|
|
|
|
x = u;
|
|
|
|
|
else
|
|
|
|
|
x = z;
|
|
|
|
|
break;
|
2007-12-26 17:55:27 +01:00
|
|
|
case '>':
|
2011-02-13 20:19:02 +01:00
|
|
|
if (x > y)
|
|
|
|
|
x = u;
|
|
|
|
|
else
|
|
|
|
|
x = z;
|
|
|
|
|
break;
|
2007-12-26 17:55:27 +01:00
|
|
|
case '<':
|
2011-02-13 20:19:02 +01:00
|
|
|
if (x < y)
|
|
|
|
|
x = u;
|
|
|
|
|
else
|
|
|
|
|
x = z;
|
|
|
|
|
break;
|
2012-09-20 20:30:53 +02:00
|
|
|
case 'G': /* >= */
|
2011-02-13 20:19:02 +01:00
|
|
|
if (x >= y)
|
|
|
|
|
x = u;
|
|
|
|
|
else
|
|
|
|
|
x = z;
|
|
|
|
|
break;
|
2012-09-20 20:30:53 +02:00
|
|
|
case 'L': /* <= */
|
2011-02-13 20:19:02 +01:00
|
|
|
if (x <= y)
|
|
|
|
|
x = u;
|
|
|
|
|
else
|
|
|
|
|
x = z;
|
|
|
|
|
break;
|
2012-09-20 20:30:53 +02:00
|
|
|
case '!': /* ! */
|
2011-02-13 20:19:02 +01:00
|
|
|
if (y == z)
|
|
|
|
|
x = u;
|
|
|
|
|
else
|
|
|
|
|
x = z;
|
|
|
|
|
break;
|
2012-09-20 20:30:53 +02:00
|
|
|
case '%': /* % */
|
2016-04-30 19:20:49 +02:00
|
|
|
t = trunc(x / y);
|
2011-02-13 20:19:02 +01:00
|
|
|
x = x - y * t;
|
|
|
|
|
break;
|
2012-09-20 20:30:53 +02:00
|
|
|
case '\\': /* / */
|
2016-04-30 19:20:49 +02:00
|
|
|
x = trunc(fabs(x / y));
|
2011-02-13 20:19:02 +01:00
|
|
|
break;
|
2012-09-20 20:30:53 +02:00
|
|
|
}
|
|
|
|
|
|
2011-02-13 20:19:02 +01:00
|
|
|
return x;
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2016-03-05 21:07:56 +01:00
|
|
|
#define nprece 9 /* maximal nb of precedence levels */
|
|
|
|
|
|
2007-12-26 17:55:27 +01:00
|
|
|
static double
|
2014-08-10 20:21:34 +02:00
|
|
|
formula(dico_t *dico, const char *s, const char *s_end, bool *perror)
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2011-02-13 20:19:02 +01:00
|
|
|
/* Expression parser.
|
2012-09-20 20:30:53 +02:00
|
|
|
s is a formula with parentheses and math ops +-* / ...
|
|
|
|
|
State machine and an array of accumulators handle operator precedence.
|
|
|
|
|
Parentheses handled by recursion.
|
|
|
|
|
Empty expression is forbidden: must find at least 1 atom.
|
|
|
|
|
Syntax error if no toggle between binoperator && (unop/state1) !
|
|
|
|
|
States : 1=atom, 2=binOp, 3=unOp, 4= stop-codon.
|
|
|
|
|
Allowed transitions: 1->2->(3,1) and 3->(3,1).
|
2011-02-13 20:19:02 +01:00
|
|
|
*/
|
|
|
|
|
bool error = *perror;
|
|
|
|
|
bool negate = 0;
|
2013-11-07 21:42:02 +01:00
|
|
|
unsigned char state, oldstate, topop, ustack, level, fu;
|
2013-10-08 18:38:43 +02:00
|
|
|
double u = 0.0;
|
2011-02-13 20:19:02 +01:00
|
|
|
double accu[nprece + 1];
|
|
|
|
|
char oper[nprece + 1];
|
|
|
|
|
char uop[nprece + 1];
|
2013-10-08 18:38:43 +02:00
|
|
|
int i, natom;
|
2011-02-13 20:19:02 +01:00
|
|
|
bool ok;
|
2012-09-20 20:30:53 +02:00
|
|
|
SPICE_DSTRING tstr;
|
2013-10-08 18:38:43 +02:00
|
|
|
const char *s_orig = s;
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
spice_dstring_init(&tstr);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i <= nprece; i++) {
|
2011-02-13 20:19:02 +01:00
|
|
|
accu[i] = 0.0;
|
|
|
|
|
oper[i] = ' ';
|
|
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2013-10-08 18:38:43 +02:00
|
|
|
/* trim trailing whitespace */
|
|
|
|
|
while ((s_end > s) && (s_end[-1] <= ' '))
|
|
|
|
|
s_end--;
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2013-10-07 18:21:02 +02:00
|
|
|
state = S_init;
|
2011-02-13 20:19:02 +01:00
|
|
|
natom = 0;
|
|
|
|
|
ustack = 0;
|
|
|
|
|
topop = 0;
|
2013-10-07 18:21:02 +02:00
|
|
|
oldstate = S_init;
|
2011-02-13 20:19:02 +01:00
|
|
|
fu = 0;
|
|
|
|
|
error = 0;
|
|
|
|
|
level = 0;
|
|
|
|
|
|
2013-10-08 18:38:43 +02:00
|
|
|
while ((s < s_end) && !error) {
|
|
|
|
|
char c = *s;
|
2012-09-20 20:30:53 +02:00
|
|
|
if (c == '(') {
|
2011-02-13 20:19:02 +01:00
|
|
|
/* sub-formula or math function */
|
2013-10-08 18:38:43 +02:00
|
|
|
double v = 1.0, w = 0.0;
|
2011-02-13 20:19:02 +01:00
|
|
|
/* new: must support multi-arg functions */
|
2013-10-08 18:38:43 +02:00
|
|
|
const char *kptr = ++s;
|
|
|
|
|
const char *arg2 = NULL;
|
|
|
|
|
const char *arg3 = NULL;
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2013-10-08 18:38:43 +02:00
|
|
|
level = 1;
|
2016-05-14 12:34:21 +02:00
|
|
|
for (; kptr < s_end; kptr++)
|
2011-02-13 20:19:02 +01:00
|
|
|
{
|
2016-05-14 12:31:51 +02:00
|
|
|
char d = *kptr;
|
2011-02-13 20:19:02 +01:00
|
|
|
|
|
|
|
|
if (d == '(')
|
|
|
|
|
level++;
|
|
|
|
|
else if (d == ')')
|
|
|
|
|
level--;
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
if ((d == ',') && (level == 1)) {
|
2013-10-08 18:38:43 +02:00
|
|
|
if (arg2 == NULL)
|
2016-05-14 12:36:39 +02:00
|
|
|
arg2 = kptr;
|
2011-02-13 20:19:02 +01:00
|
|
|
else
|
2016-05-14 12:36:39 +02:00
|
|
|
arg3 = kptr; /* kludge for more than 2 args (ternary expression) */
|
2012-09-20 20:30:53 +02:00
|
|
|
} /* comma list? */
|
|
|
|
|
|
2016-05-14 12:13:29 +02:00
|
|
|
if ((d == ')') && (level <= 0)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2013-10-08 18:38:43 +02:00
|
|
|
// fixme, here level = 0 !!!!! (almost)
|
|
|
|
|
|
2016-05-14 12:52:48 +02:00
|
|
|
if (kptr >= s_end) {
|
2014-05-18 20:39:17 +02:00
|
|
|
error = message(dico, "Closing \")\" not found.\n");
|
2012-09-20 20:30:53 +02:00
|
|
|
natom++; /* shut up other error message */
|
|
|
|
|
} else {
|
2016-05-14 12:36:39 +02:00
|
|
|
if (arg2 >= s) {
|
|
|
|
|
v = formula(dico, s, arg2, &error);
|
|
|
|
|
s = arg2 + 1;
|
2008-01-19 22:35:44 +01:00
|
|
|
}
|
2016-05-14 12:36:39 +02:00
|
|
|
if (arg3 >= s) {
|
|
|
|
|
w = formula(dico, s, arg3, &error);
|
|
|
|
|
s = arg3 + 1;
|
2008-01-19 22:35:44 +01:00
|
|
|
}
|
2016-05-14 12:52:48 +02:00
|
|
|
u = formula(dico, s, kptr, &error);
|
2013-10-07 18:21:02 +02:00
|
|
|
state = S_atom;
|
2012-09-20 20:30:53 +02:00
|
|
|
if (fu > 0) {
|
2013-12-01 12:01:00 +01:00
|
|
|
if ((fu == XFU_TERNARY_FCN))
|
2013-11-01 20:15:21 +01:00
|
|
|
u = ternary_fcn(v, w, u);
|
2013-12-01 12:01:00 +01:00
|
|
|
else if ((fu == XFU_AGAUSS))
|
2012-09-20 20:30:53 +02:00
|
|
|
u = agauss(v, w, u);
|
2013-12-01 12:01:00 +01:00
|
|
|
else if ((fu == XFU_GAUSS))
|
2012-09-20 20:30:53 +02:00
|
|
|
u = gauss(v, w, u);
|
2013-12-01 12:01:00 +01:00
|
|
|
else if ((fu == XFU_UNIF))
|
2012-09-20 20:30:53 +02:00
|
|
|
u = unif(v, u);
|
2013-12-01 12:01:00 +01:00
|
|
|
else if ((fu == XFU_AUNIF))
|
2012-09-20 20:30:53 +02:00
|
|
|
u = aunif(v, u);
|
2013-12-01 12:01:00 +01:00
|
|
|
else if ((fu == XFU_LIMIT))
|
2012-09-20 20:30:53 +02:00
|
|
|
u = limit(v, u);
|
2011-02-13 20:19:02 +01:00
|
|
|
else
|
2012-09-20 20:30:53 +02:00
|
|
|
u = mathfunction(fu, v, u);
|
2008-01-19 22:35:44 +01:00
|
|
|
}
|
|
|
|
|
}
|
2016-05-14 12:52:48 +02:00
|
|
|
s = kptr + 1;
|
2011-02-13 20:19:02 +01:00
|
|
|
fu = 0;
|
2012-09-20 20:30:53 +02:00
|
|
|
} else if (alfa(c)) {
|
2015-10-11 14:39:05 +02:00
|
|
|
const char *s_next = fetchid(s, s_end);
|
2015-11-07 19:10:25 +01:00
|
|
|
fu = keyword(fmathS, s, s_next); /* numeric function? */
|
|
|
|
|
if (fu > 0) {
|
|
|
|
|
state = S_init; /* S_init means: ignore for the moment */
|
|
|
|
|
} else {
|
|
|
|
|
spice_dstring_reinit(&tstr);
|
2015-11-07 19:11:54 +01:00
|
|
|
while (s < s_next)
|
2016-04-30 20:29:13 +02:00
|
|
|
cadd(&tstr, toupper_c(*s++));
|
2015-11-07 19:10:25 +01:00
|
|
|
u = fetchnumentry(dico, spice_dstring_value(&tstr), &error);
|
|
|
|
|
state = S_atom;
|
2013-10-08 18:38:43 +02:00
|
|
|
}
|
2015-10-11 14:39:05 +02:00
|
|
|
s = s_next;
|
2012-09-20 20:30:53 +02:00
|
|
|
} else if (((c == '.') || ((c >= '0') && (c <= '9')))) {
|
2013-10-08 18:38:43 +02:00
|
|
|
u = fetchnumber(dico, &s, &error);
|
2012-09-20 20:30:53 +02:00
|
|
|
if (negate) {
|
2011-02-13 20:19:02 +01:00
|
|
|
u = -1 * u;
|
|
|
|
|
negate = 0;
|
2008-01-19 22:35:44 +01:00
|
|
|
}
|
2013-10-07 18:21:02 +02:00
|
|
|
state = S_atom;
|
2012-09-20 20:30:53 +02:00
|
|
|
} else {
|
2013-10-08 18:38:43 +02:00
|
|
|
c = fetchoperator(dico, s_end, &s, &state, &level, &error);
|
2008-01-19 22:35:44 +01:00
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2011-02-13 20:19:02 +01:00
|
|
|
/* may change c to some other operator char! */
|
|
|
|
|
/* control chars <' ' ignored */
|
|
|
|
|
|
2013-10-07 18:21:02 +02:00
|
|
|
ok = (oldstate == S_init) || (state == S_init) ||
|
|
|
|
|
((oldstate == S_atom) && (state == S_binop)) ||
|
|
|
|
|
((oldstate != S_atom) && (state != S_binop));
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2013-10-07 18:21:02 +02:00
|
|
|
if (oldstate == S_binop && state == S_binop && c == '-') {
|
2011-02-13 20:19:02 +01:00
|
|
|
ok = 1;
|
|
|
|
|
negate = 1;
|
|
|
|
|
continue;
|
2008-01-19 22:35:44 +01:00
|
|
|
}
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2011-02-13 20:19:02 +01:00
|
|
|
if (!ok)
|
2014-05-18 20:39:17 +02:00
|
|
|
error = message(dico, " Misplaced operator\n");
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2013-10-07 18:21:02 +02:00
|
|
|
if (state == S_unop) {
|
2011-02-13 20:19:02 +01:00
|
|
|
/* push unary operator */
|
2013-10-08 18:38:43 +02:00
|
|
|
uop[++ustack] = c;
|
2013-10-07 18:21:02 +02:00
|
|
|
} else if (state == S_atom) {
|
2011-02-13 20:19:02 +01:00
|
|
|
/* atom pending */
|
|
|
|
|
natom++;
|
2013-10-08 18:38:43 +02:00
|
|
|
if (s >= s_end) {
|
2013-10-07 18:21:02 +02:00
|
|
|
state = S_stop;
|
2011-02-13 20:19:02 +01:00
|
|
|
level = topop;
|
2012-09-20 20:30:53 +02:00
|
|
|
} /* close all ops below */
|
|
|
|
|
|
2013-10-08 18:38:43 +02:00
|
|
|
while (ustack > 0)
|
|
|
|
|
u = operate(uop[ustack--], u, u);
|
2008-01-19 22:35:44 +01:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
accu[0] = u; /* done: all pending unary operators */
|
2008-01-19 22:35:44 +01:00
|
|
|
}
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2013-10-07 18:21:02 +02:00
|
|
|
if ((state == S_binop) || (state == S_stop)) {
|
2011-02-13 20:19:02 +01:00
|
|
|
/* do pending binaries of priority Upto "level" */
|
2013-10-08 18:38:43 +02:00
|
|
|
for (i = 1; i <= level; i++) {
|
2013-10-15 19:20:52 +02:00
|
|
|
if (i < level && oper[i] == ':' && (oper[i+1] == '?' || oper[i+1] == 'x')) {
|
|
|
|
|
if (oper[i+1] == 'x') {
|
|
|
|
|
/* this is a `first-of-triple' op */
|
|
|
|
|
accu[i+1] = accu[i+1];
|
|
|
|
|
c = 'x'; /* transform next '?' to 'first-of-triple' */
|
|
|
|
|
} else if (accu[i+1] != 0.0) {
|
|
|
|
|
/* this is a `true' ternary */
|
|
|
|
|
accu[i+1] = accu[i];
|
|
|
|
|
c = 'x'; /* transform next '?' to `first-of-triple' */
|
|
|
|
|
} else {
|
|
|
|
|
/* this is a `false' ternary */
|
|
|
|
|
accu[i+1] = accu[i-1];
|
|
|
|
|
}
|
|
|
|
|
accu[i-1] = 0.0;
|
|
|
|
|
oper[i] = ' '; /* reset intermediates */
|
|
|
|
|
i++;
|
|
|
|
|
accu[i-1] = 0.0;
|
|
|
|
|
oper[i] = ' '; /* reset intermediates */
|
|
|
|
|
} else {
|
2013-11-07 21:42:02 +01:00
|
|
|
/* not yet speed optimized! */
|
|
|
|
|
accu[i] = operate(oper[i], accu[i], accu[i-1]);
|
|
|
|
|
accu[i-1] = 0.0;
|
|
|
|
|
oper[i] = ' '; /* reset intermediates */
|
2013-10-15 19:20:52 +02:00
|
|
|
}
|
2008-01-19 22:35:44 +01:00
|
|
|
}
|
2011-02-13 20:19:02 +01:00
|
|
|
oper[level] = c;
|
2008-01-19 22:35:44 +01:00
|
|
|
|
2013-06-02 17:15:51 +02:00
|
|
|
if (topop < level)
|
2011-02-13 20:19:02 +01:00
|
|
|
topop = level;
|
2008-01-19 22:35:44 +01:00
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2013-10-07 18:21:02 +02:00
|
|
|
if (state != S_init)
|
2011-02-13 20:19:02 +01:00
|
|
|
oldstate = state;
|
2012-09-20 20:30:53 +02:00
|
|
|
}
|
2011-02-19 15:45:42 +01:00
|
|
|
|
2013-10-07 18:21:02 +02:00
|
|
|
if ((natom == 0) || (oldstate != S_stop))
|
2014-05-18 20:39:17 +02:00
|
|
|
error = message(dico, " Expression err: %s\n", s_orig);
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2011-02-13 20:19:02 +01:00
|
|
|
if (negate == 1)
|
2012-09-20 20:30:53 +02:00
|
|
|
error = message(dico,
|
2014-05-18 20:39:17 +02:00
|
|
|
" Problem with formula eval -- wrongly determined negation!\n");
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2011-02-13 20:19:02 +01:00
|
|
|
*perror = error;
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
spice_dstring_free(&tstr);
|
2009-03-22 22:03:02 +01:00
|
|
|
|
2011-02-13 20:19:02 +01:00
|
|
|
if (error)
|
|
|
|
|
return 1.0;
|
|
|
|
|
else
|
|
|
|
|
return accu[topop];
|
2012-09-20 20:30:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-04-29 18:38:39 +02:00
|
|
|
/* stupid, produce a string representation of a given double
|
|
|
|
|
* to be spliced back into the circuit deck
|
|
|
|
|
* we want *exactly* 25 chars, we have
|
|
|
|
|
* sign, leading digit, '.', 'e', sign, upto 3 digits exponent
|
|
|
|
|
* ==> 8 chars, thus we have 17 left for precision
|
|
|
|
|
* don't print a leading '+', something choked
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
double_to_string(SPICE_DSTRINGPTR qstr_p, double value)
|
|
|
|
|
{
|
|
|
|
|
char buf[ACT_CHARACTS + 1];
|
|
|
|
|
if (snprintf(buf, sizeof(buf), "% 25.17e", value) != ACT_CHARACTS) {
|
|
|
|
|
fprintf(stderr, "ERROR: xpressn.c, %s(%d)\n", __FUNCTION__, __LINE__);
|
|
|
|
|
controlled_exit(1);
|
|
|
|
|
}
|
|
|
|
|
scopys(qstr_p, buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-11-04 18:33:47 +01:00
|
|
|
/* expand parameter in string `t' to result `q' */
|
2010-11-02 18:55:32 +01:00
|
|
|
static bool
|
2016-05-15 20:28:56 +02:00
|
|
|
evaluate_variable(dico_t *dico, SPICE_DSTRINGPTR qstr_p, const char * const t, const char * const t_end)
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2014-08-10 20:21:43 +02:00
|
|
|
entry_t *entry;
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
spice_dstring_reinit(qstr_p);
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2016-05-15 20:28:56 +02:00
|
|
|
char *tx = copy_substring(t, t_end);
|
|
|
|
|
strtoupper(tx);
|
|
|
|
|
entry = entrynb(dico, tx);
|
|
|
|
|
tfree(tx);
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2017-11-04 18:33:47 +01:00
|
|
|
if (!entry)
|
|
|
|
|
return message(dico,
|
2016-05-15 20:28:56 +02:00
|
|
|
"\"%.*s\" not evaluated. Lookup failure.\n", (int) (t_end - t), t);
|
2017-10-25 21:33:13 +02:00
|
|
|
|
2017-11-04 18:33:47 +01:00
|
|
|
if (entry->tp == NUPA_REAL) {
|
|
|
|
|
double_to_string(qstr_p, entry->vl);
|
|
|
|
|
}
|
|
|
|
|
else if (entry->tp == NUPA_STRING) {
|
|
|
|
|
/* suppose source text "..." at */
|
|
|
|
|
int j = entry->ivl + 1;
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2017-11-04 18:33:47 +01:00
|
|
|
for (;;) {
|
|
|
|
|
char c = entry->sbbase[j++];
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2017-11-04 18:33:47 +01:00
|
|
|
if ((c == '\"') || (c < ' '))
|
|
|
|
|
return 0;
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2017-11-04 18:33:47 +01:00
|
|
|
cadd(qstr_p, c);
|
2008-01-19 22:35:44 +01:00
|
|
|
}
|
2016-04-29 21:26:06 +02:00
|
|
|
}
|
2017-11-04 18:33:47 +01:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* transform exression in string `t' to result q */
|
|
|
|
|
static bool
|
2016-05-01 15:59:17 +02:00
|
|
|
evaluate_expr(dico_t *dico, SPICE_DSTRINGPTR qstr_p, const char *t, const char * const t_end)
|
2017-11-04 18:33:47 +01:00
|
|
|
{
|
|
|
|
|
bool err = 0;
|
|
|
|
|
double u;
|
|
|
|
|
|
|
|
|
|
spice_dstring_reinit(qstr_p);
|
|
|
|
|
|
2016-05-01 15:59:17 +02:00
|
|
|
u = formula(dico, t, t_end, &err);
|
2017-11-04 18:33:47 +01:00
|
|
|
if (err)
|
|
|
|
|
return err;
|
|
|
|
|
|
|
|
|
|
double_to_string(qstr_p, u);
|
|
|
|
|
|
2016-04-29 21:26:06 +02:00
|
|
|
return 0;
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
2003-09-25 19:19:44 +02:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
|
|
|
|
/********* interface functions for spice3f5 extension ***********/
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2016-05-01 18:13:24 +02:00
|
|
|
static char *
|
2016-05-01 17:55:11 +02:00
|
|
|
insertnumber(dico_t *dico, char * const s, SPICE_DSTRINGPTR ustr_p)
|
2003-09-25 19:19:44 +02:00
|
|
|
/* insert u in string s in place of the next placeholder number */
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2011-02-19 15:49:07 +01:00
|
|
|
const char *u = spice_dstring_value(ustr_p);
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2011-02-19 15:49:07 +01:00
|
|
|
char buf[ACT_CHARACTS+1];
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2011-02-19 15:49:07 +01:00
|
|
|
long id = 0;
|
|
|
|
|
int n = 0;
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2016-05-01 17:55:11 +02:00
|
|
|
char *p = strstr(s, "numparm__________");
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
if (p &&
|
2013-11-09 14:45:26 +01:00
|
|
|
(1 == sscanf(p, "numparm__________%8lx%n", &id, &n)) &&
|
2011-02-19 15:49:07 +01:00
|
|
|
(n == ACT_CHARACTS) &&
|
|
|
|
|
(id > 0) && (id < dynsubst + 1) &&
|
2013-11-09 14:45:26 +01:00
|
|
|
(snprintf(buf, sizeof(buf), "%-25s", u) == ACT_CHARACTS))
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2011-02-19 15:49:07 +01:00
|
|
|
memcpy(p, buf, ACT_CHARACTS);
|
2016-05-01 18:13:24 +02:00
|
|
|
return p + ACT_CHARACTS;
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
|
|
|
|
|
2011-02-19 15:49:07 +01:00
|
|
|
message
|
2012-09-20 20:30:53 +02:00
|
|
|
(dico,
|
|
|
|
|
"insertnumber: fails.\n"
|
2016-05-01 17:52:58 +02:00
|
|
|
" s = \"%s\" u=\"%s\" id=%ld\n",
|
2016-05-01 17:55:11 +02:00
|
|
|
s, u, id);
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2011-02-19 15:49:07 +01:00
|
|
|
/* swallow everything on failure */
|
2016-05-01 18:13:24 +02:00
|
|
|
return s + strlen(s);
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
2010-11-02 18:55:32 +01:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2010-11-02 18:55:32 +01:00
|
|
|
bool
|
2017-11-17 19:26:37 +01:00
|
|
|
nupa_substitute(dico_t *dico, const char *s, char *r)
|
2003-09-25 19:19:44 +02:00
|
|
|
/* s: pointer to original source line.
|
2008-01-19 22:35:44 +01:00
|
|
|
r: pointer to result line, already heavily modified wrt s
|
2003-09-25 19:19:44 +02:00
|
|
|
anywhere we find a 10-char numstring in r, substitute it.
|
2012-09-20 20:30:53 +02:00
|
|
|
bug: wont flag overflow!
|
2003-09-25 19:19:44 +02:00
|
|
|
*/
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2016-05-14 16:43:34 +02:00
|
|
|
const char * const s_end = s + strlen(s);
|
2016-05-15 20:01:31 +02:00
|
|
|
bool err = 0;
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
SPICE_DSTRING qstr; /* temp result dynamic string */
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
spice_dstring_init(&qstr);
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2016-05-05 22:38:18 +02:00
|
|
|
while (s < s_end) {
|
2016-05-01 15:53:22 +02:00
|
|
|
|
2017-11-18 21:24:14 +01:00
|
|
|
char c = *s++;
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2016-05-05 12:11:20 +02:00
|
|
|
if (c == '{') {
|
2011-05-29 12:07:10 +02:00
|
|
|
/* try ps expression syntax */
|
2016-05-14 15:48:55 +02:00
|
|
|
const char *kptr = s;
|
2017-11-18 21:24:14 +01:00
|
|
|
int nnest = 1;
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2016-05-14 15:46:48 +02:00
|
|
|
for (; *kptr; kptr++) {
|
2016-05-14 13:35:52 +02:00
|
|
|
|
2016-05-14 15:40:22 +02:00
|
|
|
char d = *kptr;
|
2016-05-01 15:53:22 +02:00
|
|
|
|
2011-02-13 20:19:02 +01:00
|
|
|
if (d == '{')
|
|
|
|
|
nnest++;
|
|
|
|
|
else if (d == '}')
|
|
|
|
|
nnest--;
|
|
|
|
|
|
2016-05-14 15:48:18 +02:00
|
|
|
if (nnest == 0)
|
2016-05-14 13:35:52 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2016-05-14 13:56:55 +02:00
|
|
|
if (*kptr == '\0') {
|
2014-05-18 20:39:17 +02:00
|
|
|
err = message(dico, "Closing \"}\" not found.\n");
|
2016-05-05 22:38:18 +02:00
|
|
|
goto Lend;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-18 21:43:40 +01:00
|
|
|
/* exeption made for .meas */
|
|
|
|
|
if (s + 4 == kptr && strncasecmp(s, "LAST", 4) == 0) {
|
|
|
|
|
spice_dstring_reinit(&qstr);
|
|
|
|
|
sadd(&qstr, "last");
|
|
|
|
|
} else {
|
|
|
|
|
err = evaluate_expr(dico, &qstr, s, kptr);
|
|
|
|
|
if (err) {
|
|
|
|
|
err = message(dico, "Cannot compute substitute\n");
|
|
|
|
|
goto Lend;
|
2011-02-13 20:19:02 +01:00
|
|
|
}
|
2017-11-18 21:43:40 +01:00
|
|
|
}
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2016-05-14 13:59:49 +02:00
|
|
|
s = kptr + 1;
|
2017-11-17 19:26:37 +01:00
|
|
|
r = insertnumber(dico, r, &qstr);
|
2012-09-20 20:30:53 +02:00
|
|
|
|
|
|
|
|
} else if (c == Intro) {
|
2011-02-13 20:19:02 +01:00
|
|
|
/* skip "&&" which may occur in B source */
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2016-05-14 16:43:34 +02:00
|
|
|
if ((s < s_end - 1) && (*s == Intro)) {
|
2016-05-01 15:46:47 +02:00
|
|
|
s++;
|
2010-02-28 17:00:40 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-14 15:52:34 +02:00
|
|
|
while ((s < s_end - 1) && (*s <= ' '))
|
2016-05-01 15:46:47 +02:00
|
|
|
s++;
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2016-05-14 15:52:34 +02:00
|
|
|
if (*s == '(') {
|
2011-02-13 20:19:02 +01:00
|
|
|
/* sub-formula */
|
2016-05-15 19:40:15 +02:00
|
|
|
const char *kptr = s + 1;
|
2017-11-18 21:24:14 +01:00
|
|
|
int level = 1;
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2016-05-14 16:43:34 +02:00
|
|
|
for (; *kptr; kptr++) {
|
2016-05-14 13:35:52 +02:00
|
|
|
|
2016-05-14 15:46:48 +02:00
|
|
|
char d = *kptr;
|
2016-05-01 15:53:22 +02:00
|
|
|
|
2011-02-13 20:19:02 +01:00
|
|
|
if (d == '(')
|
|
|
|
|
level++;
|
|
|
|
|
else if (d == ')')
|
|
|
|
|
level--;
|
2008-01-19 22:35:44 +01:00
|
|
|
|
2016-05-14 15:48:18 +02:00
|
|
|
if ((d == ')') && (level <= 0))
|
2016-05-14 13:35:52 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2016-05-14 16:43:34 +02:00
|
|
|
if (*kptr == '\0') {
|
2014-05-18 20:39:17 +02:00
|
|
|
err = message(dico, "Closing \")\" not found.\n");
|
2016-05-05 22:38:18 +02:00
|
|
|
goto Lend;
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-15 19:40:15 +02:00
|
|
|
err = evaluate_expr(dico, &qstr, s + 1, kptr);
|
2016-05-05 22:38:18 +02:00
|
|
|
if (err) {
|
|
|
|
|
message(dico, "Cannot compute &(expression)\n");
|
|
|
|
|
goto Lend;
|
2008-01-19 22:35:44 +01:00
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2016-05-14 13:59:49 +02:00
|
|
|
s = kptr + 1;
|
2012-09-20 20:30:53 +02:00
|
|
|
|
|
|
|
|
} else {
|
2011-02-13 20:19:02 +01:00
|
|
|
/* simple identifier may also be string? */
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2016-05-14 16:43:34 +02:00
|
|
|
/* fixme, kptr might point behind the terminating '\0' here
|
|
|
|
|
* causing serious troubles in evaluate_variable()
|
|
|
|
|
* and/or when updating s
|
|
|
|
|
*/
|
2016-05-05 22:37:55 +02:00
|
|
|
const char *kptr = s + 1;
|
2016-05-14 15:47:28 +02:00
|
|
|
for (; kptr < s_end; kptr++)
|
|
|
|
|
if (*kptr <= ' ')
|
2016-05-14 13:35:52 +02:00
|
|
|
break;
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2016-05-05 22:37:55 +02:00
|
|
|
err = evaluate_variable(dico, &qstr, s, kptr);
|
2016-05-05 22:38:18 +02:00
|
|
|
if (err) {
|
|
|
|
|
message(dico, "Cannot compute &identifier\n");
|
|
|
|
|
goto Lend;
|
|
|
|
|
}
|
2016-05-14 15:48:18 +02:00
|
|
|
s = kptr;
|
2008-01-19 22:35:44 +01:00
|
|
|
}
|
|
|
|
|
|
2017-11-17 19:26:37 +01:00
|
|
|
r = insertnumber(dico, r, &qstr);
|
2008-01-19 22:35:44 +01:00
|
|
|
}
|
2011-02-13 20:19:02 +01:00
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2016-05-05 22:38:18 +02:00
|
|
|
Lend:
|
2012-09-20 20:30:53 +02:00
|
|
|
spice_dstring_free(&qstr);
|
|
|
|
|
|
2011-02-13 20:19:02 +01:00
|
|
|
return err;
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2017-11-12 21:13:26 +01:00
|
|
|
static const char *
|
2016-05-22 13:01:50 +02:00
|
|
|
getword(const char *s, SPICE_DSTRINGPTR tstr_p)
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2016-05-22 13:01:50 +02:00
|
|
|
const char *s_end = s + strlen(s);
|
|
|
|
|
|
2016-05-01 17:36:12 +02:00
|
|
|
while ((s < s_end - 1) && !alfa(*s))
|
2016-05-06 20:08:06 +02:00
|
|
|
s++;
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
spice_dstring_reinit(tstr_p);
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2016-05-01 17:32:56 +02:00
|
|
|
while ((s < s_end) && (alfa(*s) || isdigit_c(*s)))
|
|
|
|
|
cadd(tstr_p, toupper_c(*s++));
|
|
|
|
|
|
2016-05-22 14:52:07 +02:00
|
|
|
return s;
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
2003-09-25 19:19:44 +02:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2016-05-22 12:38:46 +02:00
|
|
|
static char *
|
|
|
|
|
getexpress(nupa_type *type, SPICE_DSTRINGPTR tstr_p, const char *s)
|
2003-09-25 19:19:44 +02:00
|
|
|
/* returns expression-like string until next separator
|
2012-09-20 20:30:53 +02:00
|
|
|
Input i=position before expr, output i=just after expr, on separator.
|
|
|
|
|
returns tpe=='R' if (numeric, 'S' if (string only
|
2003-09-25 19:19:44 +02:00
|
|
|
*/
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2017-11-18 11:54:53 +01:00
|
|
|
const char * const s_end = s + strlen(s);
|
2017-11-18 12:41:04 +01:00
|
|
|
const char *p;
|
2017-10-31 10:45:48 +01:00
|
|
|
nupa_type tpe;
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2017-11-18 11:54:53 +01:00
|
|
|
while ((s < s_end - 1) && (*s <= ' '))
|
2016-05-22 12:38:46 +02:00
|
|
|
s++; /*white space ? */
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2017-11-18 11:54:53 +01:00
|
|
|
if (*s == '"') { /* string constant */
|
|
|
|
|
|
2016-05-22 12:38:46 +02:00
|
|
|
s++;
|
|
|
|
|
p = s;
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2017-11-18 11:54:53 +01:00
|
|
|
while ((p < s_end - 1) && (*p != '"'))
|
2017-11-18 12:07:25 +01:00
|
|
|
p++;
|
2011-02-13 16:16:48 +01:00
|
|
|
|
2011-02-13 20:19:02 +01:00
|
|
|
do
|
2017-11-18 12:07:25 +01:00
|
|
|
p++;
|
2017-11-18 11:54:53 +01:00
|
|
|
while ((p < s_end) && (*p <= ' '));
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2017-11-18 11:54:53 +01:00
|
|
|
tpe = NUPA_STRING;
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
} else {
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2016-05-22 12:38:46 +02:00
|
|
|
if (*s == '{')
|
|
|
|
|
s++;
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2017-11-18 11:54:53 +01:00
|
|
|
p = s;
|
2008-01-19 22:35:44 +01:00
|
|
|
|
2017-11-18 11:54:53 +01:00
|
|
|
for (; p < s_end; p++) {
|
2017-11-18 12:33:01 +01:00
|
|
|
|
2017-11-18 11:54:53 +01:00
|
|
|
if (strchr(",;)}", *p)) /* legal separators */
|
2016-05-06 20:53:09 +02:00
|
|
|
break;
|
|
|
|
|
|
2017-11-18 11:54:53 +01:00
|
|
|
if (*p == '(') {
|
2011-02-13 20:19:02 +01:00
|
|
|
/* sub-formula */
|
2017-11-18 12:20:38 +01:00
|
|
|
int level = 1;
|
2017-11-18 12:28:56 +01:00
|
|
|
p++;
|
2017-11-18 11:54:53 +01:00
|
|
|
for (; p < s_end; p++) {
|
2017-11-18 12:21:32 +01:00
|
|
|
|
2017-11-18 12:30:31 +01:00
|
|
|
char d = *p;
|
2008-01-19 22:35:44 +01:00
|
|
|
|
2011-02-13 20:19:02 +01:00
|
|
|
if (d == '(')
|
|
|
|
|
level++;
|
|
|
|
|
else if (d == ')')
|
|
|
|
|
level--;
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2016-05-06 20:51:42 +02:00
|
|
|
if (level <= 0)
|
2016-05-01 15:07:02 +02:00
|
|
|
break;
|
2017-11-18 12:28:56 +01:00
|
|
|
}
|
2008-01-19 22:35:44 +01:00
|
|
|
}
|
2017-11-18 12:34:42 +01:00
|
|
|
}
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2017-10-31 10:45:48 +01:00
|
|
|
tpe = NUPA_REAL;
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
|
|
|
|
|
2016-05-22 12:38:46 +02:00
|
|
|
pscopy(tstr_p, s, 0, (int) (p - s));
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2017-11-18 12:08:48 +01:00
|
|
|
if (*p == '}')
|
2017-11-18 12:07:25 +01:00
|
|
|
p++;
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2017-10-31 10:45:48 +01:00
|
|
|
if (tpe == NUPA_STRING)
|
2017-11-18 12:07:25 +01:00
|
|
|
p++; /* beyond quote */
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2016-05-22 12:33:47 +02:00
|
|
|
if (type)
|
|
|
|
|
*type = tpe;
|
2017-11-18 12:45:58 +01:00
|
|
|
|
2017-11-18 12:50:09 +01:00
|
|
|
return (char *) p;
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
2003-09-25 19:19:44 +02:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2010-11-02 18:55:32 +01:00
|
|
|
bool
|
2016-05-01 17:41:55 +02:00
|
|
|
nupa_assignment(dico_t *dico, const char * const s, char mode)
|
2003-09-25 19:19:44 +02:00
|
|
|
/* is called for all 'Param' lines of the input file.
|
|
|
|
|
is also called for the params: section of a subckt .
|
|
|
|
|
mode='N' define new local variable, else global...
|
|
|
|
|
bug: we cannot rely on the transformed line, must re-parse everything!
|
|
|
|
|
*/
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2011-02-13 20:19:02 +01:00
|
|
|
/* s has the format: ident = expression; ident= expression ... */
|
2017-11-18 15:54:18 +01:00
|
|
|
const char * const s_end = s + strlen(s);
|
2017-11-18 15:27:00 +01:00
|
|
|
const char *p = s;
|
2017-11-18 15:36:40 +01:00
|
|
|
|
2017-11-18 15:55:43 +01:00
|
|
|
bool error = 0;
|
2017-10-31 10:45:48 +01:00
|
|
|
nupa_type dtype;
|
2011-02-13 20:19:02 +01:00
|
|
|
int wval = 0;
|
|
|
|
|
double rval = 0.0;
|
2012-09-20 20:30:53 +02:00
|
|
|
char *t_p; /* dstring contents value */
|
2017-11-18 15:36:40 +01:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
SPICE_DSTRING tstr; /* temporary dstring */
|
|
|
|
|
SPICE_DSTRING ustr; /* temporary dstring */
|
|
|
|
|
|
|
|
|
|
spice_dstring_init(&tstr);
|
|
|
|
|
spice_dstring_init(&ustr);
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2017-11-18 15:33:31 +01:00
|
|
|
while ((p < s_end) && (*p <= ' '))
|
2017-11-18 15:27:00 +01:00
|
|
|
p++;
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2017-11-18 15:28:10 +01:00
|
|
|
if (*p == Intro)
|
2017-11-18 15:27:00 +01:00
|
|
|
p++;
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2017-11-18 15:28:10 +01:00
|
|
|
if (*p == '.') /* skip any dot keyword */
|
|
|
|
|
while (*p > ' ')
|
2017-11-18 15:27:00 +01:00
|
|
|
p++;
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2017-11-18 15:55:43 +01:00
|
|
|
while (p < s_end) {
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2017-11-18 15:39:22 +01:00
|
|
|
p = getword(p, &tstr);
|
2012-09-20 20:30:53 +02:00
|
|
|
t_p = spice_dstring_value(&tstr);
|
2017-11-18 15:55:43 +01:00
|
|
|
if (t_p[0] == '\0') {
|
2014-05-18 20:39:17 +02:00
|
|
|
error = message(dico, " Identifier expected\n");
|
2017-11-18 15:55:43 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2017-11-18 15:36:40 +01:00
|
|
|
/* assignment expressions */
|
2017-11-18 15:39:22 +01:00
|
|
|
while ((p < s_end) && (*p != '='))
|
2017-11-18 15:36:40 +01:00
|
|
|
p++;
|
2008-01-19 22:35:44 +01:00
|
|
|
|
2017-11-18 15:39:22 +01:00
|
|
|
if (p >= s_end) {
|
2017-11-18 15:36:40 +01:00
|
|
|
error = message(dico, " = sign expected.\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2008-01-19 22:35:44 +01:00
|
|
|
|
2017-11-18 15:39:22 +01:00
|
|
|
p = getexpress(&dtype, &ustr, p + 1) + 1;
|
2008-01-19 22:35:44 +01:00
|
|
|
|
2017-11-18 15:36:40 +01:00
|
|
|
if (dtype == NUPA_REAL) {
|
|
|
|
|
const char *tmp = spice_dstring_value(&ustr);
|
|
|
|
|
rval = formula(dico, tmp, tmp + strlen(tmp), &error);
|
|
|
|
|
if (error) {
|
|
|
|
|
message(dico,
|
|
|
|
|
" Formula() error.\n"
|
|
|
|
|
" %s\n", s);
|
|
|
|
|
break;
|
2012-09-20 20:30:53 +02:00
|
|
|
}
|
2017-11-18 15:36:40 +01:00
|
|
|
} else if (dtype == NUPA_STRING) {
|
|
|
|
|
wval = (int) (p - s);
|
|
|
|
|
}
|
2008-01-19 22:35:44 +01:00
|
|
|
|
2017-11-18 15:36:40 +01:00
|
|
|
error = nupa_define(dico, spice_dstring_value(&tstr), mode /* was ' ' */ ,
|
|
|
|
|
dtype, rval, wval, NULL);
|
|
|
|
|
if (error)
|
|
|
|
|
break;
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2017-11-18 15:55:43 +01:00
|
|
|
if ((p < s_end) && (p[-1] != ';')) {
|
2014-05-18 20:39:17 +02:00
|
|
|
error = message(dico, " ; sign expected.\n");
|
2017-11-18 15:55:43 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
|
|
|
|
spice_dstring_free(&tstr);
|
|
|
|
|
spice_dstring_free(&ustr);
|
|
|
|
|
|
2011-02-13 20:19:02 +01:00
|
|
|
return error;
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2010-11-02 18:55:32 +01:00
|
|
|
bool
|
2017-11-25 15:11:52 +01:00
|
|
|
nupa_subcktcall(dico_t *dico, char *s, char * const x, char * const inst_name)
|
2003-09-25 19:19:44 +02:00
|
|
|
/* s= a subckt define line, with formal params.
|
2008-01-19 22:35:44 +01:00
|
|
|
x= a matching subckt call line, with actual params
|
2003-09-25 19:19:44 +02:00
|
|
|
*/
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2016-05-15 19:54:02 +02:00
|
|
|
int n, narg = 0;
|
2012-09-20 20:30:53 +02:00
|
|
|
SPICE_DSTRING subname;
|
|
|
|
|
SPICE_DSTRING tstr;
|
|
|
|
|
SPICE_DSTRING ustr;
|
|
|
|
|
SPICE_DSTRING vstr;
|
|
|
|
|
SPICE_DSTRING idlist;
|
|
|
|
|
SPICE_DSTRING parsebuf;
|
2016-04-27 18:28:32 +02:00
|
|
|
bool err = 0;
|
2012-09-20 20:30:53 +02:00
|
|
|
|
|
|
|
|
spice_dstring_init(&subname);
|
|
|
|
|
spice_dstring_init(&tstr);
|
|
|
|
|
spice_dstring_init(&ustr);
|
|
|
|
|
spice_dstring_init(&vstr);
|
|
|
|
|
spice_dstring_init(&idlist);
|
|
|
|
|
|
2011-02-13 20:19:02 +01:00
|
|
|
/***** first, analyze the subckt definition line */
|
2012-09-20 20:30:53 +02:00
|
|
|
n = 0; /* number of parameters if any */
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2014-05-19 21:15:11 +02:00
|
|
|
scopy_up(&tstr, s);
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2017-11-19 11:44:07 +01:00
|
|
|
const char *j2 = strstr(spice_dstring_value(&tstr), "SUBCKT");
|
|
|
|
|
if (j2) {
|
|
|
|
|
j2 = j2 + 6; /* fetch its name - skip subckt */
|
|
|
|
|
while (*j2 && (*j2 <= ' '))
|
|
|
|
|
j2++;
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2017-11-19 11:44:07 +01:00
|
|
|
while (*j2 && (*j2 != ' ')) {
|
|
|
|
|
cadd(&subname, *j2);
|
|
|
|
|
j2++;
|
2008-01-19 22:35:44 +01:00
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
} else {
|
2014-05-18 20:39:17 +02:00
|
|
|
err = message(dico, " ! a subckt line!\n");
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
|
|
|
|
|
2016-05-15 19:48:12 +02:00
|
|
|
const char *i2 = strstr(spice_dstring_value(&tstr), "PARAMS:");
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2016-05-15 19:48:12 +02:00
|
|
|
if (i2) {
|
2011-12-03 10:10:07 +01:00
|
|
|
const char *optr, *jptr;
|
|
|
|
|
|
2016-05-15 19:48:12 +02:00
|
|
|
pscopy(&tstr, i2 + 7, 0, (int) strlen(i2 + 7));
|
2011-12-03 10:10:07 +01:00
|
|
|
|
|
|
|
|
/* search identifier to the left of '=' assignments */
|
|
|
|
|
|
|
|
|
|
for (optr = spice_dstring_value(&tstr);
|
2012-09-20 20:30:53 +02:00
|
|
|
(jptr = strchr(optr, '=')) != NULL;
|
|
|
|
|
optr = jptr + 1)
|
2011-02-13 20:19:02 +01:00
|
|
|
{
|
2011-12-03 10:10:07 +01:00
|
|
|
const char *kptr, *hptr;
|
|
|
|
|
|
|
|
|
|
/* skip "==" */
|
2012-09-20 20:30:53 +02:00
|
|
|
if (jptr[1] == '=') {
|
2011-12-03 10:10:07 +01:00
|
|
|
jptr++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* skip "<=" ">=" "!=" */
|
2012-09-20 20:30:53 +02:00
|
|
|
if (jptr > optr && strchr("<>!", jptr[-1]))
|
2011-12-03 10:10:07 +01:00
|
|
|
continue;
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2011-12-03 10:10:07 +01:00
|
|
|
kptr = jptr;
|
2016-03-08 21:20:11 +01:00
|
|
|
while (--kptr >= optr && isspace_c(*kptr))
|
2011-12-03 10:10:07 +01:00
|
|
|
;
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2011-12-03 10:10:07 +01:00
|
|
|
hptr = kptr;
|
|
|
|
|
while (hptr >= optr && alfanum(*hptr))
|
|
|
|
|
hptr--;
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
if (hptr < kptr && alfa(hptr[1])) {
|
|
|
|
|
while (hptr++ < kptr)
|
|
|
|
|
cadd(&idlist, *hptr);
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
sadd(&idlist, "=$;");
|
2011-02-13 20:19:02 +01:00
|
|
|
n++;
|
2012-09-20 20:30:53 +02:00
|
|
|
} else {
|
2014-05-18 20:39:17 +02:00
|
|
|
message(dico, "identifier expected.\n");
|
2008-01-19 22:35:44 +01:00
|
|
|
}
|
|
|
|
|
}
|
2007-10-08 16:52:25 +02:00
|
|
|
}
|
2011-12-03 10:10:07 +01:00
|
|
|
|
2011-02-13 20:19:02 +01:00
|
|
|
/***** next, analyze the circuit call line */
|
2012-09-20 20:30:53 +02:00
|
|
|
if (!err) {
|
|
|
|
|
|
2017-11-25 15:09:20 +01:00
|
|
|
/*
|
|
|
|
|
skip over instance name -- fixes bug where instance 'x1' is
|
|
|
|
|
same name as subckt 'x1'
|
|
|
|
|
*/
|
2017-11-25 15:11:52 +01:00
|
|
|
scopy_up(&tstr, skip_non_ws(x));
|
2016-05-16 11:35:25 +02:00
|
|
|
int j0 = 0;
|
2007-12-26 17:55:27 +01:00
|
|
|
|
2017-11-19 11:43:25 +01:00
|
|
|
char * const t_p = spice_dstring_value(&tstr);
|
2016-05-16 11:55:06 +02:00
|
|
|
char * const ls_ptr = t_p + spice_dstring_length(&tstr);
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
spice_dstring_init(&parsebuf);
|
|
|
|
|
scopyd(&parsebuf, &tstr);
|
2016-05-15 19:54:02 +02:00
|
|
|
char * const buf = spice_dstring_value(&parsebuf);
|
2011-02-13 20:19:02 +01:00
|
|
|
|
2016-05-15 19:54:02 +02:00
|
|
|
int found = 0, found_j = 0;
|
|
|
|
|
char *token = strtok(buf, " "); /* a bit more exact - but not sufficient everytime */
|
2016-05-16 11:35:25 +02:00
|
|
|
j0 = j0 + (int) strlen(token) + 1;
|
2011-02-13 20:19:02 +01:00
|
|
|
if (strcmp(token, spice_dstring_value(&subname)))
|
2012-09-20 20:30:53 +02:00
|
|
|
while ((token = strtok(NULL, " ")) != NULL) {
|
|
|
|
|
if (!strcmp(token, spice_dstring_value(&subname))) {
|
2011-02-13 20:19:02 +01:00
|
|
|
found = 1;
|
2016-05-16 11:35:25 +02:00
|
|
|
found_j = j0;
|
2011-02-13 20:19:02 +01:00
|
|
|
}
|
2016-05-16 11:35:25 +02:00
|
|
|
j0 = j0 + (int) strlen(token) + 1;
|
2011-02-13 20:19:02 +01:00
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2016-05-16 11:35:25 +02:00
|
|
|
j0 = found_j; /* last occurence of subname in buf */
|
2012-09-20 20:30:53 +02:00
|
|
|
spice_dstring_free(&parsebuf);
|
2011-02-13 20:19:02 +01:00
|
|
|
|
|
|
|
|
/* make sure that subname followed by space */
|
2012-09-20 20:30:53 +02:00
|
|
|
if (found) {
|
2017-11-25 13:20:12 +01:00
|
|
|
char *jp = t_p + j0 + spice_dstring_length(&subname) + 1; /* 1st position of arglist: jp */
|
2008-01-19 22:35:44 +01:00
|
|
|
|
2016-05-16 12:00:28 +02:00
|
|
|
while ((jp < ls_ptr) && ((*jp <= ' ') || (*jp == ',')))
|
2017-11-25 13:20:12 +01:00
|
|
|
jp++;
|
2008-01-19 22:35:44 +01:00
|
|
|
|
2016-05-16 12:00:28 +02:00
|
|
|
while (jp < ls_ptr) {
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2011-02-13 20:19:02 +01:00
|
|
|
/* try to fetch valid arguments */
|
2016-05-16 12:00:28 +02:00
|
|
|
char *kp = jp;
|
2012-09-20 20:30:53 +02:00
|
|
|
spice_dstring_reinit(&ustr);
|
|
|
|
|
|
2016-05-16 12:00:28 +02:00
|
|
|
if (*kp == Intro) {
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2011-02-13 20:19:02 +01:00
|
|
|
/* handle historical syntax... */
|
2016-05-16 12:00:28 +02:00
|
|
|
if (alfa(kp[1])) {
|
2016-05-16 11:45:51 +02:00
|
|
|
kp++;
|
2016-05-16 12:00:28 +02:00
|
|
|
} else if (kp[1] == '(') {
|
2011-02-13 20:19:02 +01:00
|
|
|
/* transform to braces... */
|
2016-05-16 11:45:51 +02:00
|
|
|
kp++;
|
2016-05-16 12:00:28 +02:00
|
|
|
*kp = '{';
|
|
|
|
|
char *gp = kp;
|
2016-05-15 19:54:02 +02:00
|
|
|
int nest = 1;
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2016-05-16 12:00:28 +02:00
|
|
|
while ((nest > 0) && (gp < ls_ptr)) {
|
2017-11-17 21:20:15 +01:00
|
|
|
gp++;
|
2016-05-16 12:00:28 +02:00
|
|
|
if (*gp == '(')
|
2011-02-13 20:19:02 +01:00
|
|
|
nest++;
|
2016-05-16 12:00:28 +02:00
|
|
|
else if (*gp == ')')
|
2011-02-13 20:19:02 +01:00
|
|
|
nest--;
|
2008-01-19 22:35:44 +01:00
|
|
|
}
|
|
|
|
|
|
2016-05-16 12:00:28 +02:00
|
|
|
if ((gp < ls_ptr) && (nest == 0))
|
|
|
|
|
*gp = '}';
|
2008-01-19 22:35:44 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-16 12:00:28 +02:00
|
|
|
if (alfanum(*kp) || *kp == '.') {
|
2011-02-13 20:19:02 +01:00
|
|
|
/* number, identifier */
|
2016-05-16 12:00:28 +02:00
|
|
|
char *hp = kp;
|
|
|
|
|
while (*kp > ' ')
|
2016-05-16 11:45:51 +02:00
|
|
|
kp++;
|
2016-05-16 12:15:42 +02:00
|
|
|
pscopy(&ustr, hp, 0, (int) (kp - hp));
|
2016-05-16 12:00:28 +02:00
|
|
|
jp = kp;
|
|
|
|
|
} else if (*kp == '{') {
|
|
|
|
|
jp = getexpress(NULL, &ustr, jp);
|
2012-09-20 20:30:53 +02:00
|
|
|
} else {
|
2017-11-25 13:20:12 +01:00
|
|
|
jp++;
|
2016-05-16 12:00:28 +02:00
|
|
|
if (*kp > ' ')
|
|
|
|
|
message(dico, "Subckt call, symbol %c not understood\n", *kp);
|
2008-01-19 22:35:44 +01:00
|
|
|
}
|
|
|
|
|
|
2016-05-15 19:54:02 +02:00
|
|
|
char * const u_p = spice_dstring_value(&ustr);
|
2012-09-20 20:30:53 +02:00
|
|
|
if (u_p[0]) {
|
2016-05-16 21:40:50 +02:00
|
|
|
char * const idlist_p = spice_dstring_value(&idlist);
|
|
|
|
|
char *dollar = strchr(idlist_p, '$');
|
2016-04-30 12:20:35 +02:00
|
|
|
if (dollar) {
|
2016-05-16 21:40:50 +02:00
|
|
|
int kk = (int) (dollar - idlist_p);
|
2011-02-13 20:19:02 +01:00
|
|
|
/* replace dollar with expression string u */
|
2016-05-16 21:40:50 +02:00
|
|
|
pscopy(&vstr, idlist_p, 0, kk);
|
2012-09-20 20:30:53 +02:00
|
|
|
sadd(&vstr, spice_dstring_value(&ustr));
|
2016-05-16 21:40:50 +02:00
|
|
|
sadd(&vstr, idlist_p + kk + 1);
|
2012-09-20 20:30:53 +02:00
|
|
|
scopyd(&idlist, &vstr);
|
2008-01-19 22:35:44 +01:00
|
|
|
}
|
2017-11-25 15:17:48 +01:00
|
|
|
narg++;
|
2008-01-19 22:35:44 +01:00
|
|
|
}
|
|
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
} else {
|
2014-05-18 20:39:17 +02:00
|
|
|
message(dico, "Cannot find called subcircuit\n");
|
2008-01-19 22:35:44 +01:00
|
|
|
}
|
2011-02-13 20:19:02 +01:00
|
|
|
}
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2011-02-13 20:19:02 +01:00
|
|
|
/***** finally, execute the multi-assignment line */
|
2016-04-27 18:42:52 +02:00
|
|
|
dicostack_push(dico, inst_name); /* create local symbol scope */
|
2012-09-20 20:30:53 +02:00
|
|
|
|
|
|
|
|
if (narg != n) {
|
|
|
|
|
err = message(dico,
|
2014-05-18 20:39:17 +02:00
|
|
|
" Mismatch: %d formal but %d actual params.\n"
|
|
|
|
|
"%s\n",
|
2012-09-20 20:30:53 +02:00
|
|
|
n, narg, spice_dstring_value(&idlist));
|
|
|
|
|
/* ;} else { debugwarn(dico, idlist) */
|
2011-02-13 20:19:02 +01:00
|
|
|
}
|
|
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
err = nupa_assignment(dico, spice_dstring_value(&idlist), 'N');
|
|
|
|
|
|
|
|
|
|
spice_dstring_free(&subname);
|
|
|
|
|
spice_dstring_free(&tstr);
|
|
|
|
|
spice_dstring_free(&ustr);
|
|
|
|
|
spice_dstring_free(&vstr);
|
|
|
|
|
spice_dstring_free(&idlist);
|
|
|
|
|
|
2011-02-13 20:19:02 +01:00
|
|
|
return err;
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
2003-09-25 19:19:44 +02:00
|
|
|
|
2012-09-20 20:30:53 +02:00
|
|
|
|
2007-12-26 17:55:27 +01:00
|
|
|
void
|
2014-08-10 20:21:34 +02:00
|
|
|
nupa_subcktexit(dico_t *dico)
|
2007-12-26 17:55:27 +01:00
|
|
|
{
|
2014-08-09 19:38:18 +02:00
|
|
|
dicostack_pop(dico);
|
2007-12-26 17:55:27 +01:00
|
|
|
}
|
2017-10-31 10:45:48 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
struct nupa_type { /* used as a type-checked enum */
|
|
|
|
|
const char *name;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const struct nupa_type S_nupa_real = { "NUPA_REAL" };
|
|
|
|
|
const struct nupa_type S_nupa_string = { "NUPA_STRING" };
|
|
|
|
|
const struct nupa_type S_nupa_subckt = { "NUPA_SUBCKT" };
|
|
|
|
|
const struct nupa_type S_nupa_unknown = { "NUPA_UNKNOWN" };
|
|
|
|
|
const struct nupa_type S_nupa_model = { "NUPA_MODEL" };
|