Add (enhanced) patch by Giles Atkinson

Add controlled_exit() to errors when parsing functions.
Add verbose error messages, including line number and
name of the source file.

.lib file handlinmg with its recursive structure probably needs
testing and improvements.

More error messages may need this update.
This commit is contained in:
Holger Vogt 2024-04-28 14:32:24 +02:00
parent 8d539aa9ba
commit 279fe0afcf
6 changed files with 87 additions and 46 deletions

View File

@ -583,7 +583,12 @@ static struct library *read_a_lib(const char *y, const char *dir_name)
lib->habitat = ngdirname(yy); lib->habitat = ngdirname(yy);
lib->deck = lib->deck =
inp_read(newfp, 1 /*dummy*/, lib->habitat, NULL, FALSE, FALSE).cc; inp_read(newfp, 1 /*dummy*/, lib->habitat, lib->realpath, FALSE, FALSE).cc;
struct card* tmpdeck;
int cnumber = 1;
for (tmpdeck = lib->deck; tmpdeck; tmpdeck = tmpdeck->nextcard)
tmpdeck->linenum_orig = cnumber++;
fclose(newfp); fclose(newfp);
} }
@ -1432,17 +1437,14 @@ static struct inp_read_t inp_read(FILE* fp, int call_depth, const char* dir_name
if (!y_resolved) { if (!y_resolved) {
fprintf(cp_err, "Error: Could not find include file %s\n", fprintf(cp_err, "Error: Could not find include file %s\n",
y); y);
if (ft_stricterror) controlled_exit(EXIT_FAILURE);
controlled_exit(EXIT_FAILURE);
rv.line_number = line_number;
rv.cc = NULL;
return rv;
} }
newfp = fopen(y_resolved, "r"); newfp = fopen(y_resolved, "r");
if (!newfp) { if (!newfp) {
fprintf(cp_err, "Error: .include statement failed.\n"); fprintf(cp_err, "Error: .include statement failed.\n"
"Could not open file\n%s\n", y_resolved);
tfree(buffer); /* allocated by readline() above */ tfree(buffer); /* allocated by readline() above */
controlled_exit(EXIT_FAILURE); controlled_exit(EXIT_FAILURE);
} }
@ -1465,8 +1467,12 @@ static struct inp_read_t inp_read(FILE* fp, int call_depth, const char* dir_name
/* append `buffer' to the (cc, end) chain of decks */ /* append `buffer' to the (cc, end) chain of decks */
{ {
end = insert_new_line( if (end)
end, copy(buffer), line_number, end->linenum_orig, end->linesource); end = insert_new_line(
end, copy(buffer), line_number, end->linenum_orig, end->linesource);
else
end = insert_new_line(
end, copy(buffer), line_number, 1, file_name);
if (!cc) if (!cc)
cc = end; cc = end;
@ -5868,8 +5874,10 @@ static void inp_compat(struct card *card)
&cut_line, '}', TRUE, TRUE); /* expression */ &cut_line, '}', TRUE, TRUE); /* expression */
if (!expression || !str_ptr) { if (!expression || !str_ptr) {
fprintf(stderr, fprintf(stderr,
"Error: bad syntax in line %d\n %s\n", "Error: bad syntax in line %d\n %s\n"
card->linenum_orig, card->line); "from file\n"
" %s\n",
card->linenum_orig, card->line, card->linesource);
controlled_exit(EXIT_BAD); controlled_exit(EXIT_BAD);
} }
tfree(str_ptr); tfree(str_ptr);
@ -6063,8 +6071,11 @@ static void inp_compat(struct card *card)
// skip "table" // skip "table"
cut_line = skip_ws(cut_line); cut_line = skip_ws(cut_line);
if (!ciprefix("table", cut_line)) { if (!ciprefix("table", cut_line)) {
fprintf(stderr, "Error: bad syntax in line %d\n %s\n", fprintf(stderr,
card->linenum_orig, card->line); "Error: bad syntax in line %d\n %s\n"
"from file\n"
" %s\n",
card->linenum_orig, card->line, card->linesource);
controlled_exit(EXIT_BAD); controlled_exit(EXIT_BAD);
} }
cut_line += 5; cut_line += 5;
@ -6075,8 +6086,11 @@ static void inp_compat(struct card *card)
str_ptr = gettok_char(&cut_line, '{', FALSE, FALSE); str_ptr = gettok_char(&cut_line, '{', FALSE, FALSE);
expression = gettok_char(&cut_line, '}', TRUE, TRUE); expression = gettok_char(&cut_line, '}', TRUE, TRUE);
if (!expression || !str_ptr) { if (!expression || !str_ptr) {
fprintf(stderr, "Error: bad syntax in line %d\n %s\n", fprintf(stderr,
card->linenum_orig, card->line); "Error: bad syntax in line %d\n %s\n"
"from file\n"
" %s\n",
card->linenum_orig, card->line, card->linesource);
controlled_exit(EXIT_BAD); controlled_exit(EXIT_BAD);
} }
tfree(str_ptr); tfree(str_ptr);

View File

@ -1369,7 +1369,11 @@ struct card *pspice_compat(struct card *oldcard)
for (i = 0; i < 6; i++) { for (i = 0; i < 6; i++) {
stoks[i] = gettok_node(&cut_line); stoks[i] = gettok_node(&cut_line);
if (!stoks[i]) { if (!stoks[i]) {
fprintf(stderr, "Error: Bad syntax in line:\n %s\n", card->line); fprintf(stderr,
"Error: bad syntax in line %d\n %s\n"
"from file\n"
" %s\n",
card->linenum_orig, card->line, card->linesource);
good = FALSE; good = FALSE;
break; break;
} }

View File

@ -97,7 +97,9 @@ struct INPmodel {
GENmodel *INPmodfast; /* high speed pointer to model for access */ GENmodel *INPmodfast; /* high speed pointer to model for access */
}; };
// Ugly way to pass line onfo (number and source file) to lower-level error handlers.
extern int Current_parse_line;
extern char* Sourcefile;
/* listing types - used for debug listings */ /* listing types - used for debug listings */
#define LOGICAL 1 #define LOGICAL 1

View File

@ -16,6 +16,9 @@ Author: 1985 Thomas L. Quarles
/* gtri - end - wbk - 11/9/90 */ /* gtri - end - wbk - 11/9/90 */
#endif #endif
// Ugly way to pass line info (number and source file) to lower-level error handlers.
int Current_parse_line;
char* Sourcefile;
/* uncomment to trace in this file */ /* uncomment to trace in this file */
/*#define TRACE*/ /*#define TRACE*/
@ -41,10 +44,6 @@ void INPpas2(CKTcircuit *ckt, struct card *data, INPtables * tab, TSKtask *task)
printf("Entered INPpas2 . . . .\n"); printf("Entered INPpas2 . . . .\n");
#endif #endif
#ifdef XSPICE
if (!ckt->CKTadevFlag) ckt->CKTadevFlag = 0;
#endif
error = INPgetTok(&groundname, &gname, 1); error = INPgetTok(&groundname, &gname, 1);
if (error) if (error)
data->error = data->error =
@ -81,12 +80,16 @@ void INPpas2(CKTcircuit *ckt, struct card *data, INPtables * tab, TSKtask *task)
#endif #endif
#ifdef HAS_PROGREP #ifdef HAS_PROGREP
if (linecount > 0) { if (linecount > 0) {
SetAnalyse( "Parse", (int) (1000.*actcount/linecount)); SetAnalyse( "Parse", (int) (1000.*actcount/linecount));
actcount++; actcount++;
} }
#endif #endif
Current_parse_line =
current->linenum_orig ? current->linenum_orig : current->linenum;
Sourcefile = current->linesource;
c = *(current->line); c = *(current->line);
if(islower_c(c)) if(islower_c(c))
c = toupper_c(c); c = toupper_c(c);

View File

@ -5,6 +5,7 @@
#include "ngspice/ngspice.h" #include "ngspice/ngspice.h"
#include "ngspice/inpptree.h" #include "ngspice/inpptree.h"
#include "ngspice/inpdefs.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -143,5 +144,11 @@ PTerror (YYLTYPE *locp, char **line, struct INPparseNode **retval, void *ckt, ch
NG_IGNORE(retval); NG_IGNORE(retval);
NG_IGNORE(ckt); NG_IGNORE(ckt);
fprintf (stderr, "\n%s: %s, parsing stopped at\n %s\n\n", __func__, s, locp->start); fprintf (stderr,
"\nYYparse error, %s, in expression: parsing stopped at line %d"
"\n %s in %s\n"
"\nfrom file"
" %s\n\n",
s, Current_parse_line, locp->start, *line, Sourcefile);
controlled_exit(EXIT_BAD); // Unsafe to continue.
} }

View File

@ -1029,7 +1029,8 @@ static INPparseNode *prepare_PTF_PWL(INPparseNode *p)
int i; int i;
if (p->funcnum != PTF_PWL) { if (p->funcnum != PTF_PWL) {
fprintf(stderr, "PWL-INFO: %s, very unexpected\n", __func__); fprintf(stderr, "PWL-INFO: %s, very unexpected at line %d\nfrom file\n %s\n\n",
__func__, Current_parse_line, Sourcefile);
controlled_exit(EXIT_BAD); controlled_exit(EXIT_BAD);
} }
@ -1041,7 +1042,10 @@ static INPparseNode *prepare_PTF_PWL(INPparseNode *p)
i++; i++;
if (i<2 || (i%1)) { if (i<2 || (i%1)) {
fprintf(stderr, "Error: PWL(expr, points...) needs an even and >=2 number of constant args\n"); fprintf(stderr,
"Error: PWL(expr, points...) needs an even and >=2 number "
"of constant args at line %d\nfrom file\n %s\n\n",
Current_parse_line, Sourcefile);
controlled_exit(EXIT_BAD); controlled_exit(EXIT_BAD);
} }
@ -1060,10 +1064,13 @@ static INPparseNode *prepare_PTF_PWL(INPparseNode *p)
w->right->left->type == PT_CONSTANT) { w->right->left->type == PT_CONSTANT) {
data->vals[i] = - w->right->left->constant; data->vals[i] = - w->right->left->constant;
} else { } else {
fprintf(stderr, "PWL-ERROR: %s, not a constant\n", __func__); fprintf(stderr,
fprintf(stderr, " type = %d\n", w->right->type); "Error: PWL(expr, points...) only *literal* points "
fprintf(stderr, "Error: PWL(expr, points...) only *literal* points are supported\n"); "are supported at line %d\nfrom file\n %s\n",
controlled_exit(EXIT_BAD); Current_parse_line, Sourcefile);
// In case #671, "Crash when loading an Infineon model: IR4427S",
// a crash occurred after this error. There can be no recovery.
controlled_exit(EXIT_BAD);
} }
#ifdef TRACE #ifdef TRACE
@ -1073,7 +1080,9 @@ static INPparseNode *prepare_PTF_PWL(INPparseNode *p)
for (i = 2 ; i < data->n ; i += 2) for (i = 2 ; i < data->n ; i += 2)
if(data->vals[i-2] >= data->vals[i]) { if(data->vals[i-2] >= data->vals[i]) {
fprintf(stderr, "Error: PWL(expr, points...) the abscissa of points must be ascending\n"); fprintf(stderr,
"Error: PWL(expr, points...) the abscissa of points "
"must be ascending at line %d\nfrom file\n %s\n", Current_parse_line, Sourcefile);
controlled_exit(EXIT_BAD); controlled_exit(EXIT_BAD);
} }
@ -1110,13 +1119,15 @@ INPparseNode *PT_mkfnode(const char *fname, INPparseNode * arg)
char buf[128]; char buf[128];
if (!fname) { if (!fname) {
fprintf(stderr, "Error: bogus function name \n"); fprintf(stderr, "Error: bogus function name at line %d\nfrom file\n %s\n",
return mkfirst(NULL, arg); Current_parse_line, Sourcefile);
controlled_exit(EXIT_BAD);
} }
if (!arg) { if (!arg) {
fprintf(stderr, "Error: bad function arguments \n"); fprintf(stderr, "Error: bad function arguments at line %d\nfrom file\n %s\n",
return mkfirst(NULL, arg); Current_parse_line, Sourcefile);
controlled_exit(EXIT_BAD);
} }
/* Make sure the case is ok. */ /* Make sure the case is ok. */
@ -1143,8 +1154,9 @@ INPparseNode *PT_mkfnode(const char *fname, INPparseNode * arg)
return mkfirst(p, arg); return mkfirst(p, arg);
} }
fprintf(stderr, "Error: bogus ternary_fcn form\n"); fprintf(stderr, "Error: bogus ternary_fcn form at line %d\nfrom file\n %s\n",
return mkfirst(NULL, arg); Current_parse_line, Sourcefile);
controlled_exit(EXIT_BAD);
} }
/* This is used only to evaluate fcn gauss(a1, a2, a3) in .model files, where /* This is used only to evaluate fcn gauss(a1, a2, a3) in .model files, where
@ -1160,8 +1172,9 @@ INPparseNode *PT_mkfnode(const char *fname, INPparseNode * arg)
double a3 = arg3->constant; double a3 = arg3->constant;
if (a2 == 0.0 || a3 == 0.0) { if (a2 == 0.0 || a3 == 0.0) {
fprintf(stderr, "Error: bogus gauss form\n"); fprintf(stderr, "Error: bogus gauss form at line %d\nfrom file\n %s\n",
return mkfirst(NULL, arg); //return mkcon(a1); Current_parse_line, Sourcefile);
controlled_exit(EXIT_BAD);
} }
return mkcon(gauss(a1, a2, a3)); return mkcon(gauss(a1, a2, a3));
@ -1176,10 +1189,9 @@ INPparseNode *PT_mkfnode(const char *fname, INPparseNode * arg)
break; break;
if (i == NUM_FUNCS) { if (i == NUM_FUNCS) {
fprintf(stderr, "Error: no such function '%s'\n", buf); fprintf(stderr, "Error: no such function '%s' at line %d\nfrom file\n %s\n",
if (ft_stricterror) buf, Current_parse_line, Sourcefile);
controlled_exit(EXIT_BAD); controlled_exit(EXIT_BAD);
return mkfirst(NULL, arg);
} }
p = TMALLOC(INPparseNode, 1); p = TMALLOC(INPparseNode, 1);
@ -1196,10 +1208,9 @@ INPparseNode *PT_mkfnode(const char *fname, INPparseNode * arg)
if (p->funcnum == PTF_PWL) { if (p->funcnum == PTF_PWL) {
p = prepare_PTF_PWL(p); p = prepare_PTF_PWL(p);
if (p == NULL) { if (p == NULL) {
fprintf(stderr, "Error while parsing function '%s'\n", buf); fprintf(stderr, "Error while parsing function '%s' at line %d\nfrom file\n %s\n",
if (ft_stricterror) buf, Current_parse_line, Sourcefile);
controlled_exit(EXIT_BAD); controlled_exit(EXIT_BAD);
return mkfirst(NULL, arg);
} }
} }