diff --git a/base/netfile.c b/base/netfile.c index ff37c4a..36020ec 100644 --- a/base/netfile.c +++ b/base/netfile.c @@ -175,7 +175,7 @@ void CloseFile(char *filename) /* STUFF TO READ INPUT FILES */ static char *line = NULL; /* actual line read in */ -static char *linetok; /* line copied to this, then munged by strtok */ +static char *linetok; /* line copied to this, then munged by strdtok */ static int linesize = 0; /* amount of memory allocated for line */ static int linenum; char *nexttok; @@ -191,7 +191,7 @@ struct filestack { static struct filestack *OpenFiles = NULL; -#define TOKEN_DELIMITER " \t\n\r" +#define WHITESPACE_DELIMITER " \t\n\r" /*----------------------------------------------------------------------*/ /* TrimQuoted() --- */ @@ -296,7 +296,7 @@ int GetNextLineNoNewline(char *delimiter) strcpy(linetok, line); TrimQuoted(linetok); - nexttok = strtok(linetok, delimiter); + nexttok = strdtok(linetok, WHITESPACE_DELIMITER, delimiter); return 0; } @@ -319,10 +319,9 @@ void GetNextLine(char *delimiter) void SkipTok(char *delimiter) { if (nexttok != NULL && - (nexttok = strtok(NULL, (delimiter) ? delimiter : TOKEN_DELIMITER)) - != NULL) + (nexttok = strdtok(NULL, WHITESPACE_DELIMITER, delimiter))) return; - GetNextLine((delimiter) ? delimiter : TOKEN_DELIMITER); + GetNextLine(delimiter); } /*----------------------------------------------------------------------*/ @@ -332,7 +331,7 @@ void SkipTok(char *delimiter) void SkipTokNoNewline(char *delimiter) { - nexttok = strtok(NULL, (delimiter) ? delimiter : TOKEN_DELIMITER); + nexttok = strdtok(NULL, WHITESPACE_DELIMITER, delimiter); } /*----------------------------------------------------------------------*/ @@ -354,12 +353,12 @@ void SpiceTokNoNewline(void) { int contline; - if ((nexttok = strtok(NULL, TOKEN_DELIMITER)) != NULL) return; + if ((nexttok = strdtok(NULL, WHITESPACE_DELIMITER, NULL)) != NULL) return; while (nexttok == NULL) { contline = getc(infile); if (contline == '*') { - GetNextLine(TOKEN_DELIMITER); + GetNextLine(WHITESPACE_DELIMITER); SkipNewLine(NULL); continue; } @@ -367,7 +366,28 @@ void SpiceTokNoNewline(void) ungetc(contline, infile); return; } - if (GetNextLineNoNewline(TOKEN_DELIMITER) == -1) break; + if (GetNextLineNoNewline(WHITESPACE_DELIMITER) == -1) break; + } +} + +/*----------------------------------------------------------------------*/ +/* Skip to the next token, ignoring any C-style comments. */ +/*----------------------------------------------------------------------*/ + +void SkipTokComments(char *delimiter) +{ + SkipTok(delimiter); + while (nexttok) { + if (match(nexttok, "//")) { + SkipNewLine(delimiter); + SkipTok(delimiter); + } + else if (match(nexttok, "/*")) { + while (nexttok && !match(nexttok, "*/")) + SkipTok(delimiter); + if (nexttok) SkipTok(delimiter); + } + else break; } } @@ -378,7 +398,7 @@ void SpiceTokNoNewline(void) void SkipNewLine(char *delimiter) { while (nexttok != NULL) - nexttok = strtok(NULL, (delimiter) ? delimiter : TOKEN_DELIMITER); + nexttok = strdtok(NULL, WHITESPACE_DELIMITER, delimiter); } /*----------------------------------------------------------------------*/ @@ -395,13 +415,119 @@ void SpiceSkipNewLine(void) while (contline == '+') { ungetc(contline, infile); - GetNextLine(TOKEN_DELIMITER); + GetNextLine(WHITESPACE_DELIMITER); SkipNewLine(NULL); contline = getc(infile); } ungetc(contline, infile); } +/*----------------------------------------------------------------------*/ +/* Function similar to strtok() for token parsing. The difference is */ +/* that it takes two sets of delimiters. The first is whitespace */ +/* delimiters, which separate tokens. The second is functional */ +/* delimiters, which separate tokens and have additional meaning, such */ +/* as parentheses, commas, semicolons, etc. The parser needs to know */ +/* when such tokens occur in the string, so they are returned as */ +/* individual tokens. */ +/* */ +/* Definition of delim2: String of single delimiter characters. The */ +/* special character "X" (which is never a delimiter in practice) is */ +/* used to separate single-character delimiters from two-character */ +/* delimiters (this presumably could be further extended as needed). */ +/* so ",;()" would be a valid delimiter set, but to include C-style */ +/* comments and verilog-style parameter lists, one would need */ +/* ",;()X/**///#(". */ +/*----------------------------------------------------------------------*/ + +char *strdtok(char *pstring, char *delim1, char *delim2) +{ + static char *stoken = NULL; + static char *sstring = NULL; + char *s, *s2; + char first = FALSE; + int twofer; + + if (pstring != NULL) { + /* Allocate enough memory to hold the string; tokens will be put here */ + if (sstring != NULL) FREE(sstring); + sstring = (char *)MALLOC(strlen(pstring) + 1); + stoken = pstring; + first = TRUE; + } + + /* Skip over "delim1" delimiters at the string beginning */ + for (; *stoken; stoken++) { + for (s2 = delim1; *s2; s2++) + if (*stoken == *s2) + break; + if (*s2 == '\0') break; + } + + if (*stoken == '\0') return NULL; /* Finished parsing */ + + /* "stoken" is now set. Now find the end of the current token */ + + /* Check string from position stoken. If a character in "delim2" is found, */ + /* save the character in "lastdelim", null the byte at that position, and */ + /* return the token. If a character in "delim1" is found, do the same but */ + /* continue checking characters as long as there are contiguous "delim1" */ + /* characters. If the series ends in a character from "delim2", then treat */ + /* as for "delim2" above. If not, then set "lastdelim" to a null byte and */ + /* return the token. */ + + for (s = stoken; *s; s++) { + twofer = FALSE; + for (s2 = delim2; s2 && *s2; s2++) { + if (*s2 == 'X') { + twofer = TRUE; + continue; + } + if (twofer) { + if ((*s == *s2) && (*(s + 1) == *(s2 + 1))) { + if (s == stoken) { + strncpy(sstring, stoken, 2); + *(sstring + 2) = '\0'; + stoken = s + 2; + } + else { + strncpy(sstring, stoken, (int)(s - stoken)); + *(sstring + (s - stoken)) = '\0'; + stoken = s; + } + return sstring; + } + s2++; + if (*s2 == '\0') break; + } + else if (*s == *s2) { + if (s == stoken) { + strncpy(sstring, stoken, 1); + *(sstring + 1) = '\0'; + stoken = s + 1; + } + else { + strncpy(sstring, stoken, (int)(s - stoken)); + *(sstring + (s - stoken)) = '\0'; + stoken = s; + } + return sstring; + } + } + for (s2 = delim1; *s2; s2++) { + if (*s == *s2) { + strncpy(sstring, stoken, (int)(s - stoken)); + *(sstring + (s - stoken)) = '\0'; + stoken = s; + return sstring; + } + } + } + strcpy(sstring, stoken); /* Just copy to the end */ + stoken = s; + return sstring; +} + /*----------------------------------------------------------------------*/ void InputParseError(FILE *f) diff --git a/base/netfile.h b/base/netfile.h index dbf22b6..fbcf413 100644 --- a/base/netfile.h +++ b/base/netfile.h @@ -29,6 +29,7 @@ extern int File; extern char *nexttok; #define SKIPTO(a) do {SkipTok(NULL);} while (!match(nexttok,a)) +extern char *strdtok(char *pstring, char *delim1, char *delim2); extern void SkipTok(char *delimiter); extern void SkipTokNoNewline(char *delimiter); extern void SkipNewLine(char *delimiter); diff --git a/base/verilog.c b/base/verilog.c index f72c380..e305956 100644 --- a/base/verilog.c +++ b/base/verilog.c @@ -57,8 +57,10 @@ the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "netfile.h" #include "print.h" -#define VLOG_DELIMITERS " \t\r\n,;" -#define VLOG_DELIMITERS2 " \t\r\n,()" +// See netfile.c for explanation of delimiters. 'X' +// separates single-character delimiters from two-character delimiters. +#define VLOG_DELIMITERS ",;:(){}[]=\"X///**/#(" +#define VLOG_PIN_NAME_DELIMITERS "()X///**/" // Global storage for verilog parameters struct hashdict verilogparams; @@ -95,21 +97,159 @@ struct bus *NewBus() return (wb); } +//------------------------------------------------------------------------- // Get bus indexes from the notation name[a:b]. If there is only "name" // then look up the name in the bus hash list and return the index bounds. // Return 0 on success, 1 on syntax error, and -1 if signal is not a bus. +// +// Note that this routine relies on the delimiter characters including +// "[", ":", and "]" when calling NextTok. +//------------------------------------------------------------------------- + +int GetBusTok(struct bus *wb) +{ + int result, start, end; + struct property *kl = NULL; + + if (wb == NULL) return 0; + else { + wb->start = -1; + wb->end = -1; + } + + if (match(nexttok, "[")) { + SkipTokComments(VLOG_DELIMITERS); + + // Check for parameter names and substitute values if found. + if (nexttok[0] == '`') { + kl = (struct property *)HashLookup(nexttok + 1, &verilogdefs); + if (kl == NULL) { + Printf("Unknown definition %s found in array notation.\n", nexttok); + } + else { + /* Note: all verilog definitions have been saved as PROP_STRING */ + result = sscanf(kl->pdefault.string, "%d", &start); + if (result != 1) { + Printf("Cannot parse first digit from parameter %s value %s\n", + nexttok, kl->pdefault.string); + return 1; + } + } + } + else { + result = sscanf(nexttok, "%d", &start); + if (result != 1) { + // Is name in the parameter list? + kl = (struct property *)HashLookup(nexttok, &verilogparams); + if (kl == NULL) { + Printf("Array value %s is not a number or a parameter.\n", + nexttok); + return 1; + } + else { + result = sscanf(kl->pdefault.string, "%d", &start); + if (result != 1) { + Printf("Parameter %s has value %s that cannot be parsed" + " as an integer.\n", nexttok, kl->pdefault.string); + return 1; + } + } + } + } + SkipTokComments(VLOG_DELIMITERS); + if (match(nexttok, "]")) { + result = 1; + end = start; // Single bit + } + else if (!match(nexttok, ":")) { + Printf("Badly formed array notation: Expected colon, found %s\n", nexttok); + return 1; + } + else { + SkipTokComments(VLOG_DELIMITERS); + + // Check for parameter names and substitute values if found. + if (nexttok[0] == '`') { + kl = (struct property *)HashLookup(nexttok + 1, &verilogdefs); + if (kl == NULL) { + Printf("Unknown definition %s found in array notation.\n", nexttok); + } + else { + /* Note: all verilog definitions have been saved as PROP_STRING */ + result = sscanf(kl->pdefault.string, "%d", &end); + if (result != 1) { + Printf("Cannot parse second digit from parameter %s value %s\n", + nexttok, kl->pdefault.string); + return 1; + } + } + } + else { + result = sscanf(nexttok, "%d", &end); + if (result != 1) { + // Is name in the parameter list? + kl = (struct property *)HashLookup(nexttok, &verilogparams); + if (kl == NULL) { + Printf("Array value %s is not a number or a parameter.\n", + nexttok); + return 1; + } + else { + result = sscanf(kl->pdefault.string, "%d", &end); + if (result != 1) { + Printf("Parameter %s has value %s that cannot be parsed" + " as an integer.\n", nexttok, + kl->pdefault.string); + return 1; + } + } + } + } + } + wb->start = start; + wb->end = end; + + while (!match(nexttok, "]")) { + SkipTokComments(VLOG_DELIMITERS); + if (nexttok == NULL) { + Printf("End of file reached while reading array bounds.\n"); + return 1; + } + else if (match(nexttok, ";")) { + // Better than reading to end-of-file, give up on end-of-statement + Printf("End of statement reached while reading array bounds.\n"); + return 1; + } + } + } + else { + struct bus *hbus; + hbus = (struct bus *)HashLookup(nexttok, &buses); + if (hbus != NULL) { + wb->start = hbus->start; + wb->end = hbus->end; + } + else + return -1; + } + return 0; +} + +//-------------------------------------------------------------------- +// GetBus() is similar to GetBusTok() (see above), but it parses from +// a string instead of the input tokenizer. +//-------------------------------------------------------------------- int GetBus(char *astr, struct bus *wb) { char *colonptr, *brackstart, *brackend; int result, start, end; - if (wb == NULL) return; + if (wb == NULL) return 0; else { wb->start = -1; wb->end = -1; } - brackstart = strchr(astr, '['); if (brackstart != NULL) { brackend = strchr(astr, ']'); @@ -129,10 +269,10 @@ int GetBus(char *astr, struct bus *wb) } if (colonptr) result = sscanf(colonptr + 1, "%d", &end); - else { + else { result = 1; - end = start; // Single bit - } + end = start; // Single bit + } *brackend = ']'; if (result != 1) { Printf("Badly formed array notation \"%s\"\n", astr); @@ -372,8 +512,8 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr, { int cdnum = 1, rdnum = 1, i; int warnings = 0, hasports, inlined_decls = 0, localcount = 1; - char devtype, in_module, in_comment, in_param; - char *eqptr, *parptr, *matchptr; + char devtype, in_module, in_param; + char *eqptr, *matchptr; struct keyvalue *kvlist = NULL; char inst[256], model[256], instname[256], portname[256], pkey[256]; struct nlist *tp; @@ -383,33 +523,24 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr, model[255] = '\0'; instname[255] = '\0'; in_module = (char)0; - in_comment = (char)0; in_param = (char)0; while (!EndParseFile()) { - SkipTok(VLOG_DELIMITERS); /* get the next token */ + SkipTokComments(VLOG_DELIMITERS); /* get the next token */ if ((EndParseFile()) && (nexttok == NULL)) break; + else if (nexttok == NULL) + break; - /* Handle comment blocks */ - if (nexttok[0] == '/' && nexttok[1] == '*') { - in_comment = (char)1; - } - else if (nexttok[0] == '*' && nexttok[1] == '/') { - in_comment = (char)0; - continue; - } - if (in_comment == (char)1) continue; - - /* Handle comment lines */ - if (match(nexttok, "//")) - SkipNewLine(VLOG_DELIMITERS); + /* Ignore end-of-statement markers */ + else if (match(nexttok, ";")) + continue; /* Ignore primitive definitions */ else if (match(nexttok, "primitive")) { while (1) { SkipNewLine(VLOG_DELIMITERS); - SkipTok(VLOG_DELIMITERS); + SkipTokComments(VLOG_DELIMITERS); if (EndParseFile()) break; if (match(nexttok, "endprimitive")) { in_module = 0; @@ -505,54 +636,35 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr, /* definition, and those which declare everything */ /* inside the pin list. */ - SkipTok(VLOG_DELIMITERS); + SkipTokComments(VLOG_DELIMITERS); // Check for parameters within #( ... ) if (match(nexttok, "#(")) { - SkipTok(VLOG_DELIMITERS); - while (match(nexttok, "//")) { - SkipNewLine(VLOG_DELIMITERS); - SkipTok(VLOG_DELIMITERS); - } + SkipTokComments(VLOG_DELIMITERS); in_param = (char)1; } - else if (nexttok[0] == '(') { - if (match(nexttok, "(")) - SkipTok(VLOG_DELIMITERS); - else - nexttok++; - while (match(nexttok, "//")) { - SkipNewLine(VLOG_DELIMITERS); - SkipTok(VLOG_DELIMITERS); - } + else if (match(nexttok, "(")) { + SkipTokComments(VLOG_DELIMITERS); } wb.start = wb.end = -1; - while ((nexttok != NULL) && (nexttok[0] != ';')) { + while ((nexttok != NULL) && !match(nexttok, ";")) { if (in_param) { - if (!strcmp(nexttok, ")")) { + if (match(nexttok, ")")) { in_param = (char)0; - SkipTok(VLOG_DELIMITERS); - if (strcmp(nexttok, "(")) { + SkipTokComments(VLOG_DELIMITERS); + if (!match(nexttok, "(")) { Fprintf(stderr, "Badly formed module block parameter list.\n"); goto skip_endmodule; } } - else if ((eqptr = strchr(nexttok, '=')) != NULL) { + else if (match(nexttok, "=")) { double dval; - *eqptr = '\0'; - /* In case the variable name is not followed by whitespace */ - if (eqptr > nexttok) strcpy(pkey, nexttok); - eqptr++; - - // Equal sign may be followed by whitespace, in which case - // the parameter value is the next token. - if (strlen(eqptr) == 0) { - SkipTok(VLOG_DELIMITERS); /* get the next token */ - eqptr = nexttok; - } + // The parameter value is the next token. + SkipTokComments(VLOG_DELIMITERS); /* get the next token */ + eqptr = nexttok; // Try first as a double, otherwise it's a string // Double value's slop defaults to 1%. @@ -566,7 +678,7 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr, strcpy(pkey, nexttok); } } - else { + else if (!match(nexttok, ",")) { if (match(nexttok, ")")) break; // Ignore input, output, and inout keywords, and handle buses. @@ -579,8 +691,8 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr, if (!match(nexttok, "input") && !match(nexttok, "output") && !match(nexttok, "inout") && !match(nexttok, "real") && !match(nexttok, "logic") && !match(nexttok, "integer")) { - if (nexttok[0] == '[') { - if (GetBus(nexttok, &wb) != 0) { + if (match(nexttok, "[")) { + if (GetBusTok(&wb) != 0) { // Didn't parse as a bus, so wing it wb.start = wb.end = -1; Port(nexttok); @@ -603,21 +715,15 @@ void ReadVerilogFile(char *fname, int filenum, struct cellstack **CellStackPtr, wb.start = wb.end = -1; } else { - char *pptr; - - if ((pptr = strrchr(nexttok, ')')) != NULL) - *pptr = '\0'; Port(nexttok); - if (pptr != NULL) break; } } hasports = 1; } } } - SkipTok(VLOG_DELIMITERS); + SkipTokComments(VLOG_DELIMITERS); if (nexttok == NULL) break; - while (match(nexttok, "//")) { SkipNewLine(VLOG_DELIMITERS); SkipTok(VLOG_DELIMITERS); } } SetClass((blackbox) ? CLASS_MODULE : CLASS_SUBCKT); @@ -638,7 +744,7 @@ skip_endmodule: while (1) { SkipNewLine(VLOG_DELIMITERS); - SkipTok(VLOG_DELIMITERS); + SkipTokComments(VLOG_DELIMITERS); if (EndParseFile()) break; if (match(nexttok, "endmodule")) { in_module = 0; @@ -802,11 +908,9 @@ skip_endmodule: /* Skip to matching `endif */ while (1) { SkipNewLine(VLOG_DELIMITERS); - SkipTok(VLOG_DELIMITERS); + SkipTokComments(VLOG_DELIMITERS); if (EndParseFile()) break; - if (match(nexttok, "//")) - continue; - else if (match(nexttok, "`ifdef") || match(nexttok, "`ifndef")) { + if (match(nexttok, "`ifdef") || match(nexttok, "`ifndef")) { nested++; } else if (match(nexttok, "`endif")) { @@ -826,7 +930,7 @@ skip_endmodule: if (match(nexttok, "real")) SkipTokNoNewline(VLOG_DELIMITERS); while (nexttok != NULL) { /* Handle bus notation */ - if (GetBus(nexttok, &wb) == 0) { + if (GetBusTok(&wb) == 0) { SkipTokNoNewline(VLOG_DELIMITERS); if (wb.start > wb.end) { for (i = wb.end; i <= wb.start; i++) { @@ -895,115 +999,118 @@ skip_endmodule: head = NULL; tail = NULL; - SkipTok(VLOG_DELIMITERS); + SkipTokComments(VLOG_DELIMITERS); - // Next token must be '#(' (parameters) or '(' (pin list) + // Next token must be '#(' (parameters) or an instance name - if (!strcmp(nexttok, "#(")) { + if (match(nexttok, "#(")) { // Read the parameter list + SkipTokComments(VLOG_DELIMITERS); while (nexttok != NULL) { char *paramname; - SkipTok(VLOG_DELIMITERS2); - while (match(nexttok, "//")) { - SkipNewLine(VLOG_DELIMITERS); - SkipTok(VLOG_DELIMITERS2); - } - if (!strcasecmp(nexttok, ";")) { - SkipTok(VLOG_DELIMITERS); + if (match(nexttok, ")")) { + SkipTokComments(VLOG_DELIMITERS); break; } + else if (match(nexttok, ",")) { + SkipTokComments(VLOG_DELIMITERS); + continue; + } // We need to look for parameters of the type ".name(value)" - if (nexttok[0] != '.') break; - else { + else if (nexttok[0] == '.') { paramname = strsave(nexttok + 1); - SkipTok(VLOG_DELIMITERS2); - while (match(nexttok, "//")) { - SkipNewLine(VLOG_DELIMITERS); - SkipTok(VLOG_DELIMITERS2); + SkipTokComments(VLOG_DELIMITERS); + if (!match(nexttok, "(")) { + Printf("Error: Expecting parameter value, got %s.\n", nexttok); + } + SkipTokComments(VLOG_DELIMITERS); + if (match(nexttok, ")")) { + Printf("Error: Parameter with no value found.\n"); + } + else { + AddProperty(&kvlist, paramname, nexttok); + SkipTokComments(VLOG_DELIMITERS); + if (!match(nexttok, ")")) { + Printf("Error: Expecting end of parameter value, " + "got %s.\n", nexttok); + } } - AddProperty(&kvlist, paramname, nexttok); FREE(paramname); } + SkipTokComments(VLOG_DELIMITERS); + } + if (!nexttok) { + Printf("Error: Still reading module, but got end-of-file.\n"); + goto skip_endmodule; } } - // Catch instance name followed by open parenthesis with no space - if ((parptr = strchr(nexttok, '(')) != NULL) *parptr = '\0'; - - // Then comes the instance name strncpy(instancename, nexttok, 99); - if (!parptr) - SkipTok(VLOG_DELIMITERS); - else { - *parptr = '('; - nexttok = parptr; - } /* Printf("Diagnostic: new instance is %s\n", instancename); */ - while (match(nexttok, "//")) { - SkipNewLine(VLOG_DELIMITERS); - SkipTok(VLOG_DELIMITERS); - } + SkipTokComments(VLOG_DELIMITERS); arraystart = arrayend = -1; - if (nexttok[0] == '[') { + if (match(nexttok, "[")) { // Handle instance array notation. struct bus wb; - if (GetBus(nexttok, &wb) == 0) { + if (GetBusTok(&wb) == 0) { arraystart = wb.start; arrayend = wb.end; } - SkipTok(VLOG_DELIMITERS); + SkipTokComments(VLOG_DELIMITERS); } - if (nexttok[0] == '(') { + if (match(nexttok, "(")) { char savetok = (char)0; struct portelement *new_port; - // Note that the open parens does not necessarily have to be - // followed by space. - if (nexttok[1] != '\0') { - nexttok++; - savetok = (char)1; - } - // Read the pin list while (nexttok != NULL) { - if (savetok == (char)0) SkipTok(VLOG_DELIMITERS2); - savetok = (char)0; + SkipTokComments(VLOG_DELIMITERS); // NOTE: Deal with `ifdef et al. properly. Ignoring for now. - while (match(nexttok, "//") || (nexttok[0] == '`')) { + while (nexttok[0] == '`') { SkipNewLine(VLOG_DELIMITERS); - SkipTok(VLOG_DELIMITERS2); + SkipTokComments(VLOG_DELIMITERS); } - if (!strcasecmp(nexttok, ";")) break; + if (match(nexttok, ")")) break; + else if (match(nexttok, ",")) continue; // We need to look for pins of the type ".name(value)" if (nexttok[0] != '.') { Printf("Badly formed subcircuit pin line at \"%s\"\n", nexttok); + SkipNewLine(VLOG_DELIMITERS); } else { new_port = (struct portelement *)CALLOC(1, sizeof(struct portelement)); new_port->name = strsave(nexttok + 1); - SkipTok(VLOG_DELIMITERS2); - while (match(nexttok, "//")) { - SkipNewLine(VLOG_DELIMITERS); - SkipTok(VLOG_DELIMITERS2); + SkipTokComments(VLOG_DELIMITERS); + if (!match(nexttok, "(")) { + Printf("Badly formed subcircuit pin line at \"%s\"\n", nexttok); + SkipNewLine(VLOG_DELIMITERS); } - if (match(nexttok, ";") || (nexttok[0] == '.')) { + SkipTokComments(VLOG_PIN_NAME_DELIMITERS); + if (match(nexttok, ")")) { char localnet[100]; // Empty parens, so create a new local node savetok = (char)1; sprintf(localnet, "_noconnect_%d_", localcount++); new_port->net = strsave(localnet); } - else + else { new_port->net = strsave(nexttok); + /* Read array information along with name; will be parsed later */ + SkipTokComments(VLOG_DELIMITERS); + if (!match(nexttok, ")")) { + Printf("Badly formed subcircuit pin line at \"%s\"\n", nexttok); + SkipNewLine(VLOG_DELIMITERS); + } + } if (head == NULL) head = new_port; else tail->next = new_port; @@ -1013,13 +1120,12 @@ skip_endmodule: } } else { - // There are too many statements in too many variants of verilog - // to track them all, let alone dealing with macro substitutions - // and such. If it doesn't look like a circuit instance and isn't - // otherwise handled above, treat as a non-structural statement - // and recast the device class as a black-box module. - SetClass(CLASS_MODULE); - goto skip_endmodule; + Printf("Expected to find instance pin block but got \"%s\"\n", nexttok); + } + /* Instance should end with a semicolon */ + SkipTokComments(VLOG_DELIMITERS); + if (!match(nexttok, ";")) { + Printf("Expected to find end of instance but got \"%s\"\n", nexttok); } /* Check for ignored class */