xref: /Universal-ctags/parsers/verilog.c (revision 46313f460f7c57588df5217354db1556fe155f26)
1 /*
2  *   Copyright (c) 2003, Darren Hiebert
3  *   Copyright (c) 2017, Vitor Antunes
4  *   Copyright (c) 2020, Hiroo Hayashi
5  *
6  *   This source code is released for free distribution under the terms of the
7  *   GNU General Public License version 2 or (at your option) any later version.
8  *
9  *   This module contains functions for generating tags for the Verilog or
10  *   SystemVerilog HDL (Hardware Description Language).
11  *
12  *   References:
13  *       IEEE Std 1800-2017, SystemVerilog Language Reference Manual
14  *          https://ieeexplore.ieee.org/document/8299595
15  *       SystemVerilog IEEE Std 1800-2012 Grammer
16  *          https://insights.sigasi.com/tech/systemverilog.ebnf/
17  *       Verilog Formal Syntax Specification
18  *          http://www.verilog.com/VerilogBNF.html
19  */
20 
21 /*
22  *   INCLUDE FILES
23  */
24 #include "general.h"  /* must always come first */
25 
26 #include <string.h>
27 
28 #include "debug.h"
29 #include "entry.h"
30 #include "keyword.h"
31 #include "options.h"
32 #include "parse.h"
33 #include "read.h"
34 #include "routines.h"
35 #include "xtag.h"
36 #include "ptrarray.h"
37 
38 /*
39  *   MACROS
40  */
41 #define NUMBER_LANGUAGES    2   /* Indicates number of defined indexes */
42 #define IDX_SYSTEMVERILOG   0
43 #define IDX_VERILOG         1
44 
45 /*
46  *   DATA DECLARATIONS
47  */
48 
49 /* A callback function searching a symbol from the cork symbol table assumes
50  * this kind definitions are shared in Verilog and SystemVerilog parsers.
51  * If you will separate the definitions for the parsers, you must revise the
52  * code related to the symbol table. */
53 typedef enum {
54 	/* parser private items */
55 	K_IGNORE = -16,	/* Verilog/SystemVerilog keywords to be ignored */
56 	K_DEFINE,
57 	K_DIRECTIVE,
58 	K_END,
59 	K_END_DE,	/* End of Design Elements */
60 	K_IDENTIFIER,
61 	K_LOCALPARAM,
62 	K_PARAMETER,
63 	K_IMPORT,
64 	K_WITH,
65 
66 	K_UNDEFINED = KEYWORD_NONE,
67 	/* the followings items are also used as indices for VerilogKinds[] and SystemVerilogKinds[] */
68 	K_CONSTANT= 0,
69 	K_EVENT,
70 	K_FUNCTION,
71 	K_MODULE,
72 	K_NET,
73 	K_PORT,
74 	K_REGISTER,
75 	K_TASK,
76 	K_BLOCK,
77 	K_INSTANCE,
78 	K_ASSERTION,
79 	K_CLASS,
80 	K_COVERGROUP,
81 	K_ENUM,
82 	K_INTERFACE,
83 	K_MODPORT,
84 	K_PACKAGE,
85 	K_PROGRAM,
86 	K_PROTOTYPE,
87 	K_PROPERTY,
88 	K_STRUCT,
89 	K_TYPEDEF,
90 	K_CHECKER,
91 	K_CLOCKING,
92 	K_SEQUENCE,
93 	K_MEMBER,
94 	K_IFCLASS,	/* interface class */
95 	K_CONSTRAINT,
96 	K_NETTYPE,
97 } verilogKind;
98 
99 typedef struct {
100 	const char *keyword;
101 	verilogKind kind;
102 	short isValid [NUMBER_LANGUAGES];
103 } keywordAssoc;
104 
105 typedef struct sTokenInfo {
106 	verilogKind         kind;
107 	vString*            name;          /* the name of the token */
108 	unsigned long       lineNumber;    /* line number where token was found */
109 	MIOPos              filePosition;  /* file position where token was found */
110 	struct sTokenInfo*  scope;         /* context of keyword */
111 	int                 nestLevel;     /* Current nest level */
112 	verilogKind         lastKind;      /* Kind of last found tag */
113 	vString*            blockName;     /* Current block name */
114 	vString*            inheritance;   /* Class inheritance */
115 	bool                prototype;     /* Is only a prototype */
116 	bool                classScope;    /* Context is local to the current sub-context */
117 	bool				parameter;	   /* parameter which can be overridden */
118 	bool				hasParamList;  /* module definition has a parameter port list */
119 } tokenInfo;
120 
121 typedef enum {
122 	F_PARAMETER,
123 } verilogField;
124 
125 /*
126  *   DATA DEFINITIONS
127  */
128 static int Ungetc;
129 static int Lang_verilog;
130 static int Lang_systemverilog;
131 
132 static kindDefinition VerilogKinds [] = {
133  { true, 'c', "constant",  "constants (define, parameter, specparam)" },
134  { true, 'e', "event",     "events" },
135  { true, 'f', "function",  "functions" },
136  { true, 'm', "module",    "modules" },
137  { true, 'n', "net",       "net data types" },
138  { true, 'p', "port",      "ports" },
139  { true, 'r', "register",  "variable data types" },
140  { true, 't', "task",      "tasks" },
141  { true, 'b', "block",     "blocks (begin, fork)" },
142  { true, 'i', "instance",  "instances of module" },
143 };
144 
145 static kindDefinition SystemVerilogKinds [] = {
146  { true, 'c', "constant",  "constants (define, parameter, specparam, enum values)" },
147  { true, 'e', "event",     "events" },
148  { true, 'f', "function",  "functions" },
149  { true, 'm', "module",    "modules" },
150  { true, 'n', "net",       "net data types" },
151  { true, 'p', "port",      "ports" },
152  { true, 'r', "register",  "variable data types" },
153  { true, 't', "task",      "tasks" },
154  { true, 'b', "block",     "blocks (begin, fork)" },
155  { true, 'i', "instance",  "instances of module or interface" },
156  { true, 'A', "assert",    "assertions (assert, assume, cover, restrict)" },
157  { true, 'C', "class",     "classes" },
158  { true, 'V', "covergroup","covergroups" },
159  { true, 'E', "enum",      "enumerators" },
160  { true, 'I', "interface", "interfaces" },
161  { true, 'M', "modport",   "modports" },
162  { true, 'K', "package",   "packages" },
163  { true, 'P', "program",   "programs" },
164  { false,'Q', "prototype", "prototypes (extern, pure)" },
165  { true, 'R', "property",  "properties" },
166  { true, 'S', "struct",    "structs and unions" },
167  { true, 'T', "typedef",   "type declarations" },
168  { true, 'H', "checker",   "checkers" },
169  { true, 'L', "clocking",  "clocking" },
170  { true, 'q', "sequence",  "sequences" },
171  { true, 'w', "member",    "struct and union members" },
172  { true, 'l', "ifclass",   "interface class" },
173  { true, 'O', "constraint","constraints" },
174  { true, 'N', "nettype",   "nettype declarations" },
175 };
176 
177 static const keywordAssoc KeywordTable [] = {
178 	/*                 	             	  SystemVerilog */
179 	/*                 	             	  |  Verilog    */
180 	/* keyword         	keyword ID   	  |  |          */
181 	{ "`define",       	K_DEFINE,   	{ 1, 1 } },
182 	{ "begin",         	K_BLOCK,     	{ 1, 1 } },
183 	{ "end",           	K_END,       	{ 1, 1 } },
184 	{ "endfunction",   	K_END_DE,    	{ 1, 1 } },
185 	{ "endmodule",     	K_END_DE,    	{ 1, 1 } },
186 	{ "endtask",       	K_END_DE,    	{ 1, 1 } },
187 	{ "event",         	K_EVENT,     	{ 1, 1 } },
188 	{ "fork",          	K_BLOCK,     	{ 1, 1 } },
189 	{ "function",      	K_FUNCTION,  	{ 1, 1 } },
190 	{ "genvar",        	K_REGISTER,  	{ 1, 1 } },
191 	{ "inout",         	K_PORT,      	{ 1, 1 } },
192 	{ "input",         	K_PORT,      	{ 1, 1 } },
193 	{ "integer",       	K_REGISTER,  	{ 1, 1 } },
194 	{ "join",          	K_END,       	{ 1, 1 } },
195 	{ "localparam",    	K_LOCALPARAM,  	{ 1, 1 } },
196 	{ "module",        	K_MODULE,    	{ 1, 1 } },
197 	{ "output",        	K_PORT,      	{ 1, 1 } },
198 	{ "parameter",     	K_PARAMETER,  	{ 1, 1 } },
199 	{ "real",          	K_REGISTER,  	{ 1, 1 } },
200 	{ "realtime",      	K_REGISTER,  	{ 1, 1 } },
201 	{ "reg",           	K_REGISTER,  	{ 1, 1 } },
202 	{ "signed",        	K_IGNORE,    	{ 1, 1 } },
203 	{ "specparam",     	K_CONSTANT,  	{ 1, 1 } },
204 	{ "supply0",       	K_NET,       	{ 1, 1 } },
205 	{ "supply1",       	K_NET,       	{ 1, 1 } },
206 	{ "task",          	K_TASK,      	{ 1, 1 } },
207 	{ "time",          	K_REGISTER,  	{ 1, 1 } },
208 	{ "tri",           	K_NET,       	{ 1, 1 } },
209 	{ "triand",        	K_NET,       	{ 1, 1 } },
210 	{ "trior",         	K_NET,       	{ 1, 1 } },
211 	{ "trireg",        	K_NET,       	{ 1, 1 } },
212 	{ "tri0",          	K_NET,       	{ 1, 1 } },
213 	{ "tri1",          	K_NET,       	{ 1, 1 } },
214 	{ "uwire",         	K_NET,       	{ 1, 1 } },
215 	{ "wand",          	K_NET,       	{ 1, 1 } },
216 	{ "wire",          	K_NET,       	{ 1, 1 } },
217 	{ "wor",           	K_NET,       	{ 1, 1 } },
218 	{ "assert",        	K_ASSERTION, 	{ 1, 0 } },
219 	{ "assume",        	K_ASSERTION, 	{ 1, 0 } },
220 	{ "bit",           	K_REGISTER,  	{ 1, 0 } },
221 	{ "byte",          	K_REGISTER,  	{ 1, 0 } },
222 	{ "chandle",       	K_REGISTER,  	{ 1, 0 } },
223 	{ "checker",       	K_CHECKER,  	{ 1, 0 } },
224 	{ "class",         	K_CLASS,     	{ 1, 0 } },
225 	{ "constraint",   	K_CONSTRAINT, 	{ 1, 0 } },
226 	{ "cover",         	K_ASSERTION, 	{ 1, 0 } },
227 	{ "clocking",       K_CLOCKING,     { 1, 0 } },
228 	{ "covergroup",    	K_COVERGROUP,	{ 1, 0 } },
229 	{ "endchecker",    	K_END_DE,    	{ 1, 0 } },
230 	{ "endclass",      	K_END_DE,    	{ 1, 0 } },
231 	{ "endclocking",    K_END_DE,     	{ 1, 0 } },
232 	{ "endgroup",      	K_END_DE,    	{ 1, 0 } },
233 	{ "endinterface",  	K_END_DE,    	{ 1, 0 } },
234 	{ "endpackage",    	K_END_DE,    	{ 1, 0 } },
235 	{ "endprogram",    	K_END_DE,    	{ 1, 0 } },
236 	{ "endproperty",   	K_END_DE,    	{ 1, 0 } },
237 	{ "endsequence",   	K_END_DE,    	{ 1, 0 } },
238 	{ "enum",          	K_ENUM,      	{ 1, 0 } },
239 	{ "extern",        	K_PROTOTYPE, 	{ 1, 0 } },
240 	{ "import",        	K_IMPORT,	  	{ 1, 0 } },
241 	{ "int",           	K_REGISTER,  	{ 1, 0 } },
242 	{ "interconnect",  	K_NET,       	{ 1, 0 } },
243 	{ "interface",     	K_INTERFACE, 	{ 1, 0 } },
244 	{ "join_any",      	K_END,       	{ 1, 0 } },
245 	{ "join_none",     	K_END,       	{ 1, 0 } },
246 	{ "logic",         	K_REGISTER,  	{ 1, 0 } },
247 	{ "longint",       	K_REGISTER,  	{ 1, 0 } },
248 	{ "modport",       	K_MODPORT,   	{ 1, 0 } },
249 	{ "package",       	K_PACKAGE,   	{ 1, 0 } },
250 	{ "program",       	K_PROGRAM,   	{ 1, 0 } },
251 	{ "property",      	K_PROPERTY,  	{ 1, 0 } },
252 	{ "pure",          	K_PROTOTYPE, 	{ 1, 0 } },
253 	{ "ref",           	K_PORT,      	{ 1, 0 } },
254 	{ "restrict",      	K_ASSERTION, 	{ 1, 0 } },
255 	{ "sequence",      	K_SEQUENCE,  	{ 1, 0 } },
256 	{ "shortint",      	K_REGISTER,  	{ 1, 0 } },
257 	{ "shortreal",     	K_REGISTER,  	{ 1, 0 } },
258 	{ "string",        	K_REGISTER,  	{ 1, 0 } },
259 	{ "struct",        	K_STRUCT,    	{ 1, 0 } },
260 	{ "type",          	K_REGISTER,  	{ 1, 0 } },
261 	{ "typedef",       	K_TYPEDEF,   	{ 1, 0 } },
262 	{ "union",         	K_STRUCT,    	{ 1, 0 } },
263 	{ "var",           	K_REGISTER,  	{ 1, 0 } },
264 	{ "void",          	K_REGISTER,  	{ 1, 0 } },
265 	{ "with",          	K_WITH,			{ 1, 0 } },
266 	{ "nettype",       	K_NETTYPE,		{ 1, 0 } },
267 //	{ "virtual",       	K_PROTOTYPE,	{ 1, 0 } },		// do not add for now
268 };
269 
270 static tokenInfo *currentContext = NULL;
271 static ptrArray *tagContents;
272 static fieldDefinition *fieldTable = NULL;
273 
274 // IEEE Std 1364-2005 LRM, Appendix B "List of Keywords"
275 const static struct keywordGroup verilogKeywords = {
276 	.value = K_IGNORE,
277 	.addingUnlessExisting = true,
278 	.keywords = {
279 		"always", "and", "assign", "automatic", "begin", "buf", "bufif0",
280 		"bufif1", "case", "casex", "casez", "cell", "cmos", "config",
281 		"deassign", "default", "defparam", "design", "disable", "edge",
282 		"else", "end", "endcase", "endconfig", "endfunction", "endgenerate",
283 		"endmodule", "endprimitive", "endspecify", "endtable", "endtask",
284 		"event", "for", "force", "forever", "fork", "function", "generate",
285 		"genvar", "highz0", "highz1", "if", "ifnone", "incdir", "include",
286 		"initial", "inout", "input", "instance", "integer", "join", "large",
287 		"liblist", "library", "localparam", "macromodule", "medium", "module",
288 		"nand", "negedge", "nmos", "nor", "noshowcancelled", "not", "notif0",
289 		"notif1", "or", "output", "parameter", "pmos", "posedge", "primitive",
290 		"pull0", "pull1", "pulldown", "pullup", "pulsestyle_onevent",
291 		"pulsestyle_ondetect", "rcmos", "real", "realtime", "reg", "release",
292 		"repeat", "rnmos", "rpmos", "rtran", "rtranif0", "rtranif1",
293 		"scalared", "showcancelled", "signed", "small", "specify",
294 		"specparam", "strong0", "strong1", "supply0", "supply1", "table",
295 		"task", "time", "tran", "tranif0", "tranif1", "tri", "tri0", "tri1",
296 		"triand", "trior", "trireg", "unsigned1", "use", "uwire", "vectored",
297 		"wait", "wand", "weak0", "weak1", "while", "wire", "wor", "xnor", "xor",
298 		NULL
299 	},
300 };
301 // IEEE Std 1800-2017 LRM, Annex B "Keywords"
302 const static struct keywordGroup systemVerilogKeywords = {
303 	.value = K_IGNORE,
304 	.addingUnlessExisting = true,
305 	.keywords = {
306 		"accept_on", "alias", "always", "always_comb", "always_ff",
307 		"always_latch", "and", "assert", "assign", "assume", "automatic",
308 		"before", "begin", "bind", "bins", "binsof", "bit", "break", "buf",
309 		"bufif0", "bufif1", "byte", "case", "casex", "casez", "cell",
310 		"chandle", "checker", "class", "clocking", "cmos", "config", "const",
311 		"constraint", "context", "continue", "cover", "covergroup",
312 		"coverpoint", "cross", "deassign", "default", "defparam", "design",
313 		"disable", "dist", "do", "edge", "else", "end", "endcase",
314 		"endchecker", "endclass", "endclocking", "endconfig", "endfunction",
315 		"endgenerate", "endgroup", "endinterface", "endmodule", "endpackage",
316 		"endprimitive", "endprogram", "endproperty", "endspecify",
317 		"endsequence", "endtable", "endtask", "enum", "event", "eventually",
318 		"expect", "export", "extends", "extern", "final", "first_match",
319 		"for", "force", "foreach", "forever", "fork", "forkjoin", "function",
320 		"generate", "genvar", "global", "highz0", "highz1", "if", "iff",
321 		"ifnone", "ignore_bins", "illegal_bins", "implements", "implies",
322 		"import", "incdir", "include", "initial", "inout", "input", "inside",
323 		"instance", "int", "integer", "interconnect", "interface",
324 		"intersect", "join", "join_any", "join_none", "large", "let",
325 		"liblist", "library", "local", "localparam", "logic", "longint",
326 		"macromodule", "matches", "medium", "modport", "module", "nand",
327 		"negedge", "nettype", "new", "nexttime", "nmos", "nor",
328 		"noshowcancelled", "not", "notif0", "notif1", "null", "or", "output",
329 		"package", "packed", "parameter", "pmos", "posedge", "primitive",
330 		"priority", "program", "property", "protected", "pull0", "pull1",
331 		"pulldown", "pullup", "pulsestyle_ondetect", "pulsestyle_onevent",
332 		"pure", "rand", "randc", "randcase", "randsequence", "rcmos", "real",
333 		"realtime", "ref", "reg", "reject_on", "release", "repeat",
334 		"restrict", "return", "rnmos", "rpmos", "rtran", "rtranif0",
335 		"rtranif1", "s_always", "s_eventually", "s_nexttime", "s_until",
336 		"s_until_with", "scalared", "sequence", "shortint", "shortreal",
337 		"showcancelled", "signed", "small", "soft", "solve", "specify",
338 		"specparam", "static", "string", "strong", "strong0", "strong1",
339 		"struct", "super", "supply0", "supply1", "sync_accept_on",
340 		"sync_reject_on", "table", "tagged", "task", "this", "throughout",
341 		"time", "timeprecision", "timeunit", "tran", "tranif0", "tranif1",
342 		"tri", "tri0", "tri1", "triand", "trior", "trireg", "type", "typedef",
343 		"union", "unique", "unique0", "unsigned", "until", "until_with",
344 		"untyped", "use", "uwire", "var", "vectored", "virtual", "void",
345 		"wait", "wait_order", "wand", "weak", "weak0", "weak1", "while",
346 		"wildcard", "wire", "with", "within", "wor", "xnor", "xor",
347 		NULL
348 	},
349 };
350 
351 // IEEE Std 1364-2005 LRM, "19. Compiler directives"
352 const static struct keywordGroup verilogDirectives = {
353 	.value = K_DIRECTIVE,
354 	.addingUnlessExisting = true,
355 	.keywords = {
356 		"`begin_keywords", "`celldefine", "`default_nettype", "`define",
357 		"`else", "`elsif", "`end_keywords", "`endcelldefine", "`endif",
358 		"`ifdef", "`ifndef", "`include", "`line", "`nounconnected_drive",
359 		"`pragma", "`resetall", "`timescale", "`unconnected_drive", "`undef",
360 		NULL
361 	},
362 };
363 
364 // IEEE Std 1800-2017 LRM, "22. Compiler directives"
365 const static struct keywordGroup systemVerilogDirectives = {
366 	.value = K_DIRECTIVE,
367 	.addingUnlessExisting = true,
368 	.keywords = {
369 		"`__LINE__", "`begin_keywords", "`celldefine", "`default_nettype",
370 		"`define", "`else", "`elsif", "`end_keywords", "`endcelldefine",
371 		"`endif", "`ifdef", "`ifndef", "`include", "`line",
372 		"`nounconnected_drive", "`pragma", "`resetall", "`timescale",
373 		"`unconnected_drive", "`undef", "`undefineall",
374 		NULL
375 	},
376 };
377 
378 // .enabled field cannot be shared by two languages
379 static fieldDefinition VerilogFields[] = {
380 	{ .name = "parameter",
381 	  .description = "parameter whose value can be overridden.",
382 	  .enabled = false,
383 	  .dataType = FIELDTYPE_BOOL },
384 };
385 
386 static fieldDefinition SystemVerilogFields[] = {
387 	{ .name = "parameter",
388 	  .description = "parameter whose value can be overridden.",
389 	  .enabled = false,
390 	  .dataType = FIELDTYPE_BOOL },
391 };
392 
393 /*
394  *   PROTOTYPE DEFINITIONS
395  */
396 
397 static bool isIdentifier (tokenInfo* token);
398 static int processDefine (tokenInfo *const token, int c);
399 static int processType (tokenInfo* token, int c, verilogKind* kind, bool* with);
400 static int pushEnumNames (tokenInfo* token, int c);
401 static int pushMembers (tokenInfo* token, int c);
402 static int readWordToken (tokenInfo *const token, int c);
403 static int readWordTokenNoSkip (tokenInfo *const token, int c);
404 static int skipBlockName (tokenInfo *const token, int c);
405 static int skipClockEvent (tokenInfo* token, int c);
406 static int skipDelay (tokenInfo* token, int c);
407 static int tagIdentifierList (tokenInfo *const token, int c, verilogKind kind, bool mayPortDecl);
408 static int tagNameList (tokenInfo* token, int c, verilogKind kind);
409 
410 /*
411  *   FUNCTION DEFINITIONS
412  */
413 
isContainer(verilogKind kind)414 static short isContainer (verilogKind kind)
415 {
416 	switch (kind)
417 	{
418 		case K_MODULE:
419 		case K_TASK:
420 		case K_FUNCTION:
421 		case K_BLOCK:
422 		case K_CHECKER:
423 		case K_CLASS:
424 		case K_CLOCKING:
425 		case K_COVERGROUP:
426 		case K_IFCLASS:
427 		case K_INTERFACE:
428 		case K_PACKAGE:
429 		case K_PROGRAM:
430 		case K_PROPERTY:
431 		case K_SEQUENCE:
432 		case K_TYPEDEF:
433 		case K_NETTYPE:
434 		case K_ENUM:
435 		case K_STRUCT:
436 			return true;
437 		default:
438 			return false;
439 	}
440 }
441 
isTempContext(tokenInfo const * token)442 static short isTempContext (tokenInfo const* token)
443 {
444 	switch (token->kind)
445 	{
446 		case K_TYPEDEF:
447 		case K_NETTYPE:
448 		case K_ENUM:
449 		case K_STRUCT:
450 			return true;
451 		default:
452 			return false;
453 	}
454 }
455 
clearToken(tokenInfo * token)456 static void clearToken (tokenInfo *token)
457 {
458 	token->kind = K_UNDEFINED;	// to be set by updateKind()
459 	vStringClear (token->name);
460 	token->lineNumber = getInputLineNumber ();
461 	token->filePosition = getInputFilePosition ();
462 	token->scope = NULL;
463 	token->nestLevel = 0;
464 	token->lastKind = K_UNDEFINED;
465 	vStringClear (token->blockName);
466 	vStringClear (token->inheritance);
467 	token->prototype = false;
468 	token->classScope = false;
469 	token->parameter = false;
470 	token->hasParamList = false;
471 }
472 
newToken(void)473 static tokenInfo *newToken (void)
474 {
475 	tokenInfo *const token = xMalloc (1, tokenInfo);
476 	token->name = vStringNew ();
477 	token->blockName = vStringNew ();
478 	token->inheritance = vStringNew ();
479 	clearToken (token);
480 	return token;
481 }
482 
dupToken(tokenInfo * token)483 static tokenInfo *dupToken (tokenInfo *token)
484 {
485 	tokenInfo *dup = newToken ();
486 	tokenInfo tmp = *dup;	// save vStrings, name, blockName, and inheritance
487 	*dup = *token;
488 	// revert vStrings allocated for dup
489 	dup->name = tmp.name;
490 	dup->blockName = tmp.blockName;
491 	dup->inheritance = tmp.inheritance;
492 	// copy contents of vStrings
493 	vStringCopy (dup->name, token->name);
494 	vStringCopy (dup->blockName, token->blockName);
495 	vStringCopy (dup->inheritance, token->inheritance);
496 	return dup;
497 }
498 
deleteToken(tokenInfo * const token)499 static void deleteToken (tokenInfo * const token)
500 {
501 	if (token != NULL)
502 	{
503 		vStringDelete (token->name);
504 		vStringDelete (token->blockName);
505 		vStringDelete (token->inheritance);
506 		eFree (token);
507 	}
508 }
509 
pushToken(tokenInfo * const token,tokenInfo * const tokenPush)510 static tokenInfo *pushToken (tokenInfo * const token, tokenInfo * const tokenPush)
511 {
512 	tokenPush->scope = token;
513 	return tokenPush;
514 }
515 
popToken(tokenInfo * const token)516 static tokenInfo *popToken (tokenInfo * const token)
517 {
518 	tokenInfo *localToken;
519 	if (token != NULL)
520 	{
521 		localToken = token->scope;
522 		deleteToken (token);
523 		return localToken;
524 	}
525 	return NULL;
526 }
527 
pruneTokens(tokenInfo * token)528 static void pruneTokens (tokenInfo * token)
529 {
530 	while ((token = popToken (token)))
531 		;
532 }
533 
swapToken(tokenInfo * t0,tokenInfo * t1)534 static void swapToken (tokenInfo *t0, tokenInfo *t1)
535 {
536 	tokenInfo tmp = *t0;
537 	*t0 = *t1;
538 	*t1 = tmp;
539 }
540 
getNameForKind(const verilogKind kind)541 static const char *getNameForKind (const verilogKind kind)
542 {
543 	if (isInputLanguage (Lang_systemverilog))
544 		return (SystemVerilogKinds[kind]).name;
545 	else /* isInputLanguage (Lang_verilog) */
546 		return (VerilogKinds[kind]).name;
547 }
548 
kindEnabled(const verilogKind kind)549 static char kindEnabled (const verilogKind kind)
550 {
551 	if (isInputLanguage (Lang_systemverilog))
552 		return SystemVerilogKinds[kind].enabled;
553 	else /* isInputLanguage (Lang_verilog) */
554 		return VerilogKinds[kind].enabled;
555 }
556 
buildKeywordHash(const langType language,unsigned int idx)557 static void buildKeywordHash (const langType language, unsigned int idx)
558 {
559 	size_t i;
560 	const size_t count = ARRAY_SIZE (KeywordTable);
561 	for (i = 0  ;  i < count  ;  ++i)
562 	{
563 		const keywordAssoc *p = &KeywordTable [i];
564 		if (p->isValid [idx])
565 			addKeyword (p->keyword, language, (int) p->kind);
566 	}
567 }
568 
initializeVerilog(const langType language)569 static void initializeVerilog (const langType language)
570 {
571 	Lang_verilog = language;
572 	buildKeywordHash (language, IDX_VERILOG);
573 	addKeywordGroup (&verilogKeywords, language);
574 	addKeywordGroup (&verilogDirectives, language);
575 	if (tagContents == NULL)
576 		tagContents = ptrArrayNew ((ptrArrayDeleteFunc)deleteToken);
577 
578 }
579 
initializeSystemVerilog(const langType language)580 static void initializeSystemVerilog (const langType language)
581 {
582 	Lang_systemverilog = language;
583 	buildKeywordHash (language, IDX_SYSTEMVERILOG);
584 	addKeywordGroup (&systemVerilogKeywords, language);
585 	addKeywordGroup (&systemVerilogDirectives, language);
586 	if (tagContents == NULL)
587 		tagContents = ptrArrayNew ((ptrArrayDeleteFunc)deleteToken);
588 }
589 
vUngetc(int c)590 static void vUngetc (int c)
591 {
592 	Assert (Ungetc == '\0');
593 	Ungetc = c;
594 }
595 
596 /* Mostly copied from cppSkipOverCComment() in cpreprocessor.c.
597  *
598  * cppSkipOverCComment() uses the internal ungetc buffer of
599  * CPreProcessor.  On the other hand, the Verilog parser uses
600  * getcFromInputFile() directly. getcFromInputFile() uses just
601  * another internal ungetc buffer. Using them mixed way will
602  * cause a trouble. */
verilogSkipOverCComment(void)603 static int verilogSkipOverCComment (void)
604 {
605 	int c =  getcFromInputFile ();
606 
607 	while (c != EOF)
608 	{
609 		if (c != '*')
610 			c = getcFromInputFile ();
611 		else
612 		{
613 			const int next = getcFromInputFile ();
614 
615 			if (next != '/')
616 				c = next;
617 			else
618 			{
619 				c = SPACE;  /* replace comment with space */
620 				break;
621 			}
622 		}
623 	}
624 	return c;
625 }
626 
_vGetc(bool inSkipPastMatch)627 static int _vGetc (bool inSkipPastMatch)
628 {
629 	int c;
630 	if (Ungetc == '\0')
631 		c = getcFromInputFile ();
632 	else
633 	{
634 		c = Ungetc;
635 		Ungetc = '\0';
636 	}
637 	if (c == '/')
638 	{
639 		int c2 = getcFromInputFile ();
640 		if (c2 == EOF)
641 			return EOF;
642 		else if (c2 == '/')  /* strip comment until end-of-line */
643 		{
644 			do
645 				c = getcFromInputFile ();
646 			while (c != '\n'  &&  c != EOF);
647 		}
648 		else if (c2 == '*')  /* strip block comment */
649 			c = verilogSkipOverCComment ();
650 		else
651 			ungetcToInputFile (c2);
652 	}
653 	// replace a string with "@" only in skipPastMatch()
654 	// because the string may contain parens, etc.
655 	else if (inSkipPastMatch && c == '"')
656 	{
657 		int c2;
658 		do
659 			c2 = getcFromInputFile ();
660 		while (c2 != '"'  &&  c2 != EOF);
661 		c = '@';
662 	}
663 	return c;
664 }
665 
vGetc(void)666 static int vGetc (void)
667 {
668 	return _vGetc (false);
669 }
670 
671 // Is the first charactor in an identifier? [a-zA-Z_`]
isWordToken(const int c)672 static bool isWordToken (const int c)
673 {
674 	return (isalpha (c) || c == '_' || c == '`');
675 }
676 
677 // Is a charactor in an identifier? [a-zA-Z0-9_`$]
isIdentifierCharacter(const int c)678 static bool isIdentifierCharacter (const int c)
679 {
680 	return (isalnum (c) || c == '_' || c == '`' || c == '$');
681 }
682 
skipWhite(int c)683 static int skipWhite (int c)
684 {
685 	while (isspace (c))
686 		c = vGetc ();
687 	return c;
688 }
689 
skipPastMatch(const char * const pair)690 static int skipPastMatch (const char *const pair)
691 {
692 	const int begin = pair [0], end = pair [1];
693 	int matchLevel = 1;
694 	int c;
695 	do
696 	{
697 		c = _vGetc (true);
698 		if (c == begin)
699 			++matchLevel;
700 		else if (c == end)
701 			--matchLevel;
702 	}
703 	while (matchLevel > 0 && c != EOF);
704 	return skipWhite (vGetc ());
705 }
706 
skipDimension(int c)707 static int skipDimension (int c)
708 {
709 	while (c == '[' && c != EOF)
710 		c = skipPastMatch ("[]");
711 	return c;
712 }
713 
skipToSemiColon(int c)714 static int skipToSemiColon (int c)
715 {
716 	while (c != ';' && c != EOF)
717 		c = vGetc ();
718 	return c;	// ';' or EOF
719 }
720 
skipString(int c)721 static int skipString (int c)
722 {
723 	if (c == '"')
724 	{
725 		do
726 			c = vGetc ();
727 		while (c != '"' && c != EOF);
728 	}
729 	c = skipWhite (vGetc ());
730 	return c;
731 }
732 
skipExpression(int c)733 static int skipExpression (int c)
734 {
735 	while (c != ','  &&  c != ';' && c != ')' && c != '}' && c != ']' && c != EOF)
736 	{
737 		if (c == '(')
738 			c = skipPastMatch ("()");
739 		else if (c == '{')
740 			c = skipPastMatch ("{}");
741 		else if (c == '[')
742 			c = skipPastMatch ("[]");
743 		else if (c == '"')
744 			c = skipString (c);
745 		else
746 			c = skipWhite (vGetc ());
747 	}
748 	return c;
749 }
750 
751 // Skip to newline. The newline preceded by a backslash ( \ ) is ignored.
752 // Should be used after readWordTokenNoSkip() for compiler directives
skipToNewLine(int c)753 static int skipToNewLine (int c)
754 {
755 	bool escape = false;
756 	for ( ; (c != '\n' || escape) &&  c != EOF; c = vGetc ())
757 		escape = (c == '\\');
758 
759 	return c;	// '\n' or EOF
760 }
761 
skipMacro(int c,tokenInfo * token)762 static int skipMacro (int c, tokenInfo *token)
763 {
764 	tokenInfo *localToken = newToken ();	// don't update token outside
765 	while (c == '`')	// to support back-to-back compiler directives
766 	{
767 		c = readWordTokenNoSkip (localToken, c);
768 		/* Skip compiler directive other than `define */
769 		if (localToken->kind == K_DIRECTIVE)
770 		{
771 			c = skipToNewLine (c);
772 			c = skipWhite (c);
773 		}
774 		/* Skip `define */
775 		else if (localToken->kind == K_DEFINE)
776 		{
777 			c = skipWhite (c);
778 			c = processDefine (localToken, c);
779 		}
780 		/* return macro expansion */
781 		else
782 		{
783 			swapToken (token, localToken);
784 			c = skipWhite (c);
785 			if (c == '(')
786 				c = skipPastMatch ("()");
787 			break;
788 		}
789 	}
790 	deleteToken (localToken);
791 	return c;
792 }
793 
_updateKind(tokenInfo * const token)794 static void _updateKind (tokenInfo *const token)
795 {
796 	verilogKind kind = (verilogKind) lookupKeyword (vStringValue (token->name), getInputLanguage () );
797 	token->kind = ((kind == K_UNDEFINED) && isIdentifier (token)) ? K_IDENTIFIER : kind;
798 }
799 
800 /* read an identifier, keyword, number, compiler directive, or macro identifier */
_readWordToken(tokenInfo * const token,int c,bool skip)801 static int _readWordToken (tokenInfo *const token, int c, bool skip)
802 {
803 	Assert (isWordToken (c));
804 
805 	clearToken (token);
806 	do
807 	{
808 		vStringPut (token->name, c);
809 		c = vGetc ();
810 	} while (isIdentifierCharacter (c));
811 	_updateKind (token);
812 
813 	if (skip)
814 		return skipWhite (c);
815 	else
816 		return c;
817 }
818 
819 // read a word token starting with "c".
820 // returns the first charactor of the next token.
readWordToken(tokenInfo * const token,int c)821 static int readWordToken (tokenInfo *const token, int c)
822 {
823 	return _readWordToken (token, c, true);
824 }
825 
826 // read a word token starting with "c".
827 // returns the next charactor of the token read.
828 // for compiler directives.  Since they are line-based, skipWhite() cannot be used.
readWordTokenNoSkip(tokenInfo * const token,int c)829 static int readWordTokenNoSkip (tokenInfo *const token, int c)
830 {
831 	return _readWordToken (token, c, false);
832 }
833 
834 /* check if an identifier:
835  *   simple_identifier ::= [ a-zA-Z_ ] { [ a-zA-Z0-9_$ ] } */
isIdentifier(tokenInfo * token)836 static bool isIdentifier (tokenInfo* token)
837 {
838 	if (token->kind == K_UNDEFINED)
839 	{
840 		for (int i = 0; i < vStringLength (token->name); i++)
841 		{
842 			int c = vStringChar (token->name, i);
843 			if (i == 0)
844 			{
845 				if (c == '`' || !isWordToken (c))
846 					return false;
847 			}
848 			else
849 			{
850 				if (!isIdentifierCharacter (c))
851 					return false;
852 			}
853 		}
854 		return true;
855 	}
856 	else
857 		return false;
858 }
859 
createContext(verilogKind kind,vString * const name)860 static void createContext (verilogKind kind, vString* const name)
861 {
862 	tokenInfo *const scope = newToken ();
863 	vStringCopy (scope->name, name);
864 	scope->kind = kind;
865 
866 	if (scope)
867 	{
868 		vString *contextName = vStringNew ();
869 
870 		/* Determine full context name */
871 		if (currentContext->kind != K_UNDEFINED)
872 		{
873 			vStringCopy (contextName, currentContext->name);
874 			vStringPut (contextName, '.');
875 		}
876 		vStringCat (contextName, scope->name);
877 		/* Create context */
878 		currentContext = pushToken (currentContext, scope);
879 		vStringCopy (currentContext->name, contextName);
880 		vStringDelete (contextName);
881 		verbose ("Created new context %s (kind %d)\n", vStringValue (currentContext->name), currentContext->kind);
882 	}
883 }
884 
dropContext()885 static void dropContext ()
886 {
887 	verbose ("Dropping context %s\n", vStringValue (currentContext->name));
888 	currentContext = popToken (currentContext);
889 }
890 
891 /* Drop context, but only if an end token is found */
dropEndContext(tokenInfo * const token,int c)892 static int dropEndContext (tokenInfo *const token, int c)
893 {
894 	verbose ("current context %s; context kind %0d; nest level %0d\n", vStringValue (currentContext->name), currentContext->kind, currentContext->nestLevel);
895 	if ((currentContext->kind == K_COVERGROUP && strcmp (vStringValue (token->name), "endgroup") == 0)
896 	    || (currentContext->kind == K_IFCLASS && strcmp (vStringValue (token->name), "endclass") == 0))
897 	{
898 		dropContext ();
899 		c = skipBlockName (token ,c);
900 	}
901 	else if (currentContext->kind != K_UNDEFINED)
902 	{
903 		vString *endTokenName = vStringNewInit ("end");
904 		vStringCatS (endTokenName, getNameForKind (currentContext->kind));
905 		if (strcmp (vStringValue (token->name), vStringValue (endTokenName)) == 0)
906 		{
907 			dropContext ();
908 			c = skipBlockName (token ,c);
909 			if (currentContext->classScope)
910 			{
911 				verbose ("Dropping local context %s\n", vStringValue (currentContext->name));
912 				currentContext = popToken (currentContext);
913 			}
914 		}
915 		vStringDelete (endTokenName);
916 	}
917 	else
918 		verbose ("Unexpected current context %s\n", vStringValue (currentContext->name));
919 	return c;
920 }
921 
922 
createTag(tokenInfo * const token,verilogKind kind)923 static void createTag (tokenInfo *const token, verilogKind kind)
924 {
925 	tagEntryInfo tag;
926 
927 	if (kind == K_LOCALPARAM)
928 		kind = K_CONSTANT;
929 	else if (kind == K_PARAMETER)
930 	{
931 		kind = K_CONSTANT;
932 		// See LRM 2017 6.20.1 Parameter declaration syntax
933 		if (currentContext->kind != K_CLASS && currentContext->kind != K_PACKAGE && !currentContext->hasParamList)
934 			token->parameter = true;
935 	}
936 	Assert (kind >= 0 && kind != K_UNDEFINED && kind != K_IDENTIFIER);
937 	Assert (vStringLength (token->name) > 0);
938 
939 	/* check if a container before kind is modified by prototype */
940 	/* BTW should we create a context for a prototype? */
941 	bool container = isContainer (kind);
942 
943 	/* Determine if kind is prototype */
944 	if (currentContext->prototype)
945 		kind = K_PROTOTYPE;
946 
947 	/* Do nothing if tag kind is disabled */
948 	if (! kindEnabled (kind))
949 	{
950 		verbose ("kind disabled\n");
951 		return;
952 	}
953 
954 	/* Create tag */
955 	initTagEntry (&tag, vStringValue (token->name), kind);
956 	tag.lineNumber = token->lineNumber;
957 	tag.filePosition = token->filePosition;
958 
959 	verbose ("Adding tag %s (kind %d)", vStringValue (token->name), kind);
960 	if (currentContext->kind != K_UNDEFINED)
961 	{
962 		verbose (" to context %s\n", vStringValue (currentContext->name));
963 		currentContext->lastKind = kind;
964 		tag.extensionFields.scopeKindIndex = currentContext->kind;
965 		tag.extensionFields.scopeName = vStringValue (currentContext->name);
966 	}
967 	verbose ("\n");
968 	if (vStringLength (token->inheritance) > 0)
969 	{
970 		tag.extensionFields.inheritance = vStringValue (token->inheritance);
971 		verbose ("Class %s extends %s\n", vStringValue (token->name), tag.extensionFields.inheritance);
972 	}
973 
974 	if (token->parameter)
975 		attachParserField (&tag, false, fieldTable [F_PARAMETER].ftype, "");
976 
977 	makeTagEntry (&tag);
978 
979 	if (isXtagEnabled (XTAG_QUALIFIED_TAGS) && currentContext->kind != K_UNDEFINED)
980 	{
981 		vString *const scopedName = vStringNew ();
982 
983 		vStringCopy (scopedName, currentContext->name);
984 		vStringPut (scopedName, '.');
985 		vStringCat (scopedName, token->name);
986 		tag.name = vStringValue (scopedName);
987 
988 		markTagExtraBit (&tag, XTAG_QUALIFIED_TAGS);
989 		makeTagEntry (&tag);
990 
991 		vStringDelete (scopedName);
992 	}
993 
994 	/* Push token as context if it is a container */
995 	if (container)
996 	{
997 		createContext (kind, token->name);
998 
999 		/* Put found contents in context */
1000 		verbose ("Putting tagContents: %d element(s)\n",
1001 				 ptrArrayCount (tagContents));
1002 		for (unsigned int i = 0; i < ptrArrayCount (tagContents); i++)
1003 		{
1004 			tokenInfo *content = ptrArrayItem (tagContents, i);
1005 			createTag (content, content->kind);
1006 		}
1007 
1008 		/* Drop temporary contexts */
1009 		if (isTempContext (currentContext))
1010 			dropContext ();
1011 	}
1012 
1013 	/* Clear no longer required inheritance information */
1014 	vStringClear (token->inheritance);
1015 }
1016 
skipBlockName(tokenInfo * const token,int c)1017 static int skipBlockName (tokenInfo *const token, int c)
1018 {
1019 	if (c == ':')
1020 	{
1021 		c = skipWhite (vGetc ());
1022 		if (isWordToken (c))
1023 			c = readWordToken (token, c);
1024 	}
1025 	return c;
1026 }
1027 
1028 // begin, fork
processBlock(tokenInfo * const token,int c)1029 static int processBlock (tokenInfo *const token, int c)
1030 {
1031 	if (c == ':')	// tag an optional block identifier
1032 	{
1033 		c = skipWhite (vGetc ());
1034 		if (isWordToken (c))
1035 		{
1036 			c = readWordToken (token, c);
1037 			verbose ("Found block: %s\n", vStringValue (token->name));
1038 			createTag (token, K_BLOCK);
1039 			verbose ("Current context %s\n", vStringValue (currentContext->name));
1040 		}
1041 	}
1042 	currentContext->nestLevel++;	// increment after creating a context
1043 	return c;
1044 }
1045 
1046 // end, join, join_any, join_none
processEnd(tokenInfo * const token,int c)1047 static int processEnd (tokenInfo *const token, int c)
1048 {
1049 	if (currentContext->nestLevel > 0)	// for sanity check
1050 		currentContext->nestLevel--;
1051 	if (currentContext->kind == K_BLOCK && currentContext->nestLevel == 0)
1052 		dropContext ();
1053 
1054 	c = skipBlockName (token, c);
1055 	return c;
1056 }
1057 
processPortList(tokenInfo * token,int c,bool mayPortDecl)1058 static int processPortList (tokenInfo *token, int c, bool mayPortDecl)
1059 {
1060 	if (c == '(')
1061 	{
1062 		c = skipWhite (vGetc ());	// skip '('
1063 		c = tagIdentifierList (token, c, K_PORT, mayPortDecl);
1064 		if (c == ')')	// sanity check
1065 			c = skipWhite (vGetc ());
1066 		else
1067 			verbose ("Unexpected input: %c\n", c);
1068 	}
1069 	return c;
1070 }
1071 
skipParameterAssignment(int c)1072 static int skipParameterAssignment (int c)
1073 {
1074 	if (c == '#')
1075 	{
1076 		c = skipWhite (vGetc ());
1077 		if (c == '(')
1078 			c = skipPastMatch ("()");
1079 	}
1080 	return c;
1081 }
1082 
1083 // Functions are treated differently because they may also include the type of the return value.
1084 // Tasks are treated in the same way, although not having a return value.
1085 //
1086 // function [ lifetime ] function_data_type_or_implicit [ interface_identifier . | class_scope ] function_identifier [ ( [ tf_port_list ] ) ] ;
1087 // task     [ lifetime ] task_body_declaration          [ interface_identifier . | class_scope ] task_identifier     [ ( [ tf_port_list ] ) ] ;
processFunction(tokenInfo * const token,int c)1088 static int processFunction (tokenInfo *const token, int c)
1089 {
1090 	verilogKind kind = token->kind;	// K_FUNCTION or K_TASK
1091 
1092 	/* Search for function name
1093 	 * Last identifier found before a '(' or a ';' is the function name */
1094 	while (c != '(' && c != ';' && c != EOF)
1095 	{
1096 		if (isWordToken (c))
1097 			c = readWordToken (token, c);
1098 		else
1099 			c = skipWhite (vGetc ());
1100 		/* skip parameter assignment of a class type
1101 		 *    ex. function uvm_port_base #(IF) get_if(int index=0); */
1102 		c = skipParameterAssignment (c);
1103 
1104 		/* Identify class type prefixes and create respective context*/
1105 		if (isInputLanguage (Lang_systemverilog) && c == ':')
1106 		{
1107 			c = vGetc ();
1108 			if (c == ':')
1109 			{
1110 				verbose ("Found function declaration with class type %s\n", vStringValue (token->name));
1111 				createContext (K_CLASS, token->name);
1112 				currentContext->classScope = true;
1113 			}
1114 			else
1115 				vUngetc (c);
1116 		}
1117 	}
1118 	verbose ("Found function: %s\n", vStringValue (token->name));
1119 	createTag (token, kind);
1120 
1121 	/* Get port list from function */
1122 	c = skipWhite (c);
1123 	c = processPortList (token, c, false);
1124 	return c;
1125 }
1126 
1127 // ( enum | union ) [ enum_base_type ] { < enum_name_declaration > }  { [ ... ] }
processEnum(tokenInfo * const token,int c)1128 static int processEnum (tokenInfo *const token, int c)
1129 {
1130 	tokenInfo* enumToken = dupToken (token);	// save enum token
1131 
1132 	/* skip enum_base_type */
1133 	while (isWordToken (c))
1134 		c = readWordToken (token, c);
1135 	c = skipDimension (c);
1136 
1137 	/* Search enum elements */
1138 	c = pushEnumNames (token, c);
1139 
1140 	/* Skip bus width definition */
1141 	c = skipDimension (c);
1142 
1143 	/* Following identifiers are tag names */
1144 	verbose ("Find enum tags. Token %s kind %d\n", vStringValue (enumToken->name), enumToken->kind);
1145 	c = tagNameList (enumToken, c, enumToken->kind);
1146 	deleteToken (enumToken);
1147 
1148 	// Clean up the tag content list at the end of the declaration to support multiple variables
1149 	//   enum { ... } foo, bar;
1150 	ptrArrayClear (tagContents);
1151 	return c;
1152 }
1153 
1154 // [ struct | union [ tagged ] ] [ packed [ signed | unsigned ] ] { struct_union_member { struct_union_member } } { [ ... ] }
processStruct(tokenInfo * const token,int c)1155 static int processStruct (tokenInfo *const token, int c)
1156 {
1157 	verilogKind kind = token->kind;	// K_STRUCT, K_TYPEDEF, or K_NETTYPE
1158 
1159 	/* Skip packed, signed, and unsigned */
1160 	while (isWordToken (c))
1161 		c = readWordToken (token, c);
1162 
1163 	/* create a list of members */
1164 	c = pushMembers (token, c);
1165 
1166 	/* Skip packed_dimension */
1167 	c = skipDimension (c);
1168 
1169 	/* Following identifiers are tag names */
1170 	verbose ("Find struct|union tags. Token %s kind %d\n", vStringValue (token->name), token->kind);
1171 	c = tagNameList (token, c, kind);
1172 	ptrArrayClear (tagContents);
1173 	return c;
1174 }
1175 
1176 // data_declaration ::=
1177 //       [ const ] [ var ] [ static | automatic ] data_type_or_implicit list_of_variable_decl_assignments ;
1178 //     | typedef data_type type_identifier { [ ... ] } ;
1179 //     | typedef interface_instance_identifier [ ... ] . type_identifier type_identifier ; // interface based typedef
1180 //     | typedef [ enum | struct | union | class | interface class ] type_identifier ;
1181 //     | import < package_import_item > ;
1182 //     | nettype data_type net_type_identifier [ with [ class_type :: | package_identifier :: | $unit :: ] tf_identifier ] ;
1183 //     | nettype [ class_type :: | package_identifier :: | $unit :: ] net_type_identifier net_type_identifier ;
processTypedef(tokenInfo * const token,int c)1184 static int processTypedef (tokenInfo *const token, int c)
1185 {
1186 	verilogKind kindSave = token->kind;	// K_TYPEDEF or K_NETTYPE
1187 	verilogKind kind = K_UNDEFINED;
1188 	bool not_used;
1189 	if (isWordToken (c))
1190 	{
1191 		c = readWordToken (token, c);
1192 		kind = token->kind;
1193 	}
1194 	// forward typedef (LRM 6.18) is tagged as prototype
1195 	//   (I don't know why...)
1196 	switch (kind)
1197 	{
1198 		case K_CLASS:
1199 		case K_INTERFACE:
1200 			currentContext->prototype = true;
1201 			break;
1202 		case K_ENUM:
1203 		case K_STRUCT:
1204 			if (isWordToken (c))
1205 			{
1206 				c = readWordToken (token, c);
1207 				if (token->kind == K_IDENTIFIER && c == ';')
1208 					currentContext->prototype = true;
1209 			}
1210 			break;
1211 		case K_IDENTIFIER:
1212 			// interface based typedef
1213 			c = skipDimension (c);
1214 			if (c == '.')
1215 			{
1216 				c = skipWhite (vGetc ());
1217 				if (isWordToken (c))
1218 					c = readWordToken (token, c);
1219 			}
1220 			if (c == ';')
1221 				currentContext->prototype = true;
1222 			break;
1223 		default:
1224 			; // do nothing
1225 	}
1226 	c = processType (token, c, &kind, &not_used);
1227 
1228 	createTag (token, kindSave);
1229 
1230 	ptrArrayClear (tagContents);
1231 	return c;
1232 }
1233 
processParameterList(tokenInfo * token,int c)1234 static int processParameterList (tokenInfo *token, int c)
1235 {
1236 	bool parameter = true;	// default "parameter"
1237 
1238 	if (c != '#')
1239 		return c;
1240 	c = skipWhite (vGetc ());
1241 
1242 	if (c != '(')
1243 		return c;
1244 	c = skipWhite (vGetc ());
1245 
1246 	while (c != ')' && c != EOF)
1247 	{
1248 		if (isWordToken (c))
1249 		{
1250 			c = readWordToken (token, c);
1251 			verbose ("Found parameter %s\n", vStringValue (token->name));
1252 			if (token->kind == K_IDENTIFIER)
1253 			{
1254 				if (c == ',' || c == ')' || c == '=')	// ignore user defined type
1255 				{
1256 					tokenInfo *param = dupToken (token);
1257 					param->kind = K_CONSTANT;
1258 					param->parameter = parameter;
1259 					ptrArrayAdd (tagContents, param);
1260 					if (c == '=')
1261 						c = skipExpression (vGetc ());
1262 					else if (c == ',')
1263 						c = skipWhite (vGetc ());
1264 					else	// ')'
1265 						break;
1266 				}
1267 			}
1268 			else if (token->kind == K_PARAMETER)
1269 				parameter = true;
1270 			else if (token->kind == K_LOCALPARAM)
1271 				parameter = false;
1272 		}
1273 		else
1274 			c = skipWhite (vGetc ());
1275 		// unpacked array is not allowed for a parameter
1276 	}
1277 	c = skipWhite (vGetc ());	// skip ')'
1278 	return c;
1279 }
1280 
1281 // [ virtual ] class [ static | automatic ] class_identifier [ parameter_port_list ]
1282 //     [ extends class_type [ ( list_of_arguments ) ] ] [ implements < interface_class_type > ] ;
1283 // interface class class_identifier [ parameter_port_list ] [ extends < interface_class_type > ] ;
processClass(tokenInfo * const token,int c,verilogKind kind)1284 static int processClass (tokenInfo *const token, int c, verilogKind kind)
1285 {
1286 	tokenInfo *classToken;
1287 
1288 	/* Get identifiers */
1289 	while (isWordToken (c))
1290 	{
1291 		c = readWordToken (token, c);
1292 		// skip static or automatic
1293 		if (token->kind != K_IGNORE)
1294 			break;
1295 	}
1296 
1297 	if (token->kind != K_IDENTIFIER)
1298 	{
1299 		verbose ("Unexpected input: class name is expected.\n");
1300 		return c;
1301 	}
1302 
1303 	/* save token */
1304 	classToken = dupToken (token);
1305 
1306 	/* Find class parameters list */
1307 	c = processParameterList (token, c);
1308 
1309 	/* Search for inheritance information */
1310 	if (isWordToken (c))
1311 	{
1312 		c = readWordToken (token, c);
1313 		if (strcmp (vStringValue (token->name), "extends") == 0)
1314 		{
1315 			if (isWordToken (c))
1316 				c = readWordToken (token, c);
1317 			vStringCopy (classToken->inheritance, token->name);
1318 			verbose ("Inheritance %s\n", vStringValue (classToken->inheritance));
1319 		}
1320 	}
1321 	// process implements: FIXME
1322 
1323 	createTag (classToken, kind);
1324 	deleteToken (classToken);
1325 	ptrArrayClear (tagContents);
1326 	return c;
1327 }
1328 
1329 // constraint_declaration ::= [ static ] constraint constraint_identifier '{' { constraint_block_item } '}'
1330 // constraint_prototype ::= [ extern | pure ] [ static ] constraint constraint_identifier ;
processConstraint(tokenInfo * const token,int c)1331 static int processConstraint (tokenInfo *const token, int c)
1332 {
1333 	verilogKind kind;
1334 	if (isWordToken (c))
1335 		c = readWordToken (token, c);
1336 	if (c == '{')
1337 	{
1338 		c = skipPastMatch ("{}");
1339 		kind = K_CONSTRAINT;
1340 	}
1341 	else
1342 		kind = K_PROTOTYPE;
1343 	createTag (token, kind);
1344 	return c;
1345 }
1346 
processDefine(tokenInfo * const token,int c)1347 static int processDefine (tokenInfo *const token, int c)
1348 {
1349 	/* Bug #961001: Verilog compiler directives are line-based. */
1350 	if (isWordToken (c))
1351 	{
1352 		c = readWordTokenNoSkip (token, c);
1353 		createTag (token, K_CONSTANT);
1354 	}
1355 	c = skipToNewLine (c);
1356 	c = skipWhite (c);
1357 	return c;
1358 }
1359 
1360 // immediate_assertion_statement ::=
1361 //     ( assert | asume | cover ) [ #0 | final ] '(' expression ')' block
1362 // concurrent_assertion_statement ::=
1363 //     ( assert | assume ) property ( property_spec ) action_block
1364 //   | expect ( property_spec ) action_block  # ignore : processed as same as "if"
1365 //   | cover property ( property_spec ) statement_or_null
1366 //   | cover sequence ( [clocking_event ] [ disable iff ( expression_or_dist ) ] sequence_expr ) statement_or_null
1367 //   | restrict property ( property_spec ) ;
processAssertion(tokenInfo * const token,int c)1368 static int processAssertion (tokenInfo *const token, int c)
1369 {
1370 	if (vStringLength (currentContext->blockName) > 0)
1371 	{
1372 		vStringCopy (token->name, currentContext->blockName);
1373 		vStringClear (currentContext->blockName);	// clear block name not to be reused
1374 		createTag (token, K_ASSERTION);
1375 	}
1376 	// skip final | property | sequence
1377 	if (isWordToken (c))
1378 		c = readWordToken (token, c);
1379 	// skip #0
1380 	c = skipDelay (token, c);
1381 	// skip ( ... )
1382 	if (c == '(')
1383 		c = skipPastMatch ("()");
1384 	return c;
1385 }
1386 
1387 // non-ANSI type
1388 // ( module | interface | program ) [ static | automatic ] identifier { package_import_declaration } [ parameter_port_list ] ( port { , port } ) ;
1389 // ANSI type
1390 // ( module | interface | program ) [ static | automatic ] identifier { package_import_declaration } [ parameter_port_list ] [ ( [ < { (* ... *) } ansi_port_declaration > ] ) ] ;
1391 //
1392 // interface class class_identifier [ parameter_port_list ] [ extends < interface_class_type > ] ;
processDesignElementL(tokenInfo * const token,int c)1393 static int processDesignElementL (tokenInfo *const token, int c)
1394 {
1395 	verilogKind kind = token->kind;
1396 
1397 	while (isWordToken (c))
1398 	{
1399 		c = readWordToken (token, c);
1400 		// interface class
1401 		if (token->kind == K_CLASS)
1402 			return processClass (token, c, K_IFCLASS);
1403 		// skip static or automatic
1404 		else if (token->kind != K_IGNORE)
1405 			break;
1406 	}
1407 	if (token->kind == K_IDENTIFIER)
1408 		createTag (token, kind);	// identifier
1409 
1410 	// skip package_import_declaration
1411 	while (isWordToken (c))
1412 	{
1413 		c = readWordToken (token, c);
1414 		if (token->kind == K_IMPORT)
1415 		{
1416 			c = skipToSemiColon (c);
1417 			c = skipWhite (vGetc ());	// skip semicolon
1418 		}
1419 		else
1420 		{
1421 			verbose ("Unexpected input\n");
1422 			return c;
1423 		}
1424 	}
1425 	if (c == '#')	// parameter_port_list
1426 	{
1427 		c = processParameterList (token, c);
1428 
1429 		/* Put found parameters in context */
1430 		verbose ("Putting parameters: %d element(s)\n",
1431 				ptrArrayCount (tagContents));
1432 		for (unsigned int i = 0; i < ptrArrayCount (tagContents); i++)
1433 		{
1434 			tokenInfo *content = ptrArrayItem (tagContents, i);
1435 			createTag (content, K_CONSTANT);
1436 		}
1437 		ptrArrayClear (tagContents);
1438 		// disable parameter property on parameter declaration statement
1439 		currentContext->hasParamList = true;
1440 	}
1441 	// Process ANSI/non-ANSI port list in main loop
1442 	c = processPortList (token, c, true);
1443 	return c;
1444 }
1445 
1446 // ( checker | property | sequence ) identifier [ ( [ port_list ] ) ] ;
1447 // covergroup identifier [ ( [ port_list ] ) ] [ coverage_event ] ;
1448 //   coverage_event ::= clocking_event | with function sample ( ... ) | @@( ... )
1449 // package identifier ;
1450 // modport < identifier ( < ports_declaration > ) > ;
1451 // [ default | global ] clocking [ identifier ] ( @ identifier | @ ( event_expression ) )
processDesignElementS(tokenInfo * const token,int c)1452 static int processDesignElementS (tokenInfo *const token, int c)
1453 {
1454 	verilogKind kind = token->kind;
1455 
1456 	if (isWordToken (c))
1457 		c = readWordToken (token, c);
1458 	else
1459 		return c;
1460 
1461 	createTag (token, kind);	// identifier
1462 
1463 	/* Get port list if required */
1464 	if (c == '(')	// port_list
1465 	{
1466 		if (kind == K_MODPORT)
1467 			c = skipPastMatch ("()");	// ignore port list
1468 		else
1469 			c = processPortList (token, c, false);
1470 	}
1471 	// skip clocking_event for clocking block or coverage_event for covergroup
1472 	// "with function sample ()" is processed in the main loop
1473 	if (c == '@')
1474 		c = skipClockEvent (token, c);
1475 	return c;
1476 }
1477 
skipDelay(tokenInfo * token,int c)1478 static int skipDelay (tokenInfo* token, int c)
1479 {
1480 	if (c == '#')
1481 	{
1482 		c = skipWhite (vGetc ());
1483 		if (c == '(')
1484 			c = skipPastMatch ("()");
1485 		else if (c == '#')
1486 			// a dirty hack for "x ##delay1 y[*min:max];"
1487 			c = skipToSemiColon (vGetc ());
1488 		else	// time literals
1489 		{
1490 			while (isIdentifierCharacter (c) || c == '.')
1491 				c = vGetc ();
1492 			c = skipWhite (c);
1493 		}
1494 	}
1495 	return c;
1496 }
1497 
skipClockEvent(tokenInfo * token,int c)1498 static int skipClockEvent (tokenInfo* token, int c)
1499 {
1500 	if (c == '@')
1501 	{
1502 		c = skipWhite (vGetc ());
1503 		// for @@ ( ... ) : coverage_event
1504 		if (c == '@')
1505 			c = skipWhite (vGetc ());
1506 		if (c == '(')
1507 			c = skipPastMatch ("()");
1508 		else if (isWordToken (c))
1509 			c = readWordToken (token, c);
1510 	}
1511 	return c;
1512 }
1513 
pushEnumNames(tokenInfo * token,int c)1514 static int pushEnumNames (tokenInfo* token, int c)
1515 {
1516 	if (c == '{')
1517 	{
1518 		c = skipWhite (vGetc ());
1519 		while (c != '}' && c != EOF)
1520 		{
1521 			if (!isWordToken (c))
1522 			{
1523 				verbose ("Unexpected input: %c\n", c);
1524 				return c;
1525 			}
1526 			c = readWordToken (token, c);
1527 
1528 			token->kind = K_CONSTANT;
1529 			ptrArrayAdd (tagContents, dupToken (token));
1530 			verbose ("Pushed enum element \"%s\"\n", vStringValue (token->name));
1531 
1532 			/* Skip element ranges */
1533 			/* TODO Implement element ranges */
1534 			c = skipDimension (c);
1535 
1536 			/* Skip value assignments */
1537 			if (c == '=')
1538 				c = skipExpression (vGetc ());
1539 
1540 			/* Skip comma */
1541 			if (c == ',')
1542 				c = skipWhite (vGetc ());
1543 		}
1544 		c = skipWhite (vGetc ());	// skip '}'
1545 	}
1546 	return c;
1547 }
1548 
1549 // create a list of struct/union members
pushMembers(tokenInfo * token,int c)1550 static int pushMembers (tokenInfo* token, int c)
1551 {
1552 	if (c == '{')
1553 	{
1554 		c = skipWhite (vGetc ());
1555 		while (c != '}' && c != EOF)
1556 		{
1557 			verilogKind kind = K_UNDEFINED;	// set kind of context for processType()
1558 			bool not_used;
1559 			if (!isWordToken (c))
1560 			{
1561 				verbose ("Unexpected input: %c\n", c);
1562 				return c;
1563 			}
1564 			c = readWordToken (token, c);
1565 
1566 			c = processType (token, c, &kind, &not_used);
1567 			while (true)
1568 			{
1569 				token->kind = K_MEMBER;
1570 				ptrArrayAdd (tagContents, dupToken (token));
1571 				verbose ("Pushed struct/union member \"%s\"\n", vStringValue (token->name));
1572 
1573 				/* Skip unpacked dimensions */
1574 				c = skipDimension (c);
1575 
1576 				/* Skip value assignments */
1577 				if (c == '=')
1578 					c = skipExpression (vGetc ());
1579 
1580 				if (c != ',' || c == EOF)
1581 					break;		// should be ';'
1582 
1583 				c = skipWhite (vGetc ());	// skip ','
1584 				if (isWordToken (c))
1585 					c = readWordToken (token, c);
1586 				else
1587 				{
1588 					verbose ("Unexpected input.\n");
1589 					break;
1590 				}
1591 			}
1592 			/* Skip semicolon */
1593 			if (c == ';')
1594 				c = skipWhite (vGetc ());
1595 			/* End of enum elements list */
1596 		}
1597 		c = skipWhite (vGetc ());	// skip '}'
1598 	}
1599 	return c;
1600 }
1601 
1602 // input
1603 //   kind: kind of context
1604 // output
1605 //   kind: kind of type
1606 //   token: identifier token (unless K_IDENTIFIER nor K_UNDEFINED)
processType(tokenInfo * token,int c,verilogKind * kind,bool * with)1607 static int processType (tokenInfo* token, int c, verilogKind* kind, bool* with)
1608 {
1609 	verilogKind actualKind = K_UNDEFINED;
1610 	tokenInfo *tokenSaved;
1611 	*with = false;
1612 	do
1613 	{
1614 		c = skipDimension (c);
1615 		c = skipDelay (token, c);	// class parameter #(...)
1616 		if (c == '{')	// skip enum, struct, or union member
1617 		{
1618 			if (*kind == K_ENUM)
1619 				c = pushEnumNames (token, c);
1620 			else if (*kind == K_STRUCT)
1621 				c = pushMembers (token, c);
1622 			else	// for a nested structure
1623 				c = skipPastMatch ("{}");
1624 		}
1625 		c = skipDimension (c);
1626 		c = skipMacro (c, token);
1627 
1628 		// break on ',', ';', ')', '}', or other unexpected charactors
1629 		if (!isWordToken (c))
1630 			break;
1631 
1632 		tokenSaved = dupToken (token);
1633 		c = readWordToken (token, c);
1634 		// break on "with"
1635 		if (token->kind == K_WITH)
1636 		{
1637  			swapToken (token, tokenSaved);
1638 			deleteToken (tokenSaved);
1639 			*with = true;	// inform to caller
1640 			break;
1641 		}
1642 		deleteToken (tokenSaved);
1643 
1644 		// fix kind of user defined type
1645 		if (*kind == K_IDENTIFIER)
1646 		{
1647 			if (token->kind == K_NET)
1648 				actualKind = K_NET;
1649 			else if (token->kind == K_REGISTER)
1650 				actualKind = K_REGISTER;
1651 			else if (token->kind == K_PORT)
1652 				actualKind = K_PORT;
1653 			else if (token->kind == K_IDENTIFIER)
1654 			{	// identifier of a user defined type
1655 				*kind = K_REGISTER;	// FIXME: consider kind of the user defined type
1656 				break;
1657 			}
1658 			else
1659 			{
1660 				verbose ("Unexpected input\n");	// FIXME: x dist {}, with
1661 				break;
1662 			}
1663 		}
1664 	} while (c != '`' && c != EOF);	// break on compiler directive
1665 
1666 	// skip unpacked dimension (or packed dimension after type-words)
1667 	c = skipDimension (skipWhite (c));
1668 
1669 	if (*kind == K_UNDEFINED && *kind != K_PORT)
1670 		*kind = actualKind;
1671 	return c;
1672 }
1673 
1674 // class_type ::=
1675 //       ps_class_identifier [ # ( ... ) ] { :: class_identifier [ # ( ... ) ] }
1676 // "interface_identifier ." is also handled
skipClassType(tokenInfo * token,int c)1677 static int skipClassType (tokenInfo* token, int c)
1678 {
1679 	while (c == '#' || c == ':' || c == '.')
1680 	{
1681 		if (c == '#')
1682 		{
1683 			c = skipWhite (vGetc ());
1684 			// a dirty hack for "x ##delay1 y[*min:max];"
1685 			if (c == '#')
1686 				return skipToSemiColon (vGetc ());
1687 			c = skipPastMatch ("()");
1688 		}
1689 		else if (c == ':')
1690 		{
1691 			c = skipWhite (vGetc ());
1692 			if (c != ':')
1693 			{
1694 				verbose ("Unexpected input.\n");
1695 				vUngetc (c);
1696 				return ':';
1697 			}
1698 			c = skipWhite (vGetc ());
1699 			if (isWordToken (c))
1700 				c = readWordToken (token, c);
1701 		}
1702 		else	// c == '.' : interface_identifier .
1703 		{
1704 			c = skipWhite (vGetc ());
1705 			if (isWordToken (c))
1706 				c = readWordToken (token, c);
1707 		}
1708 	}
1709 	return c;
1710 }
1711 
1712 // Tag a list of identifiers
1713 // data_type :: =
1714 //   ...
1715 //   | virtual [ interface ] identifier [ # ( [ ... ] ) ]  [ . identifier ]
1716 //   | [ class_type :: | identifier :: | $unit :: ] identifier { [ ... ] }
1717 //   | [ identifier :: | $unit :: ] identifier [ # ( ... ) ] { :: identifier [ # ( ... ) ] }
1718 //   | ...
1719 //
1720 //   mayPortDecl: may be a ANSI port declaration.  true for module, interface, or program.
tagIdentifierList(tokenInfo * const token,int c,verilogKind kind,bool mayPortDecl)1721 static int tagIdentifierList (tokenInfo *const token, int c, verilogKind kind, bool mayPortDecl)
1722 {
1723 	bool first_port = true;
1724 	bool enableTag = true;
1725 	verilogKind localKind;
1726 	bool not_used;
1727 
1728 	while (c != ')' && c != EOF)	// skip empty port, "()"
1729 	{
1730 		// skip attribute_instance: (* ... *)
1731 		if (c == '(')
1732 			c = skipPastMatch ("()");
1733 
1734 		// skip port direction, "virtual", or "interface"
1735 		while (isWordToken (c))
1736 		{
1737 			c = readWordToken (token, c);
1738 			if (token->kind == K_PORT || token->kind == K_IGNORE || token->kind == K_INTERFACE)
1739 				mayPortDecl = false;	// now never be a non-ANSI port
1740 			else
1741 				break;
1742 		}
1743 		if (token->kind == K_IDENTIFIER)
1744 			c = skipClassType (token, c);
1745 		c = skipMacro (c, token);	// `ifdef, `else, `endif, etc. (between identifiers)
1746 
1747 		if (isWordToken (c))
1748 		{
1749 			c = readWordToken (token, c);
1750 			if (token->kind == K_IDENTIFIER)
1751 			{
1752 				mayPortDecl = false;
1753 				c = skipClassType (token, c);
1754 			}
1755 		}
1756 		// aoid tagging enum and struct items
1757 		localKind = token->kind == K_ENUM || token->kind == K_STRUCT ? K_PORT : token->kind;
1758 		c = processType (token, c, &localKind, &not_used);
1759 
1760 		// LRM 23.2.2.3 Rules for determining port kind, data type, and direction
1761 		// If the direction, port kind, and data type are all omitted for
1762 		// the first port in the port list, ... non-ANSI style, ...
1763 		if (mayPortDecl && first_port)
1764 		{
1765 			first_port = false;
1766 			if (localKind == K_IDENTIFIER)
1767 				enableTag = false;	// don't tag for non-ANSI port
1768 		}
1769 		if (enableTag && token->kind == K_IDENTIFIER)
1770 			createTag (token, kind);
1771 
1772 		if (c == '=')
1773 			c = skipExpression (vGetc ());
1774 
1775 		c = skipMacro (c, token);	// `ifdef, `else, `endif, etc. (before comma)
1776 		if (c != ',' || c == EOF)
1777 			break;
1778 		c = skipWhite (vGetc ());	// skip ','
1779 		c = skipMacro (c, token);	// `ifdef, `else, `endif, etc. (after comma)
1780 	}
1781 	return c;
1782 }
1783 
tagNameList(tokenInfo * token,int c,verilogKind kind)1784 static int tagNameList (tokenInfo* token, int c, verilogKind kind)
1785 {
1786 	c = skipClassType (token, c);
1787 	if (c == ':' || c == ';')	// ## (cycle delay) or unexpected input
1788 		return c;
1789 
1790 	// skip drive|charge strength or type_reference, dimensions, and delay for net
1791 	if (c == '(')
1792 		c = skipPastMatch ("()");
1793 	c = skipDimension (c);
1794 	if (c == '.')
1795 		return c;	// foo[...].bar = ..;
1796 	c = skipDelay (token, c);
1797 
1798 	while (c != EOF)
1799 	{
1800 		bool with = false;
1801 		c = processType (token, c, &kind, &with);	// update token and kind
1802 
1803 		if (c == '=' || c == ',' || c == ';' || c == ')' || c == '`' || with)
1804 		{
1805 			// ignore an empty token or procedual assignment: foo = bar;
1806 			if (kind != K_UNDEFINED && kind != K_IDENTIFIER && token->kind != K_UNDEFINED)
1807 				createTag (token, kind);
1808 			if (c == '=')
1809 				c = skipExpression (c);
1810 		}
1811 		else if (c == '(' || c == '[')	// should be instance
1812 		{
1813 			c = skipDimension (c); // name_of_instance {unpacked_dimension}
1814 			c = skipPastMatch ("()"); // list_of_port_connections
1815 
1816 			// if without the next "if" clause, get a instance named: `add_t from the following example
1817 			// var `add_t(foo) = '0;
1818 			if (c == ';' || c == ',')
1819 			{
1820 				verbose ("find instance: %s with kind %s\n", vStringValue (token->name), getNameForKind (K_INSTANCE));
1821 				createTag (token, K_INSTANCE);
1822 			}
1823 		}
1824 		c = skipMacro (c, token);	// `ifdef, `else, `endif, etc. (before comma)
1825 		if (c != ',' || c == EOF)
1826 			break;
1827 		c = skipWhite (vGetc ());	// skip ','
1828 		c = skipMacro (c, token);	// `ifdef, `else, `endif, etc. (after comma)
1829 	}
1830 	return c;
1831 }
1832 
findTag(tokenInfo * const token,int c)1833 static int findTag (tokenInfo *const token, int c)
1834 {
1835 	verbose ("Checking token %s of kind %d\n", vStringValue (token->name), token->kind);
1836 
1837 	switch (token->kind)
1838 	{
1839 		case K_CONSTANT:
1840 		case K_EVENT:
1841 		case K_LOCALPARAM:
1842 		case K_NET:
1843 		case K_PARAMETER:
1844 		case K_PORT:
1845 		case K_REGISTER:
1846 			if (token->kind == K_PORT && currentContext->kind == K_CLOCKING)
1847 				c = skipToSemiColon (c); // clocking items are not port definitions
1848 			else
1849 				c = tagNameList (token, c, token->kind);
1850 			break;
1851 		case K_IDENTIFIER:
1852 			{
1853 				if (c == '[')	// for a case label foo[x]:
1854 					c = skipPastMatch ("[]");
1855 
1856 				if (c == ':')
1857 					; /* label */
1858 				else if (c == ',' || c == '{')	// "foo, ..." or "coverpoint foo { ... }"
1859 					c = skipWhite (vGetc ());
1860 				else if (c == '(')	// task, function, or method call
1861 					c = skipPastMatch ("()");
1862 				else if (c == '=')	// assignment
1863 					c = skipExpression (skipWhite (vGetc ()));
1864 				else
1865 					c = tagNameList (token, c, token->kind); /* user defined type */
1866 			}
1867 			break;
1868 		case K_CLASS:
1869 			c = processClass (token, c, K_CLASS);
1870 			break;
1871 		case K_TYPEDEF:
1872 		case K_NETTYPE:
1873 			c = processTypedef (token, c);
1874 			break;
1875 		case K_ENUM:
1876 			c = processEnum (token, c);
1877 			break;
1878 		case K_STRUCT:
1879 			c = processStruct (token, c);
1880 			break;
1881 		case K_PROTOTYPE:
1882 		case K_IMPORT:
1883 		case K_WITH:
1884 			currentContext->prototype = true;
1885 			break;
1886 
1887 		case K_INTERFACE:
1888 		case K_MODULE:
1889 		case K_PROGRAM:
1890 			c = processDesignElementL (token, c);
1891 			break;
1892 		case K_CHECKER:
1893 		case K_CLOCKING:
1894 		case K_COVERGROUP:
1895 		case K_MODPORT:
1896 		case K_PACKAGE:
1897 		case K_PROPERTY:
1898 		case K_SEQUENCE:
1899 			c = processDesignElementS (token, c);
1900 			break;
1901 		case K_END_DE:
1902 			c = dropEndContext (token, c);
1903 			break;
1904 		case K_BLOCK:
1905 			c = processBlock (token, c);
1906 			break;
1907 		case K_END:
1908 			c = processEnd (token, c);
1909 			break;
1910 		case K_FUNCTION:
1911 		case K_TASK:
1912 			c = processFunction (token, c);
1913 			break;
1914 		case K_ASSERTION:
1915 			c = processAssertion (token, c);
1916 			break;
1917 		case K_CONSTRAINT:
1918 			c = processConstraint (token, c);
1919 			break;
1920 
1921 		case K_DEFINE:
1922 			c = processDefine (token, c);
1923 			break;
1924 
1925 		case K_IGNORE:
1926 			break;
1927 		default:
1928 			verbose ("Unexpected kind->token %d\n", token->kind);
1929 	}
1930 	return c;
1931 }
1932 
findVerilogTags(void)1933 static void findVerilogTags (void)
1934 {
1935 	tokenInfo *const token = newToken ();
1936 	int c = skipWhite (vGetc ());
1937 	currentContext = newToken ();
1938 	fieldTable = isInputLanguage (Lang_verilog) ? VerilogFields : SystemVerilogFields;
1939 	ptrArrayClear (tagContents);
1940 
1941 	while (c != EOF)
1942 	{
1943 		switch (c)
1944 		{
1945 			case ':':
1946 				/* Store current block name whenever a : is found
1947 				 * This is used later by any tag type that requires this information */
1948 				vStringCopy (currentContext->blockName, token->name);
1949 				c = skipWhite (vGetc ());
1950 				break;
1951 			case ';':
1952 				/* Drop context on prototypes because they don't have an
1953 				 * end statement */
1954 				if (currentContext->scope && currentContext->scope->prototype)
1955 					dropContext ();
1956 
1957 				/* Prototypes end at the end of statement */
1958 				currentContext->prototype = false;
1959 				c = skipWhite (vGetc ());
1960 				break;
1961 			case '(':	// ignore locally declared variables in a for-loop (LRM 12.7.1)
1962 				c = skipPastMatch ("()");;
1963 				break;
1964 			case '{':
1965 				c = skipPastMatch ("{}");;
1966 				break;
1967 			case '#':
1968 				c = skipDelay (token, c);
1969 				break;
1970 			case '@':
1971 				c = skipClockEvent (token, c);
1972 				break;
1973 			case '"':
1974 				c = skipString (c);
1975 				break;
1976 			default :
1977 				if (isWordToken (c))
1978 				{
1979 					c = readWordTokenNoSkip (token, c);
1980 					if (token->kind == K_DIRECTIVE)
1981 					{
1982 						// Skip compiler directives which are line-based.
1983 						c = skipToNewLine (c);
1984 						c = skipWhite (c);
1985 					}
1986 					else if (token->kind != K_UNDEFINED)
1987 						c = findTag (token, skipWhite (c));
1988 				}
1989 				else
1990 					c = skipWhite (vGetc ());
1991 		}
1992 	}
1993 	deleteToken (token);
1994 	pruneTokens (currentContext);
1995 	currentContext = NULL;
1996 }
1997 
VerilogParser(void)1998 extern parserDefinition* VerilogParser (void)
1999 {
2000 	static const char *const extensions [] = { "v", NULL };
2001 	parserDefinition* def = parserNew ("Verilog");
2002 	def->kindTable  = VerilogKinds;
2003 	def->kindCount  = ARRAY_SIZE (VerilogKinds);
2004 	def->fieldTable = VerilogFields;
2005 	def->fieldCount = ARRAY_SIZE (VerilogFields);
2006 	def->extensions = extensions;
2007 	def->parser     = findVerilogTags;
2008 	def->initialize = initializeVerilog;
2009 	return def;
2010 }
2011 
SystemVerilogParser(void)2012 extern parserDefinition* SystemVerilogParser (void)
2013 {
2014 	static const char *const extensions [] = { "sv", "svh", "svi", NULL };
2015 	parserDefinition* def = parserNew ("SystemVerilog");
2016 	def->kindTable  = SystemVerilogKinds;
2017 	def->kindCount  = ARRAY_SIZE (SystemVerilogKinds);
2018 	def->fieldTable = SystemVerilogFields;
2019 	def->fieldCount = ARRAY_SIZE (SystemVerilogFields);
2020 	def->extensions = extensions;
2021 	def->parser     = findVerilogTags;
2022 	def->initialize = initializeSystemVerilog;
2023 	return def;
2024 }
2025