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 false);
910 tagEntryInfo *e = getEntryInCorkQueue (index);
911 if (e)
912 {
913 e->extensionFields.scopeIndex = (
914 entity_index == CORK_NIL
915 ? role_index
916 : entity_index);
917
918 /* TODO: append thes architecture name to
919 * architecture: field of *e*. */
920 }
921
922 attachParserFieldToCorkEntry (role_index,
923 VhdlFields[F_ARCHITECTURE].ftype,
924 vStringValue (name->string));
925
926 readToken (token);
927 if (isKeyword (token, KEYWORD_IS))
928 {
929 parseTillBegin (token, index);
930 parseTillEnd (token, index, KEYWORD_ARCHITECTURE);
931 }
932 }
933 }
934 deleteToken (name);
935 }
936
parseSignal(tokenInfo * const token,int parent)937 static void parseSignal (tokenInfo * const token, int parent)
938 {
939 readToken (token);
940 parseDeclElement (token, VHDLTAG_SIGNAL, parent, true);
941 }
942
parseLabel(tokenInfo * const name,int parent)943 static void parseLabel (tokenInfo * const name, int parent)
944 {
945 tokenInfo *const token = newToken ();
946
947 readToken (token);
948 if (isType (token, TOKEN_COLON))
949 {
950 readToken (token);
951 if (isType (token, TOKEN_KEYWORD))
952 parseKeywords (token, name, parent);
953 }
954 deleteToken (token);
955 }
956
parseProcess(tokenInfo * const token,tokenInfo * const label,int parent)957 static void parseProcess (tokenInfo * const token, tokenInfo * const label, int parent)
958 {
959 tokenInfo *process = label? label: copyToken (token);
960
961 if (label == NULL)
962 {
963 process->type = TOKEN_IDENTIFIER;
964 vStringClear (process->string);
965 anonGenerate (process->string, "anonProcess", VHDLTAG_PROCESS);
966 }
967
968 int index = makeVhdlTagWithScope (process, VHDLTAG_PROCESS, parent);
969
970 if (label == NULL)
971 {
972 tagEntryInfo *e = getEntryInCorkQueue (index);
973 if (e)
974 markTagExtraBit (e, XTAG_ANONYMOUS);
975 deleteToken (process);
976 }
977
978 skipToMatched (token);
979 parseTillBegin (token, index);
980 parseTillEnd (token, index, KEYWORD_PROCESS);
981 }
982
parseVariable(tokenInfo * const token,int parent)983 static void parseVariable (tokenInfo * const token, int parent)
984 {
985 readToken (token);
986 parseDeclElement (token, VHDLTAG_VARIABLE, parent, true);
987 }
988
parseAlias(tokenInfo * const token,int parent)989 static void parseAlias (tokenInfo * const token, int parent)
990 {
991 readToken (token);
992 parseDeclElement (token, VHDLTAG_ALIAS, parent, true);
993 }
994
995 /* TODO */
996 /* records */
parseKeywords(tokenInfo * const token,tokenInfo * const label,int index)997 static void parseKeywords (tokenInfo * const token, tokenInfo * const label, int index)
998 {
999 switch (token->keyword)
1000 {
1001 case KEYWORD_END:
1002 skipToCharacterInInputFile (';');
1003 break;
1004 case KEYWORD_CONSTANT:
1005 parseConstant (index);
1006 break;
1007 case KEYWORD_TYPE:
1008 parseTypes (token, index);
1009 break;
1010 case KEYWORD_SUBTYPE:
1011 parseTypes (token, index);
1012 break;
1013 case KEYWORD_ENTITY:
1014 parseModule (token, index);
1015 break;
1016 case KEYWORD_COMPONENT:
1017 parseModule (token, index);
1018 break;
1019 case KEYWORD_FUNCTION:
1020 parseSubProgram (token, index);
1021 break;
1022 case KEYWORD_PROCEDURE:
1023 parseSubProgram (token, index);
1024 break;
1025 case KEYWORD_PACKAGE:
1026 parsePackage (token);
1027 break;
1028 case KEYWORD_ARCHITECTURE:
1029 parseArchitecture (token);
1030 break;
1031 case KEYWORD_SIGNAL:
1032 parseSignal (token, index);
1033 break;
1034 case KEYWORD_PROCESS:
1035 parseProcess (token, label, index);
1036 break;
1037 case KEYWORD_VARIABLE:
1038 parseVariable (token, index);
1039 break;
1040 case KEYWORD_ALIAS:
1041 parseAlias (token, index);
1042 break;
1043 default:
1044 if (isType (token, TOKEN_IDENTIFIER))
1045 parseLabel (token, index);
1046 break;
1047 }
1048 }
1049
parseVhdlFile(tokenInfo * const token)1050 static tokenType parseVhdlFile (tokenInfo * const token)
1051 {
1052 do
1053 {
1054 readToken (token);
1055 parseKeywords (token, NULL, CORK_NIL);
1056 } while (!isKeyword (token, KEYWORD_END) && !isType (token, TOKEN_EOF));
1057 return token->type;
1058 }
1059
findVhdlTags(void)1060 static void findVhdlTags (void)
1061 {
1062 tokenInfo *const token = newToken ();
1063
1064 while (parseVhdlFile (token) != TOKEN_EOF);
1065
1066 deleteToken (token);
1067 }
1068
VhdlParser(void)1069 extern parserDefinition *VhdlParser (void)
1070 {
1071 static const char *const extensions[] = { "vhdl", "vhd", NULL };
1072 parserDefinition *def = parserNew ("VHDL");
1073 def->kindTable = VhdlKinds;
1074 def->kindCount = ARRAY_SIZE (VhdlKinds);
1075 def->extensions = extensions;
1076 def->parser = findVhdlTags;
1077 def->initialize = initialize;
1078 def->keywordTable = VhdlKeywordTable;
1079 def->keywordCount = ARRAY_SIZE (VhdlKeywordTable);
1080 def->fieldTable = VhdlFields;
1081 def->fieldCount = ARRAY_SIZE (VhdlFields);
1082 def->useCork = CORK_QUEUE|CORK_SYMTAB;
1083 return def;
1084 }
1085