From 279fe0afcf71e54e596446e3cc8235fb6f538201 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 28 Apr 2024 14:32:24 +0200 Subject: [PATCH] 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. --- src/frontend/inpcom.c | 44 ++++++++++++++------- src/frontend/inpcompat.c | 6 ++- src/include/ngspice/inpdefs.h | 4 +- src/spicelib/parser/inppas2.c | 13 +++--- src/spicelib/parser/inpptree-parser.y | 9 ++++- src/spicelib/parser/inpptree.c | 57 ++++++++++++++++----------- 6 files changed, 87 insertions(+), 46 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index a5c90a15c..fe3e296cb 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -583,7 +583,12 @@ static struct library *read_a_lib(const char *y, const char *dir_name) lib->habitat = ngdirname(yy); 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); } @@ -1432,17 +1437,14 @@ static struct inp_read_t inp_read(FILE* fp, int call_depth, const char* dir_name if (!y_resolved) { fprintf(cp_err, "Error: Could not find include file %s\n", y); - if (ft_stricterror) - controlled_exit(EXIT_FAILURE); - rv.line_number = line_number; - rv.cc = NULL; - return rv; + controlled_exit(EXIT_FAILURE); } newfp = fopen(y_resolved, "r"); 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 */ 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 */ { - end = insert_new_line( - end, copy(buffer), line_number, end->linenum_orig, end->linesource); + if (end) + 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) cc = end; @@ -5868,8 +5874,10 @@ static void inp_compat(struct card *card) &cut_line, '}', TRUE, TRUE); /* expression */ if (!expression || !str_ptr) { fprintf(stderr, - "Error: bad syntax in line %d\n %s\n", - 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); } tfree(str_ptr); @@ -6063,8 +6071,11 @@ static void inp_compat(struct card *card) // skip "table" cut_line = skip_ws(cut_line); if (!ciprefix("table", cut_line)) { - fprintf(stderr, "Error: bad syntax in line %d\n %s\n", - card->linenum_orig, 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); controlled_exit(EXIT_BAD); } cut_line += 5; @@ -6075,8 +6086,11 @@ static void inp_compat(struct card *card) str_ptr = gettok_char(&cut_line, '{', FALSE, FALSE); expression = gettok_char(&cut_line, '}', TRUE, TRUE); if (!expression || !str_ptr) { - fprintf(stderr, "Error: bad syntax in line %d\n %s\n", - card->linenum_orig, 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); controlled_exit(EXIT_BAD); } tfree(str_ptr); diff --git a/src/frontend/inpcompat.c b/src/frontend/inpcompat.c index 56d8b48ce..503d190d1 100644 --- a/src/frontend/inpcompat.c +++ b/src/frontend/inpcompat.c @@ -1369,7 +1369,11 @@ struct card *pspice_compat(struct card *oldcard) for (i = 0; i < 6; i++) { stoks[i] = gettok_node(&cut_line); 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; break; } diff --git a/src/include/ngspice/inpdefs.h b/src/include/ngspice/inpdefs.h index 18bc92ca4..36203bc11 100644 --- a/src/include/ngspice/inpdefs.h +++ b/src/include/ngspice/inpdefs.h @@ -97,7 +97,9 @@ struct INPmodel { 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 */ #define LOGICAL 1 diff --git a/src/spicelib/parser/inppas2.c b/src/spicelib/parser/inppas2.c index bfc4b060a..6cc1bfe6a 100644 --- a/src/spicelib/parser/inppas2.c +++ b/src/spicelib/parser/inppas2.c @@ -16,6 +16,9 @@ Author: 1985 Thomas L. Quarles /* gtri - end - wbk - 11/9/90 */ #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 */ /*#define TRACE*/ @@ -41,10 +44,6 @@ void INPpas2(CKTcircuit *ckt, struct card *data, INPtables * tab, TSKtask *task) printf("Entered INPpas2 . . . .\n"); #endif -#ifdef XSPICE - if (!ckt->CKTadevFlag) ckt->CKTadevFlag = 0; -#endif - error = INPgetTok(&groundname, &gname, 1); if (error) data->error = @@ -81,12 +80,16 @@ void INPpas2(CKTcircuit *ckt, struct card *data, INPtables * tab, TSKtask *task) #endif #ifdef HAS_PROGREP - if (linecount > 0) { + if (linecount > 0) { SetAnalyse( "Parse", (int) (1000.*actcount/linecount)); actcount++; } #endif + Current_parse_line = + current->linenum_orig ? current->linenum_orig : current->linenum; + Sourcefile = current->linesource; + c = *(current->line); if(islower_c(c)) c = toupper_c(c); diff --git a/src/spicelib/parser/inpptree-parser.y b/src/spicelib/parser/inpptree-parser.y index 1dde6a591..38e919a5b 100644 --- a/src/spicelib/parser/inpptree-parser.y +++ b/src/spicelib/parser/inpptree-parser.y @@ -5,6 +5,7 @@ #include "ngspice/ngspice.h" #include "ngspice/inpptree.h" + #include "ngspice/inpdefs.h" #include #include @@ -143,5 +144,11 @@ PTerror (YYLTYPE *locp, char **line, struct INPparseNode **retval, void *ckt, ch NG_IGNORE(retval); 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. } diff --git a/src/spicelib/parser/inpptree.c b/src/spicelib/parser/inpptree.c index de97c2468..bc1850154 100644 --- a/src/spicelib/parser/inpptree.c +++ b/src/spicelib/parser/inpptree.c @@ -1029,7 +1029,8 @@ static INPparseNode *prepare_PTF_PWL(INPparseNode *p) int i; 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); } @@ -1041,7 +1042,10 @@ static INPparseNode *prepare_PTF_PWL(INPparseNode *p) i++; 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); } @@ -1060,10 +1064,13 @@ static INPparseNode *prepare_PTF_PWL(INPparseNode *p) w->right->left->type == PT_CONSTANT) { data->vals[i] = - w->right->left->constant; } else { - fprintf(stderr, "PWL-ERROR: %s, not a constant\n", __func__); - fprintf(stderr, " type = %d\n", w->right->type); - fprintf(stderr, "Error: PWL(expr, points...) only *literal* points are supported\n"); - controlled_exit(EXIT_BAD); + fprintf(stderr, + "Error: PWL(expr, points...) only *literal* points " + "are supported at line %d\nfrom file\n %s\n", + 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 @@ -1073,7 +1080,9 @@ static INPparseNode *prepare_PTF_PWL(INPparseNode *p) for (i = 2 ; i < data->n ; i += 2) 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); } @@ -1110,13 +1119,15 @@ INPparseNode *PT_mkfnode(const char *fname, INPparseNode * arg) char buf[128]; if (!fname) { - fprintf(stderr, "Error: bogus function name \n"); - return mkfirst(NULL, arg); + fprintf(stderr, "Error: bogus function name at line %d\nfrom file\n %s\n", + Current_parse_line, Sourcefile); + controlled_exit(EXIT_BAD); } if (!arg) { - fprintf(stderr, "Error: bad function arguments \n"); - return mkfirst(NULL, arg); + fprintf(stderr, "Error: bad function arguments at line %d\nfrom file\n %s\n", + Current_parse_line, Sourcefile); + controlled_exit(EXIT_BAD); } /* Make sure the case is ok. */ @@ -1143,8 +1154,9 @@ INPparseNode *PT_mkfnode(const char *fname, INPparseNode * arg) return mkfirst(p, arg); } - fprintf(stderr, "Error: bogus ternary_fcn form\n"); - return mkfirst(NULL, arg); + fprintf(stderr, "Error: bogus ternary_fcn form at line %d\nfrom file\n %s\n", + Current_parse_line, Sourcefile); + controlled_exit(EXIT_BAD); } /* 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; if (a2 == 0.0 || a3 == 0.0) { - fprintf(stderr, "Error: bogus gauss form\n"); - return mkfirst(NULL, arg); //return mkcon(a1); + fprintf(stderr, "Error: bogus gauss form at line %d\nfrom file\n %s\n", + Current_parse_line, Sourcefile); + controlled_exit(EXIT_BAD); } return mkcon(gauss(a1, a2, a3)); @@ -1176,10 +1189,9 @@ INPparseNode *PT_mkfnode(const char *fname, INPparseNode * arg) break; if (i == NUM_FUNCS) { - fprintf(stderr, "Error: no such function '%s'\n", buf); - if (ft_stricterror) - controlled_exit(EXIT_BAD); - return mkfirst(NULL, arg); + fprintf(stderr, "Error: no such function '%s' at line %d\nfrom file\n %s\n", + buf, Current_parse_line, Sourcefile); + controlled_exit(EXIT_BAD); } p = TMALLOC(INPparseNode, 1); @@ -1196,10 +1208,9 @@ INPparseNode *PT_mkfnode(const char *fname, INPparseNode * arg) if (p->funcnum == PTF_PWL) { p = prepare_PTF_PWL(p); if (p == NULL) { - fprintf(stderr, "Error while parsing function '%s'\n", buf); - if (ft_stricterror) - controlled_exit(EXIT_BAD); - return mkfirst(NULL, arg); + fprintf(stderr, "Error while parsing function '%s' at line %d\nfrom file\n %s\n", + buf, Current_parse_line, Sourcefile); + controlled_exit(EXIT_BAD); } }