From b39e5d9507ae6f752466a5d1c3302d6fde05842f Mon Sep 17 00:00:00 2001 From: Jim Monte Date: Mon, 9 Dec 2019 19:09:39 -0500 Subject: [PATCH] Made checking for single-character words faster. The testing now also uses less memory and works for 8-bit characters, which would have previously caused buffer overruns. It is also more modular and has additional documentation. --- src/frontend/init.c | 11 ------ src/frontend/parser/lexical.c | 73 ++++++++++++++++++++++++++++------- src/include/ngspice/cpdefs.h | 5 --- 3 files changed, 60 insertions(+), 29 deletions(-) diff --git a/src/frontend/init.c b/src/frontend/init.c index fddb48679..5e963e585 100644 --- a/src/frontend/init.c +++ b/src/frontend/init.c @@ -12,10 +12,6 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group #include "variable.h" -char cp_chars[128]; /* used in fcn cp_lexer() from lexical.c */ - -static char *singlec = "<>;&"; - void cp_init(void) /* called from ft_cpinit() in cpitf.c. @@ -25,13 +21,6 @@ cp_init(void) cp_curin, cp_curout, cp_curerr (defined in streams.c) */ { - char *s; - - memset(cp_chars, 0, 128); - for (s = singlec; *s; s++) - /* break word to right or left of characters <>;&*/ - cp_chars[(int) *s] = (CPC_BRR | CPC_BRL); - cp_vset("history", CP_NUM, &cp_maxhistlength); cp_curin = stdin; diff --git a/src/frontend/parser/lexical.c b/src/frontend/parser/lexical.c index 32fae3767..e5ba348c6 100644 --- a/src/frontend/parser/lexical.c +++ b/src/frontend/parser/lexical.c @@ -7,6 +7,7 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group * Initial lexer. */ +#include "ngspice/defines.h" #include "ngspice/ngspice.h" #include "ngspice/cpdefs.h" @@ -44,6 +45,23 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group #include "ngspice/fteinput.h" #include "lexical.h" +/** Constants related to characters that form their own words. + ** These expressions will be resolved at compile time */ +#define ID_SOLO_CHAR 1 /* Identifier for special chars */ + +/* Largest of the special chars */ +#define MAX_SOLO_CHAR1 ('<' > '>' ? '<' : '>') +#define MAX_SOLO_CHAR2 (MAX_SOLO_CHAR1 > ';' ? MAX_SOLO_CHAR1 : ';') +#define MAX_SOLO_CHAR (MAX_SOLO_CHAR2 > '&' ? MAX_SOLO_CHAR2 : '&') + +/* Smallest of the special chars */ +#define MIN_SOLO_CHAR1 ('<' < '>' ? '<' : '>') +#define MIN_SOLO_CHAR2 (MIN_SOLO_CHAR1 < ';' ? MIN_SOLO_CHAR1 : ';') +#define MIN_SOLO_CHAR (MIN_SOLO_CHAR2 < '&' ? MIN_SOLO_CHAR2 : '&') + +/* Largest index of solo char array */ +#define MAX_INDEX_SOLO_CHAR (MAX_SOLO_CHAR - MIN_SOLO_CHAR) + static void prompt(void); extern bool cp_echo; /* For CDHW patches: defined in variable.c */ @@ -370,19 +388,48 @@ nloop: goto ldefault; default: - /* We have to remember the special case $< - * here - */ - ldefault: - if ((cp_chars[c] & CPC_BRL) && (buf.i > 0)) - if ((c != '<') || (buf.s[buf.i - 1] != '$')) - newword; - push(&buf, c); - if (cp_chars[c] & CPC_BRR) - if ((c != '<') || (buf.i < 2) || (buf.s[buf.i - 2] != '$')) - newword; - } - } + /* $< is a special case where the '<' is not treated + * as a character forming its own word */ + ldefault: { + /* Lookup table for "solo" chars forming their own word */ + static const char id_solo_chars[MAX_INDEX_SOLO_CHAR + 1] = { + ['<' - MIN_SOLO_CHAR] = ID_SOLO_CHAR, + ['>' - MIN_SOLO_CHAR] = ID_SOLO_CHAR, + [';' - MIN_SOLO_CHAR] = ID_SOLO_CHAR, + ['&' - MIN_SOLO_CHAR] = ID_SOLO_CHAR + }; + + /* Find index into solo chars table */ + const unsigned int index_char = + (unsigned int) c - (unsigned int) MIN_SOLO_CHAR; + + /* Flag that the current character c is a solo character */ + const bool f_solo_char = index_char <= MAX_INDEX_SOLO_CHAR && + id_solo_chars[index_char]; + bool f_is_dollar_lt = FALSE; + + if (f_solo_char && buf.i > 0) { + /* The current char is a character forming its own word, + * unless it is "$<" */ + if (c == '<' && buf.s[buf.i - 1] == '$') { /* is "$<" */ + f_is_dollar_lt = TRUE; /* set flag that "$<" found */ + } + else { + /* not "$<", so terminate current word and start + * another one */ + newword; + } + } + + push(&buf, c); /* Add the current char to the current word */ + + if (f_solo_char && !f_is_dollar_lt) { + /* Split into a new word if this char forms its own word */ + newword; + } + } /* end of ldefault block */ + } /* end of switch over character value */ + } /* end of loop over characters */ done: if (wlist->wl_word) diff --git a/src/include/ngspice/cpdefs.h b/src/include/ngspice/cpdefs.h index 00ba6908e..8fc78dfd8 100644 --- a/src/include/ngspice/cpdefs.h +++ b/src/include/ngspice/cpdefs.h @@ -84,11 +84,6 @@ struct alias { struct alias *al_prev; } ; -/* The current record of what characters are special. */ - -#define CPC_BRR 004 /* Break word to right of character. */ -#define CPC_BRL 010 /* Break word to left of character. */ - #define CT_ALIASES 1 #define CT_LABEL 15