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