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).
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
24 #include "general.h" /* must always come first */
41 #define NUMBER_LANGUAGES 2 /* Indicates number of defined indexes */
42 #define IDX_SYSTEMVERILOG 0
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. */
54 /* parser private items */
55 K_IGNORE
= -16, /* Verilog/SystemVerilog keywords to be ignored */
59 K_END_DE
, /* End of Design Elements */
66 K_UNDEFINED
= KEYWORD_NONE
,
67 /* the followings items are also used as indices for VerilogKinds[] and SystemVerilogKinds[] */
94 K_IFCLASS
, /* interface class */
102 short isValid
[NUMBER_LANGUAGES
];
105 typedef struct sTokenInfo
{
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 */
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
[] = {
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
= {
277 .addingUnlessExisting
= true,
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",
301 // IEEE Std 1800-2017 LRM, Annex B "Keywords"
302 const static struct keywordGroup systemVerilogKeywords
= {
304 .addingUnlessExisting
= true,
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",
351 // IEEE Std 1364-2005 LRM, "19. Compiler directives"
352 const static struct keywordGroup verilogDirectives
= {
353 .value
= K_DIRECTIVE
,
354 .addingUnlessExisting
= true,
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",
364 // IEEE Std 1800-2017 LRM, "22. Compiler directives"
365 const static struct keywordGroup systemVerilogDirectives
= {
366 .value
= K_DIRECTIVE
,
367 .addingUnlessExisting
= true,
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",
378 // .enabled field cannot be shared by two languages
379 static fieldDefinition VerilogFields
[] = {
380 { .name
= "parameter",
381 .description
= "parameter whose value can be overridden.",
383 .dataType
= FIELDTYPE_BOOL
},
386 static fieldDefinition SystemVerilogFields
[] = {
387 { .name
= "parameter",
388 .description
= "parameter whose value can be overridden.",
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
)
442 static short isTempContext (tokenInfo
const* token
)
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 ();
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 ();
483 static tokenInfo
*dupToken (tokenInfo
*token
)
485 tokenInfo
*dup
= newToken ();
486 tokenInfo tmp
= *dup
; // save vStrings, name, blockName, and inheritance
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
);
499 static void deleteToken (tokenInfo
* const token
)
503 vStringDelete (token
->name
);
504 vStringDelete (token
->blockName
);
505 vStringDelete (token
->inheritance
);
510 static tokenInfo
*pushToken (tokenInfo
* const token
, tokenInfo
* const tokenPush
)
512 tokenPush
->scope
= token
;
516 static tokenInfo
*popToken (tokenInfo
* const token
)
518 tokenInfo
*localToken
;
521 localToken
= token
->scope
;
528 static void pruneTokens (tokenInfo
* token
)
530 while ((token
= popToken (token
)))
534 static void swapToken (tokenInfo
*t0
, tokenInfo
*t1
)
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
)
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');
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 ();
610 c
= getcFromInputFile ();
613 const int next
= getcFromInputFile ();
619 c
= SPACE
; /* replace comment with space */
627 static int _vGetc (bool inSkipPastMatch
)
631 c
= getcFromInputFile ();
639 int c2
= getcFromInputFile ();
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 ();
651 ungetcToInputFile (c2
);
653 // replace a string with "@" only in skipPastMatch()
654 // because the string may contain parens, etc.
655 else if (inSkipPastMatch
&& c
== '"')
659 c2
= getcFromInputFile ();
660 while (c2
!= '"' && c2
!= EOF
);
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
)
690 static int skipPastMatch (const char *const pair
)
692 const int begin
= pair
[0], end
= pair
[1];
703 while (matchLevel
> 0 && c
!= EOF
);
704 return skipWhite (vGetc ());
707 static int skipDimension (int c
)
709 while (c
== '[' && c
!= EOF
)
710 c
= skipPastMatch ("[]");
714 static int skipToSemiColon (int c
)
716 while (c
!= ';' && c
!= EOF
)
718 return c
; // ';' or EOF
721 static int skipString (int c
)
727 while (c
!= '"' && c
!= EOF
);
729 c
= skipWhite (vGetc ());
733 static int skipExpression (int c
)
735 while (c
!= ',' && c
!= ';' && c
!= ')' && c
!= '}' && c
!= ']' && c
!= EOF
)
738 c
= skipPastMatch ("()");
740 c
= skipPastMatch ("{}");
742 c
= skipPastMatch ("[]");
746 c
= skipWhite (vGetc ());
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
)
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
);
775 else if (localToken
->kind
== K_DEFINE
)
778 c
= processDefine (localToken
, c
);
780 /* return macro expansion */
783 swapToken (token
, localToken
);
786 c
= skipPastMatch ("()");
790 deleteToken (localToken
);
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
));
808 vStringPut (token
->name
, c
);
810 } while (isIdentifierCharacter (c
));
814 return skipWhite (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
);
845 if (c
== '`' || !isWordToken (c
))
850 if (!isIdentifierCharacter (c
))
860 static void createContext (verilogKind kind
, vString
* const name
)
862 tokenInfo
*const scope
= newToken ();
863 vStringCopy (scope
->name
, name
);
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
);
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))
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)
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
);
918 verbose ("Unexpected current context %s\n", vStringValue (currentContext
->name
));
923 static void createTag (tokenInfo
*const token
, verilogKind kind
)
927 if (kind
== K_LOCALPARAM
)
929 else if (kind
== K_PARAMETER
)
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
)
947 /* Do nothing if tag kind is disabled */
948 if (! kindEnabled (kind
))
950 verbose ("kind disabled\n");
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
);
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
, "");
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
);
991 vStringDelete (scopedName
);
994 /* Push token as context if it is a 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
))
1013 /* Clear no longer required inheritance information */
1014 vStringClear (token
->inheritance
);
1017 static int skipBlockName (tokenInfo
*const token
, int c
)
1021 c
= skipWhite (vGetc ());
1022 if (isWordToken (c
))
1023 c
= readWordToken (token
, c
);
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
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)
1054 c
= skipBlockName (token
, c
);
1058 static int processPortList (tokenInfo
*token
, int c
, bool mayPortDecl
)
1062 c
= skipWhite (vGetc ()); // skip '('
1063 c
= tagIdentifierList (token
, c
, K_PORT
, mayPortDecl
);
1064 if (c
== ')') // sanity check
1065 c
= skipWhite (vGetc ());
1067 verbose ("Unexpected input: %c\n", c
);
1072 static int skipParameterAssignment (int c
)
1076 c
= skipWhite (vGetc ());
1078 c
= skipPastMatch ("()");
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
);
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
== ':')
1110 verbose ("Found function declaration with class type %s\n", vStringValue (token
->name
));
1111 createContext (K_CLASS
, token
->name
);
1112 currentContext
->classScope
= true;
1118 verbose ("Found function: %s\n", vStringValue (token
->name
));
1119 createTag (token
, kind
);
1121 /* Get port list from function */
1123 c
= processPortList (token
, c
, false);
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
);
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
);
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
;
1189 if (isWordToken (c
))
1191 c
= readWordToken (token
, c
);
1194 // forward typedef (LRM 6.18) is tagged as prototype
1195 // (I don't know why...)
1200 currentContext
->prototype
= true;
1204 if (isWordToken (c
))
1206 c
= readWordToken (token
, c
);
1207 if (token
->kind
== K_IDENTIFIER
&& c
== ';')
1208 currentContext
->prototype
= true;
1212 // interface based typedef
1213 c
= skipDimension (c
);
1216 c
= skipWhite (vGetc ());
1217 if (isWordToken (c
))
1218 c
= readWordToken (token
, c
);
1221 currentContext
->prototype
= true;
1226 c
= processType (token
, c
, &kind
, ¬_used
);
1228 createTag (token
, kindSave
);
1230 ptrArrayClear (tagContents
);
1234 static int processParameterList (tokenInfo
*token
, int c
)
1236 bool parameter
= true; // default "parameter"
1240 c
= skipWhite (vGetc ());
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
);
1261 c
= skipExpression (vGetc ());
1263 c
= skipWhite (vGetc ());
1268 else if (token
->kind
== K_PARAMETER
)
1270 else if (token
->kind
== K_LOCALPARAM
)
1274 c
= skipWhite (vGetc ());
1275 // unpacked array is not allowed for a parameter
1277 c
= skipWhite (vGetc ()); // skip ')'
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
)
1297 if (token
->kind
!= K_IDENTIFIER
)
1299 verbose ("Unexpected input: class name is expected.\n");
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
);
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
)
1334 if (isWordToken (c
))
1335 c
= readWordToken (token
, c
);
1338 c
= skipPastMatch ("{}");
1339 kind
= K_CONSTRAINT
;
1343 createTag (token
, kind
);
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
);
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
);
1380 c
= skipDelay (token
, c
);
1383 c
= skipPastMatch ("()");
1388 // ( module | interface | program ) [ static | automatic ] identifier { package_import_declaration } [ parameter_port_list ] ( port { , port } ) ;
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
);
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
)
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
1421 verbose ("Unexpected input\n");
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);
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
);
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
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
1474 c
= skipClockEvent (token
, c
);
1478 static int skipDelay (tokenInfo
* token
, int c
)
1482 c
= skipWhite (vGetc ());
1484 c
= skipPastMatch ("()");
1486 // a dirty hack for "x ##delay1 y[*min:max];"
1487 c
= skipToSemiColon (vGetc ());
1488 else // time literals
1490 while (isIdentifierCharacter (c
) || c
== '.')
1498 static int skipClockEvent (tokenInfo
* token
, int c
)
1502 c
= skipWhite (vGetc ());
1503 // for @@ ( ... ) : coverage_event
1505 c
= skipWhite (vGetc ());
1507 c
= skipPastMatch ("()");
1508 else if (isWordToken (c
))
1509 c
= readWordToken (token
, c
);
1514 static int pushEnumNames (tokenInfo
* token
, int c
)
1518 c
= skipWhite (vGetc ());
1519 while (c
!= '}' && c
!= EOF
)
1521 if (!isWordToken (c
))
1523 verbose ("Unexpected input: %c\n", 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 */
1538 c
= skipExpression (vGetc ());
1542 c
= skipWhite (vGetc ());
1544 c
= skipWhite (vGetc ()); // skip '}'
1549 // create a list of struct/union members
1550 static int pushMembers (tokenInfo
* token
, int c
)
1554 c
= skipWhite (vGetc ());
1555 while (c
!= '}' && c
!= EOF
)
1557 verilogKind kind
= K_UNDEFINED
; // set kind of context for processType()
1559 if (!isWordToken (c
))
1561 verbose ("Unexpected input: %c\n", c
);
1564 c
= readWordToken (token
, c
);
1566 c
= processType (token
, c
, &kind
, ¬_used
);
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 */
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
);
1588 verbose ("Unexpected input.\n");
1592 /* Skip semicolon */
1594 c
= skipWhite (vGetc ());
1595 /* End of enum elements list */
1597 c
= skipWhite (vGetc ()); // skip '}'
1603 // kind: kind of context
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
;
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
))
1632 tokenSaved
= dupToken (token
);
1633 c
= readWordToken (token
, c
);
1635 if (token
->kind
== K_WITH
)
1637 swapToken (token
, tokenSaved
);
1638 deleteToken (tokenSaved
);
1639 *with
= true; // inform to caller
1642 deleteToken (tokenSaved
);
1644 // fix kind of user defined type
1645 if (*kind
== K_IDENTIFIER
)
1647 if (token
->kind
== 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
1660 verbose ("Unexpected input\n"); // FIXME: x dist {}, with
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
)
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
== '.')
1683 c
= skipWhite (vGetc ());
1684 // a dirty hack for "x ##delay1 y[*min:max];"
1686 return skipToSemiColon (vGetc ());
1687 c
= skipPastMatch ("()");
1691 c
= skipWhite (vGetc ());
1694 verbose ("Unexpected input.\n");
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
);
1712 // Tag a list of identifiers
1715 // | virtual [ interface ] identifier [ # ( [ ... ] ) ] [ . identifier ]
1716 // | [ class_type :: | identifier :: | $unit :: ] identifier { [ ... ] }
1717 // | [ identifier :: | $unit :: ] identifier [ # ( ... ) ] { :: identifier [ # ( ... ) ] }
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
;
1728 while (c
!= ')' && c
!= EOF
) // skip empty port, "()"
1730 // skip attribute_instance: (* ... *)
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
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
, ¬_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
)
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
);
1773 c
= skipExpression (vGetc ());
1775 c
= skipMacro (c
, token
); // `ifdef, `else, `endif, etc. (before comma)
1776 if (c
!= ',' || c
== EOF
)
1778 c
= skipWhite (vGetc ()); // skip ','
1779 c
= skipMacro (c
, token
); // `ifdef, `else, `endif, etc. (after comma)
1784 static int tagNameList (tokenInfo
* token
, int c
, verilogKind kind
)
1786 c
= skipClassType (token
, c
);
1787 if (c
== ':' || c
== ';') // ## (cycle delay) or unexpected input
1790 // skip drive|charge strength or type_reference, dimensions, and delay for net
1792 c
= skipPastMatch ("()");
1793 c
= skipDimension (c
);
1795 return c
; // foo[...].bar = ..;
1796 c
= skipDelay (token
, c
);
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
);
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
)
1827 c
= skipWhite (vGetc ()); // skip ','
1828 c
= skipMacro (c
, token
); // `ifdef, `else, `endif, etc. (after comma)
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
)
1846 if (token
->kind
== K_PORT
&& currentContext
->kind
== K_CLOCKING
)
1847 c
= skipToSemiColon (c
); // clocking items are not port definitions
1849 c
= tagNameList (token
, c
, token
->kind
);
1853 if (c
== '[') // for a case label foo[x]:
1854 c
= skipPastMatch ("[]");
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 ()));
1865 c
= tagNameList (token
, c
, token
->kind
); /* user defined type */
1869 c
= processClass (token
, c
, K_CLASS
);
1873 c
= processTypedef (token
, c
);
1876 c
= processEnum (token
, c
);
1879 c
= processStruct (token
, c
);
1884 currentContext
->prototype
= true;
1890 c
= processDesignElementL (token
, c
);
1899 c
= processDesignElementS (token
, c
);
1902 c
= dropEndContext (token
, c
);
1905 c
= processBlock (token
, c
);
1908 c
= processEnd (token
, c
);
1912 c
= processFunction (token
, c
);
1915 c
= processAssertion (token
, c
);
1918 c
= processConstraint (token
, c
);
1922 c
= processDefine (token
, c
);
1928 verbose ("Unexpected kind->token %d\n", token
->kind
);
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
);
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 ());
1952 /* Drop context on prototypes because they don't have an
1954 if (currentContext
->scope
&& currentContext
->scope
->prototype
)
1957 /* Prototypes end at the end of statement */
1958 currentContext
->prototype
= false;
1959 c
= skipWhite (vGetc ());
1961 case '(': // ignore locally declared variables in a for-loop (LRM 12.7.1)
1962 c
= skipPastMatch ("()");;
1965 c
= skipPastMatch ("{}");;
1968 c
= skipDelay (token
, c
);
1971 c
= skipClockEvent (token
, c
);
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
);
1986 else if (token
->kind
!= K_UNDEFINED
)
1987 c
= findTag (token
, skipWhite (c
));
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
;
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
;