Add limited support for string-valued parameters in .param lines.
The right-hand side of an assignment may be a string expression
made up from quoted strings, and identifiers for other string parameters,
optionally in braces. There may be no un-quoted spaces.
Example: .param str4=str1"String 4"str2{str3}
Subcircuits may have default and actual string parameters, but the values
must be single identifiers, not quoted strings or string expressions.
This commit is contained in:
parent
bb7034b559
commit
b576716caa
|
|
@ -2869,8 +2869,10 @@ static char *inp_spawn_brace(char *s)
|
||||||
removes " " quotes, returns lower case letters,
|
removes " " quotes, returns lower case letters,
|
||||||
replaces non-printable characters with '_', however if
|
replaces non-printable characters with '_', however if
|
||||||
non-printable character is the only character in a line,
|
non-printable character is the only character in a line,
|
||||||
replace it by '*'. If there is a XSPICE code model .model
|
replace it by '*'. Leave quotes in .param, .subckt and x
|
||||||
line with file input, keep quotes and case for the file path.
|
(subcircuit instance) cards to allow string-valued parameters.
|
||||||
|
If there is a XSPICE code model .model line with file input,
|
||||||
|
keep quotes and case for the file path.
|
||||||
*-------------------------------------------------------------------------*/
|
*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
void inp_casefix(char *string)
|
void inp_casefix(char *string)
|
||||||
|
|
@ -2883,20 +2885,23 @@ void inp_casefix(char *string)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (string) {
|
if (string) {
|
||||||
|
bool keepquotes;
|
||||||
|
|
||||||
#ifdef XSPICE
|
#ifdef XSPICE
|
||||||
/* special treatment of code model file input */
|
|
||||||
char* tmpstr = NULL;
|
char* tmpstr = NULL;
|
||||||
bool keepquotes = ciprefix(".model", string);
|
|
||||||
if (keepquotes){
|
/* Special treatment of code model file input. */
|
||||||
|
|
||||||
|
if (ciprefix(".model", string))
|
||||||
tmpstr = strstr(string, "file=");
|
tmpstr = strstr(string, "file=");
|
||||||
keepquotes = keepquotes && tmpstr;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
keepquotes = ciprefix(".param", string); // Allow string params
|
||||||
|
|
||||||
while (*string) {
|
while (*string) {
|
||||||
#ifdef XSPICE
|
#ifdef XSPICE
|
||||||
/* exclude file name inside of quotes from getting lower case,
|
/* exclude file name inside of quotes from getting lower case,
|
||||||
keep quotes to enable spaces in file path */
|
keep quotes to enable spaces in file path */
|
||||||
if (keepquotes && string == tmpstr) {
|
if (string == tmpstr) {
|
||||||
string = string + 6; // past first quote
|
string = string + 6; // past first quote
|
||||||
while (*string && *string != '"')
|
while (*string && *string != '"')
|
||||||
string++;
|
string++;
|
||||||
|
|
@ -2907,12 +2912,13 @@ void inp_casefix(char *string)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (*string == '"') {
|
if (*string == '"') {
|
||||||
*string++ = ' ';
|
if (!keepquotes)
|
||||||
|
*string++ = ' ';
|
||||||
while (*string && *string != '"')
|
while (*string && *string != '"')
|
||||||
string++;
|
string++;
|
||||||
if (*string == '\0')
|
if (*string == '\0')
|
||||||
continue; /* needed if string is "something ! */
|
continue; /* needed if string is "something ! */
|
||||||
if (*string == '"')
|
if (*string == '"' && !keepquotes)
|
||||||
*string = ' ';
|
*string = ' ';
|
||||||
}
|
}
|
||||||
if (*string && !isspace_c(*string) && !isprint_c(*string))
|
if (*string && !isspace_c(*string) && !isprint_c(*string))
|
||||||
|
|
@ -5054,24 +5060,40 @@ static int inp_split_multi_param_lines(struct card *card, int line_num)
|
||||||
|
|
||||||
char *beg_param, *end_param;
|
char *beg_param, *end_param;
|
||||||
|
|
||||||
bool get_expression = FALSE;
|
int expression_depth = 0;
|
||||||
bool get_paren_expression = FALSE;
|
int paren_depth = 0;
|
||||||
|
|
||||||
beg_param = skip_back_ws(equal_ptr, curr_line);
|
beg_param = skip_back_ws(equal_ptr, curr_line);
|
||||||
beg_param = skip_back_non_ws(beg_param, curr_line);
|
beg_param = skip_back_non_ws(beg_param, curr_line);
|
||||||
end_param = skip_ws(equal_ptr + 1);
|
end_param = skip_ws(equal_ptr + 1);
|
||||||
while (*end_param != '\0' &&
|
while (*end_param && !isspace_c(*end_param)) {
|
||||||
(!isspace_c(*end_param) || get_expression ||
|
/* Advance over numeric or string expression. */
|
||||||
get_paren_expression)) {
|
|
||||||
if (*end_param == '{')
|
if (*end_param == '"') {
|
||||||
get_expression = TRUE;
|
/* RHS is quoted string. */
|
||||||
if (*end_param == '(')
|
|
||||||
get_paren_expression = TRUE;
|
end_param++;
|
||||||
if (*end_param == '}')
|
while (*end_param != '\0' && *end_param != '"')
|
||||||
get_expression = FALSE;
|
end_param++;
|
||||||
if (*end_param == ')')
|
if (*end_param == '"')
|
||||||
get_paren_expression = FALSE;
|
end_param++;
|
||||||
end_param++;
|
} else {
|
||||||
|
while (*end_param != '\0' && *end_param != '"' &&
|
||||||
|
(!isspace_c(*end_param) ||
|
||||||
|
expression_depth || paren_depth)) {
|
||||||
|
if (*end_param == ',' && paren_depth == 0)
|
||||||
|
break;
|
||||||
|
if (*end_param == '{')
|
||||||
|
++expression_depth;
|
||||||
|
if (*end_param == '(')
|
||||||
|
++paren_depth;
|
||||||
|
if (*end_param == '}' && expression_depth > 0)
|
||||||
|
--expression_depth;
|
||||||
|
if (*end_param == ')' && paren_depth > 0)
|
||||||
|
--paren_depth;
|
||||||
|
end_param++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end_param[-1] == ',')
|
if (end_param[-1] == ',')
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
#include "ngspice/bool.h"
|
#include "ngspice/bool.h"
|
||||||
|
|
||||||
|
|
||||||
|
void pscat(DSTRINGPTR s, const char *str, const char *stop);
|
||||||
void pscopy(DSTRINGPTR s, const char *str, const char *stop);
|
void pscopy(DSTRINGPTR s, const char *str, const char *stop);
|
||||||
void scopyd(DSTRINGPTR dst, const DSTRINGPTR src);
|
void scopyd(DSTRINGPTR dst, const DSTRINGPTR src);
|
||||||
void scopys(DSTRINGPTR a, const char *b);
|
void scopys(DSTRINGPTR a, const char *b);
|
||||||
|
|
|
||||||
|
|
@ -123,21 +123,26 @@ scopys(DSTRINGPTR s, const char *t) /* returns success flag */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Copy until stop char (exclusive) or end of string if none given */
|
/* Concatentate until stop char (exclusive) or end of string if none given */
|
||||||
|
|
||||||
void
|
void
|
||||||
pscopy(DSTRINGPTR dstr_p, const char *t, const char *stop)
|
pscat(DSTRINGPTR dstr_p, const char *t, const char *stop)
|
||||||
{
|
{
|
||||||
if (!stop) { /* locate end of string if no stop char given */
|
if (!stop) { /* locate end of string if no stop char given */
|
||||||
stop = strchr(t, '\0');
|
stop = strchr(t, '\0');
|
||||||
}
|
}
|
||||||
|
|
||||||
ds_clear(dstr_p);
|
|
||||||
if (ds_cat_mem(dstr_p, t, (size_t) (stop - t)) != DS_E_OK) {
|
if (ds_cat_mem(dstr_p, t, (size_t) (stop - t)) != DS_E_OK) {
|
||||||
fprintf(stderr, "Error: DS could not copy partially string %s\n", t);
|
fprintf(stderr, "Error: DS could not copy partially string %s\n", t);
|
||||||
controlled_exit(-1);
|
controlled_exit(-1);
|
||||||
}
|
}
|
||||||
|
} /* end of function pscat */
|
||||||
|
|
||||||
return;
|
/* Copy until stop char (exclusive) or end of string if none given */
|
||||||
|
void
|
||||||
|
pscopy(DSTRINGPTR dstr_p, const char *t, const char *stop)
|
||||||
|
{
|
||||||
|
ds_clear(dstr_p);
|
||||||
|
pscat(dstr_p, t, stop);
|
||||||
} /* end of function pscopy */
|
} /* end of function pscopy */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,9 @@ extern int nupa_eval(struct card *card);
|
||||||
extern void nupa_signal(int sig);
|
extern void nupa_signal(int sig);
|
||||||
extern void nupa_scan(const struct card *card);
|
extern void nupa_scan(const struct card *card);
|
||||||
extern void nupa_list_params(FILE *cp_out);
|
extern void nupa_list_params(FILE *cp_out);
|
||||||
extern double nupa_get_param(char *param_name, int *found);
|
extern double nupa_get_param(const char *param_name, int *found);
|
||||||
|
extern const char *nupa_get_string_param(const char *param_name);
|
||||||
extern void nupa_add_param(char *param_name, double value);
|
extern void nupa_add_param(char *param_name, double value);
|
||||||
extern void nupa_add_inst_param(char *param_name, double value);
|
|
||||||
extern void nupa_copy_inst_dico(void);
|
extern void nupa_copy_inst_dico(void);
|
||||||
extern void nupa_del_dicoS(void);
|
extern void nupa_del_dicoS(void);
|
||||||
extern int nupa_add_dicoslist(void);
|
extern int nupa_add_dicoslist(void);
|
||||||
|
|
|
||||||
|
|
@ -68,3 +68,4 @@ void nupa_subcktexit(dico_t *);
|
||||||
entry_t *entrynb(dico_t *dico, char *s);
|
entry_t *entrynb(dico_t *dico, char *s);
|
||||||
entry_t *attrib(dico_t *, NGHASHPTR htable, char *t, char op);
|
entry_t *attrib(dico_t *, NGHASHPTR htable, char *t, char op);
|
||||||
void del_attrib(void *);
|
void del_attrib(void *);
|
||||||
|
void nupa_copy_inst_entry(char *param_name, entry_t *proto);
|
||||||
|
|
|
||||||
|
|
@ -415,6 +415,9 @@ dump_symbol_table(NGHASHPTR htable_p, FILE *fp)
|
||||||
{
|
{
|
||||||
if (entry->tp == NUPA_REAL)
|
if (entry->tp == NUPA_REAL)
|
||||||
fprintf(fp, " ---> %s = %g\n", entry->symbol, entry->vl);
|
fprintf(fp, " ---> %s = %g\n", entry->symbol, entry->vl);
|
||||||
|
else if (entry->tp == NUPA_STRING)
|
||||||
|
fprintf(fp, " ---> %s = \"%s\"\n",
|
||||||
|
entry->symbol, entry->sbbase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -456,8 +459,7 @@ nupa_list_params(FILE *fp)
|
||||||
* Otherwise, we have to exhaust all of the tables including the global
|
* Otherwise, we have to exhaust all of the tables including the global
|
||||||
* table.
|
* table.
|
||||||
* ----------------------------------------------------------------- */
|
* ----------------------------------------------------------------- */
|
||||||
double
|
static entry_t *nupa_get_entry(const char *param_name)
|
||||||
nupa_get_param(char *param_name, int *found)
|
|
||||||
{
|
{
|
||||||
dico_t *dico = dicoS; /* local copy for speed */
|
dico_t *dico = dicoS; /* local copy for speed */
|
||||||
int depth; /* nested subcircit depth */
|
int depth; /* nested subcircit depth */
|
||||||
|
|
@ -465,21 +467,40 @@ nupa_get_param(char *param_name, int *found)
|
||||||
for (depth = dico->stack_depth; depth >= 0; depth--) {
|
for (depth = dico->stack_depth; depth >= 0; depth--) {
|
||||||
NGHASHPTR htable_p = dico->symbols[depth];
|
NGHASHPTR htable_p = dico->symbols[depth];
|
||||||
if (htable_p) {
|
if (htable_p) {
|
||||||
entry_t *entry = (entry_t *) nghash_find(htable_p, param_name);
|
entry_t *entry;
|
||||||
if (entry) {
|
|
||||||
*found = 1;
|
entry = (entry_t *)nghash_find(htable_p, (void *)param_name);
|
||||||
return entry->vl;
|
if (entry)
|
||||||
}
|
return entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
double
|
||||||
|
nupa_get_param(const char *param_name, int *found)
|
||||||
|
{
|
||||||
|
entry_t *entry = nupa_get_entry(param_name);
|
||||||
|
if (entry && entry->tp == NUPA_REAL) {
|
||||||
|
*found = 1;
|
||||||
|
return entry->vl;
|
||||||
|
}
|
||||||
*found = 0;
|
*found = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
nupa_get_string_param(const char *param_name)
|
||||||
|
{
|
||||||
|
entry_t *entry = nupa_get_entry(param_name);
|
||||||
|
if (entry && entry->tp == NUPA_STRING)
|
||||||
|
return entry->sbbase;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
|
||||||
nupa_add_param(char *param_name, double value)
|
static void
|
||||||
|
nupa_copy_entry(entry_t *proto)
|
||||||
{
|
{
|
||||||
dico_t *dico = dicoS; /* local copy for speed */
|
dico_t *dico = dicoS; /* local copy for speed */
|
||||||
entry_t *entry; /* current entry */
|
entry_t *entry; /* current entry */
|
||||||
|
|
@ -491,18 +512,32 @@ nupa_add_param(char *param_name, double value)
|
||||||
|
|
||||||
htable_p = dico->symbols[dico->stack_depth];
|
htable_p = dico->symbols[dico->stack_depth];
|
||||||
|
|
||||||
entry = attrib(dico, htable_p, param_name, 'N');
|
entry = attrib(dico, htable_p, proto->symbol, 'N');
|
||||||
if (entry) {
|
if (entry) {
|
||||||
entry->vl = value;
|
entry->vl = proto->vl;
|
||||||
entry->tp = NUPA_REAL;
|
entry->tp = proto->tp;
|
||||||
entry->ivl = 0;
|
entry->ivl = proto->ivl;
|
||||||
entry->sbbase = NULL;
|
entry->sbbase = proto->sbbase;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
nupa_add_inst_param(char *param_name, double value)
|
nupa_add_param(char *param_name, double value)
|
||||||
|
{
|
||||||
|
entry_t entry;
|
||||||
|
|
||||||
|
entry.symbol = param_name;
|
||||||
|
entry.vl = value;
|
||||||
|
entry.tp = NUPA_REAL;
|
||||||
|
entry.ivl = 0;
|
||||||
|
entry.sbbase = NULL;
|
||||||
|
nupa_copy_entry(&entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
nupa_copy_inst_entry(char *param_name, entry_t *proto)
|
||||||
{
|
{
|
||||||
dico_t *dico = dicoS; /* local copy for speed */
|
dico_t *dico = dicoS; /* local copy for speed */
|
||||||
entry_t *entry; /* current entry */
|
entry_t *entry; /* current entry */
|
||||||
|
|
@ -512,10 +547,10 @@ nupa_add_inst_param(char *param_name, double value)
|
||||||
|
|
||||||
entry = attrib(dico, dico->inst_symbols, param_name, 'N');
|
entry = attrib(dico, dico->inst_symbols, param_name, 'N');
|
||||||
if (entry) {
|
if (entry) {
|
||||||
entry->vl = value;
|
entry->vl = proto->vl;
|
||||||
entry->tp = NUPA_REAL;
|
entry->tp = proto->tp;
|
||||||
entry->ivl = 0;
|
entry->ivl = proto->ivl;
|
||||||
entry->sbbase = NULL;
|
entry->sbbase = proto->sbbase;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -542,7 +577,7 @@ nupa_copy_inst_dico(void)
|
||||||
entry;
|
entry;
|
||||||
entry = (entry_t *) nghash_enumerateRE(dico->inst_symbols, &iter))
|
entry = (entry_t *) nghash_enumerateRE(dico->inst_symbols, &iter))
|
||||||
{
|
{
|
||||||
nupa_add_param(entry->symbol, entry->vl);
|
nupa_copy_entry(entry);
|
||||||
dico_free_entry(entry);
|
dico_free_entry(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -232,7 +232,6 @@ message(dico_t *dico, const char *fmt, ...)
|
||||||
dico->oldline);
|
dico->oldline);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
vfprintf(stderr, fmt, ap);
|
vfprintf(stderr, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
@ -275,7 +274,6 @@ dico_free_entry(entry_t *entry)
|
||||||
{
|
{
|
||||||
if (entry->symbol)
|
if (entry->symbol)
|
||||||
txfree(entry->symbol);
|
txfree(entry->symbol);
|
||||||
|
|
||||||
txfree(entry);
|
txfree(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -339,7 +337,7 @@ dicostack_pop(dico_t *dico)
|
||||||
fprintf(stderr, "Error: DS could not add string %s\n", inst_name);
|
fprintf(stderr, "Error: DS could not add string %s\n", inst_name);
|
||||||
controlled_exit(-1);
|
controlled_exit(-1);
|
||||||
}
|
}
|
||||||
nupa_add_inst_param(ds_get_buf(¶m_name), entry->vl);
|
nupa_copy_inst_entry(ds_get_buf(¶m_name), entry);
|
||||||
dico_free_entry(entry);
|
dico_free_entry(entry);
|
||||||
}
|
}
|
||||||
nghash_free(htable_p, NULL, NULL);
|
nghash_free(htable_p, NULL, NULL);
|
||||||
|
|
@ -440,6 +438,8 @@ del_attrib(void *entry_p)
|
||||||
entry_t *entry = (entry_t*) entry_p;
|
entry_t *entry = (entry_t*) entry_p;
|
||||||
if(entry) {
|
if(entry) {
|
||||||
tfree(entry->symbol);
|
tfree(entry->symbol);
|
||||||
|
if (entry->sbbase)
|
||||||
|
tfree(entry->sbbase);
|
||||||
tfree(entry);
|
tfree(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1085,6 +1085,79 @@ formula(dico_t *dico, const char *s, const char *s_end, bool *perror)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Check for a string expression, return end pointer or NULL.
|
||||||
|
* A string expression is a sequence of quoted strings and string
|
||||||
|
* variables, optionally enclosed by '{}' with no interventing space.
|
||||||
|
* If successful return pointer to next char, otherwise NULL.
|
||||||
|
* Evaluated string is returned in *qstr_p (may be NULL).
|
||||||
|
*/
|
||||||
|
|
||||||
|
static char *string_expr(dico_t *dico, DSTRINGPTR qstr_p,
|
||||||
|
const char *t, const char *t_end)
|
||||||
|
{
|
||||||
|
const char *tie;
|
||||||
|
bool ok = FALSE;
|
||||||
|
|
||||||
|
while (isblank(*t) && t < t_end)
|
||||||
|
++t;
|
||||||
|
if (qstr_p)
|
||||||
|
ds_clear(qstr_p);
|
||||||
|
for (; t < t_end; ) {
|
||||||
|
if (*t == '"') {
|
||||||
|
/* String constant. */
|
||||||
|
|
||||||
|
tie = ++t;
|
||||||
|
while (*t != '"' && t < t_end)
|
||||||
|
++t;
|
||||||
|
if (qstr_p)
|
||||||
|
pscat(qstr_p, tie, t);
|
||||||
|
if (*t == '"')
|
||||||
|
++t;
|
||||||
|
ok = TRUE;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (*t == '{') {
|
||||||
|
/* Isolate and check wrapped identifier. */
|
||||||
|
|
||||||
|
tie = ++t;
|
||||||
|
while (t < t_end) {
|
||||||
|
if (*t == '}')
|
||||||
|
break;
|
||||||
|
++t;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Last option: naked string-valued param. */
|
||||||
|
|
||||||
|
tie = t;
|
||||||
|
t = fetchid(t, t_end);
|
||||||
|
if (t == tie )
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* Now pointers tie, t should bracket an identifier. */
|
||||||
|
|
||||||
|
{
|
||||||
|
DS_CREATE(lcl_str, 200);
|
||||||
|
entry_t *entry;
|
||||||
|
|
||||||
|
/* Formula is a single identifier. */
|
||||||
|
|
||||||
|
pscopy(&lcl_str, tie, t);
|
||||||
|
entry = entrynb(dico, ds_get_buf(&lcl_str));
|
||||||
|
ds_free(&lcl_str);
|
||||||
|
if (entry && (entry->tp == NUPA_STRING)) {
|
||||||
|
if (qstr_p)
|
||||||
|
pscat(qstr_p, entry->sbbase, NULL);
|
||||||
|
ok = TRUE;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (*t == '}')
|
||||||
|
++t;
|
||||||
|
}
|
||||||
|
return ok ? (char *)t : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* stupid, produce a string representation of a given double
|
/* stupid, produce a string representation of a given double
|
||||||
* to be spliced back into the circuit deck
|
* to be spliced back into the circuit deck
|
||||||
* we want *exactly* 25 chars, we have
|
* we want *exactly* 25 chars, we have
|
||||||
|
|
@ -1113,7 +1186,8 @@ evaluate_expr(dico_t *dico, DSTRINGPTR qstr_p, const char *t, const char * const
|
||||||
double u;
|
double u;
|
||||||
|
|
||||||
ds_clear(qstr_p);
|
ds_clear(qstr_p);
|
||||||
|
if (string_expr(dico, qstr_p, t, t_end))
|
||||||
|
return 0;
|
||||||
u = formula(dico, t, t_end, &err);
|
u = formula(dico, t, t_end, &err);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -1247,38 +1321,31 @@ getword(const char *s, DSTRINGPTR tstr_p)
|
||||||
|
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
getexpress(nupa_type *type, DSTRINGPTR tstr_p, const char *s)
|
getexpress(dico_t *dico, nupa_type *type, DSTRINGPTR tstr_p, const char *s)
|
||||||
/* returns expression-like string until next separator
|
/* returns expression-like string until next separator
|
||||||
Input i=position before expr, output i=just after expr, on separator.
|
Input i=position before expr, output i=just after expr, on separator.
|
||||||
returns tpe=='R' if (numeric, 'S' if (string only
|
returns tpe=='R' if (numeric, 'S' if (string only
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
const char * const s_end = s + strlen(s);
|
const char *s_end = s + strlen(s);
|
||||||
const char *p;
|
const char *p;
|
||||||
nupa_type tpe;
|
nupa_type tpe;
|
||||||
|
|
||||||
while ((s < s_end - 1) && ((unsigned char)(* s) <= ' '))
|
while ((s < s_end - 1) && ((unsigned char)(* s) <= ' '))
|
||||||
s++; /*white space ? */
|
s++; /*white space ? */
|
||||||
|
|
||||||
if (*s == '"') { /* string constant */
|
/* Check for injected semicolon separator in assignment list. */
|
||||||
|
p = strchr(s, ';');
|
||||||
s++;
|
if (p)
|
||||||
p = s;
|
s_end = p;
|
||||||
|
|
||||||
while ((p < s_end - 1) && (*p != '"'))
|
|
||||||
p++;
|
|
||||||
|
|
||||||
do
|
|
||||||
p++;
|
|
||||||
while ((p < s_end) && ((unsigned char)(*p) <= ' '));
|
|
||||||
|
|
||||||
|
p = string_expr(dico, NULL, s, s_end);
|
||||||
|
if (p) {
|
||||||
tpe = NUPA_STRING;
|
tpe = NUPA_STRING;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (*s == '{')
|
if (*s == '{')
|
||||||
s++;
|
s++;
|
||||||
|
|
||||||
p = s;
|
p = s;
|
||||||
|
|
||||||
for (; p < s_end; p++) {
|
for (; p < s_end; p++) {
|
||||||
|
|
@ -1304,7 +1371,6 @@ getexpress(nupa_type *type, DSTRINGPTR tstr_p, const char *s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tpe = NUPA_REAL;
|
tpe = NUPA_REAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1313,9 +1379,6 @@ getexpress(nupa_type *type, DSTRINGPTR tstr_p, const char *s)
|
||||||
if (*p == '}')
|
if (*p == '}')
|
||||||
p++;
|
p++;
|
||||||
|
|
||||||
if (tpe == NUPA_STRING)
|
|
||||||
p++; /* beyond quote */
|
|
||||||
|
|
||||||
if (type)
|
if (type)
|
||||||
*type = tpe;
|
*type = tpe;
|
||||||
|
|
||||||
|
|
@ -1334,7 +1397,8 @@ nupa_assignment(dico_t *dico, const char *s, char mode)
|
||||||
/* s has the format: ident = expression; ident= expression ... */
|
/* s has the format: ident = expression; ident= expression ... */
|
||||||
const char * const s_end = s + strlen(s);
|
const char * const s_end = s + strlen(s);
|
||||||
const char *p = s;
|
const char *p = s;
|
||||||
|
const char *tmp;
|
||||||
|
char *sval = NULL;
|
||||||
bool error = 0;
|
bool error = 0;
|
||||||
nupa_type dtype;
|
nupa_type dtype;
|
||||||
int wval = 0;
|
int wval = 0;
|
||||||
|
|
@ -1369,23 +1433,26 @@ nupa_assignment(dico_t *dico, const char *s, char mode)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = getexpress(&dtype, &ustr, p + 1) + 1;
|
p = getexpress(dico, &dtype, &ustr, p + 1) + 1;
|
||||||
|
|
||||||
|
tmp = ds_get_buf(&ustr);
|
||||||
if (dtype == NUPA_REAL) {
|
if (dtype == NUPA_REAL) {
|
||||||
const char *tmp = ds_get_buf(&ustr);
|
|
||||||
rval = formula(dico, tmp, tmp + strlen(tmp), &error);
|
rval = formula(dico, tmp, tmp + strlen(tmp), &error);
|
||||||
if (error) {
|
if (error) {
|
||||||
message(dico,
|
message(dico,
|
||||||
" Formula() error.\n"
|
" Formula() error.\n"
|
||||||
" %s\n", s);
|
" |%s| : |%s|=|%s|\n", s, ds_get_buf(&tstr), ds_get_buf(&ustr));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (dtype == NUPA_STRING) {
|
} else if (dtype == NUPA_STRING) {
|
||||||
wval = (int) (p - s);
|
DS_CREATE(sstr, 200);
|
||||||
|
string_expr(dico, &sstr, tmp, tmp + strlen(tmp));
|
||||||
|
sval = copy(ds_get_buf(&sstr));
|
||||||
|
ds_free(&sstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
error = nupa_define(dico, ds_get_buf(&tstr), mode /* was ' ' */ ,
|
error = nupa_define(dico, ds_get_buf(&tstr), mode /* was ' ' */ ,
|
||||||
dtype, rval, wval, NULL);
|
dtype, rval, wval, sval);
|
||||||
if (error)
|
if (error)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -1445,9 +1512,10 @@ nupa_subcktcall(dico_t *dico, const char *s, const char *x,
|
||||||
|
|
||||||
/***** first, analyze the subckt definition line */
|
/***** first, analyze the subckt definition line */
|
||||||
n = 0; /* number of parameters if any */
|
n = 0; /* number of parameters if any */
|
||||||
|
|
||||||
scopys(&tstr, s);
|
scopys(&tstr, s);
|
||||||
|
|
||||||
|
/* Get the subcircuit name in subname. */
|
||||||
|
|
||||||
const char *j2 = strstr(ds_get_buf(&tstr), "subckt");
|
const char *j2 = strstr(ds_get_buf(&tstr), "subckt");
|
||||||
if (j2) {
|
if (j2) {
|
||||||
j2 = skip_ws(j2 + 6); /* skip subckt and whitespace */
|
j2 = skip_ws(j2 + 6); /* skip subckt and whitespace */
|
||||||
|
|
@ -1456,6 +1524,8 @@ nupa_subcktcall(dico_t *dico, const char *s, const char *x,
|
||||||
err = message(dico, " ! a subckt line!\n");
|
err = message(dico, " ! a subckt line!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Scan the .subckt line for assignments, copying templates to idlist. */
|
||||||
|
|
||||||
const char *i2 = strstr(ds_get_buf(&tstr), "params:");
|
const char *i2 = strstr(ds_get_buf(&tstr), "params:");
|
||||||
|
|
||||||
if (i2) {
|
if (i2) {
|
||||||
|
|
@ -1510,7 +1580,7 @@ nupa_subcktcall(dico_t *dico, const char *s, const char *x,
|
||||||
char * const t_p = ds_get_buf(&tstr);
|
char * const t_p = ds_get_buf(&tstr);
|
||||||
char *jp = NULL;
|
char *jp = NULL;
|
||||||
|
|
||||||
/* search for the last occurence of `subname' in the given line */
|
/* Search for the last occurence of `subname' in the call line. */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
char *next_p = search_isolated_identifier(jp ? jp + 1 : t_p,
|
char *next_p = search_isolated_identifier(jp ? jp + 1 : t_p,
|
||||||
ds_get_buf(&subname));
|
ds_get_buf(&subname));
|
||||||
|
|
@ -1528,7 +1598,6 @@ nupa_subcktcall(dico_t *dico, const char *s, const char *x,
|
||||||
/* jp is pointing to the 1st position of arglist now */
|
/* jp is pointing to the 1st position of arglist now */
|
||||||
|
|
||||||
while (*jp) {
|
while (*jp) {
|
||||||
|
|
||||||
/* try to fetch valid arguments */
|
/* try to fetch valid arguments */
|
||||||
char *kp = jp;
|
char *kp = jp;
|
||||||
ds_clear(&ustr);
|
ds_clear(&ustr);
|
||||||
|
|
@ -1538,13 +1607,16 @@ nupa_subcktcall(dico_t *dico, const char *s, const char *x,
|
||||||
jp = skip_non_ws(kp);
|
jp = skip_non_ws(kp);
|
||||||
pscopy(&ustr, kp, jp);
|
pscopy(&ustr, kp, jp);
|
||||||
} else if (*kp == '{') {
|
} else if (*kp == '{') {
|
||||||
jp = getexpress(NULL, &ustr, jp);
|
jp = getexpress(dico, NULL, &ustr, jp);
|
||||||
} else {
|
} else {
|
||||||
jp++;
|
jp++;
|
||||||
if ((unsigned char) (*kp) > ' ')
|
if ((unsigned char) (*kp) > ' ')
|
||||||
message(dico, "Subckt call, symbol %c not understood\n", *kp);
|
message(dico, "Subckt call, symbol %c not understood\n", *kp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Substitute the parameter for one of the '$' characters
|
||||||
|
* in idlist.
|
||||||
|
*/
|
||||||
char * const u_p = ds_get_buf(&ustr);
|
char * const u_p = ds_get_buf(&ustr);
|
||||||
if (*u_p) {
|
if (*u_p) {
|
||||||
char * const idlist_p = ds_get_buf(&idlist);
|
char * const idlist_p = ds_get_buf(&idlist);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue