Remove unused variable
[geany-mirror.git] / ctags / parsers / verilog.c
blob25a9ba8d584b6c97a0f9d9566e6725f5f550a74d
1 /*
2 * Copyright (c) 2003, Darren Hiebert
3 * Copyright (c) 2017, Vitor Antunes
4 * Copyright (c) 2020, Hiroo Hayashi
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.
9 * This module contains functions for generating tags for the Verilog or
10 * SystemVerilog HDL (Hardware Description Language).
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
22 * INCLUDE FILES
24 #include "general.h" /* must always come first */
26 #include <string.h>
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"
39 * MACROS
41 #define NUMBER_LANGUAGES 2 /* Indicates number of defined indexes */
42 #define IDX_SYSTEMVERILOG 0
43 #define IDX_VERILOG 1
46 * DATA DECLARATIONS
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,
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;
99 typedef struct {
100 const char *keyword;
101 verilogKind kind;
102 short isValid [NUMBER_LANGUAGES];
103 } keywordAssoc;
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;
121 typedef enum {
122 F_PARAMETER,
123 } verilogField;
126 * DATA DEFINITIONS
128 static int Ungetc;
129 static int Lang_verilog;
130 static int Lang_systemverilog;
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" },
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" },
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
270 static tokenInfo *currentContext = NULL;
271 static ptrArray *tagContents;
272 static fieldDefinition *fieldTable = NULL;
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
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
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
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
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 },
386 static fieldDefinition SystemVerilogFields[] = {
387 { .name = "parameter",
388 .description = "parameter whose value can be overridden.",
389 .enabled = false,
390 .dataType = FIELDTYPE_BOOL },
394 * PROTOTYPE DEFINITIONS
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);
411 * FUNCTION DEFINITIONS
414 static short isContainer (verilogKind kind)
416 switch (kind)
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;
442 static short isTempContext (tokenInfo const* token)
444 switch (token->kind)
446 case K_TYPEDEF:
447 case K_NETTYPE:
448 case K_ENUM:
449 case K_STRUCT:
450 return true;
451 default:
452 return false;
456 static void clearToken (tokenInfo *token)
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;
473 static tokenInfo *newToken (void)
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;
483 static tokenInfo *dupToken (tokenInfo *token)
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;
499 static void deleteToken (tokenInfo * const token)
501 if (token != NULL)
503 vStringDelete (token->name);
504 vStringDelete (token->blockName);
505 vStringDelete (token->inheritance);
506 eFree (token);
510 static tokenInfo *pushToken (tokenInfo * const token, tokenInfo * const tokenPush)
512 tokenPush->scope = token;
513 return tokenPush;
516 static tokenInfo *popToken (tokenInfo * const token)
518 tokenInfo *localToken;
519 if (token != NULL)
521 localToken = token->scope;
522 deleteToken (token);
523 return localToken;
525 return NULL;
528 static void pruneTokens (tokenInfo * token)
530 while ((token = popToken (token)))
534 static void swapToken (tokenInfo *t0, tokenInfo *t1)
536 tokenInfo tmp = *t0;
537 *t0 = *t1;
538 *t1 = tmp;
541 static const char *getNameForKind (const verilogKind kind)
543 if (isInputLanguage (Lang_systemverilog))
544 return (SystemVerilogKinds[kind]).name;
545 else /* isInputLanguage (Lang_verilog) */
546 return (VerilogKinds[kind]).name;
549 static char kindEnabled (const verilogKind kind)
551 if (isInputLanguage (Lang_systemverilog))
552 return SystemVerilogKinds[kind].enabled;
553 else /* isInputLanguage (Lang_verilog) */
554 return VerilogKinds[kind].enabled;
557 static void buildKeywordHash (const langType language, unsigned int idx)
559 size_t i;
560 const size_t count = ARRAY_SIZE (KeywordTable);
561 for (i = 0 ; i < count ; ++i)
563 const keywordAssoc *p = &KeywordTable [i];
564 if (p->isValid [idx])
565 addKeyword (p->keyword, language, (int) p->kind);
569 static void initializeVerilog (const langType language)
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);
580 static void initializeSystemVerilog (const langType language)
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);
590 static void vUngetc (int c)
592 Assert (Ungetc == '\0');
593 Ungetc = c;
596 /* Mostly copied from cppSkipOverCComment() in cpreprocessor.c.
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. */
603 static int verilogSkipOverCComment (void)
605 int c = getcFromInputFile ();
607 while (c != EOF)
609 if (c != '*')
610 c = getcFromInputFile ();
611 else
613 const int next = getcFromInputFile ();
615 if (next != '/')
616 c = next;
617 else
619 c = SPACE; /* replace comment with space */
620 break;
624 return c;
627 static int _vGetc (bool inSkipPastMatch)
629 int c;
630 if (Ungetc == '\0')
631 c = getcFromInputFile ();
632 else
634 c = Ungetc;
635 Ungetc = '\0';
637 if (c == '/')
639 int c2 = getcFromInputFile ();
640 if (c2 == EOF)
641 return EOF;
642 else if (c2 == '/') /* strip comment until end-of-line */
645 c = getcFromInputFile ();
646 while (c != '\n' && c != EOF);
648 else if (c2 == '*') /* strip block comment */
649 c = verilogSkipOverCComment ();
650 else
651 ungetcToInputFile (c2);
653 // replace a string with "@" only in skipPastMatch()
654 // because the string may contain parens, etc.
655 else if (inSkipPastMatch && c == '"')
657 int c2;
659 c2 = getcFromInputFile ();
660 while (c2 != '"' && c2 != EOF);
661 c = '@';
663 return c;
666 static int vGetc (void)
668 return _vGetc (false);
671 // Is the first charactor in an identifier? [a-zA-Z_`]
672 static bool isWordToken (const int c)
674 return (isalpha (c) || c == '_' || c == '`');
677 // Is a charactor in an identifier? [a-zA-Z0-9_`$]
678 static bool isIdentifierCharacter (const int c)
680 return (isalnum (c) || c == '_' || c == '`' || c == '$');
683 static int skipWhite (int c)
685 while (isspace (c))
686 c = vGetc ();
687 return c;
690 static int skipPastMatch (const char *const pair)
692 const int begin = pair [0], end = pair [1];
693 int matchLevel = 1;
694 int c;
697 c = _vGetc (true);
698 if (c == begin)
699 ++matchLevel;
700 else if (c == end)
701 --matchLevel;
703 while (matchLevel > 0 && c != EOF);
704 return skipWhite (vGetc ());
707 static int skipDimension (int c)
709 while (c == '[' && c != EOF)
710 c = skipPastMatch ("[]");
711 return c;
714 static int skipToSemiColon (int c)
716 while (c != ';' && c != EOF)
717 c = vGetc ();
718 return c; // ';' or EOF
721 static int skipString (int c)
723 if (c == '"')
726 c = vGetc ();
727 while (c != '"' && c != EOF);
729 c = skipWhite (vGetc ());
730 return c;
733 static int skipExpression (int c)
735 while (c != ',' && c != ';' && c != ')' && c != '}' && c != ']' && c != EOF)
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 ());
748 return c;
751 // Skip to newline. The newline preceded by a backslash ( \ ) is ignored.
752 // Should be used after readWordTokenNoSkip() for compiler directives
753 static int skipToNewLine (int c)
755 bool escape = false;
756 for ( ; (c != '\n' || escape) && c != EOF; c = vGetc ())
757 escape = (c == '\\');
759 return c; // '\n' or EOF
762 static int skipMacro (int c, tokenInfo *token)
764 tokenInfo *localToken = newToken (); // don't update token outside
765 while (c == '`') // to support back-to-back compiler directives
767 c = readWordTokenNoSkip (localToken, c);
768 /* Skip compiler directive other than `define */
769 if (localToken->kind == K_DIRECTIVE)
771 c = skipToNewLine (c);
772 c = skipWhite (c);
774 /* Skip `define */
775 else if (localToken->kind == K_DEFINE)
777 c = skipWhite (c);
778 c = processDefine (localToken, c);
780 /* return macro expansion */
781 else
783 swapToken (token, localToken);
784 c = skipWhite (c);
785 if (c == '(')
786 c = skipPastMatch ("()");
787 break;
790 deleteToken (localToken);
791 return c;
794 static void _updateKind (tokenInfo *const token)
796 verilogKind kind = (verilogKind) lookupKeyword (vStringValue (token->name), getInputLanguage () );
797 token->kind = ((kind == K_UNDEFINED) && isIdentifier (token)) ? K_IDENTIFIER : kind;
800 /* read an identifier, keyword, number, compiler directive, or macro identifier */
801 static int _readWordToken (tokenInfo *const token, int c, bool skip)
803 Assert (isWordToken (c));
805 clearToken (token);
808 vStringPut (token->name, c);
809 c = vGetc ();
810 } while (isIdentifierCharacter (c));
811 _updateKind (token);
813 if (skip)
814 return skipWhite (c);
815 else
816 return c;
819 // read a word token starting with "c".
820 // returns the first charactor of the next token.
821 static int readWordToken (tokenInfo *const token, int c)
823 return _readWordToken (token, c, true);
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.
829 static int readWordTokenNoSkip (tokenInfo *const token, int c)
831 return _readWordToken (token, c, false);
834 /* check if an identifier:
835 * simple_identifier ::= [ a-zA-Z_ ] { [ a-zA-Z0-9_$ ] } */
836 static bool isIdentifier (tokenInfo* token)
838 if (token->kind == K_UNDEFINED)
840 for (int i = 0; i < vStringLength (token->name); i++)
842 int c = vStringChar (token->name, i);
843 if (i == 0)
845 if (c == '`' || !isWordToken (c))
846 return false;
848 else
850 if (!isIdentifierCharacter (c))
851 return false;
854 return true;
856 else
857 return false;
860 static void createContext (verilogKind kind, vString* const name)
862 tokenInfo *const scope = newToken ();
863 vStringCopy (scope->name, name);
864 scope->kind = kind;
866 if (scope)
868 vString *contextName = vStringNew ();
870 /* Determine full context name */
871 if (currentContext->kind != K_UNDEFINED)
873 vStringCopy (contextName, currentContext->name);
874 vStringPut (contextName, '.');
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);
885 static void dropContext ()
887 verbose ("Dropping context %s\n", vStringValue (currentContext->name));
888 currentContext = popToken (currentContext);
891 /* Drop context, but only if an end token is found */
892 static int dropEndContext (tokenInfo *const token, int c)
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))
898 dropContext ();
899 c = skipBlockName (token ,c);
901 else if (currentContext->kind != K_UNDEFINED)
903 vString *endTokenName = vStringNewInit ("end");
904 vStringCatS (endTokenName, getNameForKind (currentContext->kind));
905 if (strcmp (vStringValue (token->name), vStringValue (endTokenName)) == 0)
907 dropContext ();
908 c = skipBlockName (token ,c);
909 if (currentContext->classScope)
911 verbose ("Dropping local context %s\n", vStringValue (currentContext->name));
912 currentContext = popToken (currentContext);
915 vStringDelete (endTokenName);
917 else
918 verbose ("Unexpected current context %s\n", vStringValue (currentContext->name));
919 return c;
923 static void createTag (tokenInfo *const token, verilogKind kind)
925 tagEntryInfo tag;
927 if (kind == K_LOCALPARAM)
928 kind = K_CONSTANT;
929 else if (kind == K_PARAMETER)
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;
936 Assert (kind >= 0 && kind != K_UNDEFINED && kind != K_IDENTIFIER);
937 Assert (vStringLength (token->name) > 0);
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);
943 /* Determine if kind is prototype */
944 if (currentContext->prototype)
945 kind = K_PROTOTYPE;
947 /* Do nothing if tag kind is disabled */
948 if (! kindEnabled (kind))
950 verbose ("kind disabled\n");
951 return;
954 /* Create tag */
955 initTagEntry (&tag, vStringValue (token->name), kind);
956 tag.lineNumber = token->lineNumber;
957 tag.filePosition = token->filePosition;
959 verbose ("Adding tag %s (kind %d)", vStringValue (token->name), kind);
960 if (currentContext->kind != K_UNDEFINED)
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);
967 verbose ("\n");
968 if (vStringLength (token->inheritance) > 0)
970 tag.extensionFields.inheritance = vStringValue (token->inheritance);
971 verbose ("Class %s extends %s\n", vStringValue (token->name), tag.extensionFields.inheritance);
974 if (token->parameter)
975 attachParserField (&tag, false, fieldTable [F_PARAMETER].ftype, "");
977 makeTagEntry (&tag);
979 if (isXtagEnabled (XTAG_QUALIFIED_TAGS) && currentContext->kind != K_UNDEFINED)
981 vString *const scopedName = vStringNew ();
983 vStringCopy (scopedName, currentContext->name);
984 vStringPut (scopedName, '.');
985 vStringCat (scopedName, token->name);
986 tag.name = vStringValue (scopedName);
988 markTagExtraBit (&tag, XTAG_QUALIFIED_TAGS);
989 makeTagEntry (&tag);
991 vStringDelete (scopedName);
994 /* Push token as context if it is a container */
995 if (container)
997 createContext (kind, token->name);
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++)
1004 tokenInfo *content = ptrArrayItem (tagContents, i);
1005 createTag (content, content->kind);
1008 /* Drop temporary contexts */
1009 if (isTempContext (currentContext))
1010 dropContext ();
1013 /* Clear no longer required inheritance information */
1014 vStringClear (token->inheritance);
1017 static int skipBlockName (tokenInfo *const token, int c)
1019 if (c == ':')
1021 c = skipWhite (vGetc ());
1022 if (isWordToken (c))
1023 c = readWordToken (token, c);
1025 return c;
1028 // begin, fork
1029 static int processBlock (tokenInfo *const token, int c)
1031 if (c == ':') // tag an optional block identifier
1033 c = skipWhite (vGetc ());
1034 if (isWordToken (c))
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));
1042 currentContext->nestLevel++; // increment after creating a context
1043 return c;
1046 // end, join, join_any, join_none
1047 static int processEnd (tokenInfo *const token, int c)
1049 if (currentContext->nestLevel > 0) // for sanity check
1050 currentContext->nestLevel--;
1051 if (currentContext->kind == K_BLOCK && currentContext->nestLevel == 0)
1052 dropContext ();
1054 c = skipBlockName (token, c);
1055 return c;
1058 static int processPortList (tokenInfo *token, int c, bool mayPortDecl)
1060 if (c == '(')
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);
1069 return c;
1072 static int skipParameterAssignment (int c)
1074 if (c == '#')
1076 c = skipWhite (vGetc ());
1077 if (c == '(')
1078 c = skipPastMatch ("()");
1080 return c;
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.
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 ] ) ] ;
1088 static int processFunction (tokenInfo *const token, int c)
1090 verilogKind kind = token->kind; // K_FUNCTION or K_TASK
1092 /* Search for function name
1093 * Last identifier found before a '(' or a ';' is the function name */
1094 while (c != '(' && c != ';' && c != EOF)
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);
1104 /* Identify class type prefixes and create respective context*/
1105 if (isInputLanguage (Lang_systemverilog) && c == ':')
1107 c = vGetc ();
1108 if (c == ':')
1110 verbose ("Found function declaration with class type %s\n", vStringValue (token->name));
1111 createContext (K_CLASS, token->name);
1112 currentContext->classScope = true;
1114 else
1115 vUngetc (c);
1118 verbose ("Found function: %s\n", vStringValue (token->name));
1119 createTag (token, kind);
1121 /* Get port list from function */
1122 c = skipWhite (c);
1123 c = processPortList (token, c, false);
1124 return c;
1127 // ( enum | union ) [ enum_base_type ] { < enum_name_declaration > } { [ ... ] }
1128 static int processEnum (tokenInfo *const token, int c)
1130 tokenInfo* enumToken = dupToken (token); // save enum token
1132 /* skip enum_base_type */
1133 while (isWordToken (c))
1134 c = readWordToken (token, c);
1135 c = skipDimension (c);
1137 /* Search enum elements */
1138 c = pushEnumNames (token, c);
1140 /* Skip bus width definition */
1141 c = skipDimension (c);
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);
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;
1154 // [ struct | union [ tagged ] ] [ packed [ signed | unsigned ] ] { struct_union_member { struct_union_member } } { [ ... ] }
1155 static int processStruct (tokenInfo *const token, int c)
1157 verilogKind kind = token->kind; // K_STRUCT, K_TYPEDEF, or K_NETTYPE
1159 /* Skip packed, signed, and unsigned */
1160 while (isWordToken (c))
1161 c = readWordToken (token, c);
1163 /* create a list of members */
1164 c = pushMembers (token, c);
1166 /* Skip packed_dimension */
1167 c = skipDimension (c);
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;
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 ;
1184 static int processTypedef (tokenInfo *const token, int c)
1186 verilogKind kindSave = token->kind; // K_TYPEDEF or K_NETTYPE
1187 verilogKind kind = K_UNDEFINED;
1188 bool not_used;
1189 if (isWordToken (c))
1191 c = readWordToken (token, c);
1192 kind = token->kind;
1194 // forward typedef (LRM 6.18) is tagged as prototype
1195 // (I don't know why...)
1196 switch (kind)
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))
1206 c = readWordToken (token, c);
1207 if (token->kind == K_IDENTIFIER && c == ';')
1208 currentContext->prototype = true;
1210 break;
1211 case K_IDENTIFIER:
1212 // interface based typedef
1213 c = skipDimension (c);
1214 if (c == '.')
1216 c = skipWhite (vGetc ());
1217 if (isWordToken (c))
1218 c = readWordToken (token, c);
1220 if (c == ';')
1221 currentContext->prototype = true;
1222 break;
1223 default:
1224 ; // do nothing
1226 c = processType (token, c, &kind, &not_used);
1228 createTag (token, kindSave);
1230 ptrArrayClear (tagContents);
1231 return c;
1234 static int processParameterList (tokenInfo *token, int c)
1236 bool parameter = true; // default "parameter"
1238 if (c != '#')
1239 return c;
1240 c = skipWhite (vGetc ());
1242 if (c != '(')
1243 return c;
1244 c = skipWhite (vGetc ());
1246 while (c != ')' && c != EOF)
1248 if (isWordToken (c))
1250 c = readWordToken (token, c);
1251 verbose ("Found parameter %s\n", vStringValue (token->name));
1252 if (token->kind == K_IDENTIFIER)
1254 if (c == ',' || c == ')' || c == '=') // ignore user defined type
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;
1268 else if (token->kind == K_PARAMETER)
1269 parameter = true;
1270 else if (token->kind == K_LOCALPARAM)
1271 parameter = false;
1273 else
1274 c = skipWhite (vGetc ());
1275 // unpacked array is not allowed for a parameter
1277 c = skipWhite (vGetc ()); // skip ')'
1278 return c;
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 > ] ;
1284 static int processClass (tokenInfo *const token, int c, verilogKind kind)
1286 tokenInfo *classToken;
1288 /* Get identifiers */
1289 while (isWordToken (c))
1291 c = readWordToken (token, c);
1292 // skip static or automatic
1293 if (token->kind != K_IGNORE)
1294 break;
1297 if (token->kind != K_IDENTIFIER)
1299 verbose ("Unexpected input: class name is expected.\n");
1300 return c;
1303 /* save token */
1304 classToken = dupToken (token);
1306 /* Find class parameters list */
1307 c = processParameterList (token, c);
1309 /* Search for inheritance information */
1310 if (isWordToken (c))
1312 c = readWordToken (token, c);
1313 if (strcmp (vStringValue (token->name), "extends") == 0)
1315 if (isWordToken (c))
1316 c = readWordToken (token, c);
1317 vStringCopy (classToken->inheritance, token->name);
1318 verbose ("Inheritance %s\n", vStringValue (classToken->inheritance));
1321 // process implements: FIXME
1323 createTag (classToken, kind);
1324 deleteToken (classToken);
1325 ptrArrayClear (tagContents);
1326 return c;
1329 // constraint_declaration ::= [ static ] constraint constraint_identifier '{' { constraint_block_item } '}'
1330 // constraint_prototype ::= [ extern | pure ] [ static ] constraint constraint_identifier ;
1331 static int processConstraint (tokenInfo *const token, int c)
1333 verilogKind kind;
1334 if (isWordToken (c))
1335 c = readWordToken (token, c);
1336 if (c == '{')
1338 c = skipPastMatch ("{}");
1339 kind = K_CONSTRAINT;
1341 else
1342 kind = K_PROTOTYPE;
1343 createTag (token, kind);
1344 return c;
1347 static int processDefine (tokenInfo *const token, int c)
1349 /* Bug #961001: Verilog compiler directives are line-based. */
1350 if (isWordToken (c))
1352 c = readWordTokenNoSkip (token, c);
1353 createTag (token, K_CONSTANT);
1355 c = skipToNewLine (c);
1356 c = skipWhite (c);
1357 return c;
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 ) ;
1368 static int processAssertion (tokenInfo *const token, int c)
1370 if (vStringLength (currentContext->blockName) > 0)
1372 vStringCopy (token->name, currentContext->blockName);
1373 vStringClear (currentContext->blockName); // clear block name not to be reused
1374 createTag (token, K_ASSERTION);
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;
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 > ] ) ] ;
1392 // interface class class_identifier [ parameter_port_list ] [ extends < interface_class_type > ] ;
1393 static int processDesignElementL (tokenInfo *const token, int c)
1395 verilogKind kind = token->kind;
1397 while (isWordToken (c))
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;
1407 if (token->kind == K_IDENTIFIER)
1408 createTag (token, kind); // identifier
1410 // skip package_import_declaration
1411 while (isWordToken (c))
1413 c = readWordToken (token, c);
1414 if (token->kind == K_IMPORT)
1416 c = skipToSemiColon (c);
1417 c = skipWhite (vGetc ()); // skip semicolon
1419 else
1421 verbose ("Unexpected input\n");
1422 return c;
1425 if (c == '#') // parameter_port_list
1427 c = processParameterList (token, c);
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++)
1434 tokenInfo *content = ptrArrayItem (tagContents, i);
1435 createTag (content, K_CONSTANT);
1437 ptrArrayClear (tagContents);
1438 // disable parameter property on parameter declaration statement
1439 currentContext->hasParamList = true;
1441 // Process ANSI/non-ANSI port list in main loop
1442 c = processPortList (token, c, true);
1443 return c;
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 ) )
1452 static int processDesignElementS (tokenInfo *const token, int c)
1454 verilogKind kind = token->kind;
1456 if (isWordToken (c))
1457 c = readWordToken (token, c);
1458 else
1459 return c;
1461 createTag (token, kind); // identifier
1463 /* Get port list if required */
1464 if (c == '(') // port_list
1466 if (kind == K_MODPORT)
1467 c = skipPastMatch ("()"); // ignore port list
1468 else
1469 c = processPortList (token, c, false);
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;
1478 static int skipDelay (tokenInfo* token, int c)
1480 if (c == '#')
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
1490 while (isIdentifierCharacter (c) || c == '.')
1491 c = vGetc ();
1492 c = skipWhite (c);
1495 return c;
1498 static int skipClockEvent (tokenInfo* token, int c)
1500 if (c == '@')
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);
1511 return c;
1514 static int pushEnumNames (tokenInfo* token, int c)
1516 if (c == '{')
1518 c = skipWhite (vGetc ());
1519 while (c != '}' && c != EOF)
1521 if (!isWordToken (c))
1523 verbose ("Unexpected input: %c\n", c);
1524 return c;
1526 c = readWordToken (token, c);
1528 token->kind = K_CONSTANT;
1529 ptrArrayAdd (tagContents, dupToken (token));
1530 verbose ("Pushed enum element \"%s\"\n", vStringValue (token->name));
1532 /* Skip element ranges */
1533 /* TODO Implement element ranges */
1534 c = skipDimension (c);
1536 /* Skip value assignments */
1537 if (c == '=')
1538 c = skipExpression (vGetc ());
1540 /* Skip comma */
1541 if (c == ',')
1542 c = skipWhite (vGetc ());
1544 c = skipWhite (vGetc ()); // skip '}'
1546 return c;
1549 // create a list of struct/union members
1550 static int pushMembers (tokenInfo* token, int c)
1552 if (c == '{')
1554 c = skipWhite (vGetc ());
1555 while (c != '}' && c != EOF)
1557 verilogKind kind = K_UNDEFINED; // set kind of context for processType()
1558 bool not_used;
1559 if (!isWordToken (c))
1561 verbose ("Unexpected input: %c\n", c);
1562 return c;
1564 c = readWordToken (token, c);
1566 c = processType (token, c, &kind, &not_used);
1567 while (true)
1569 token->kind = K_MEMBER;
1570 ptrArrayAdd (tagContents, dupToken (token));
1571 verbose ("Pushed struct/union member \"%s\"\n", vStringValue (token->name));
1573 /* Skip unpacked dimensions */
1574 c = skipDimension (c);
1576 /* Skip value assignments */
1577 if (c == '=')
1578 c = skipExpression (vGetc ());
1580 if (c != ',' || c == EOF)
1581 break; // should be ';'
1583 c = skipWhite (vGetc ()); // skip ','
1584 if (isWordToken (c))
1585 c = readWordToken (token, c);
1586 else
1588 verbose ("Unexpected input.\n");
1589 break;
1592 /* Skip semicolon */
1593 if (c == ';')
1594 c = skipWhite (vGetc ());
1595 /* End of enum elements list */
1597 c = skipWhite (vGetc ()); // skip '}'
1599 return c;
1602 // input
1603 // kind: kind of context
1604 // output
1605 // kind: kind of type
1606 // token: identifier token (unless K_IDENTIFIER nor K_UNDEFINED)
1607 static int processType (tokenInfo* token, int c, verilogKind* kind, bool* with)
1609 verilogKind actualKind = K_UNDEFINED;
1610 tokenInfo *tokenSaved;
1611 *with = false;
1614 c = skipDimension (c);
1615 c = skipDelay (token, c); // class parameter #(...)
1616 if (c == '{') // skip enum, struct, or union member
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 ("{}");
1625 c = skipDimension (c);
1626 c = skipMacro (c, token);
1628 // break on ',', ';', ')', '}', or other unexpected charactors
1629 if (!isWordToken (c))
1630 break;
1632 tokenSaved = dupToken (token);
1633 c = readWordToken (token, c);
1634 // break on "with"
1635 if (token->kind == K_WITH)
1637 swapToken (token, tokenSaved);
1638 deleteToken (tokenSaved);
1639 *with = true; // inform to caller
1640 break;
1642 deleteToken (tokenSaved);
1644 // fix kind of user defined type
1645 if (*kind == K_IDENTIFIER)
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;
1658 else
1660 verbose ("Unexpected input\n"); // FIXME: x dist {}, with
1661 break;
1664 } while (c != '`' && c != EOF); // break on compiler directive
1666 // skip unpacked dimension (or packed dimension after type-words)
1667 c = skipDimension (skipWhite (c));
1669 if (*kind == K_UNDEFINED && *kind != K_PORT)
1670 *kind = actualKind;
1671 return c;
1674 // class_type ::=
1675 // ps_class_identifier [ # ( ... ) ] { :: class_identifier [ # ( ... ) ] }
1676 // "interface_identifier ." is also handled
1677 static int skipClassType (tokenInfo* token, int c)
1679 while (c == '#' || c == ':' || c == '.')
1681 if (c == '#')
1683 c = skipWhite (vGetc ());
1684 // a dirty hack for "x ##delay1 y[*min:max];"
1685 if (c == '#')
1686 return skipToSemiColon (vGetc ());
1687 c = skipPastMatch ("()");
1689 else if (c == ':')
1691 c = skipWhite (vGetc ());
1692 if (c != ':')
1694 verbose ("Unexpected input.\n");
1695 vUngetc (c);
1696 return ':';
1698 c = skipWhite (vGetc ());
1699 if (isWordToken (c))
1700 c = readWordToken (token, c);
1702 else // c == '.' : interface_identifier .
1704 c = skipWhite (vGetc ());
1705 if (isWordToken (c))
1706 c = readWordToken (token, c);
1709 return c;
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 // | ...
1720 // mayPortDecl: may be a ANSI port declaration. true for module, interface, or program.
1721 static int tagIdentifierList (tokenInfo *const token, int c, verilogKind kind, bool mayPortDecl)
1723 bool first_port = true;
1724 bool enableTag = true;
1725 verilogKind localKind;
1726 bool not_used;
1728 while (c != ')' && c != EOF) // skip empty port, "()"
1730 // skip attribute_instance: (* ... *)
1731 if (c == '(')
1732 c = skipPastMatch ("()");
1734 // skip port direction, "virtual", or "interface"
1735 while (isWordToken (c))
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;
1743 if (token->kind == K_IDENTIFIER)
1744 c = skipClassType (token, c);
1745 c = skipMacro (c, token); // `ifdef, `else, `endif, etc. (between identifiers)
1747 if (isWordToken (c))
1749 c = readWordToken (token, c);
1750 if (token->kind == K_IDENTIFIER)
1752 mayPortDecl = false;
1753 c = skipClassType (token, c);
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);
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)
1765 first_port = false;
1766 if (localKind == K_IDENTIFIER)
1767 enableTag = false; // don't tag for non-ANSI port
1769 if (enableTag && token->kind == K_IDENTIFIER)
1770 createTag (token, kind);
1772 if (c == '=')
1773 c = skipExpression (vGetc ());
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)
1781 return c;
1784 static int tagNameList (tokenInfo* token, int c, verilogKind kind)
1786 c = skipClassType (token, c);
1787 if (c == ':' || c == ';') // ## (cycle delay) or unexpected input
1788 return c;
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);
1798 while (c != EOF)
1800 bool with = false;
1801 c = processType (token, c, &kind, &with); // update token and kind
1803 if (c == '=' || c == ',' || c == ';' || c == ')' || c == '`' || with)
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);
1811 else if (c == '(' || c == '[') // should be instance
1813 c = skipDimension (c); // name_of_instance {unpacked_dimension}
1814 c = skipPastMatch ("()"); // list_of_port_connections
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 == ',')
1820 verbose ("find instance: %s with kind %s\n", vStringValue (token->name), getNameForKind (K_INSTANCE));
1821 createTag (token, K_INSTANCE);
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)
1830 return c;
1833 static int findTag (tokenInfo *const token, int c)
1835 verbose ("Checking token %s of kind %d\n", vStringValue (token->name), token->kind);
1837 switch (token->kind)
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:
1853 if (c == '[') // for a case label foo[x]:
1854 c = skipPastMatch ("[]");
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 */
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;
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;
1921 case K_DEFINE:
1922 c = processDefine (token, c);
1923 break;
1925 case K_IGNORE:
1926 break;
1927 default:
1928 verbose ("Unexpected kind->token %d\n", token->kind);
1930 return c;
1933 static void findVerilogTags (void)
1935 tokenInfo *const token = newToken ();
1936 int c = skipWhite (vGetc ());
1937 currentContext = newToken ();
1938 fieldTable = isInputLanguage (Lang_verilog) ? VerilogFields : SystemVerilogFields;
1939 ptrArrayClear (tagContents);
1941 while (c != EOF)
1943 switch (c)
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 ();
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))
1979 c = readWordTokenNoSkip (token, c);
1980 if (token->kind == K_DIRECTIVE)
1982 // Skip compiler directives which are line-based.
1983 c = skipToNewLine (c);
1984 c = skipWhite (c);
1986 else if (token->kind != K_UNDEFINED)
1987 c = findTag (token, skipWhite (c));
1989 else
1990 c = skipWhite (vGetc ());
1993 deleteToken (token);
1994 pruneTokens (currentContext);
1995 currentContext = NULL;
1998 extern parserDefinition* VerilogParser (void)
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;
2012 extern parserDefinition* SystemVerilogParser (void)
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;