1 /*
2 * Copyright (c) 2008, Nicolas Vincent
3 *
4 * This source code is released for free distribution under the terms of the
5 * GNU General Public License version 2 or (at your option) any later version.
6 *
7 * This module contains functions for generating tags for VHDL files.
8 *
9 * References:
10 * https://rti.etf.bg.ac.rs/rti/ri5rvl/tutorial/TUTORIAL/IEEE/HTML/1076_TOC.HTM
11 * https://tams.informatik.uni-hamburg.de/vhdl/tools/grammar/vhdl93-bnf.html
12 * http://www.vhdl.renerta.com/mobile/index.html
13 * https://www.hdlworks.com/hdl_corner/vhdl_ref/
14 * https://www.ics.uci.edu/~jmoorkan/vhdlref/Synario%20VHDL%20Manual.pdf
15 * http://atlas.physics.arizona.edu/~kjohns/downloads/vhdl/VHDL-xilinx-help.pdf
16 * http://www.csit-sun.pub.ro/resources/xilinx/synvhdl.pdf
17 * https://edg.uchicago.edu/~tang/VHDLref.pdf
18 */
19
20 /*
21 * INCLUDE FILES
22 */
23 #include "general.h" /* must always come first */
24
25 #include <ctype.h> /* to define isalpha () */
26 #include <string.h>
27
28 #include "debug.h"
29 #include "entry.h"
30 #include "keyword.h"
31 #include "parse.h"
32 #include "read.h"
33 #include "routines.h"
34 #include "vstring.h"
35 #include "trace.h"
36
37 /*
38 * MACROS
39 */
40 #define isType(token,t) (bool) ((token)->type == (t))
41 #define isKeyword(token,k) (bool) ((token)->keyword == (k))
42 #define isIdentChar1(c) (isalpha (c) || (c) == '_')
43 #define isIdentChar(c) (isalpha (c) || isdigit (c) || (c) == '_')
44
45 /*
46 * DATA DECLARATIONS
47 */
48
49 /*
50 * Used to specify type of keyword.
51 */
52 enum eKeywordId {
53 KEYWORD_ABS,
54 KEYWORD_ACCESS,
55 KEYWORD_AFTER,
56 KEYWORD_ALIAS,
57 KEYWORD_ALL,
58 KEYWORD_AND,
59 KEYWORD_ARCHITECTURE,
60 KEYWORD_ARRAY,
61 KEYWORD_ASSERT,
62 KEYWORD_ATTRIBUTE,
63 KEYWORD_BEGIN,
64 KEYWORD_BLOCK,
65 KEYWORD_BODY,
66 KEYWORD_BUFFER,
67 KEYWORD_BUS,
68 KEYWORD_CASE,
69 KEYWORD_COMPONENT,
70 KEYWORD_CONFIGURATION,
71 KEYWORD_CONSTANT,
72 KEYWORD_DISCONNECT,
73 KEYWORD_DOWNTO,
74 KEYWORD_ELSE,
75 KEYWORD_ELSIF,
76 KEYWORD_END,
77 KEYWORD_ENTITY,
78 KEYWORD_EXIT,
79 KEYWORD_FILE,
80 KEYWORD_FOR,
81 KEYWORD_FUNCTION,
82 KEYWORD_GENERATE,
83 KEYWORD_GENERIC,
84 KEYWORD_GROUP,
85 KEYWORD_GUARDED,
86 KEYWORD_IF,
87 KEYWORD_IMPURE,
88 KEYWORD_IN,
89 KEYWORD_INERTIAL,
90 KEYWORD_INOUT,
91 KEYWORD_IS,
92 KEYWORD_LABEL,
93 KEYWORD_LIBRARY,
94 KEYWORD_LINKAGE,
95 KEYWORD_LITERAL,
96 KEYWORD_LOOP,
97 KEYWORD_MAP,
98 KEYWORD_MOD,
99 KEYWORD_NAND,
100 KEYWORD_NEW,
101 KEYWORD_NEXT,
102 KEYWORD_NOR,
103 KEYWORD_NOT,
104 KEYWORD_NULL,
105 KEYWORD_OF,
106 KEYWORD_ON,
107 KEYWORD_OPEN,
108 KEYWORD_OR,
109 KEYWORD_OTHERS,
110 KEYWORD_OUT,
111 KEYWORD_PACKAGE,
112 KEYWORD_PORT,
113 KEYWORD_POSTPONED,
114 KEYWORD_PROCEDURE,
115 KEYWORD_PROCESS,
116 KEYWORD_PURE,
117 KEYWORD_RANGE,
118 KEYWORD_RECORD,
119 KEYWORD_REGISTER,
120 KEYWORD_REJECT,
121 KEYWORD_RETURN,
122 KEYWORD_ROL,
123 KEYWORD_ROR,
124 KEYWORD_SELECT,
125 KEYWORD_SEVERITY,
126 KEYWORD_SIGNAL,
127 KEYWORD_SHARED,
128 KEYWORD_SLA,
129 KEYWORD_SLI,
130 KEYWORD_SRA,
131 KEYWORD_SRL,
132 KEYWORD_SUBTYPE,
133 KEYWORD_THEN,
134 KEYWORD_TO,
135 KEYWORD_TRANSPORT,
136 KEYWORD_TYPE,
137 KEYWORD_UNAFFECTED,
138 KEYWORD_UNITS,
139 KEYWORD_UNTIL,
140 KEYWORD_USE,
141 KEYWORD_VARIABLE,
142 KEYWORD_WAIT,
143 KEYWORD_WHEN,
144 KEYWORD_WHILE,
145 KEYWORD_WITH,
146 KEYWORD_XNOR,
147 KEYWORD_XOR
148 };
149 typedef int keywordId; /* to allow KEYWORD_NONE */
150
151 typedef enum eTokenType {
152 TOKEN_NONE, /* none */
153 TOKEN_EOF, /* end-of-file */
154 TOKEN_OPEN_PAREN, /* ( */
155 TOKEN_CLOSE_PAREN, /* ) */
156 TOKEN_COMMA, /* the comma character */
157 TOKEN_IDENTIFIER,
158 TOKEN_KEYWORD,
159 TOKEN_PERIOD, /* . */
160 TOKEN_OPERATOR,
161 TOKEN_SEMICOLON, /* the semicolon character */
162 TOKEN_COLON, /* : */
163 TOKEN_STRING
164 } tokenType;
165
166 typedef struct sTokenInfo {
167 tokenType type;
168 keywordId keyword;
169 vString *string; /* the name of the token */
170 unsigned long lineNumber; /* line number of tag */
171 MIOPos filePosition; /* file position of line containing name */
172 } tokenInfo;
173
174 /*
175 * DATA DEFINITIONS
176 */
177 static int Lang_vhdl;
178
179 typedef enum {
180 VHDL_ENTITY_DESIGNED,
181 } vhdlEntityRole;
182
183 static roleDefinition VhdlEntityRoles [] = {
184 { true, "desigend",
185 "designed by an architecture" },
186 };
187
188 /* Used to index into the VhdlKinds table. */
189 typedef enum {
190 VHDLTAG_UNDEFINED = -1,
191 VHDLTAG_CONSTANT,
192 VHDLTAG_TYPE,
193 VHDLTAG_SUBTYPE,
194 VHDLTAG_RECORD,
195 VHDLTAG_ENTITY,
196 VHDLTAG_COMPONENT,
197 VHDLTAG_PROTOTYPE,
198 VHDLTAG_FUNCTION,
199 VHDLTAG_PROCEDURE,
200 VHDLTAG_PACKAGE,
201 VHDLTAG_LOCAL,
202 VHDLTAG_ARCHITECTURE,
203 VHDLTAG_PORT,
204 VHDLTAG_GENERIC,
205 VHDLTAG_SIGNAL,
206 VHDLTAG_PROCESS,
207 VHDLTAG_VARIABLE,
208 VHDLTAG_ALIAS,
209 } vhdlKind;
210
211 static kindDefinition VhdlKinds[] = {
212 {true, 'c', "constant", "constant declarations"},
213 {true, 't', "type", "type definitions"},
214 {true, 'T', "subtype", "subtype definitions"},
215 {true, 'r', "record", "record names"},
216 {true, 'e', "entity", "entity declarations",
217 .referenceOnly = false, ATTACH_ROLES(VhdlEntityRoles)},
218 {false, 'C', "component", "component declarations"},
219 {false, 'd', "prototype", "prototypes"},
220 {true, 'f', "function", "function prototypes and declarations"},
221 {true, 'p', "procedure", "procedure prototypes and declarations"},
222 {true, 'P', "package", "package definitions"},
223 {false, 'l', "local", "local definitions"},
224 {true, 'a', "architecture", "architectures"},
225 {true, 'q', "port", "port declarations"},
226 {true, 'g', "generic", "generic declarations"},
227 {true , 's', "signal", "signal declarations"},
228 {true, 'Q', "process", "processes"},
229 {true, 'v', "variable", "variables"},
230 {true, 'A', "alias", "aliases"},
231 };
232
233 static const keywordTable VhdlKeywordTable[] = {
234 {"abs", KEYWORD_ABS},
235 {"access", KEYWORD_ACCESS},
236 {"after", KEYWORD_AFTER},
237 {"alias", KEYWORD_ALIAS},
238 {"all", KEYWORD_ALL},
239 {"and", KEYWORD_AND},
240 {"architecture", KEYWORD_ARCHITECTURE},
241 {"array", KEYWORD_ARRAY},
242 {"assert", KEYWORD_ASSERT},
243 {"attribute", KEYWORD_ATTRIBUTE},
244 {"begin", KEYWORD_BEGIN},
245 {"block", KEYWORD_BLOCK},
246 {"body", KEYWORD_BODY},
247 {"buffer", KEYWORD_BUFFER},
248 {"bus", KEYWORD_BUS},
249 {"case", KEYWORD_CASE},
250 {"component", KEYWORD_COMPONENT},
251 {"configuration", KEYWORD_CONFIGURATION},
252 {"constant", KEYWORD_CONSTANT},
253 {"disconnect", KEYWORD_DISCONNECT},
254 {"downto", KEYWORD_DOWNTO},
255 {"else", KEYWORD_ELSE},
256 {"elsif", KEYWORD_ELSIF},
257 {"end", KEYWORD_END},
258 {"entity", KEYWORD_ENTITY},
259 {"exit", KEYWORD_EXIT},
260 {"file", KEYWORD_FILE},
261 {"for", KEYWORD_FOR},
262 {"function", KEYWORD_FUNCTION},
263 {"generate", KEYWORD_GENERATE},
264 {"generic", KEYWORD_GENERIC},
265 {"group", KEYWORD_GROUP},
266 {"guarded", KEYWORD_GUARDED},
267 {"if", KEYWORD_IF},
268 {"impure", KEYWORD_IMPURE},
269 {"in", KEYWORD_IN},
270 {"inertial", KEYWORD_INERTIAL},
271 {"inout", KEYWORD_INOUT},
272 {"is", KEYWORD_IS},
273 {"label", KEYWORD_LABEL},
274 {"library", KEYWORD_LIBRARY},
275 {"linkage", KEYWORD_LINKAGE},
276 {"literal", KEYWORD_LITERAL},
277 {"loop", KEYWORD_LOOP},
278 {"map", KEYWORD_MAP},
279 {"mod", KEYWORD_MOD},
280 {"nand", KEYWORD_NAND},
281 {"new", KEYWORD_NEW},
282 {"next", KEYWORD_NEXT},
283 {"nor", KEYWORD_NOR},
284 {"not", KEYWORD_NOT},
285 {"null", KEYWORD_NULL},
286 {"of", KEYWORD_OF},
287 {"on", KEYWORD_ON},
288 {"open", KEYWORD_OPEN},
289 {"or", KEYWORD_OR},
290 {"others", KEYWORD_OTHERS},
291 {"out", KEYWORD_OUT},
292 {"package", KEYWORD_PACKAGE},
293 {"port", KEYWORD_PORT},
294 {"postponed", KEYWORD_POSTPONED},
295 {"procedure", KEYWORD_PROCEDURE},
296 {"process", KEYWORD_PROCESS},
297 {"pure", KEYWORD_PURE},
298 {"range", KEYWORD_RANGE},
299 {"record", KEYWORD_RECORD},
300 {"register", KEYWORD_REGISTER},
301 {"reject", KEYWORD_REJECT},
302 {"return", KEYWORD_RETURN},
303 {"rol", KEYWORD_ROL},
304 {"ror", KEYWORD_ROR},
305 {"select", KEYWORD_SELECT},
306 {"severity", KEYWORD_SEVERITY},
307 {"signal", KEYWORD_SIGNAL},
308 {"shared", KEYWORD_SHARED},
309 {"sla", KEYWORD_SLA},
310 {"sli", KEYWORD_SLI},
311 {"sra", KEYWORD_SRA},
312 {"srl", KEYWORD_SRL},
313 {"subtype", KEYWORD_SUBTYPE},
314 {"then", KEYWORD_THEN},
315 {"to", KEYWORD_TO},
316 {"transport", KEYWORD_TRANSPORT},
317 {"type", KEYWORD_TYPE},
318 {"unaffected", KEYWORD_UNAFFECTED},
319 {"units", KEYWORD_UNITS},
320 {"until", KEYWORD_UNTIL},
321 {"use", KEYWORD_USE},
322 {"variable", KEYWORD_VARIABLE},
323 {"wait", KEYWORD_WAIT},
324 {"when", KEYWORD_WHEN},
325 {"while", KEYWORD_WHILE},
326 {"with", KEYWORD_WITH},
327 {"xnor", KEYWORD_XNOR},
328 {"xor", KEYWORD_XOR}
329 };
330
331 typedef enum {
332 F_ARCHITECTURE,
333 } vhdlField;
334
335 static fieldDefinition VhdlFields [] = {
336 { .name = "architecture",
337 .description = "architecture designing the entity",
338 .enabled = true },
339 };
340
341 /*
342 * FUNCTION DECLARATIONS
343 */
344 static void parseKeywords (tokenInfo * const token, tokenInfo * const label, int parent);
345
346 /*
347 * FUNCTION DEFINITIONS
348 */
isIdentifierMatch(const tokenInfo * const token,const char * name)349 static bool isIdentifierMatch (const tokenInfo * const token,
350 const char *name)
351 {
352 return (bool) (isType (token, TOKEN_IDENTIFIER) &&
353 strncasecmp (vStringValue (token->string), name,
354 vStringLength (token->string)) == 0);
355 }
356
isSemicolonOrKeywordOrIdent(const tokenInfo * const token,const keywordId keyword,const char * name)357 static bool isSemicolonOrKeywordOrIdent (const tokenInfo * const token,
358 const keywordId keyword, const char *name)
359 {
360 return (bool) (isType (token, TOKEN_SEMICOLON)
361 || isKeyword (token, keyword)
362 || isIdentifierMatch (token, name));
363 }
364
newToken(void)365 static tokenInfo *newToken (void)
366 {
367 tokenInfo *const token = xMalloc (1, tokenInfo);
368 token->type = TOKEN_NONE;
369 token->keyword = KEYWORD_NONE;
370 token->string = vStringNew ();
371 token->lineNumber = getInputLineNumber ();
372 token->filePosition = getInputFilePosition ();
373 return token;
374 }
375
copyToken(tokenInfo * const src)376 static tokenInfo *copyToken (tokenInfo * const src)
377 {
378 tokenInfo *dst = newToken ();
379 vStringCopy (dst->string, src->string);
380 return dst;
381 }
382
deleteToken(tokenInfo * const token)383 static void deleteToken (tokenInfo * const token)
384 {
385 if (token != NULL)
386 {
387 vStringDelete (token->string);
388 eFree (token);
389 }
390 }
391
392 /*
393 * Parsing functions
394 */
395
parseString(vString * const string,const int delimiter)396 static void parseString (vString * const string, const int delimiter)
397 {
398 bool end = false;
399 while (!end)
400 {
401 int c = getcFromInputFile ();
402 if (c == EOF)
403 end = true;
404 else if (c == '\\')
405 {
406 c = getcFromInputFile (); /* This maybe a ' or ". */
407 vStringPut (string, c);
408 }
409 else if (c == delimiter)
410 end = true;
411 else
412 vStringPut (string, c);
413 }
414 }
415
416 /* Read a VHDL identifier beginning with "firstChar" and place it into "name".
417 */
parseIdentifier(vString * const string,const int firstChar)418 static void parseIdentifier (vString * const string, const int firstChar)
419 {
420 int c = firstChar;
421 Assert (isIdentChar1 (c));
422 do
423 {
424 vStringPut (string, c);
425 c = getcFromInputFile ();
426 } while (isIdentChar (c));
427 if (!isspace (c))
428 ungetcToInputFile (c); /* unget non-identifier character */
429 }
430
readToken(tokenInfo * const token)431 static void readToken (tokenInfo * const token)
432 {
433 int c;
434
435 token->type = TOKEN_NONE;
436 token->keyword = KEYWORD_NONE;
437 vStringClear (token->string);
438
439 getNextChar:
440 do
441 {
442 c = getcFromInputFile ();
443 token->lineNumber = getInputLineNumber ();
444 token->filePosition = getInputFilePosition ();
445 }
446 while (c == '\t' || c == ' ' || c == '\n');
447
448 switch (c)
449 {
450 case EOF:
451 token->type = TOKEN_EOF;
452 break;
453 case '(':
454 token->type = TOKEN_OPEN_PAREN;
455 break;
456 case ')':
457 token->type = TOKEN_CLOSE_PAREN;
458 break;
459 case ';':
460 token->type = TOKEN_SEMICOLON;
461 break;
462 case ':':
463 token->type = TOKEN_COLON;
464 break;
465 case '.':
466 token->type = TOKEN_PERIOD;
467 break;
468 case ',':
469 token->type = TOKEN_COMMA;
470 break;
471 case '\'': /* only single char are inside simple quotes */
472 break; /* or it is for attributes so we don't care */
473 case '"':
474 token->type = TOKEN_STRING;
475 parseString (token->string, c);
476 token->lineNumber = getInputLineNumber ();
477 token->filePosition = getInputFilePosition ();
478 break;
479 case '-':
480 c = getcFromInputFile ();
481 if (c == '-') /* start of a comment */
482 {
483 skipToCharacterInInputFile ('\n');
484 goto getNextChar;
485 }
486 else
487 {
488 if (!isspace (c))
489 ungetcToInputFile (c);
490 token->type = TOKEN_OPERATOR;
491 }
492 break;
493 default:
494 if (!isIdentChar1 (c))
495 token->type = TOKEN_NONE;
496 else
497 {
498 parseIdentifier (token->string, c);
499 token->lineNumber = getInputLineNumber ();
500 token->filePosition = getInputFilePosition ();
501 token->keyword = lookupCaseKeyword (vStringValue (token->string), Lang_vhdl);
502 if (isKeyword (token, KEYWORD_NONE))
503 token->type = TOKEN_IDENTIFIER;
504 else
505 token->type = TOKEN_KEYWORD;
506 }
507 break;
508 }
509 }
510
skipToKeyword(const keywordId keyword)511 static bool skipToKeyword (const keywordId keyword)
512 {
513 tokenInfo *const token = newToken ();
514 do
515 {
516 readToken (token);
517 }
518 while (!isType (token, TOKEN_EOF) && !isKeyword (token, keyword));
519
520 bool r = isKeyword (token, keyword);
521 deleteToken (token);
522 return r;
523 }
524
skipToMatched(tokenInfo * const token)525 static void skipToMatched (tokenInfo * const token)
526 {
527 int nest_level = 0;
528 tokenType open_token;
529 tokenType close_token;
530
531 switch (token->type)
532 {
533 case TOKEN_OPEN_PAREN:
534 open_token = TOKEN_OPEN_PAREN;
535 close_token = TOKEN_CLOSE_PAREN;
536 break;
537 default:
538 return;
539 }
540
541 /*
542 * This routine will skip to a matching closing token.
543 * It will also handle nested tokens like the (, ) below.
544 * ( name varchar(30), text binary(10) )
545 */
546 if (isType (token, open_token))
547 {
548 nest_level++;
549 while (!(isType (token, close_token) && (nest_level == 0)) && !isType (token, TOKEN_EOF))
550 {
551 readToken (token);
552 if (isType (token, open_token))
553 {
554 nest_level++;
555 }
556 if (isType (token, close_token))
557 {
558 if (nest_level > 0)
559 {
560 nest_level--;
561 }
562 }
563 }
564 readToken (token);
565 }
566 }
567
makeVhdlTagWithScope(tokenInfo * const token,const vhdlKind kind,int parent)568 static int makeVhdlTagWithScope (tokenInfo * const token, const vhdlKind kind, int parent)
569 {
570 const char *const name = vStringValue (token->string);
571 tagEntryInfo e;
572 initTagEntry (&e, name, kind);
573 e.lineNumber = token->lineNumber;
574 e.filePosition = token->filePosition;
575 e.extensionFields.scopeIndex = parent;
576 return makeTagEntry (&e);
577 }
578
makeVhdlTag(tokenInfo * const token,const vhdlKind kind)579 static int makeVhdlTag (tokenInfo * const token, const vhdlKind kind)
580 {
581 return makeVhdlTagWithScope (token, kind, CORK_NIL);
582 }
583
initialize(const langType language)584 static void initialize (const langType language)
585 {
586 Lang_vhdl = language;
587 }
588
parseTillEnd(tokenInfo * const token,int parent,const int end_keyword)589 static void parseTillEnd (tokenInfo * const token, int parent, const int end_keyword)
590 {
591 bool ended = false;
592 tagEntryInfo *e = getEntryInCorkQueue (parent);
593 /* If e is NULL, the input may be broken as VHDL code
594 * or unsupported syntax in this parser. */
595
596 do
597 {
598 readToken (token);
599 if (isKeyword (token, KEYWORD_END))
600 {
601 readToken (token);
602 if (e)
603 ended = isSemicolonOrKeywordOrIdent (token,
604 end_keyword, e->name);
605 if (!isType (token, TOKEN_SEMICOLON))
606 skipToCharacterInInputFile (';');
607 if (ended)
608 e->extensionFields.endLine = getInputLineNumber ();
609 }
610 else
611 {
612 if (isType (token, TOKEN_EOF))
613 {
614 ended = true;
615 }
616 else
617 {
618 parseKeywords (token, NULL, parent);
619 }
620 }
621 } while (!ended);
622 }
623
parseTillBegin(tokenInfo * const token,int parent)624 static void parseTillBegin (tokenInfo * const token, int parent)
625 {
626 bool begun = false;
627 do
628 {
629 readToken (token);
630 if (isKeyword (token, KEYWORD_BEGIN)
631 || isType (token, TOKEN_EOF))
632 begun = true;
633 else
634 parseKeywords (token, NULL, parent);
635 } while (!begun);
636 }
637
parsePackage(tokenInfo * const token)638 static void parsePackage (tokenInfo * const token)
639 {
640 tokenInfo *const name = newToken ();
641 tokenInfo *token_for_tagging = NULL;
642 Assert (isKeyword (token, KEYWORD_PACKAGE));
643 readToken (token);
644 if (isKeyword (token, KEYWORD_BODY))
645 {
646 readToken (name);
647 token_for_tagging = name;
648 }
649 else if (isType (token, TOKEN_IDENTIFIER))
650 token_for_tagging = token;
651
652 if (token_for_tagging)
653 {
654 int index = makeVhdlTag (token_for_tagging, VHDLTAG_PACKAGE);
655 parseTillEnd (token, index, KEYWORD_PACKAGE);
656 }
657
658 deleteToken (name);
659 }
660
661
parseDeclElement(tokenInfo * const token,vhdlKind kind,int parent,bool ended_with_semicolon)662 static void parseDeclElement (tokenInfo * const token,
663 vhdlKind kind, int parent,
664 bool ended_with_semicolon)
665 {
666 TRACE_ENTER ();
667 while (! (isType (token, TOKEN_EOF)
668 || isType (token, TOKEN_CLOSE_PAREN)
669 || (ended_with_semicolon && isType (token, TOKEN_SEMICOLON))))
670 {
671 if (isType (token, TOKEN_IDENTIFIER))
672 {
673 makeVhdlTagWithScope (token, kind, parent);
674 readToken (token);
675 }
676 else if (isType (token, TOKEN_COMMA))
677 readToken (token);
678 else if (isType (token, TOKEN_COLON))
679 {
680 do
681 {
682 readToken (token);
683 skipToMatched (token);
684 if (isType (token, TOKEN_CLOSE_PAREN)
685 || isType (token, TOKEN_SEMICOLON))
686 break;
687 }
688 while (!isType (token, TOKEN_EOF));
689 }
690 else
691 {
692 /* Unexpected */
693 readToken (token);
694 }
695 }
696 TRACE_LEAVE ();
697 }
698
parseModuleDecl(tokenInfo * const token,int parent)699 static void parseModuleDecl (tokenInfo * const token, int parent)
700 {
701 TRACE_ENTER ();
702 while (! (isKeyword (token, KEYWORD_END)
703 || isType (token, TOKEN_EOF)))
704 {
705 vhdlKind kind = VHDLTAG_UNDEFINED;
706 if (isKeyword (token, KEYWORD_PORT))
707 kind = VHDLTAG_PORT;
708 else if (isKeyword (token, KEYWORD_GENERIC))
709 kind = VHDLTAG_GENERIC;
710
711 if (kind != VHDLTAG_UNDEFINED)
712 {
713 readToken (token);
714 if (isType (token, TOKEN_OPEN_PAREN))
715 {
716 readToken (token);
717 parseDeclElement (token, kind, parent, false);
718 }
719 }
720 else
721 readToken (token);
722 }
723 TRACE_LEAVE ();
724 }
725
parseModule(tokenInfo * const token,int parent)726 static void parseModule (tokenInfo * const token, int parent)
727 {
728 tokenInfo *const name = newToken ();
729 const vhdlKind kind = isKeyword (token, KEYWORD_ENTITY) ?
730 VHDLTAG_ENTITY : VHDLTAG_COMPONENT;
731 Assert (isKeyword (token, KEYWORD_ENTITY) ||
732 isKeyword (token, KEYWORD_COMPONENT));
733 readToken (name);
734 readToken (token);
735 if (kind == VHDLTAG_COMPONENT || isKeyword (token, KEYWORD_IS))
736 {
737 int index = makeVhdlTagWithScope (name, kind, parent);
738 if (isKeyword (token, KEYWORD_IS))
739 readToken (token);
740 parseModuleDecl (token, index);
741
742 bool ended = isKeyword (token, KEYWORD_END);
743 if (!ended)
744 ended = skipToKeyword (KEYWORD_END);
745 skipToCharacterInInputFile (';');
746
747 if (ended)
748 {
749 tagEntryInfo *e = getEntryInCorkQueue (index);
750 if (e)
751 e->extensionFields.endLine = getInputLineNumber ();
752 }
753
754 if (kind == VHDLTAG_ENTITY)
755 registerEntry (index);
756 }
757 deleteToken (name);
758 }
759
parseRecord(tokenInfo * const token,int parent)760 static void parseRecord (tokenInfo * const token, int parent)
761 {
762 tokenInfo *const name = newToken ();
763 Assert (isKeyword (token, KEYWORD_RECORD));
764 readToken (name);
765 do
766 {
767 readToken (token); /* should be a colon */
768 skipToCharacterInInputFile (';');
769 makeVhdlTagWithScope (name, VHDLTAG_RECORD, parent);
770 readToken (name);
771 }
772 while (!isKeyword (name, KEYWORD_END) && !isType (name, TOKEN_EOF));
773 skipToCharacterInInputFile (';');
774
775 if (isKeyword (name, KEYWORD_END))
776 {
777 tagEntryInfo *e = getEntryInCorkQueue (parent);
778 if (e)
779 e->extensionFields.endLine = getInputLineNumber ();
780 }
781
782 deleteToken (name);
783 }
784
parseTypes(tokenInfo * const token,int parent)785 static void parseTypes (tokenInfo * const token, int parent)
786 {
787 tokenInfo *const name = newToken ();
788 const vhdlKind kind = isKeyword (token, KEYWORD_TYPE) ?
789 VHDLTAG_TYPE : VHDLTAG_SUBTYPE;
790 Assert (isKeyword (token, KEYWORD_TYPE) ||
791 isKeyword (token, KEYWORD_SUBTYPE));
792 readToken (name);
793 readToken (token);
794 if (isKeyword (token, KEYWORD_IS))
795 {
796 readToken (token); /* type */
797 if (isKeyword (token, KEYWORD_RECORD))
798 {
799 int index = makeVhdlTagWithScope (name, kind, parent);
800 /*TODO: make tags of the record's names */
801 parseRecord (token, index);
802 }
803 else
804 {
805 makeVhdlTagWithScope (name, kind, parent);
806 }
807 }
808 deleteToken (name);
809 }
810
parseConstant(int parent)811 static void parseConstant (int parent)
812 {
813 vhdlKind parent_kind = VHDLTAG_UNDEFINED;
814 tagEntryInfo *e = getEntryInCorkQueue (parent);
815 if (e)
816 parent_kind = e->kindIndex;
817
818 vhdlKind kind;
819 switch (parent_kind)
820 {
821 case VHDLTAG_FUNCTION:
822 case VHDLTAG_PROCEDURE:
823 kind = VHDLTAG_LOCAL;
824 break;
825 default:
826 kind = VHDLTAG_CONSTANT;
827 break;
828 }
829
830 tokenInfo *const name = newToken ();
831 readToken (name);
832 makeVhdlTagWithScope (name, kind, parent);
833 skipToCharacterInInputFile (';');
834 deleteToken (name);
835 }
836
parseSubProgram(tokenInfo * const token,int parent)837 static void parseSubProgram (tokenInfo * const token, int parent)
838 {
839 tokenInfo *const name = newToken ();
840 const vhdlKind kind = isKeyword (token, KEYWORD_FUNCTION) ?
841 VHDLTAG_FUNCTION : VHDLTAG_PROCEDURE;
842 const int end_keyword = token->keyword;
843 Assert (isKeyword (token, KEYWORD_FUNCTION) ||
844 isKeyword (token, KEYWORD_PROCEDURE));
845 readToken (name); /* the name of the function or procedure */
846 readToken (token);
847 if (isType (token, TOKEN_OPEN_PAREN))
848 {
849 skipToMatched (token);
850 }
851
852 if (kind == VHDLTAG_FUNCTION)
853 {
854 if (isKeyword (token, KEYWORD_RETURN))
855 {
856 /* Read datatype */
857 readToken (token);
858 while (! isKeyword (token, KEYWORD_IS) &&
859 ! isType (token, TOKEN_SEMICOLON) &&
860 ! isType (token, TOKEN_EOF))
861 {
862 readToken (token);
863 }
864 }
865 }
866
867 if (isType (token, TOKEN_SEMICOLON))
868 {
869 makeVhdlTagWithScope (name, VHDLTAG_PROTOTYPE, parent);
870 }
871 else if (isKeyword (token, KEYWORD_IS))
872 {
873 int index = makeVhdlTagWithScope (name, kind, parent);
874 parseTillEnd (token, index, end_keyword);
875 }
876 deleteToken (name);
877 }
878
879 /* architecture behavioral of ent is*/
parseArchitecture(tokenInfo * const token)880 static void parseArchitecture (tokenInfo * const token)
881 {
882 tokenInfo *const name = newToken ();
883
884 readToken (name);
885 if (!isType (name, TOKEN_IDENTIFIER))
886 {
887 skipToKeyword (KEYWORD_END);
888 skipToCharacterInInputFile (';');
889 deleteToken (name);
890 return;
891 }
892
893 int index = makeVhdlTag (name, VHDLTAG_ARCHITECTURE);
894 readToken (token);
895 if (isKeyword (token, KEYWORD_OF))
896 {
897 readToken (token);
898 if (isType (token, TOKEN_IDENTIFIER))
899 {
900 /* Filling scope field of this architecture.
901 If the definition for the entity can be found in the symbol table,
902 use its cork as the scope. If not, use the reference tag for the
903 entity as fallback. */
904 int role_index = makeSimpleRefTag (token->string,
905 VHDLTAG_ENTITY, VHDL_ENTITY_DESIGNED);
906 int entity_index = anyKindEntryInScope (CORK_NIL,
907 vStringValue (token->string),
908 VHDLTAG_ENTITY);
909 tagEntryInfo *e = getEntryInCorkQueue (index);
910 if (e)
911 {
912 e->extensionFields.scopeIndex = (
913 entity_index == CORK_NIL
914 ? role_index
915 : entity_index);
916
917 /* TODO: append thes architecture name to
918 * architecture: field of *e*. */
919 }
920
921 attachParserFieldToCorkEntry (role_index,
922 VhdlFields[F_ARCHITECTURE].ftype,
923 vStringValue (name->string));
924
925 readToken (token);
926 if (isKeyword (token, KEYWORD_IS))
927 {
928 parseTillBegin (token, index);
929 parseTillEnd (token, index, KEYWORD_ARCHITECTURE);
930 }
931 }
932 }
933 deleteToken (name);
934 }
935
parseSignal(tokenInfo * const token,int parent)936 static void parseSignal (tokenInfo * const token, int parent)
937 {
938 readToken (token);
939 parseDeclElement (token, VHDLTAG_SIGNAL, parent, true);
940 }
941
parseLabel(tokenInfo * const name,int parent)942 static void parseLabel (tokenInfo * const name, int parent)
943 {
944 tokenInfo *const token = newToken ();
945
946 readToken (token);
947 if (isType (token, TOKEN_COLON))
948 {
949 readToken (token);
950 if (isType (token, TOKEN_KEYWORD))
951 parseKeywords (token, name, parent);
952 }
953 deleteToken (token);
954 }
955
parseProcess(tokenInfo * const token,tokenInfo * const label,int parent)956 static void parseProcess (tokenInfo * const token, tokenInfo * const label, int parent)
957 {
958 tokenInfo *process = label? label: copyToken (token);
959
960 if (label == NULL)
961 {
962 process->type = TOKEN_IDENTIFIER;
963 vStringClear (process->string);
964 anonGenerate (process->string, "anonProcess", VHDLTAG_PROCESS);
965 }
966
967 int index = makeVhdlTagWithScope (process, VHDLTAG_PROCESS, parent);
968
969 if (label == NULL)
970 {
971 tagEntryInfo *e = getEntryInCorkQueue (index);
972 if (e)
973 markTagExtraBit (e, XTAG_ANONYMOUS);
974 deleteToken (process);
975 }
976
977 skipToMatched (token);
978 parseTillBegin (token, index);
979 parseTillEnd (token, index, KEYWORD_PROCESS);
980 }
981
parseVariable(tokenInfo * const token,int parent)982 static void parseVariable (tokenInfo * const token, int parent)
983 {
984 readToken (token);
985 parseDeclElement (token, VHDLTAG_VARIABLE, parent, true);
986 }
987
parseAlias(tokenInfo * const token,int parent)988 static void parseAlias (tokenInfo * const token, int parent)
989 {
990 readToken (token);
991 parseDeclElement (token, VHDLTAG_ALIAS, parent, true);
992 }
993
994 /* TODO */
995 /* records */
parseKeywords(tokenInfo * const token,tokenInfo * const label,int index)996 static void parseKeywords (tokenInfo * const token, tokenInfo * const label, int index)
997 {
998 switch (token->keyword)
999 {
1000 case KEYWORD_END:
1001 skipToCharacterInInputFile (';');
1002 break;
1003 case KEYWORD_CONSTANT:
1004 parseConstant (index);
1005 break;
1006 case KEYWORD_TYPE:
1007 parseTypes (token, index);
1008 break;
1009 case KEYWORD_SUBTYPE:
1010 parseTypes (token, index);
1011 break;
1012 case KEYWORD_ENTITY:
1013 parseModule (token, index);
1014 break;
1015 case KEYWORD_COMPONENT:
1016 parseModule (token, index);
1017 break;
1018 case KEYWORD_FUNCTION:
1019 parseSubProgram (token, index);
1020 break;
1021 case KEYWORD_PROCEDURE:
1022 parseSubProgram (token, index);
1023 break;
1024 case KEYWORD_PACKAGE:
1025 parsePackage (token);
1026 break;
1027 case KEYWORD_ARCHITECTURE:
1028 parseArchitecture (token);
1029 break;
1030 case KEYWORD_SIGNAL:
1031 parseSignal (token, index);
1032 break;
1033 case KEYWORD_PROCESS:
1034 parseProcess (token, label, index);
1035 break;
1036 case KEYWORD_VARIABLE:
1037 parseVariable (token, index);
1038 break;
1039 case KEYWORD_ALIAS:
1040 parseAlias (token, index);
1041 break;
1042 default:
1043 if (isType (token, TOKEN_IDENTIFIER))
1044 parseLabel (token, index);
1045 break;
1046 }
1047 }
1048
parseVhdlFile(tokenInfo * const token)1049 static tokenType parseVhdlFile (tokenInfo * const token)
1050 {
1051 do
1052 {
1053 readToken (token);
1054 parseKeywords (token, NULL, CORK_NIL);
1055 } while (!isKeyword (token, KEYWORD_END) && !isType (token, TOKEN_EOF));
1056 return token->type;
1057 }
1058
findVhdlTags(void)1059 static void findVhdlTags (void)
1060 {
1061 tokenInfo *const token = newToken ();
1062
1063 while (parseVhdlFile (token) != TOKEN_EOF);
1064
1065 deleteToken (token);
1066 }
1067
VhdlParser(void)1068 extern parserDefinition *VhdlParser (void)
1069 {
1070 static const char *const extensions[] = { "vhdl", "vhd", NULL };
1071 parserDefinition *def = parserNew ("VHDL");
1072 def->kindTable = VhdlKinds;
1073 def->kindCount = ARRAY_SIZE (VhdlKinds);
1074 def->extensions = extensions;
1075 def->parser = findVhdlTags;
1076 def->initialize = initialize;
1077 def->keywordTable = VhdlKeywordTable;
1078 def->keywordCount = ARRAY_SIZE (VhdlKeywordTable);
1079 def->fieldTable = VhdlFields;
1080 def->fieldCount = ARRAY_SIZE (VhdlFields);
1081 def->useCork = CORK_QUEUE|CORK_SYMTAB;
1082 return def;
1083 }
1084