Making "inline" behave like an attribute. Fixes #1
[arduino-ctags.git] / verilog.c
blob52afc31018cb5d77480bb60bcae08d5e92d48672
1 /*
2 * $Id: verilog.c 753 2010-02-27 17:53:32Z elliotth $
3 *
4 * Copyright (c) 2003, Darren Hiebert
5 *
6 * This source code is released for free distribution under the terms of the
7 * GNU General Public License.
8 *
9 * This module contains functions for generating tags for the Verilog HDL
10 * (Hardware Description Language).
12 * Language definition documents:
13 * http://www.eg.bucknell.edu/~cs320/verilog/verilog-manual.html
14 * http://www.sutherland-hdl.com/on-line_ref_guide/vlog_ref_top.html
15 * http://www.verilog.com/VerilogBNF.html
16 * http://eesun.free.fr/DOC/VERILOG/verilog_manual1.html
20 * INCLUDE FILES
22 #include "general.h" /* must always come first */
24 #include <string.h>
25 #include <setjmp.h>
27 #include "debug.h"
28 #include "get.h"
29 #include "keyword.h"
30 #include "parse.h"
31 #include "read.h"
32 #include "vstring.h"
35 * DATA DECLARATIONS
37 typedef enum eException { ExceptionNone, ExceptionEOF } exception_t;
39 typedef enum {
40 K_UNDEFINED = -1,
41 K_CONSTANT,
42 K_EVENT,
43 K_FUNCTION,
44 K_MODULE,
45 K_NET,
46 K_PORT,
47 K_REGISTER,
48 K_TASK
49 } verilogKind;
51 typedef struct {
52 const char *keyword;
53 verilogKind kind;
54 } keywordAssoc;
57 * DATA DEFINITIONS
59 static int Ungetc;
60 static int Lang_verilog;
61 static jmp_buf Exception;
63 static kindOption VerilogKinds [] = {
64 { TRUE, 'c', "constant", "constants (define, parameter, specparam)" },
65 { TRUE, 'e', "event", "events" },
66 { TRUE, 'f', "function", "functions" },
67 { TRUE, 'm', "module", "modules" },
68 { TRUE, 'n', "net", "net data types" },
69 { TRUE, 'p', "port", "ports" },
70 { TRUE, 'r', "register", "register data types" },
71 { TRUE, 't', "task", "tasks" }
74 static keywordAssoc VerilogKeywordTable [] = {
75 { "`define", K_CONSTANT },
76 { "event", K_EVENT },
77 { "function", K_FUNCTION },
78 { "inout", K_PORT },
79 { "input", K_PORT },
80 { "integer", K_REGISTER },
81 { "module", K_MODULE },
82 { "output", K_PORT },
83 { "parameter", K_CONSTANT },
84 { "real", K_REGISTER },
85 { "realtime", K_REGISTER },
86 { "reg", K_REGISTER },
87 { "specparam", K_CONSTANT },
88 { "supply0", K_NET },
89 { "supply1", K_NET },
90 { "task", K_TASK },
91 { "time", K_REGISTER },
92 { "tri0", K_NET },
93 { "tri1", K_NET },
94 { "triand", K_NET },
95 { "tri", K_NET },
96 { "trior", K_NET },
97 { "trireg", K_NET },
98 { "wand", K_NET },
99 { "wire", K_NET },
100 { "wor", K_NET }
104 * FUNCTION DEFINITIONS
107 static void initialize (const langType language)
109 size_t i;
110 const size_t count =
111 sizeof (VerilogKeywordTable) / sizeof (VerilogKeywordTable [0]);
112 Lang_verilog = language;
113 for (i = 0 ; i < count ; ++i)
115 const keywordAssoc* const p = &VerilogKeywordTable [i];
116 addKeyword (p->keyword, language, (int) p->kind);
120 static void vUngetc (int c)
122 Assert (Ungetc == '\0');
123 Ungetc = c;
126 static int vGetc (void)
128 int c;
129 if (Ungetc == '\0')
130 c = fileGetc ();
131 else
133 c = Ungetc;
134 Ungetc = '\0';
136 if (c == '/')
138 int c2 = fileGetc ();
139 if (c2 == EOF)
140 longjmp (Exception, (int) ExceptionEOF);
141 else if (c2 == '/') /* strip comment until end-of-line */
144 c = fileGetc ();
145 while (c != '\n' && c != EOF);
147 else if (c2 == '*') /* strip block comment */
149 c = skipOverCComment();
151 else
153 fileUngetc (c2);
156 else if (c == '"') /* strip string contents */
158 int c2;
160 c2 = fileGetc ();
161 while (c2 != '"' && c2 != EOF);
162 c = '@';
164 if (c == EOF)
165 longjmp (Exception, (int) ExceptionEOF);
166 return c;
169 static boolean isIdentifierCharacter (const int c)
171 return (boolean)(isalnum (c) || c == '_' || c == '`');
174 static int skipWhite (int c)
176 while (isspace (c))
177 c = vGetc ();
178 return c;
181 static int skipPastMatch (const char *const pair)
183 const int begin = pair [0], end = pair [1];
184 int matchLevel = 1;
185 int c;
188 c = vGetc ();
189 if (c == begin)
190 ++matchLevel;
191 else if (c == end)
192 --matchLevel;
194 while (matchLevel > 0);
195 return vGetc ();
198 static boolean readIdentifier (vString *const name, int c)
200 vStringClear (name);
201 if (isIdentifierCharacter (c))
203 while (isIdentifierCharacter (c))
205 vStringPut (name, c);
206 c = vGetc ();
208 vUngetc (c);
209 vStringTerminate (name);
211 return (boolean)(name->length > 0);
214 static void tagNameList (const verilogKind kind, int c)
216 vString *name = vStringNew ();
217 boolean repeat;
218 Assert (isIdentifierCharacter (c));
221 repeat = FALSE;
222 if (isIdentifierCharacter (c))
224 readIdentifier (name, c);
225 makeSimpleTag (name, VerilogKinds, kind);
227 else
228 break;
229 c = skipWhite (vGetc ());
230 if (c == '[')
231 c = skipPastMatch ("[]");
232 c = skipWhite (c);
233 if (c == '=')
235 c = skipWhite (vGetc ());
236 if (c == '{')
237 skipPastMatch ("{}");
238 else
241 c = vGetc ();
242 while (c != ',' && c != ';');
245 if (c == ',')
247 c = skipWhite (vGetc ());
248 repeat = TRUE;
250 else
251 repeat = FALSE;
252 } while (repeat);
253 vStringDelete (name);
254 vUngetc (c);
257 static void findTag (vString *const name)
259 const verilogKind kind = (verilogKind) lookupKeyword (vStringValue (name), Lang_verilog);
260 if (kind == K_CONSTANT && vStringItem (name, 0) == '`')
262 /* Bug #961001: Verilog compiler directives are line-based. */
263 int c = skipWhite (vGetc ());
264 readIdentifier (name, c);
265 makeSimpleTag (name, VerilogKinds, kind);
266 /* Skip the rest of the line. */
267 do {
268 c = vGetc();
269 } while (c != '\n');
270 vUngetc (c);
272 else if (kind != K_UNDEFINED)
274 int c = skipWhite (vGetc ());
276 /* Many keywords can have bit width.
277 * reg [3:0] net_name;
278 * inout [(`DBUSWIDTH-1):0] databus;
280 if (c == '(')
281 c = skipPastMatch ("()");
282 c = skipWhite (c);
283 if (c == '[')
284 c = skipPastMatch ("[]");
285 c = skipWhite (c);
286 if (c == '#')
288 c = vGetc ();
289 if (c == '(')
290 c = skipPastMatch ("()");
292 c = skipWhite (c);
293 if (isIdentifierCharacter (c))
294 tagNameList (kind, c);
298 static void findVerilogTags (void)
300 vString *const name = vStringNew ();
301 volatile boolean newStatement = TRUE;
302 volatile int c = '\0';
303 exception_t exception = (exception_t) setjmp (Exception);
305 if (exception == ExceptionNone) while (c != EOF)
307 c = vGetc ();
308 switch (c)
310 case ';':
311 case '\n':
312 newStatement = TRUE;
313 break;
315 case ' ':
316 case '\t':
317 break;
319 default:
320 if (newStatement && readIdentifier (name, c))
321 findTag (name);
322 newStatement = FALSE;
323 break;
326 vStringDelete (name);
329 extern parserDefinition* VerilogParser (void)
331 static const char *const extensions [] = { "v", NULL };
332 parserDefinition* def = parserNew ("Verilog");
333 def->kinds = VerilogKinds;
334 def->kindCount = KIND_COUNT (VerilogKinds);
335 def->extensions = extensions;
336 def->parser = findVerilogTags;
337 def->initialize = initialize;
338 return def;
341 /* vi:set tabstop=4 shiftwidth=4: */