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).
11 *
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
17 */
18
19 /*
20 * INCLUDE FILES
21 */
22 #include "general.h" /* must always come first */
23
24 #include <string.h>
25 #include <setjmp.h>
26
27 #include "debug.h"
28 #include "get.h"
29 #include "keyword.h"
30 #include "parse.h"
31 #include "read.h"
32 #include "vstring.h"
33
34 /*
35 * DATA DECLARATIONS
36 */
37 typedef enum eException { ExceptionNone, ExceptionEOF } exception_t;
38
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;
50
51 typedef struct {
52 const char *keyword;
53 verilogKind kind;
54 } keywordAssoc;
55
56 /*
57 * DATA DEFINITIONS
58 */
59 static int Ungetc;
60 static int Lang_verilog;
61 static jmp_buf Exception;
62
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" }
72 };
73
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 }
101 };
102
103 /*
104 * FUNCTION DEFINITIONS
105 */
106
initialize(const langType language)107 static void initialize (const langType language)
108 {
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)
114 {
115 const keywordAssoc* const p = &VerilogKeywordTable [i];
116 addKeyword (p->keyword, language, (int) p->kind);
117 }
118 }
119
vUngetc(int c)120 static void vUngetc (int c)
121 {
122 Assert (Ungetc == '\0');
123 Ungetc = c;
124 }
125
vGetc(void)126 static int vGetc (void)
127 {
128 int c;
129 if (Ungetc == '\0')
130 c = fileGetc ();
131 else
132 {
133 c = Ungetc;
134 Ungetc = '\0';
135 }
136 if (c == '/')
137 {
138 int c2 = fileGetc ();
139 if (c2 == EOF)
140 longjmp (Exception, (int) ExceptionEOF);
141 else if (c2 == '/') /* strip comment until end-of-line */
142 {
143 do
144 c = fileGetc ();
145 while (c != '\n' && c != EOF);
146 }
147 else if (c2 == '*') /* strip block comment */
148 {
149 c = skipOverCComment();
150 }
151 else
152 {
153 fileUngetc (c2);
154 }
155 }
156 else if (c == '"') /* strip string contents */
157 {
158 int c2;
159 do
160 c2 = fileGetc ();
161 while (c2 != '"' && c2 != EOF);
162 c = '@';
163 }
164 if (c == EOF)
165 longjmp (Exception, (int) ExceptionEOF);
166 return c;
167 }
168
isIdentifierCharacter(const int c)169 static boolean isIdentifierCharacter (const int c)
170 {
171 return (boolean)(isalnum (c) || c == '_' || c == '`');
172 }
173
skipWhite(int c)174 static int skipWhite (int c)
175 {
176 while (isspace (c))
177 c = vGetc ();
178 return c;
179 }
180
skipPastMatch(const char * const pair)181 static int skipPastMatch (const char *const pair)
182 {
183 const int begin = pair [0], end = pair [1];
184 int matchLevel = 1;
185 int c;
186 do
187 {
188 c = vGetc ();
189 if (c == begin)
190 ++matchLevel;
191 else if (c == end)
192 --matchLevel;
193 }
194 while (matchLevel > 0);
195 return vGetc ();
196 }
197
readIdentifier(vString * const name,int c)198 static boolean readIdentifier (vString *const name, int c)
199 {
200 vStringClear (name);
201 if (isIdentifierCharacter (c))
202 {
203 while (isIdentifierCharacter (c))
204 {
205 vStringPut (name, c);
206 c = vGetc ();
207 }
208 vUngetc (c);
209 vStringTerminate (name);
210 }
211 return (boolean)(name->length > 0);
212 }
213
tagNameList(const verilogKind kind,int c)214 static void tagNameList (const verilogKind kind, int c)
215 {
216 vString *name = vStringNew ();
217 boolean repeat;
218 Assert (isIdentifierCharacter (c));
219 do
220 {
221 repeat = FALSE;
222 if (isIdentifierCharacter (c))
223 {
224 readIdentifier (name, c);
225 makeSimpleTag (name, VerilogKinds, kind);
226 }
227 else
228 break;
229 c = skipWhite (vGetc ());
230 if (c == '[')
231 c = skipPastMatch ("[]");
232 c = skipWhite (c);
233 if (c == '=')
234 {
235 c = skipWhite (vGetc ());
236 if (c == '{')
237 skipPastMatch ("{}");
238 else
239 {
240 do
241 c = vGetc ();
242 while (c != ',' && c != ';');
243 }
244 }
245 if (c == ',')
246 {
247 c = skipWhite (vGetc ());
248 repeat = TRUE;
249 }
250 else
251 repeat = FALSE;
252 } while (repeat);
253 vStringDelete (name);
254 vUngetc (c);
255 }
256
findTag(vString * const name)257 static void findTag (vString *const name)
258 {
259 const verilogKind kind = (verilogKind) lookupKeyword (vStringValue (name), Lang_verilog);
260 if (kind == K_CONSTANT && vStringItem (name, 0) == '`')
261 {
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);
271 }
272 else if (kind != K_UNDEFINED)
273 {
274 int c = skipWhite (vGetc ());
275
276 /* Many keywords can have bit width.
277 * reg [3:0] net_name;
278 * inout [(`DBUSWIDTH-1):0] databus;
279 */
280 if (c == '(')
281 c = skipPastMatch ("()");
282 c = skipWhite (c);
283 if (c == '[')
284 c = skipPastMatch ("[]");
285 c = skipWhite (c);
286 if (c == '#')
287 {
288 c = vGetc ();
289 if (c == '(')
290 c = skipPastMatch ("()");
291 }
292 c = skipWhite (c);
293 if (isIdentifierCharacter (c))
294 tagNameList (kind, c);
295 }
296 }
297
findVerilogTags(void)298 static void findVerilogTags (void)
299 {
300 vString *const name = vStringNew ();
301 volatile boolean newStatement = TRUE;
302 volatile int c = '\0';
303 exception_t exception = (exception_t) setjmp (Exception);
304
305 if (exception == ExceptionNone) while (c != EOF)
306 {
307 c = vGetc ();
308 switch (c)
309 {
310 case ';':
311 case '\n':
312 newStatement = TRUE;
313 break;
314
315 case ' ':
316 case '\t':
317 break;
318
319 default:
320 if (newStatement && readIdentifier (name, c))
321 findTag (name);
322 newStatement = FALSE;
323 break;
324 }
325 }
326 vStringDelete (name);
327 }
328
VerilogParser(void)329 extern parserDefinition* VerilogParser (void)
330 {
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;
339 }
340
341 /* vi:set tabstop=4 shiftwidth=4: */
342