1 /*
2 * $Id: vhdl.c 652 2008-04-18 03:51:47Z elliotth $
3 *
4 * Copyright (c) 2008, Nicolas Vincent
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 VHDL files.
10 */
11
12 /*
13 * INCLUDE FILES
14 */
15 #include "general.h" /* must always come first */
16
17 #include <ctype.h> /* to define isalpha () */
18 #include <string.h>
19 #include <setjmp.h>
20
21 #include "debug.h"
22 #include "entry.h"
23 #include "keyword.h"
24 #include "parse.h"
25 #include "read.h"
26 #include "routines.h"
27 #include "vstring.h"
28
29 /*
30 * MACROS
31 */
32 #define isType(token,t) (boolean) ((token)->type == (t))
33 #define isKeyword(token,k) (boolean) ((token)->keyword == (k))
34
35 /*
36 * DATA DECLARATIONS
37 */
38 typedef enum eException { ExceptionNone, ExceptionEOF } exception_t;
39
40 /*
41 * Used to specify type of keyword.
42 */
43 typedef enum eKeywordId {
44 KEYWORD_NONE = -1,
45 KEYWORD_ABS,
46 KEYWORD_ACCESS,
47 KEYWORD_AFTER,
48 KEYWORD_ALIAS,
49 KEYWORD_ALL,
50 KEYWORD_AND,
51 KEYWORD_ARCHITECTURE,
52 KEYWORD_ARRAY,
53 KEYWORD_ASSERT,
54 KEYWORD_ATTRIBUTE,
55 KEYWORD_BEGIN,
56 KEYWORD_BLOCK,
57 KEYWORD_BODY,
58 KEYWORD_BUFFER,
59 KEYWORD_BUS,
60 KEYWORD_CASE,
61 KEYWORD_COMPONENT,
62 KEYWORD_CONFIGURATION,
63 KEYWORD_CONSTANT,
64 KEYWORD_DISCONNECT,
65 KEYWORD_DOWNTO,
66 KEYWORD_ELSE,
67 KEYWORD_ELSIF,
68 KEYWORD_END,
69 KEYWORD_ENTITY,
70 KEYWORD_EXIT,
71 KEYWORD_FILE,
72 KEYWORD_FOR,
73 KEYWORD_FUNCTION,
74 KEYWORD_GENERATE,
75 KEYWORD_GENERIC,
76 KEYWORD_GROUP,
77 KEYWORD_GUARDED,
78 KEYWORD_IF,
79 KEYWORD_IMPURE,
80 KEYWORD_IN,
81 KEYWORD_INERTIAL,
82 KEYWORD_INOUT,
83 KEYWORD_IS,
84 KEYWORD_LABEL,
85 KEYWORD_LIBRARY,
86 KEYWORD_LINKAGE,
87 KEYWORD_LITERAL,
88 KEYWORD_LOOP,
89 KEYWORD_MAP,
90 KEYWORD_MOD,
91 KEYWORD_NAND,
92 KEYWORD_NEW,
93 KEYWORD_NEXT,
94 KEYWORD_NOR,
95 KEYWORD_NOT,
96 KEYWORD_NULL,
97 KEYWORD_OF,
98 KEYWORD_ON,
99 KEYWORD_OPEN,
100 KEYWORD_OR,
101 KEYWORD_OTHERS,
102 KEYWORD_OUT,
103 KEYWORD_PACKAGE,
104 KEYWORD_PORT,
105 KEYWORD_POSTPONED,
106 KEYWORD_PROCEDURE,
107 KEYWORD_PROCESS,
108 KEYWORD_PURE,
109 KEYWORD_RANGE,
110 KEYWORD_RECORD,
111 KEYWORD_REGISTER,
112 KEYWORD_REJECT,
113 KEYWORD_RETURN,
114 KEYWORD_ROL,
115 KEYWORD_ROR,
116 KEYWORD_SELECT,
117 KEYWORD_SEVERITY,
118 KEYWORD_SIGNAL,
119 KEYWORD_SHARED,
120 KEYWORD_SLA,
121 KEYWORD_SLI,
122 KEYWORD_SRA,
123 KEYWORD_SRL,
124 KEYWORD_SUBTYPE,
125 KEYWORD_THEN,
126 KEYWORD_TO,
127 KEYWORD_TRANSPORT,
128 KEYWORD_TYPE,
129 KEYWORD_UNAFFECTED,
130 KEYWORD_UNITS,
131 KEYWORD_UNTIL,
132 KEYWORD_USE,
133 KEYWORD_VARIABLE,
134 KEYWORD_WAIT,
135 KEYWORD_WHEN,
136 KEYWORD_WHILE,
137 KEYWORD_WITH,
138 KEYWORD_XNOR,
139 KEYWORD_XOR
140 } keywordId;
141
142 /* Used to determine whether keyword is valid for the current language and
143 * what its ID is.
144 */
145 typedef struct sKeywordDesc {
146 const char *name;
147 keywordId id;
148 } keywordDesc;
149
150 typedef enum eTokenType {
151 TOKEN_NONE, /* none */
152 TOKEN_OPEN_PAREN, /* ( */
153 TOKEN_CLOSE_PAREN, /* ) */
154 TOKEN_COMMA, /* the comma character */
155 TOKEN_IDENTIFIER,
156 TOKEN_KEYWORD,
157 TOKEN_PERIOD, /* . */
158 TOKEN_OPERATOR,
159 TOKEN_SEMICOLON, /* the semicolon character */
160 TOKEN_STRING
161 } tokenType;
162
163 typedef struct sTokenInfo {
164 tokenType type;
165 keywordId keyword;
166 vString *string; /* the name of the token */
167 vString *scope;
168 unsigned long lineNumber; /* line number of tag */
169 long filePosition; /* file position of line containing name */
170 } tokenInfo;
171
172 /*
173 * DATA DEFINITIONS
174 */
175 static int Lang_vhdl;
176 static jmp_buf Exception;
177
178 /* Used to index into the VhdlKinds table. */
179 typedef enum {
180 VHDLTAG_UNDEFINED = -1,
181 VHDLTAG_CONSTANT,
182 VHDLTAG_TYPE,
183 VHDLTAG_SUBTYPE,
184 VHDLTAG_RECORD,
185 VHDLTAG_ENTITY,
186 VHDLTAG_COMPONENT,
187 VHDLTAG_PROTOTYPE,
188 VHDLTAG_FUNCTION,
189 VHDLTAG_PROCEDURE,
190 VHDLTAG_PACKAGE,
191 VHDLTAG_LOCAL
192 } vhdlKind;
193
194 static kindOption VhdlKinds[] = {
195 {TRUE, 'c', "constant", "constant declarations"},
196 {TRUE, 't', "type", "type definitions"},
197 {TRUE, 'T', "subtype", "subtype definitions"},
198 {TRUE, 'r', "record", "record names"},
199 {TRUE, 'e', "entity", "entity declarations"},
200 {FALSE, 'C', "component", "component declarations"},
201 {FALSE, 'd', "prototype", "prototypes"},
202 {TRUE, 'f', "function", "function prototypes and declarations"},
203 {TRUE, 'p', "procedure", "procedure prototypes and declarations"},
204 {TRUE, 'P', "package", "package definitions"},
205 {FALSE, 'l', "local", "local definitions"}
206 };
207
208 static keywordDesc VhdlKeywordTable[] = {
209 {"abs", KEYWORD_ABS},
210 {"access", KEYWORD_ACCESS},
211 {"after", KEYWORD_AFTER},
212 {"alias", KEYWORD_ALIAS},
213 {"all", KEYWORD_ALL},
214 {"and", KEYWORD_AND},
215 {"architecture", KEYWORD_ARCHITECTURE},
216 {"array", KEYWORD_ARRAY},
217 {"assert", KEYWORD_ASSERT},
218 {"attribute", KEYWORD_ATTRIBUTE},
219 {"begin", KEYWORD_BEGIN},
220 {"block", KEYWORD_BLOCK},
221 {"body", KEYWORD_BODY},
222 {"buffer", KEYWORD_BUFFER},
223 {"bus", KEYWORD_BUS},
224 {"case", KEYWORD_CASE},
225 {"component", KEYWORD_COMPONENT},
226 {"configuration", KEYWORD_CONFIGURATION},
227 {"constant", KEYWORD_CONSTANT},
228 {"disconnect", KEYWORD_DISCONNECT},
229 {"downto", KEYWORD_DOWNTO},
230 {"else", KEYWORD_ELSE},
231 {"elsif", KEYWORD_ELSIF},
232 {"end", KEYWORD_END},
233 {"entity", KEYWORD_ENTITY},
234 {"exit", KEYWORD_EXIT},
235 {"file", KEYWORD_FILE},
236 {"for", KEYWORD_FOR},
237 {"function", KEYWORD_FUNCTION},
238 {"generate", KEYWORD_GENERATE},
239 {"generic", KEYWORD_GENERIC},
240 {"group", KEYWORD_GROUP},
241 {"guarded", KEYWORD_GUARDED},
242 {"if", KEYWORD_IF},
243 {"impure", KEYWORD_IMPURE},
244 {"in", KEYWORD_IN},
245 {"inertial", KEYWORD_INERTIAL},
246 {"inout", KEYWORD_INOUT},
247 {"is", KEYWORD_IS},
248 {"label", KEYWORD_LABEL},
249 {"library", KEYWORD_LIBRARY},
250 {"linkage", KEYWORD_LINKAGE},
251 {"literal", KEYWORD_LITERAL},
252 {"loop", KEYWORD_LOOP},
253 {"map", KEYWORD_MAP},
254 {"mod", KEYWORD_MOD},
255 {"nand", KEYWORD_NAND},
256 {"new", KEYWORD_NEW},
257 {"next", KEYWORD_NEXT},
258 {"nor", KEYWORD_NOR},
259 {"not", KEYWORD_NOT},
260 {"null", KEYWORD_NULL},
261 {"of", KEYWORD_OF},
262 {"on", KEYWORD_ON},
263 {"open", KEYWORD_OPEN},
264 {"or", KEYWORD_OR},
265 {"others", KEYWORD_OTHERS},
266 {"out", KEYWORD_OUT},
267 {"package", KEYWORD_PACKAGE},
268 {"port", KEYWORD_PORT},
269 {"postponed", KEYWORD_POSTPONED},
270 {"procedure", KEYWORD_PROCEDURE},
271 {"process", KEYWORD_PROCESS},
272 {"pure", KEYWORD_PURE},
273 {"range", KEYWORD_RANGE},
274 {"record", KEYWORD_RECORD},
275 {"register", KEYWORD_REGISTER},
276 {"reject", KEYWORD_REJECT},
277 {"return", KEYWORD_RETURN},
278 {"rol", KEYWORD_ROL},
279 {"ror", KEYWORD_ROR},
280 {"select", KEYWORD_SELECT},
281 {"severity", KEYWORD_SEVERITY},
282 {"signal", KEYWORD_SIGNAL},
283 {"shared", KEYWORD_SHARED},
284 {"sla", KEYWORD_SLA},
285 {"sli", KEYWORD_SLI},
286 {"sra", KEYWORD_SRA},
287 {"srl", KEYWORD_SRL},
288 {"subtype", KEYWORD_SUBTYPE},
289 {"then", KEYWORD_THEN},
290 {"to", KEYWORD_TO},
291 {"transport", KEYWORD_TRANSPORT},
292 {"type", KEYWORD_TYPE},
293 {"unaffected", KEYWORD_UNAFFECTED},
294 {"units", KEYWORD_UNITS},
295 {"until", KEYWORD_UNTIL},
296 {"use", KEYWORD_USE},
297 {"variable", KEYWORD_VARIABLE},
298 {"wait", KEYWORD_WAIT},
299 {"when", KEYWORD_WHEN},
300 {"while", KEYWORD_WHILE},
301 {"with", KEYWORD_WITH},
302 {"xnor", KEYWORD_XNOR},
303 {"xor", KEYWORD_XOR}
304 };
305
306 /*
307 * FUNCTION DECLARATIONS
308 */
309 static void parseKeywords (tokenInfo * const token, boolean local);
310
311 /*
312 * FUNCTION DEFINITIONS
313 */
314
isIdentChar1(const int c)315 static boolean isIdentChar1 (const int c)
316 {
317 return (boolean) (isalpha (c) || c == '_');
318 }
319
isIdentChar(const int c)320 static boolean isIdentChar (const int c)
321 {
322 return (boolean) (isalpha (c) || isdigit (c) || c == '_');
323 }
324
isIdentifierMatch(const tokenInfo * const token,const vString * const name)325 static boolean isIdentifierMatch (const tokenInfo * const token,
326 const vString * const name)
327 {
328 return (boolean) (isType (token, TOKEN_IDENTIFIER) &&
329 strcasecmp (vStringValue (token->string), vStringValue (name)) == 0);
330 /* XXX this is copy/paste from eiffel.c and slightly modified */
331 /* shouldn't we use strNcasecmp ? */
332 }
333
isKeywordOrIdent(const tokenInfo * const token,const keywordId keyword,const vString * const name)334 static boolean isKeywordOrIdent (const tokenInfo * const token,
335 const keywordId keyword, const vString * const name)
336 {
337 return (boolean) (isKeyword (token, keyword) ||
338 isIdentifierMatch (token, name));
339 }
340
newToken(void)341 static tokenInfo *newToken (void)
342 {
343 tokenInfo *const token = xMalloc (1, tokenInfo);
344 token->type = TOKEN_NONE;
345 token->keyword = KEYWORD_NONE;
346 token->string = vStringNew ();
347 token->scope = vStringNew ();
348 token->lineNumber = getSourceLineNumber ();
349 token->filePosition = getInputFilePosition ();
350 return token;
351 }
352
deleteToken(tokenInfo * const token)353 static void deleteToken (tokenInfo * const token)
354 {
355 if (token != NULL)
356 {
357 vStringDelete (token->string);
358 vStringDelete (token->scope);
359 eFree (token);
360 }
361 }
362
363 /*
364 * Parsing functions
365 */
366
parseString(vString * const string,const int delimiter)367 static void parseString (vString * const string, const int delimiter)
368 {
369 boolean end = FALSE;
370 while (!end)
371 {
372 int c = fileGetc ();
373 if (c == EOF)
374 end = TRUE;
375 else if (c == '\\')
376 {
377 c = fileGetc (); /* This maybe a ' or ". */
378 vStringPut (string, c);
379 }
380 else if (c == delimiter)
381 end = TRUE;
382 else
383 vStringPut (string, c);
384 }
385 vStringTerminate (string);
386 }
387
388 /* Read a VHDL identifier beginning with "firstChar" and place it into "name".
389 */
parseIdentifier(vString * const string,const int firstChar)390 static void parseIdentifier (vString * const string, const int firstChar)
391 {
392 int c = firstChar;
393 Assert (isIdentChar1 (c));
394 do
395 {
396 vStringPut (string, c);
397 c = fileGetc ();
398 } while (isIdentChar (c));
399 vStringTerminate (string);
400 if (!isspace (c))
401 fileUngetc (c); /* unget non-identifier character */
402 }
403
readToken(tokenInfo * const token)404 static void readToken (tokenInfo * const token)
405 {
406 int c;
407
408 token->type = TOKEN_NONE;
409 token->keyword = KEYWORD_NONE;
410 vStringClear (token->string);
411
412 getNextChar:
413 do
414 {
415 c = fileGetc ();
416 token->lineNumber = getSourceLineNumber ();
417 token->filePosition = getInputFilePosition ();
418 }
419 while (c == '\t' || c == ' ' || c == '\n');
420
421 switch (c)
422 {
423 case EOF:
424 longjmp (Exception, (int) ExceptionEOF);
425 break;
426 case '(':
427 token->type = TOKEN_OPEN_PAREN;
428 break;
429 case ')':
430 token->type = TOKEN_CLOSE_PAREN;
431 break;
432 case ';':
433 token->type = TOKEN_SEMICOLON;
434 break;
435 case '.':
436 token->type = TOKEN_PERIOD;
437 break;
438 case ',':
439 token->type = TOKEN_COMMA;
440 break;
441 case '\'': /* only single char are inside simple quotes */
442 break; /* or it is for attributes so we don't care */
443 case '"':
444 token->type = TOKEN_STRING;
445 parseString (token->string, c);
446 token->lineNumber = getSourceLineNumber ();
447 token->filePosition = getInputFilePosition ();
448 break;
449 case '-':
450 c = fileGetc ();
451 if (c == '-') /* start of a comment */
452 {
453 fileSkipToCharacter ('\n');
454 goto getNextChar;
455 }
456 else
457 {
458 if (!isspace (c))
459 fileUngetc (c);
460 token->type = TOKEN_OPERATOR;
461 }
462 break;
463 default:
464 if (!isIdentChar1 (c))
465 token->type = TOKEN_NONE;
466 else
467 {
468 parseIdentifier (token->string, c);
469 token->lineNumber = getSourceLineNumber ();
470 token->filePosition = getInputFilePosition ();
471 token->keyword = analyzeToken (token->string, Lang_vhdl);
472 if (isKeyword (token, KEYWORD_NONE))
473 token->type = TOKEN_IDENTIFIER;
474 else
475 token->type = TOKEN_KEYWORD;
476 }
477 break;
478 }
479 }
480
skipToKeyword(const keywordId keyword)481 static void skipToKeyword (const keywordId keyword)
482 {
483 tokenInfo *const token = newToken ();
484 do
485 {
486 readToken (token);
487 }
488 while (!isKeyword (token, keyword));
489 deleteToken (token);
490 }
491
skipToMatched(tokenInfo * const token)492 static void skipToMatched (tokenInfo * const token)
493 {
494 int nest_level = 0;
495 tokenType open_token;
496 tokenType close_token;
497
498 switch (token->type)
499 {
500 case TOKEN_OPEN_PAREN:
501 open_token = TOKEN_OPEN_PAREN;
502 close_token = TOKEN_CLOSE_PAREN;
503 break;
504 default:
505 return;
506 }
507
508 /*
509 * This routine will skip to a matching closing token.
510 * It will also handle nested tokens like the (, ) below.
511 * ( name varchar(30), text binary(10) )
512 */
513 if (isType (token, open_token))
514 {
515 nest_level++;
516 while (!(isType (token, close_token) && (nest_level == 0)))
517 {
518 readToken (token);
519 if (isType (token, open_token))
520 {
521 nest_level++;
522 }
523 if (isType (token, close_token))
524 {
525 if (nest_level > 0)
526 {
527 nest_level--;
528 }
529 }
530 }
531 readToken (token);
532 }
533 }
534
makeConstTag(tokenInfo * const token,const vhdlKind kind)535 static void makeConstTag (tokenInfo * const token, const vhdlKind kind)
536 {
537 if (VhdlKinds[kind].enabled)
538 {
539 const char *const name = vStringValue (token->string);
540 tagEntryInfo e;
541 initTagEntry (&e, name);
542 e.lineNumber = token->lineNumber;
543 e.filePosition = token->filePosition;
544 e.kindName = VhdlKinds[kind].name;
545 e.kind = VhdlKinds[kind].letter;
546 makeTagEntry (&e);
547 }
548 }
549
makeVhdlTag(tokenInfo * const token,const vhdlKind kind)550 static void makeVhdlTag (tokenInfo * const token, const vhdlKind kind)
551 {
552 if (VhdlKinds[kind].enabled)
553 {
554 /*
555 * If a scope has been added to the token, change the token
556 * string to include the scope when making the tag.
557 */
558 if (vStringLength (token->scope) > 0)
559 {
560 vString *fulltag = vStringNew ();
561 vStringCopy (fulltag, token->scope);
562 vStringCatS (fulltag, ".");
563 vStringCatS (fulltag, vStringValue (token->string));
564 vStringTerminate (fulltag);
565 vStringCopy (token->string, fulltag);
566 vStringDelete (fulltag);
567 }
568 makeConstTag (token, kind);
569 }
570 }
571
initialize(const langType language)572 static void initialize (const langType language)
573 {
574 size_t i;
575 const size_t count =
576 sizeof (VhdlKeywordTable) / sizeof (VhdlKeywordTable[0]);
577 Lang_vhdl = language;
578 for (i = 0; i < count; ++i)
579 {
580 const keywordDesc *const p = &VhdlKeywordTable[i];
581 addKeyword (p->name, language, (int) p->id);
582 }
583 }
584
parsePackage(tokenInfo * const token)585 static void parsePackage (tokenInfo * const token)
586 {
587 tokenInfo *const name = newToken ();
588 Assert (isKeyword (token, KEYWORD_PACKAGE));
589 readToken (token);
590 if (isKeyword (token, KEYWORD_BODY))
591 {
592 readToken (name);
593 makeVhdlTag (name, VHDLTAG_PACKAGE);
594 }
595 else if (isType (token, TOKEN_IDENTIFIER))
596 {
597 makeVhdlTag (token, VHDLTAG_PACKAGE);
598 }
599 deleteToken (name);
600 }
601
parseModule(tokenInfo * const token)602 static void parseModule (tokenInfo * const token)
603 {
604 tokenInfo *const name = newToken ();
605 const vhdlKind kind = isKeyword (token, KEYWORD_ENTITY) ?
606 VHDLTAG_ENTITY : VHDLTAG_COMPONENT;
607 Assert (isKeyword (token, KEYWORD_ENTITY) ||
608 isKeyword (token, KEYWORD_COMPONENT));
609 readToken (name);
610 if (kind == VHDLTAG_COMPONENT)
611 {
612 makeVhdlTag (name, VHDLTAG_COMPONENT);
613 skipToKeyword (KEYWORD_END);
614 fileSkipToCharacter (';');
615 }
616 else
617 {
618 readToken (token);
619 if (isKeyword (token, KEYWORD_IS))
620 {
621 makeVhdlTag (name, VHDLTAG_ENTITY);
622 skipToKeyword (KEYWORD_END);
623 fileSkipToCharacter (';');
624 }
625 }
626 deleteToken (name);
627 }
628
parseRecord(tokenInfo * const token)629 static void parseRecord (tokenInfo * const token)
630 {
631 tokenInfo *const name = newToken ();
632 Assert (isKeyword (token, KEYWORD_RECORD));
633 readToken (name);
634 do
635 {
636 readToken (token); /* should be a colon */
637 fileSkipToCharacter (';');
638 makeVhdlTag (name, VHDLTAG_RECORD);
639 readToken (name);
640 }
641 while (!isKeyword (name, KEYWORD_END));
642 fileSkipToCharacter (';');
643 deleteToken (name);
644 }
645
parseTypes(tokenInfo * const token)646 static void parseTypes (tokenInfo * const token)
647 {
648 tokenInfo *const name = newToken ();
649 const vhdlKind kind = isKeyword (token, KEYWORD_TYPE) ?
650 VHDLTAG_TYPE : VHDLTAG_SUBTYPE;
651 Assert (isKeyword (token, KEYWORD_TYPE) ||
652 isKeyword (token, KEYWORD_SUBTYPE));
653 readToken (name);
654 readToken (token);
655 if (isKeyword (token, KEYWORD_IS))
656 {
657 readToken (token); /* type */
658 if (isKeyword (token, KEYWORD_RECORD))
659 {
660 makeVhdlTag (name, kind);
661 /*TODO: make tags of the record's names */
662 parseRecord (token);
663 }
664 else
665 {
666 makeVhdlTag (name, kind);
667 }
668 }
669 deleteToken (name);
670 }
671
parseConstant(boolean local)672 static void parseConstant (boolean local)
673 {
674 tokenInfo *const name = newToken ();
675 readToken (name);
676 if (local)
677 {
678 makeVhdlTag (name, VHDLTAG_LOCAL);
679 }
680 else
681 {
682 makeVhdlTag (name, VHDLTAG_CONSTANT);
683 }
684 fileSkipToCharacter (';');
685 deleteToken (name);
686 }
687
parseSubProgram(tokenInfo * const token)688 static void parseSubProgram (tokenInfo * const token)
689 {
690 tokenInfo *const name = newToken ();
691 boolean endSubProgram = FALSE;
692 const vhdlKind kind = isKeyword (token, KEYWORD_FUNCTION) ?
693 VHDLTAG_FUNCTION : VHDLTAG_PROCEDURE;
694 Assert (isKeyword (token, KEYWORD_FUNCTION) ||
695 isKeyword (token, KEYWORD_PROCEDURE));
696 readToken (name); /* the name of the function or procedure */
697 readToken (token);
698 if (isType (token, TOKEN_OPEN_PAREN))
699 {
700 skipToMatched (token);
701 }
702
703 if (kind == VHDLTAG_FUNCTION)
704 {
705 if (isKeyword (token, KEYWORD_RETURN))
706 {
707 /* Read datatype */
708 readToken (token);
709 while (! isKeyword (token, KEYWORD_IS) &&
710 ! isType (token, TOKEN_SEMICOLON))
711 {
712 readToken (token);
713 }
714 }
715 }
716
717 if (isType (token, TOKEN_SEMICOLON))
718 {
719 makeVhdlTag (name, VHDLTAG_PROTOTYPE);
720 }
721 else if (isKeyword (token, KEYWORD_IS))
722 {
723 if (kind == VHDLTAG_FUNCTION)
724 {
725 makeVhdlTag (name, VHDLTAG_FUNCTION);
726 do
727 {
728 readToken (token);
729 if (isKeyword (token, KEYWORD_END))
730 {
731 readToken (token);
732 endSubProgram = isKeywordOrIdent (token,
733 KEYWORD_FUNCTION, name->string);
734 fileSkipToCharacter (';');
735 }
736 else
737 {
738 parseKeywords (token, TRUE);
739 }
740 } while (!endSubProgram);
741 }
742 else
743 {
744 makeVhdlTag (name, VHDLTAG_PROCEDURE);
745 do
746 {
747 readToken (token);
748 if (isKeyword (token, KEYWORD_END))
749 {
750 readToken (token);
751 endSubProgram = isKeywordOrIdent (token,
752 KEYWORD_PROCEDURE, name->string);
753 fileSkipToCharacter (';');
754 }
755 else
756 {
757 parseKeywords (token, TRUE);
758 }
759 } while (!endSubProgram);
760 }
761 }
762 deleteToken (name);
763 }
764
765 /* TODO */
766 /* records */
parseKeywords(tokenInfo * const token,boolean local)767 static void parseKeywords (tokenInfo * const token, boolean local)
768 {
769 switch (token->keyword)
770 {
771 case KEYWORD_END:
772 fileSkipToCharacter (';');
773 break;
774 case KEYWORD_CONSTANT:
775 parseConstant (local);
776 break;
777 case KEYWORD_TYPE:
778 parseTypes (token);
779 break;
780 case KEYWORD_SUBTYPE:
781 parseTypes (token);
782 break;
783 case KEYWORD_ENTITY:
784 parseModule (token);
785 break;
786 case KEYWORD_COMPONENT:
787 parseModule (token);
788 break;
789 case KEYWORD_FUNCTION:
790 parseSubProgram (token);
791 break;
792 case KEYWORD_PROCEDURE:
793 parseSubProgram (token);
794 break;
795 case KEYWORD_PACKAGE:
796 parsePackage (token);
797 break;
798 default:
799 break;
800 }
801 }
802
parseVhdlFile(tokenInfo * const token)803 static void parseVhdlFile (tokenInfo * const token)
804 {
805 do
806 {
807 readToken (token);
808 parseKeywords (token, FALSE);
809 } while (!isKeyword (token, KEYWORD_END));
810 }
811
findVhdlTags(void)812 static void findVhdlTags (void)
813 {
814 tokenInfo *const token = newToken ();
815 exception_t exception = (exception_t) (setjmp (Exception));
816
817 while (exception == ExceptionNone)
818 parseVhdlFile (token);
819
820 deleteToken (token);
821 }
822
VhdlParser(void)823 extern parserDefinition *VhdlParser (void)
824 {
825 static const char *const extensions[] = { "vhdl", "vhd", NULL };
826 parserDefinition *def = parserNew ("VHDL");
827 def->kinds = VhdlKinds;
828 def->kindCount = KIND_COUNT (VhdlKinds);
829 def->extensions = extensions;
830 def->parser = findVhdlTags;
831 def->initialize = initialize;
832 return def;
833 }
834
835 /* vi:set tabstop=4 shiftwidth=4 noet: */
836