Update all parsers and related files to ctags p6.1.20240421.0
[geany-mirror.git] / ctags / parsers / vhdl.c
blob30e3d9d5e77e45a706d84f3365a0e70fae984c6b
1 /*
2 * Copyright (c) 2008, Nicolas Vincent
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.
7 * This module contains functions for generating tags for VHDL files.
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
21 * INCLUDE FILES
23 #include "general.h" /* must always come first */
25 #include <ctype.h> /* to define isalpha () */
26 #include <string.h>
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"
38 * MACROS
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) == '_')
46 * DATA DECLARATIONS
50 * Used to specify type of keyword.
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
149 typedef int keywordId; /* to allow KEYWORD_NONE */
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;
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;
175 * DATA DEFINITIONS
177 static int Lang_vhdl;
179 typedef enum {
180 VHDL_ENTITY_DESIGNED,
181 } vhdlEntityRole;
183 static roleDefinition VhdlEntityRoles [] = {
184 { true, "desigend",
185 "designed by an architecture" },
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;
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"},
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}
331 typedef enum {
332 F_ARCHITECTURE,
333 } vhdlField;
335 static fieldDefinition VhdlFields [] = {
336 { .name = "architecture",
337 .description = "architecture designing the entity",
338 .enabled = true },
342 * FUNCTION DECLARATIONS
344 static void parseKeywords (tokenInfo * const token, tokenInfo * const label, int parent);
347 * FUNCTION DEFINITIONS
349 static bool isIdentifierMatch (const tokenInfo * const token,
350 const char *name)
352 return (bool) (isType (token, TOKEN_IDENTIFIER) &&
353 strncasecmp (vStringValue (token->string), name,
354 vStringLength (token->string)) == 0);
357 static bool isSemicolonOrKeywordOrIdent (const tokenInfo * const token,
358 const keywordId keyword, const char *name)
360 return (bool) (isType (token, TOKEN_SEMICOLON)
361 || isKeyword (token, keyword)
362 || isIdentifierMatch (token, name));
365 static tokenInfo *newToken (void)
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;
376 static tokenInfo *copyToken (tokenInfo * const src)
378 tokenInfo *dst = newToken ();
379 vStringCopy (dst->string, src->string);
380 return dst;
383 static void deleteToken (tokenInfo * const token)
385 if (token != NULL)
387 vStringDelete (token->string);
388 eFree (token);
393 * Parsing functions
396 static void parseString (vString * const string, const int delimiter)
398 bool end = false;
399 while (!end)
401 int c = getcFromInputFile ();
402 if (c == EOF)
403 end = true;
404 else if (c == '\\')
406 c = getcFromInputFile (); /* This maybe a ' or ". */
407 vStringPut (string, c);
409 else if (c == delimiter)
410 end = true;
411 else
412 vStringPut (string, c);
416 /* Read a VHDL identifier beginning with "firstChar" and place it into "name".
418 static void parseIdentifier (vString * const string, const int firstChar)
420 int c = firstChar;
421 Assert (isIdentChar1 (c));
424 vStringPut (string, c);
425 c = getcFromInputFile ();
426 } while (isIdentChar (c));
427 if (!isspace (c))
428 ungetcToInputFile (c); /* unget non-identifier character */
431 static void readToken (tokenInfo * const token)
433 int c;
435 token->type = TOKEN_NONE;
436 token->keyword = KEYWORD_NONE;
437 vStringClear (token->string);
439 getNextChar:
442 c = getcFromInputFile ();
443 token->lineNumber = getInputLineNumber ();
444 token->filePosition = getInputFilePosition ();
446 while (c == '\t' || c == ' ' || c == '\n');
448 switch (c)
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 */
483 skipToCharacterInInputFile ('\n');
484 goto getNextChar;
486 else
488 if (!isspace (c))
489 ungetcToInputFile (c);
490 token->type = TOKEN_OPERATOR;
492 break;
493 default:
494 if (!isIdentChar1 (c))
495 token->type = TOKEN_NONE;
496 else
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;
507 break;
511 static bool skipToKeyword (const keywordId keyword)
513 tokenInfo *const token = newToken ();
516 readToken (token);
518 while (!isType (token, TOKEN_EOF) && !isKeyword (token, keyword));
520 bool r = isKeyword (token, keyword);
521 deleteToken (token);
522 return r;
525 static void skipToMatched (tokenInfo * const token)
527 int nest_level = 0;
528 tokenType open_token;
529 tokenType close_token;
531 switch (token->type)
533 case TOKEN_OPEN_PAREN:
534 open_token = TOKEN_OPEN_PAREN;
535 close_token = TOKEN_CLOSE_PAREN;
536 break;
537 default:
538 return;
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) )
546 if (isType (token, open_token))
548 nest_level++;
549 while (!(isType (token, close_token) && (nest_level == 0)) && !isType (token, TOKEN_EOF))
551 readToken (token);
552 if (isType (token, open_token))
554 nest_level++;
556 if (isType (token, close_token))
558 if (nest_level > 0)
560 nest_level--;
564 readToken (token);
568 static int makeVhdlTagWithScope (tokenInfo * const token, const vhdlKind kind, int parent)
570 const char *const name = vStringValue (token->string);
571 tagEntryInfo e;
572 initTagEntry (&e, name, kind);
573 updateTagLine (&e, token->lineNumber, token->filePosition);
574 e.extensionFields.scopeIndex = parent;
575 return makeTagEntry (&e);
578 static int makeVhdlTag (tokenInfo * const token, const vhdlKind kind)
580 return makeVhdlTagWithScope (token, kind, CORK_NIL);
583 static void initialize (const langType language)
585 Lang_vhdl = language;
588 static void parseTillEnd (tokenInfo * const token, int parent, const int end_keyword)
590 bool ended = false;
591 tagEntryInfo *e = getEntryInCorkQueue (parent);
592 /* If e is NULL, the input may be broken as VHDL code
593 * or unsupported syntax in this parser. */
597 readToken (token);
598 if (isKeyword (token, KEYWORD_END))
600 readToken (token);
601 if (e)
602 ended = isSemicolonOrKeywordOrIdent (token,
603 end_keyword, e->name);
604 if (!isType (token, TOKEN_SEMICOLON))
605 skipToCharacterInInputFile (';');
606 if (ended)
607 setTagEndLine (e, getInputLineNumber ());
609 else
611 if (isType (token, TOKEN_EOF))
613 ended = true;
615 else
617 parseKeywords (token, NULL, parent);
620 } while (!ended);
623 static void parseTillBegin (tokenInfo * const token, int parent)
625 bool begun = false;
628 readToken (token);
629 if (isKeyword (token, KEYWORD_BEGIN)
630 || isType (token, TOKEN_EOF))
631 begun = true;
632 else
633 parseKeywords (token, NULL, parent);
634 } while (!begun);
637 static void parsePackage (tokenInfo * const token)
639 tokenInfo *const name = newToken ();
640 tokenInfo *token_for_tagging = NULL;
641 Assert (isKeyword (token, KEYWORD_PACKAGE));
642 readToken (token);
643 if (isKeyword (token, KEYWORD_BODY))
645 readToken (name);
646 token_for_tagging = name;
648 else if (isType (token, TOKEN_IDENTIFIER))
649 token_for_tagging = token;
651 if (token_for_tagging)
653 int index = makeVhdlTag (token_for_tagging, VHDLTAG_PACKAGE);
654 parseTillEnd (token, index, KEYWORD_PACKAGE);
657 deleteToken (name);
661 static void parseDeclElement (tokenInfo * const token,
662 vhdlKind kind, int parent,
663 bool ended_with_semicolon)
665 TRACE_ENTER ();
666 while (! (isType (token, TOKEN_EOF)
667 || isType (token, TOKEN_CLOSE_PAREN)
668 || (ended_with_semicolon && isType (token, TOKEN_SEMICOLON))))
670 if (isType (token, TOKEN_IDENTIFIER))
672 makeVhdlTagWithScope (token, kind, parent);
673 readToken (token);
675 else if (isType (token, TOKEN_COMMA))
676 readToken (token);
677 else if (isType (token, TOKEN_COLON))
681 readToken (token);
682 skipToMatched (token);
683 if (isType (token, TOKEN_CLOSE_PAREN)
684 || isType (token, TOKEN_SEMICOLON))
685 break;
687 while (!isType (token, TOKEN_EOF));
689 else
691 /* Unexpected */
692 readToken (token);
695 TRACE_LEAVE ();
698 static void parseModuleDecl (tokenInfo * const token, int parent)
700 TRACE_ENTER ();
701 while (! (isKeyword (token, KEYWORD_END)
702 || isType (token, TOKEN_EOF)))
704 vhdlKind kind = VHDLTAG_UNDEFINED;
705 if (isKeyword (token, KEYWORD_PORT))
706 kind = VHDLTAG_PORT;
707 else if (isKeyword (token, KEYWORD_GENERIC))
708 kind = VHDLTAG_GENERIC;
710 if (kind != VHDLTAG_UNDEFINED)
712 readToken (token);
713 if (isType (token, TOKEN_OPEN_PAREN))
715 readToken (token);
716 parseDeclElement (token, kind, parent, false);
719 else
720 readToken (token);
722 TRACE_LEAVE ();
725 static void parseModule (tokenInfo * const token, int parent)
727 tokenInfo *const name = newToken ();
728 const vhdlKind kind = isKeyword (token, KEYWORD_ENTITY) ?
729 VHDLTAG_ENTITY : VHDLTAG_COMPONENT;
730 Assert (isKeyword (token, KEYWORD_ENTITY) ||
731 isKeyword (token, KEYWORD_COMPONENT));
732 readToken (name);
733 readToken (token);
734 if (kind == VHDLTAG_COMPONENT || isKeyword (token, KEYWORD_IS))
736 int index = makeVhdlTagWithScope (name, kind, parent);
737 if (isKeyword (token, KEYWORD_IS))
738 readToken (token);
739 parseModuleDecl (token, index);
741 bool ended = isKeyword (token, KEYWORD_END);
742 if (!ended)
743 ended = skipToKeyword (KEYWORD_END);
744 skipToCharacterInInputFile (';');
746 if (ended)
748 tagEntryInfo *e = getEntryInCorkQueue (index);
749 if (e)
750 setTagEndLine (e, getInputLineNumber ());
753 if (kind == VHDLTAG_ENTITY)
754 registerEntry (index);
756 deleteToken (name);
759 static void parseRecord (tokenInfo * const token, int parent)
761 tokenInfo *const name = newToken ();
762 Assert (isKeyword (token, KEYWORD_RECORD));
763 readToken (name);
766 readToken (token); /* should be a colon */
767 skipToCharacterInInputFile (';');
768 makeVhdlTagWithScope (name, VHDLTAG_RECORD, parent);
769 readToken (name);
771 while (!isKeyword (name, KEYWORD_END) && !isType (name, TOKEN_EOF));
772 skipToCharacterInInputFile (';');
774 if (isKeyword (name, KEYWORD_END))
776 tagEntryInfo *e = getEntryInCorkQueue (parent);
777 if (e)
778 setTagEndLine (e, getInputLineNumber ());
781 deleteToken (name);
784 static void parseTypes (tokenInfo * const token, int parent)
786 tokenInfo *const name = newToken ();
787 const vhdlKind kind = isKeyword (token, KEYWORD_TYPE) ?
788 VHDLTAG_TYPE : VHDLTAG_SUBTYPE;
789 Assert (isKeyword (token, KEYWORD_TYPE) ||
790 isKeyword (token, KEYWORD_SUBTYPE));
791 readToken (name);
792 readToken (token);
793 if (isKeyword (token, KEYWORD_IS))
795 readToken (token); /* type */
796 if (isKeyword (token, KEYWORD_RECORD))
798 int index = makeVhdlTagWithScope (name, kind, parent);
799 /*TODO: make tags of the record's names */
800 parseRecord (token, index);
802 else
804 makeVhdlTagWithScope (name, kind, parent);
807 deleteToken (name);
810 static void parseConstant (int parent)
812 vhdlKind parent_kind = VHDLTAG_UNDEFINED;
813 tagEntryInfo *e = getEntryInCorkQueue (parent);
814 if (e)
815 parent_kind = e->kindIndex;
817 vhdlKind kind;
818 switch (parent_kind)
820 case VHDLTAG_FUNCTION:
821 case VHDLTAG_PROCEDURE:
822 kind = VHDLTAG_LOCAL;
823 break;
824 default:
825 kind = VHDLTAG_CONSTANT;
826 break;
829 tokenInfo *const name = newToken ();
830 readToken (name);
831 makeVhdlTagWithScope (name, kind, parent);
832 skipToCharacterInInputFile (';');
833 deleteToken (name);
836 static void parseSubProgram (tokenInfo * const token, int parent)
838 tokenInfo *const name = newToken ();
839 const vhdlKind kind = isKeyword (token, KEYWORD_FUNCTION) ?
840 VHDLTAG_FUNCTION : VHDLTAG_PROCEDURE;
841 const int end_keyword = token->keyword;
842 Assert (isKeyword (token, KEYWORD_FUNCTION) ||
843 isKeyword (token, KEYWORD_PROCEDURE));
844 readToken (name); /* the name of the function or procedure */
845 readToken (token);
846 if (isType (token, TOKEN_OPEN_PAREN))
848 skipToMatched (token);
851 if (kind == VHDLTAG_FUNCTION)
853 if (isKeyword (token, KEYWORD_RETURN))
855 /* Read datatype */
856 readToken (token);
857 while (! isKeyword (token, KEYWORD_IS) &&
858 ! isType (token, TOKEN_SEMICOLON) &&
859 ! isType (token, TOKEN_EOF))
861 readToken (token);
866 if (isType (token, TOKEN_SEMICOLON))
868 makeVhdlTagWithScope (name, VHDLTAG_PROTOTYPE, parent);
870 else if (isKeyword (token, KEYWORD_IS))
872 int index = makeVhdlTagWithScope (name, kind, parent);
873 parseTillEnd (token, index, end_keyword);
875 deleteToken (name);
878 /* architecture behavioral of ent is*/
879 static void parseArchitecture (tokenInfo * const token)
881 tokenInfo *const name = newToken ();
883 readToken (name);
884 if (!isType (name, TOKEN_IDENTIFIER))
886 skipToKeyword (KEYWORD_END);
887 skipToCharacterInInputFile (';');
888 deleteToken (name);
889 return;
892 int index = makeVhdlTag (name, VHDLTAG_ARCHITECTURE);
893 readToken (token);
894 if (isKeyword (token, KEYWORD_OF))
896 readToken (token);
897 if (isType (token, TOKEN_IDENTIFIER))
899 /* Filling scope field of this architecture.
900 If the definition for the entity can be found in the symbol table,
901 use its cork as the scope. If not, use the reference tag for the
902 entity as fallback. */
903 int role_index = makeSimpleRefTag (token->string,
904 VHDLTAG_ENTITY, VHDL_ENTITY_DESIGNED);
905 int entity_index = anyKindEntryInScope (CORK_NIL,
906 vStringValue (token->string),
907 VHDLTAG_ENTITY,
908 false);
909 tagEntryInfo *e = getEntryInCorkQueue (index);
910 if (e)
912 e->extensionFields.scopeIndex = (
913 entity_index == CORK_NIL
914 ? role_index
915 : entity_index);
917 /* TODO: append thes architecture name to
918 * architecture: field of *e*. */
921 attachParserFieldToCorkEntry (role_index,
922 VhdlFields[F_ARCHITECTURE].ftype,
923 vStringValue (name->string));
925 readToken (token);
926 if (isKeyword (token, KEYWORD_IS))
928 parseTillBegin (token, index);
929 parseTillEnd (token, index, KEYWORD_ARCHITECTURE);
933 deleteToken (name);
936 static void parseSignal (tokenInfo * const token, int parent)
938 readToken (token);
939 parseDeclElement (token, VHDLTAG_SIGNAL, parent, true);
942 static void parseLabel (tokenInfo * const name, int parent)
944 tokenInfo *const token = newToken ();
946 readToken (token);
947 if (isType (token, TOKEN_COLON))
949 readToken (token);
950 if (isType (token, TOKEN_KEYWORD))
951 parseKeywords (token, name, parent);
953 deleteToken (token);
956 static void parseProcess (tokenInfo * const token, tokenInfo * const label, int parent)
958 tokenInfo *process = label? label: copyToken (token);
960 if (label == NULL)
962 process->type = TOKEN_IDENTIFIER;
963 vStringClear (process->string);
964 anonGenerate (process->string, "anonProcess", VHDLTAG_PROCESS);
967 int index = makeVhdlTagWithScope (process, VHDLTAG_PROCESS, parent);
969 if (label == NULL)
971 tagEntryInfo *e = getEntryInCorkQueue (index);
972 if (e)
973 markTagExtraBit (e, XTAG_ANONYMOUS);
974 deleteToken (process);
977 skipToMatched (token);
978 parseTillBegin (token, index);
979 parseTillEnd (token, index, KEYWORD_PROCESS);
982 static void parseVariable (tokenInfo * const token, int parent)
984 readToken (token);
985 parseDeclElement (token, VHDLTAG_VARIABLE, parent, true);
988 static void parseAlias (tokenInfo * const token, int parent)
990 readToken (token);
991 parseDeclElement (token, VHDLTAG_ALIAS, parent, true);
994 /* TODO */
995 /* records */
996 static void parseKeywords (tokenInfo * const token, tokenInfo * const label, int index)
998 switch (token->keyword)
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;
1049 static tokenType parseVhdlFile (tokenInfo * const token)
1053 readToken (token);
1054 parseKeywords (token, NULL, CORK_NIL);
1055 } while (!isKeyword (token, KEYWORD_END) && !isType (token, TOKEN_EOF));
1056 return token->type;
1059 static void findVhdlTags (void)
1061 tokenInfo *const token = newToken ();
1063 while (parseVhdlFile (token) != TOKEN_EOF);
1065 deleteToken (token);
1068 extern parserDefinition *VhdlParser (void)
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;