Compare commits

..
3 Commits
Author SHA1 Message Date
R. Timothy Edwards e1528a797c Corrected the parsing for assignment left-hand-side to allow for
whitespace inside the array declaration, as was (correctly) done
for pin connections.  Previously, "assign x[ 0] = 1'b1" would
fail due to "x[" being parsed as a token by itself.  Now, upon
reading an array opening bracket delimiter, the verilog parser
will continue to read tokens until it finds the closing bracket,
as it does for pin connections.
2026-07-06 10:22:02 -04:00
R. Timothy Edwards 2c94087510 Corrected an error in delimiter parsing, which is due to the lack of
any standard array delimiter character in SPICE.  Often brackets are
used, but just as often angle brackets are used instead, and do not
match the bracket syntax of verilog.  The "matchnocase" function
automatically casts common delimiter characters to a single type to
facilitate matching between names using different delimiters.
However, some code in MatchPins() was assuming square brackets and
breaking this allowance, causing pins to be marked mismatch in spite
of the handling in "matchnocase".  The code has been corrected to
make the same allowance for different delimiter characters everywhere.
2026-06-28 11:44:42 -04:00
R. Timothy Edwards 3eadc8b0dc Corrected some issues in the SPICE parser where a subcircuit name
was checked using "subcktname" before its initialization.  Added
a check for a subcircuit called inside itself, which causes an
immediate failure (see issue tracker issue #106).  If allowed to
continue, netgen will either crash or produce inscrutable output
that doesn't pinpoint the issue.
2026-06-08 14:11:07 -04:00
6 changed files with 85 additions and 14 deletions
+1 -1
View File
@@ -1 +1 @@
1.5.320
1.5.323
+11 -10
View File
@@ -7897,6 +7897,7 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
j = 0;
for (ob2 = tc2->cell; ob2 != NULL; ob2 = ob2->next) {
char *name1, *name2, *aptr1 = NULL, *aptr2 = NULL;
char delim1, delim2;
if (!IsPort(ob2)) break;
@@ -7920,8 +7921,8 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
/* matchfunc(). */
if ((tc1->flags & CELL_PLACEHOLDER) || (tc2->flags && CELL_PLACEHOLDER)) {
aptr1 = strchr(name1, '[');
aptr2 = strchr(name2, '[');
aptr1 = get_array_delimiter(name1, &delim1);
aptr2 = get_array_delimiter(name2, &delim2);
if ((aptr1 != NULL) && (aptr2 == NULL)) {
*aptr1 = '\0';
@@ -7934,8 +7935,8 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
if (!IsPort(ob3)) break;
if (ob3 == ob1) continue;
if (!strncmp(ob3->name, name1, strlen(name1)) &&
*(ob3->name + strlen(name1)) == '[') {
*aptr1 = '[';
is_delimiter(*(ob3->name + strlen(name1)))) {
*aptr1 = delim1;
break;
}
}
@@ -7953,8 +7954,8 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
if (!IsPort(ob3)) break;
if (ob3 == ob2) continue;
if (!strncmp(ob3->name, name2, strlen(name2)) &&
*(ob3->name + strlen(name2)) == '[') {
*aptr2 = '[';
is_delimiter(*(ob3->name + strlen(name2)))) {
*aptr2 = delim2;
break;
}
}
@@ -7964,8 +7965,8 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
if ((*matchfunc)(name1, name2)) {
if (aptr1) *aptr1 = '[';
if (aptr2) *aptr2 = '[';
if (aptr1) *aptr1 = delim1;
if (aptr2) *aptr2 = delim2;
/* If both sides have unconnected nodes, then pins with */
/* matching names are an automatic match. Otherwise, if */
@@ -8120,8 +8121,8 @@ int MatchPins(struct nlist *tc1, struct nlist *tc2, int dolist)
}
}
if (bangptr2) *bangptr2 = '!';
if (aptr1) *aptr1 = '[';
if (aptr2) *aptr2 = '[';
if (aptr1) *aptr1 = delim1;
if (aptr2) *aptr2 = delim2;
j++;
}
}
+27
View File
@@ -282,6 +282,33 @@ int matchfilenocase(char *st1, char *st2, int f1, int f2)
return 1;
}
/* Delimiter matching---Find an opening delimiter in a string. */
/* Return the position of the first opening delimeter in the string, */
/* like strchr(). Place the actual delimeter character in *delim. */
char *get_array_delimiter(char *name, char *delim)
{
char *stest = name;
while (*stest != '\0')
{
if (to_lower[*stest] == '<') {
*delim = *stest;
return stest;
}
stest++;
}
return NULL;
}
/* Delimiter parsing---Check if a character is an opening array delimiter. */
/* Return TRUE if the character is an opening delimiter, FALSE if not. */
int is_delimiter(char testc)
{
return (to_lower[testc] == '<') ? TRUE : FALSE;
}
#ifdef HAVE_MALLINFO
void PrintMemoryStats(void)
{
+2
View File
@@ -309,6 +309,8 @@ extern int match(char *, char *);
extern int matchnocase(char *, char *);
extern int matchfile(char *, char *, int, int);
extern int matchfilenocase(char *, char *, int, int);
extern int is_delimiter(char);
extern char *get_array_delimiter(char *, char *);
extern void GarbageCollect(void);
extern void InitGarbageCollection(void);
+12 -3
View File
@@ -1783,10 +1783,19 @@ skip_ends:
if (scan->next != NULL) scan = scan->next;
tail->next = NULL;
/* Check for class defined inside itself (self-referential loop) */
if (!strcasecmp(model, scan->name)) {
Fprintf(stderr, "Fatal: Class \"%s\" is instanced inside of itself!\n",
scan->name);
InputParseError(stderr);
return;
}
/* Check for ignored class */
if ((itype = IsIgnored(subcktname, filenum)) == IGNORE_CLASS) {
Printf("Class '%s' instanced in input but is being ignored.\n", model);
if ((itype = IsIgnored(scan->name, filenum)) == IGNORE_CLASS) {
Printf("Class '%s' instanced in input but is being ignored.\n", scan->name);
return;
}
@@ -1801,7 +1810,7 @@ skip_ends:
break;
}
if (shorted == (unsigned char)1) {
Printf("Instance of '%s' is shorted, ignoring.\n", subcktname);
Printf("Instance of '%s' is shorted, ignoring.\n", scan->name);
while (head) {
p = head->next;
FREE(head);
+32
View File
@@ -1914,6 +1914,38 @@ skip_endmodule:
else { /* "assign" */
SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
char *aptr = strvchr(nexttok, '[');
/* This is a repeat of code to handle reading of pins, and
* makes sure that all input has been read to the closing
* bracket. There needs to be a single routine to do this,
* or (better) rewrite the parser with lex instead of trying
* to enumerate all the syntax cases separately.
*/
if ((aptr != NULL) && (strvchr(nexttok, ']') == NULL))
{
/* If a bus expressions has whitespace, then concatenate
* to the closing ']'.
*/
char *array_expr = (char *)MALLOC(1);
char *new_array_expr = NULL;
*array_expr = '\0';
/* Read to "]" */
while (nexttok) {
new_array_expr = (char *)MALLOC(strlen(array_expr) +
strlen(nexttok) + 1);
/* Roundabout way to do realloc() becase there is no REALLOC() */
strcpy(new_array_expr, array_expr);
strcat(new_array_expr, nexttok);
FREE(array_expr);
array_expr = new_array_expr;
if (strchr(nexttok, ']')) break;
SkipTokComments(VLOG_PIN_CHECK_DELIMITERS);
}
if (!nexttok) {
Printf("Unterminated array in assignment %s\n", array_expr);
}
}
if (((aptr == NULL) && (GetBusTok(&wb) == 0)) ||
((aptr != NULL) && (GetBus(aptr, &wb) == 0))) {
if (aptr != NULL) {