1 /*
2 * Copyright (c) 1996-2003, Darren Hiebert
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 parsing and scanning Vera
8 * source files.
9 */
10
11 /*
12 * INCLUDE FILES
13 */
14 #include "general.h" /* must always come first */
15
16 #include <string.h>
17 #include <setjmp.h>
18
19 #include "debug.h"
20 #include "entry.h"
21 #include "cpreprocessor.h"
22 #include "keyword.h"
23 #include "options.h"
24 #include "parse.h"
25 #include "read.h"
26 #include "routines.h"
27 #include "selectors.h"
28 #include "xtag.h"
29
30 /*
31 * MACROS
32 */
33
34 #define activeToken(st) ((st)->token [(int) (st)->tokenIndex])
35 #define parentDecl(st) ((st)->parent == NULL ? \
36 DECL_NONE : (st)->parent->declaration)
37 #define isType(token,t) (bool) ((token)->type == (t))
38 #define insideEnumBody(st) ((st)->parent == NULL ? false : \
39 (bool) ((st)->parent->declaration == DECL_ENUM))
40 #define insideInterfaceBody(st) ((st)->parent == NULL ? false : \
41 (bool) ((st)->parent->declaration == DECL_INTERFACE))
42 #define isSignalDirection(token) (bool)(( (token)->keyword == KEYWORD_INPUT ) ||\
43 ( (token)->keyword == KEYWORD_OUTPUT ) ||\
44 ( (token)->keyword == KEYWORD_INOUT ) )
45
46 #define isOneOf(c,s) (bool) (strchr ((s), (c)) != NULL)
47
48
49 /*
50 * DATA DECLARATIONS
51 */
52
53 enum { NumTokens = 3 };
54
55 typedef enum eException {
56 ExceptionNone, ExceptionEOF, ExceptionFormattingError,
57 ExceptionBraceFormattingError
58 } exception_t;
59
60 /* Used to specify type of keyword.
61 */
62 enum eKeywordId {
63 KEYWORD_BAD_STATE, KEYWORD_BAD_TRANS,
64 KEYWORD_BIND, KEYWORD_BIND_VAR, KEYWORD_BIT,
65 KEYWORD_CLASS, KEYWORD_CLOCK,
66 KEYWORD_CONSTRAINT, KEYWORD_COVERAGE_BLOCK, KEYWORD_COVERAGE_DEF,
67 KEYWORD_ENUM, KEYWORD_EXTERN,
68 KEYWORD_EXTENDS, KEYWORD_EVENT,
69 KEYWORD_FUNCTION,
70 KEYWORD_HDL_NODE,
71 KEYWORD_INOUT, KEYWORD_INPUT, KEYWORD_INTEGER, KEYWORD_INTERFACE,
72 KEYWORD_LOCAL,
73 KEYWORD_M_BAD_STATE, KEYWORD_M_BAD_TRANS, KEYWORD_M_STATE, KEYWORD_M_TRANS,
74 KEYWORD_NEWCOV,
75 KEYWORD_NHOLD, KEYWORD_NSAMPLE,
76 KEYWORD_OUTPUT,
77 KEYWORD_PACKED, KEYWORD_PORT, KEYWORD_PHOLD,
78 KEYWORD_PROGRAM, KEYWORD_PROTECTED, KEYWORD_PSAMPLE, KEYWORD_PUBLIC,
79 KEYWORD_SHADOW, KEYWORD_STATE,
80 KEYWORD_STATIC, KEYWORD_STRING,
81 KEYWORD_TASK,
82 KEYWORD_TRANS, KEYWORD_TRANSITION,
83 KEYWORD_TYPEDEF,
84 KEYWORD_VIRTUAL, KEYWORD_VOID
85 };
86 typedef int keywordId; /* to allow KEYWORD_NONE */
87
88 /* Used to determine whether keyword is valid for the current language and
89 * what its ID is.
90 */
91 typedef struct sKeywordDesc {
92 const char *name;
93 keywordId id;
94 } keywordDesc;
95
96 /* Used for reporting the type of object parsed by nextToken ().
97 */
98 typedef enum eTokenType {
99 TOKEN_NONE, /* none */
100 TOKEN_ARGS, /* a parenthetical pair and its contents */
101 TOKEN_BRACE_CLOSE,
102 TOKEN_BRACE_OPEN,
103 TOKEN_COLON, /* the colon character */
104 TOKEN_COMMA, /* the comma character */
105 TOKEN_DOUBLE_COLON, /* double colon indicates nested-name-specifier */
106 TOKEN_KEYWORD,
107 TOKEN_NAME, /* an unknown name */
108 TOKEN_PAREN_NAME, /* a single name in parentheses */
109 TOKEN_SEMICOLON, /* the semicolon character */
110 TOKEN_COUNT
111 } tokenType;
112
113 /* This describes the scoping of the current statement.
114 */
115 typedef enum eTagScope {
116 SCOPE_GLOBAL, /* no storage class specified */
117 SCOPE_STATIC, /* static storage class */
118 SCOPE_EXTERN, /* external storage class */
119 SCOPE_TYPEDEF, /* scoping depends upon context */
120 SCOPE_COUNT
121 } tagScope;
122
123 typedef enum eDeclaration {
124 DECL_NONE,
125 DECL_BASE, /* base type (default) */
126 DECL_CLASS,
127 DECL_ENUM,
128 DECL_EVENT,
129 DECL_FUNCTION,
130 DECL_INTERFACE,
131 DECL_PROGRAM,
132 DECL_TASK,
133 DECL_COUNT
134 } declType;
135
136 typedef enum eVisibilityType {
137 ACCESS_UNDEFINED,
138 ACCESS_LOCAL,
139 ACCESS_PRIVATE,
140 ACCESS_PROTECTED,
141 ACCESS_PUBLIC,
142 ACCESS_COUNT
143 } accessType;
144
145 /* Information about the parent class of a member (if any).
146 */
147 typedef struct sMemberInfo {
148 accessType access; /* access of current statement */
149 accessType accessDefault; /* access default for current statement */
150 } memberInfo;
151
152 typedef struct sTokenInfo {
153 tokenType type;
154 keywordId keyword;
155 vString* name; /* the name of the token */
156 unsigned long lineNumber; /* line number of tag */
157 MIOPos filePosition; /* file position of line containing name */
158 } tokenInfo;
159
160 typedef enum eImplementation {
161 IMP_DEFAULT,
162 IMP_VIRTUAL,
163 IMP_PURE_VIRTUAL,
164 IMP_COUNT
165 } impType;
166
167 /* Describes the statement currently undergoing analysis.
168 */
169 typedef struct sStatementInfo {
170 tagScope scope;
171 declType declaration; /* specifier associated with TOKEN_SPEC */
172 bool gotName; /* was a name parsed yet? */
173 bool haveQualifyingName; /* do we have a name we are considering? */
174 bool gotParenName; /* was a name inside parentheses parsed yet? */
175 bool gotArgs; /* was a list of parameters parsed yet? */
176 bool isPointer; /* is 'name' a pointer? */
177 bool inFunction; /* are we inside of a function? */
178 bool assignment; /* have we handled an '='? */
179 bool notVariable; /* has a variable declaration been disqualified ? */
180 impType implementation; /* abstract or concrete implementation? */
181 unsigned int tokenIndex; /* currently active token */
182 tokenInfo* token [(int) NumTokens];
183 tokenInfo* context; /* accumulated scope of current statement */
184 tokenInfo* blockName; /* name of current block */
185 memberInfo member; /* information regarding parent class/struct */
186 vString* parentClasses; /* parent classes */
187 struct sStatementInfo *parent; /* statement we are nested within */
188 } statementInfo;
189
190 /* Describes the type of tag being generated.
191 */
192 typedef enum eTagType {
193 TAG_UNDEFINED,
194 TAG_CLASS, /* class name */
195 TAG_ENUM, /* enumeration name */
196 TAG_ENUMERATOR, /* enumerator (enumeration value) */
197 TAG_EVENT, /* event */
198 TAG_FUNCTION, /* function definition */
199 TAG_INTERFACE, /* interface declaration */
200 TAG_LOCAL, /* local variable definition */
201 TAG_MEMBER, /* structure, class or interface member */
202 TAG_PROGRAM, /* program name */
203 TAG_PROTOTYPE, /* function prototype or declaration */
204 TAG_SIGNAL, /* signal name */
205 TAG_TASK, /* task name */
206 TAG_TYPEDEF, /* typedef name / D alias name */
207 TAG_VARIABLE, /* variable definition */
208 TAG_EXTERN_VAR, /* external variable declaration */
209 TAG_LABEL, /* goto label */
210 TAG_COUNT /* must be last */
211 } tagType;
212
213 typedef struct sParenInfo {
214 bool isPointer;
215 bool isParamList;
216 bool isNameCandidate;
217 bool invalidContents;
218 bool nestedArgs;
219 unsigned int parameterCount;
220 } parenInfo;
221
222 /*
223 * DATA DEFINITIONS
224 */
225
226 static jmp_buf Exception;
227
228 static langType Lang_vera;
229 static vString *Signature;
230 static bool CollectingSignature;
231
232 /* Number used to uniquely identify anonymous structs and unions. */
233 static int AnonymousID = 0;
234
235 #define COMMONK_UNDEFINED -1
236
237
238 /* Used to index into the VeraKinds table. */
239 typedef enum {
240 VR_MACRO_UNDEF,
241 VR_MACRO_CONDITION,
242 } veraMacroRole;
243
244 static roleDefinition VeraMacroRoles [] = {
245 RoleTemplateUndef,
246 RoleTemplateCondition,
247 };
248
249
250 typedef enum {
251 VR_HEADER_SYSTEM,
252 VR_HEADER_LOCAL,
253 } veraHeaderRole;
254
255 static roleDefinition VeraHeaderRoles [] = {
256 RoleTemplateSystem,
257 RoleTemplateLocal,
258 };
259
260 typedef enum {
261 VK_UNDEFINED = COMMONK_UNDEFINED,
262 VK_CLASS, VK_DEFINE, VK_ENUMERATOR, VK_FUNCTION,
263 VK_ENUMERATION, VK_INTERFACE, VK_LOCAL, VK_MEMBER, VK_PROGRAM, VK_PROTOTYPE,
264 VK_SIGNAL, VK_TASK, VK_TYPEDEF, VK_VARIABLE,
265 VK_EXTERN_VARIABLE, VK_HEADER, VK_MACRO_PARAM,
266 } veraKind;
267
268 static kindDefinition VeraKinds [] = {
269 { true, 'c', "class", "classes"},
270 { true, 'd', "macro", "macro definitions",
271 .referenceOnly = false, ATTACH_ROLES(VeraMacroRoles)},
272 { true, 'e', "enumerator", "enumerators (values inside an enumeration)"},
273 { true, 'f', "function", "function definitions"},
274 { true, 'g', "enum", "enumeration names"},
275 { true, 'i', "interface", "interfaces"},
276 { false, 'l', "local", "local variables"},
277 { true, 'm', "member", "class, struct, and union members"},
278 { true, 'p', "program", "programs"},
279 { false, 'P', "prototype", "function prototypes"},
280 { true, 's', "signal", "signals"},
281 { true, 't', "task", "tasks"},
282 { true, 'T', "typedef", "typedefs"},
283 { true, 'v', "variable", "variable definitions"},
284 { false, 'x', "externvar", "external variable declarations"},
285 { true, 'h', "header", "included header files",
286 .referenceOnly = true, ATTACH_ROLES(VeraHeaderRoles)},
287 { false, 'D', "macroParameter", "cpp macro parameters"},
288 };
289
290 static const keywordDesc KeywordTable [] = {
291 { "bad_state", KEYWORD_BAD_STATE, },
292 { "bad_trans", KEYWORD_BAD_TRANS, },
293 { "bind", KEYWORD_BIND, },
294 { "bind_var", KEYWORD_BIND_VAR, },
295 { "bit", KEYWORD_BIT, },
296 { "class", KEYWORD_CLASS, },
297 { "CLOCK", KEYWORD_CLOCK, },
298 { "constraint", KEYWORD_CONSTRAINT, },
299 { "coverage_block", KEYWORD_COVERAGE_BLOCK, },
300 { "coverage_def", KEYWORD_COVERAGE_DEF, },
301 { "enum", KEYWORD_ENUM, },
302 { "event", KEYWORD_EVENT, },
303 { "extends", KEYWORD_EXTENDS, },
304 { "extern", KEYWORD_EXTERN, },
305 { "function", KEYWORD_FUNCTION, },
306 { "hdl_node", KEYWORD_HDL_NODE, },
307 { "inout", KEYWORD_INOUT, },
308 { "input", KEYWORD_INPUT, },
309 { "integer", KEYWORD_INTEGER, },
310 { "interface", KEYWORD_INTERFACE, },
311 { "local", KEYWORD_LOCAL, },
312 { "m_bad_state", KEYWORD_M_BAD_STATE, },
313 { "m_bad_trans", KEYWORD_M_BAD_TRANS, },
314 { "m_state", KEYWORD_M_STATE, },
315 { "m_trans", KEYWORD_M_TRANS, },
316 { "newcov", KEYWORD_NEWCOV, },
317 { "NHOLD", KEYWORD_NHOLD, },
318 { "NSAMPLE", KEYWORD_NSAMPLE, },
319 { "output", KEYWORD_OUTPUT, },
320 { "packed", KEYWORD_PACKED, },
321 { "PHOLD", KEYWORD_PHOLD, },
322 { "port", KEYWORD_PORT, },
323 { "program", KEYWORD_PROGRAM, },
324 { "protected", KEYWORD_PROTECTED, },
325 { "PSAMPLE", KEYWORD_PSAMPLE, },
326 { "public", KEYWORD_PUBLIC, },
327 { "shadow", KEYWORD_SHADOW, },
328 { "state", KEYWORD_STATE, },
329 { "static", KEYWORD_STATIC, },
330 { "string", KEYWORD_STRING, },
331 { "task", KEYWORD_TASK, },
332 { "trans", KEYWORD_TRANS, },
333 { "transition", KEYWORD_TRANSITION, },
334 { "typedef", KEYWORD_TYPEDEF, },
335 { "virtual", KEYWORD_VIRTUAL, },
336 { "void", KEYWORD_VOID, },
337 };
338
339 /*
340 * FUNCTION PROTOTYPES
341 */
342 static void createTags (const unsigned int nestLevel, statementInfo *const parent);
343
344 /*
345 * FUNCTION DEFINITIONS
346 */
347
348 /*
349 * Token management
350 */
351
initToken(tokenInfo * const token)352 static void initToken (tokenInfo* const token)
353 {
354 token->type = TOKEN_NONE;
355 token->keyword = KEYWORD_NONE;
356 token->lineNumber = getInputLineNumber ();
357 token->filePosition = getInputFilePosition ();
358 vStringClear (token->name);
359 }
360
advanceToken(statementInfo * const st)361 static void advanceToken (statementInfo* const st)
362 {
363 if (st->tokenIndex >= (unsigned int) NumTokens - 1)
364 st->tokenIndex = 0;
365 else
366 ++st->tokenIndex;
367 initToken (st->token [st->tokenIndex]);
368 }
369
prevToken(const statementInfo * const st,unsigned int n)370 static tokenInfo *prevToken (const statementInfo *const st, unsigned int n)
371 {
372 unsigned int tokenIndex;
373 unsigned int num = (unsigned int) NumTokens;
374 Assert (n < num);
375 tokenIndex = (st->tokenIndex + num - n) % num;
376 return st->token [tokenIndex];
377 }
378
setToken(statementInfo * const st,const tokenType type)379 static void setToken (statementInfo *const st, const tokenType type)
380 {
381 tokenInfo *token;
382 token = activeToken (st);
383 initToken (token);
384 token->type = type;
385 }
386
retardToken(statementInfo * const st)387 static void retardToken (statementInfo *const st)
388 {
389 if (st->tokenIndex == 0)
390 st->tokenIndex = (unsigned int) NumTokens - 1;
391 else
392 --st->tokenIndex;
393 setToken (st, TOKEN_NONE);
394 }
395
newToken(void)396 static tokenInfo *newToken (void)
397 {
398 tokenInfo *const token = xMalloc (1, tokenInfo);
399 token->name = vStringNew ();
400 initToken (token);
401 return token;
402 }
403
deleteToken(tokenInfo * const token)404 static void deleteToken (tokenInfo *const token)
405 {
406 if (token != NULL)
407 {
408 vStringDelete (token->name);
409 eFree (token);
410 }
411 }
412
accessString(const accessType access)413 static const char *accessString (const accessType access)
414 {
415 static const char *const names [] = {
416 "?", "local", "private", "protected", "public"
417 };
418 Assert (ARRAY_SIZE (names) == ACCESS_COUNT);
419 Assert ((int) access < ACCESS_COUNT);
420 return names [(int) access];
421 }
422
423 /*
424 * Debugging functions
425 */
426
427 #ifdef DEBUG
428
429 #define boolString(c) ((c) ? "true" : "false")
430
tokenString(const tokenType type)431 static const char *tokenString (const tokenType type)
432 {
433 static const char *const names [] = {
434 "none", "args", "}", "{", "colon", "comma", "double colon", "keyword",
435 "name", "paren-name", "semicolon"
436 };
437 Assert (ARRAY_SIZE (names) == TOKEN_COUNT);
438 Assert ((int) type < TOKEN_COUNT);
439 return names [(int) type];
440 }
441
scopeString(const tagScope scope)442 static const char *scopeString (const tagScope scope)
443 {
444 static const char *const names [] = {
445 "global", "static", "extern", "typedef"
446 };
447 Assert (ARRAY_SIZE (names) == SCOPE_COUNT);
448 Assert ((int) scope < SCOPE_COUNT);
449 return names [(int) scope];
450 }
451
declString(const declType declaration)452 static const char *declString (const declType declaration)
453 {
454 static const char *const names [] = {
455 "?", "base", "class", "enum", "event", "function",
456 "interface",
457 "program", "task"
458 };
459 Assert (ARRAY_SIZE (names) == DECL_COUNT);
460 Assert ((int) declaration < DECL_COUNT);
461 return names [(int) declaration];
462 }
463
keywordString(const keywordId keyword)464 static const char *keywordString (const keywordId keyword)
465 {
466 const size_t count = ARRAY_SIZE (KeywordTable);
467 const char *name = "none";
468 size_t i;
469 for (i = 0 ; i < count ; ++i)
470 {
471 const keywordDesc *p = &KeywordTable [i];
472 if (p->id == keyword)
473 {
474 name = p->name;
475 break;
476 }
477 }
478 return name;
479 }
480
pt(tokenInfo * const token)481 static void CTAGS_ATTR_UNUSED pt (tokenInfo *const token)
482 {
483 if (isType (token, TOKEN_NAME))
484 printf ("type: %-12s: %-13s line: %lu\n",
485 tokenString (token->type), vStringValue (token->name),
486 token->lineNumber);
487 else if (isType (token, TOKEN_KEYWORD))
488 printf ("type: %-12s: %-13s line: %lu\n",
489 tokenString (token->type), keywordString (token->keyword),
490 token->lineNumber);
491 else
492 printf ("type: %-12s line: %lu\n",
493 tokenString (token->type), token->lineNumber);
494 }
495
ps(statementInfo * const st)496 static void CTAGS_ATTR_UNUSED ps (statementInfo *const st)
497 {
498 #define P "[%-7u]"
499 static unsigned int id = 0;
500 unsigned int i;
501 printf (P"scope: %s decl: %s gotName: %s gotParenName: %s\n", id,
502 scopeString (st->scope), declString (st->declaration),
503 boolString (st->gotName), boolString (st->gotParenName));
504 printf (P"haveQualifyingName: %s\n", id, boolString (st->haveQualifyingName));
505 printf (P"access: %s default: %s\n", id, accessString (st->member.access),
506 accessString (st->member.accessDefault));
507 printf (P"token : ", id);
508 pt (activeToken (st));
509 for (i = 1 ; i < (unsigned int) NumTokens ; ++i)
510 {
511 printf (P"prev %u : ", id, i);
512 pt (prevToken (st, i));
513 }
514 printf (P"context: ", id);
515 pt (st->context);
516 id++;
517 #undef P
518 }
519
520 #endif
521
522 /*
523 * Statement management
524 */
525
isContextualKeyword(const tokenInfo * const token)526 static bool isContextualKeyword (const tokenInfo *const token)
527 {
528 bool result;
529 switch (token->keyword)
530 {
531 case KEYWORD_CLASS:
532 case KEYWORD_ENUM:
533 case KEYWORD_INTERFACE:
534 result = true;
535 break;
536
537 default: result = false; break;
538 }
539 return result;
540 }
541
isContextualStatement(const statementInfo * const st)542 static bool isContextualStatement (const statementInfo *const st)
543 {
544 bool result = false;
545 if (st != NULL) switch (st->declaration)
546 {
547 case DECL_CLASS:
548 case DECL_ENUM:
549 case DECL_INTERFACE:
550 result = true;
551 break;
552
553 default: result = false; break;
554 }
555 return result;
556 }
557
isMember(const statementInfo * const st)558 static bool isMember (const statementInfo *const st)
559 {
560 bool result;
561 if (isType (st->context, TOKEN_NAME))
562 result = true;
563 else
564 result = (bool)
565 (st->parent != NULL && isContextualStatement (st->parent));
566 return result;
567 }
568
initMemberInfo(statementInfo * const st)569 static void initMemberInfo (statementInfo *const st)
570 {
571 accessType accessDefault = ACCESS_UNDEFINED;
572 if (st->parent != NULL) switch (st->parent->declaration)
573 {
574 case DECL_ENUM:
575 accessDefault = ACCESS_UNDEFINED;
576 break;
577
578 case DECL_CLASS:
579 accessDefault = ACCESS_PRIVATE;
580 break;
581
582 case DECL_INTERFACE:
583 accessDefault = ACCESS_PUBLIC;
584 break;
585
586 default: break;
587 }
588 st->member.accessDefault = accessDefault;
589 st->member.access = accessDefault;
590 }
591
reinitStatement(statementInfo * const st,const bool partial)592 static void reinitStatement (statementInfo *const st, const bool partial)
593 {
594 unsigned int i;
595
596 if (! partial)
597 {
598 st->scope = SCOPE_GLOBAL;
599 if (isContextualStatement (st->parent))
600 st->declaration = DECL_BASE;
601 else
602 st->declaration = DECL_NONE;
603 }
604 st->gotParenName = false;
605 st->isPointer = false;
606 st->inFunction = false;
607 st->assignment = false;
608 st->notVariable = false;
609 st->implementation = IMP_DEFAULT;
610 st->gotArgs = false;
611 st->gotName = false;
612 st->haveQualifyingName = false;
613 st->tokenIndex = 0;
614
615 if (st->parent != NULL)
616 st->inFunction = st->parent->inFunction;
617
618 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
619 initToken (st->token [i]);
620
621 initToken (st->context);
622
623 /* Keep the block name, so that a variable following after a comma will
624 * still have the structure name.
625 */
626 if (! partial)
627 initToken (st->blockName);
628
629 vStringClear (st->parentClasses);
630
631 /* Init member info.
632 */
633 if (! partial)
634 st->member.access = st->member.accessDefault;
635 }
636
initStatement(statementInfo * const st,statementInfo * const parent)637 static void initStatement (statementInfo *const st, statementInfo *const parent)
638 {
639 st->parent = parent;
640 initMemberInfo (st);
641 reinitStatement (st, false);
642 }
643
644 /*
645 * Tag generation functions
646 */
647 #define veraTagKind(type) veraTagKindFull(type, true)
648 #define veraTagKindNoAssert(type) veraTagKindFull(type, false)
veraTagKindFull(const tagType type,bool with_assert)649 static veraKind veraTagKindFull (const tagType type, bool with_assert) {
650 veraKind result = VK_UNDEFINED;
651 switch (type)
652 {
653 case TAG_CLASS: result = VK_CLASS; break;
654 case TAG_ENUM: result = VK_ENUMERATION; break;
655 case TAG_ENUMERATOR: result = VK_ENUMERATOR; break;
656 case TAG_FUNCTION: result = VK_FUNCTION; break;
657 case TAG_INTERFACE: result = VK_INTERFACE; break;
658 case TAG_LOCAL: result = VK_LOCAL; break;
659 case TAG_MEMBER: result = VK_MEMBER; break;
660 case TAG_PROGRAM: result = VK_PROGRAM; break;
661 case TAG_PROTOTYPE: result = VK_PROTOTYPE; break;
662 case TAG_SIGNAL: result = VK_SIGNAL; break;
663 case TAG_TASK: result = VK_TASK; break;
664 case TAG_TYPEDEF: result = VK_TYPEDEF; break;
665 case TAG_VARIABLE: result = VK_VARIABLE; break;
666 case TAG_EXTERN_VAR: result = VK_EXTERN_VARIABLE; break;
667
668 default: if (with_assert) Assert ("Bad Vera tag type" == NULL); break;
669 }
670 return result;
671 }
672
kindIndexForType(const tagType type)673 static int kindIndexForType (const tagType type)
674 {
675 return veraTagKind (type);
676 }
677
tagName(const tagType type)678 static const char *tagName (const tagType type)
679 {
680 return VeraKinds [veraTagKind (type)].name;
681 }
682
includeTag(const tagType type,const bool isFileScope)683 static bool includeTag (const tagType type, const bool isFileScope)
684 {
685 bool result;
686 int k = COMMONK_UNDEFINED;
687
688 if (isFileScope && !isXtagEnabled(XTAG_FILE_SCOPE))
689 return false;
690
691 k = veraTagKindNoAssert (type);
692 if (k == COMMONK_UNDEFINED)
693 result = false;
694 else
695 result = isInputLanguageKindEnabled (k);
696
697 return result;
698 }
699
declToTagType(const declType declaration)700 static tagType declToTagType (const declType declaration)
701 {
702 tagType type = TAG_UNDEFINED;
703
704 switch (declaration)
705 {
706 case DECL_CLASS: type = TAG_CLASS; break;
707 case DECL_ENUM: type = TAG_ENUM; break;
708 case DECL_EVENT: type = TAG_EVENT; break;
709 case DECL_FUNCTION: type = TAG_FUNCTION; break;
710 case DECL_INTERFACE: type = TAG_INTERFACE; break;
711 case DECL_PROGRAM: type = TAG_PROGRAM; break;
712 case DECL_TASK: type = TAG_TASK; break;
713
714 default: Assert ("Unexpected declaration" == NULL); break;
715 }
716 return type;
717 }
718
accessField(const statementInfo * const st)719 static const char* accessField (const statementInfo *const st)
720 {
721 const char* result = NULL;
722 if (st->member.access != ACCESS_UNDEFINED)
723 result = accessString (st->member.access);
724 return result;
725 }
726
addOtherFields(tagEntryInfo * const tag,const tagType type,const statementInfo * const st,vString * const scope,vString * const typeRef)727 static void addOtherFields (tagEntryInfo* const tag, const tagType type,
728 const statementInfo *const st,
729 vString *const scope, vString *const typeRef)
730 {
731 /* For selected tag types, append an extension flag designating the
732 * parent object in which the tag is defined.
733 */
734 switch (type)
735 {
736 default: break;
737
738 case TAG_FUNCTION:
739 case TAG_PROTOTYPE:
740 if (vStringLength (Signature) > 0)
741 tag->extensionFields.signature = vStringValue (Signature);
742 case TAG_CLASS:
743 case TAG_ENUM:
744 case TAG_ENUMERATOR:
745 case TAG_EVENT:
746 case TAG_INTERFACE:
747 case TAG_MEMBER:
748 case TAG_SIGNAL:
749 case TAG_TASK:
750 case TAG_TYPEDEF:
751 if (vStringLength (scope) > 0 && isMember (st))
752 {
753 tagType ptype;
754
755 if (isType (st->context, TOKEN_NAME))
756 {
757 tag->extensionFields.scopeKindIndex = kindIndexForType (TAG_CLASS);
758 tag->extensionFields.scopeName = vStringValue (scope);
759 }
760 else if ((ptype = declToTagType (parentDecl (st))) &&
761 includeTag (ptype, isXtagEnabled(XTAG_FILE_SCOPE)))
762 {
763 tag->extensionFields.scopeKindIndex = kindIndexForType (ptype);
764 tag->extensionFields.scopeName = vStringValue (scope);
765 }
766 }
767 if ((type == TAG_CLASS || type == TAG_INTERFACE) &&
768 vStringLength (st->parentClasses) > 0)
769 {
770
771 tag->extensionFields.inheritance =
772 vStringValue (st->parentClasses);
773 }
774 if (isMember (st))
775 {
776 tag->extensionFields.access = accessField (st);
777 }
778 break;
779 }
780
781 /* Add typename info, type of the tag and name of struct/union/etc. */
782 if ((type == TAG_TYPEDEF || type == TAG_VARIABLE || type == TAG_MEMBER)
783 && isContextualStatement(st))
784 {
785 char *p;
786
787 tag->extensionFields.typeRef [0] =
788 tagName (declToTagType (st->declaration));
789 p = vStringValue (st->blockName->name);
790
791 /* If there was no {} block get the name from the token before the
792 * name (current token is ';' or ',', previous token is the name).
793 */
794 if (p == NULL || *p == '\0')
795 {
796 tokenInfo *const prev2 = prevToken (st, 2);
797 if (isType (prev2, TOKEN_NAME))
798 p = vStringValue (prev2->name);
799 }
800
801 /* Prepend the scope name if there is one. */
802 if (vStringLength (scope) > 0)
803 {
804 vStringCopy(typeRef, scope);
805 vStringCatS(typeRef, p);
806 p = vStringValue (typeRef);
807 }
808 tag->extensionFields.typeRef [1] = p;
809 }
810 }
811
findScopeHierarchy(vString * const string,const statementInfo * const st)812 static bool findScopeHierarchy (vString *const string, const statementInfo *const st)
813 {
814 bool found = false;
815
816 vStringClear (string);
817
818 if (isType (st->context, TOKEN_NAME))
819 {
820 vStringCopy (string, st->context->name);
821 found = true;
822 }
823
824 if (st->parent != NULL)
825 {
826 vString *temp = vStringNew ();
827 const statementInfo *s;
828 for (s = st->parent ; s != NULL ; s = s->parent)
829 {
830 if (isContextualStatement (s) ||
831 s->declaration == DECL_PROGRAM)
832 {
833 found = true;
834 vStringCopy (temp, string);
835 vStringClear (string);
836 if (isType (s->blockName, TOKEN_NAME))
837 {
838 if (isType (s->context, TOKEN_NAME) &&
839 vStringLength (s->context->name) > 0)
840 {
841 vStringCat (string, s->context->name);
842 }
843 vStringCat (string, s->blockName->name);
844 vStringCat (string, temp);
845 }
846 else
847 {
848 /* Information for building scope string
849 is lacking. Maybe input is broken. */
850 found = false;
851 }
852 }
853 }
854 vStringDelete (temp);
855 }
856 return found;
857 }
858
makeExtraTagEntry(const tagType type,tagEntryInfo * const e,vString * const scope)859 static void makeExtraTagEntry (const tagType type, tagEntryInfo *const e,
860 vString *const scope)
861 {
862 if (isXtagEnabled(XTAG_QUALIFIED_TAGS) &&
863 scope != NULL && vStringLength (scope) > 0)
864 {
865 vString *const scopedName = vStringNew ();
866
867 if (type != TAG_ENUMERATOR)
868 vStringCopy (scopedName, scope);
869 else
870 {
871 /* remove last component (i.e. enumeration name) from scope */
872 const char* const sc = vStringValue (scope);
873 const char* colon = strrchr (sc, ':');
874 if (colon != NULL)
875 {
876 while (*colon == ':' && colon > sc)
877 --colon;
878 vStringNCopy (scopedName, scope, colon + 1 - sc);
879 }
880 }
881 if (vStringLength (scopedName) > 0)
882 {
883 vStringCatS (scopedName, e->name);
884 e->name = vStringValue (scopedName);
885 markTagExtraBit (e, XTAG_QUALIFIED_TAGS);
886 makeTagEntry (e);
887 }
888 vStringDelete (scopedName);
889 }
890 }
891
makeTag(const tokenInfo * const token,const statementInfo * const st,bool isFileScope,const tagType type)892 static int makeTag (const tokenInfo *const token,
893 const statementInfo *const st,
894 bool isFileScope, const tagType type)
895 {
896 int corkIndex = CORK_NIL;
897 /* Nothing is really of file scope when it appears in a header file.
898 */
899 isFileScope = (bool) (isFileScope && ! isInputHeaderFile ());
900
901 if (isType (token, TOKEN_NAME) && vStringLength (token->name) > 0 &&
902 includeTag (type, isFileScope))
903 {
904 vString *scope;
905 vString *typeRef;
906 bool isScopeBuilt;
907 /* Use "typeRef" to store the typename from addOtherFields() until
908 * it's used in makeTagEntry().
909 */
910 tagEntryInfo e;
911 int kind;
912
913 scope = vStringNew ();
914 typeRef = vStringNew ();
915
916 kind = kindIndexForType(type);
917 initTagEntry (&e, vStringValue (token->name), kind);
918
919 e.lineNumber = token->lineNumber;
920 e.filePosition = token->filePosition;
921 e.isFileScope = isFileScope;
922 if (e.isFileScope)
923 markTagExtraBit (&e, XTAG_FILE_SCOPE);
924
925 isScopeBuilt = findScopeHierarchy (scope, st);
926 addOtherFields (&e, type, st, scope, typeRef);
927
928 corkIndex = makeTagEntry (&e);
929 if (isScopeBuilt)
930 makeExtraTagEntry (type, &e, scope);
931 vStringDelete (scope);
932 vStringDelete (typeRef);
933 }
934 return corkIndex;
935 }
936
isValidTypeSpecifier(const declType declaration)937 static bool isValidTypeSpecifier (const declType declaration)
938 {
939 bool result;
940 switch (declaration)
941 {
942 case DECL_BASE:
943 case DECL_CLASS:
944 case DECL_ENUM:
945 case DECL_EVENT:
946 result = true;
947 break;
948
949 default:
950 result = false;
951 break;
952 }
953 return result;
954 }
955
qualifyEnumeratorTag(const statementInfo * const st,const tokenInfo * const nameToken)956 static int qualifyEnumeratorTag (const statementInfo *const st,
957 const tokenInfo *const nameToken)
958 {
959 int corkIndex = CORK_NIL;
960 if (isType (nameToken, TOKEN_NAME))
961 corkIndex = makeTag (nameToken, st, true, TAG_ENUMERATOR);
962 return corkIndex;
963 }
964
qualifyFunctionTag(const statementInfo * const st,const tokenInfo * const nameToken)965 static int qualifyFunctionTag (const statementInfo *const st,
966 const tokenInfo *const nameToken)
967 {
968 int corkIndex = CORK_NIL;
969 if (isType (nameToken, TOKEN_NAME))
970 {
971 tagType type;
972 const bool isFileScope =
973 (bool) (st->member.access == ACCESS_PRIVATE ||
974 (!isMember (st) && st->scope == SCOPE_STATIC));
975 if (st->declaration == DECL_TASK)
976 type = TAG_TASK;
977 else
978 type = TAG_FUNCTION;
979 corkIndex = makeTag (nameToken, st, isFileScope, type);
980 }
981 return corkIndex;
982 }
983
qualifyFunctionDeclTag(const statementInfo * const st,const tokenInfo * const nameToken)984 static int qualifyFunctionDeclTag (const statementInfo *const st,
985 const tokenInfo *const nameToken)
986 {
987 int corkIndex = CORK_NIL;
988 if (! isType (nameToken, TOKEN_NAME))
989 ;
990 else if (st->scope == SCOPE_TYPEDEF)
991 corkIndex = makeTag (nameToken, st, true, TAG_TYPEDEF);
992 else if (isValidTypeSpecifier (st->declaration))
993 corkIndex = makeTag (nameToken, st, true, TAG_PROTOTYPE);
994 return corkIndex;
995 }
996
qualifyCompoundTag(const statementInfo * const st,const tokenInfo * const nameToken)997 static int qualifyCompoundTag (const statementInfo *const st,
998 const tokenInfo *const nameToken)
999 {
1000 int corkIndex = CORK_NIL;
1001 if (isType (nameToken, TOKEN_NAME))
1002 {
1003 const tagType type = declToTagType (st->declaration);
1004
1005 if (type != TAG_UNDEFINED)
1006 corkIndex = makeTag (nameToken, st, false, type);
1007 }
1008 return corkIndex;
1009 }
1010
qualifyBlockTag(statementInfo * const st,const tokenInfo * const nameToken)1011 static int qualifyBlockTag (statementInfo *const st,
1012 const tokenInfo *const nameToken)
1013 {
1014 int corkIndex = CORK_NIL;
1015 switch (st->declaration)
1016 {
1017
1018 case DECL_CLASS:
1019 case DECL_ENUM:
1020 case DECL_INTERFACE:
1021 case DECL_PROGRAM:
1022 corkIndex = qualifyCompoundTag (st, nameToken);
1023 break;
1024 default: break;
1025 }
1026 return corkIndex;
1027 }
1028
qualifyVariableTag(const statementInfo * const st,const tokenInfo * const nameToken)1029 static int qualifyVariableTag (const statementInfo *const st,
1030 const tokenInfo *const nameToken)
1031 {
1032 int corkIndex = CORK_NIL;
1033 /* We have to watch that we do not interpret a declaration of the
1034 * form "struct tag;" as a variable definition. In such a case, the
1035 * token preceding the name will be a keyword.
1036 */
1037 if (! isType (nameToken, TOKEN_NAME))
1038 ;
1039 else if (st->scope == SCOPE_TYPEDEF)
1040 corkIndex = makeTag (nameToken, st, true, TAG_TYPEDEF);
1041 else if (st->declaration == DECL_EVENT)
1042 corkIndex = makeTag (nameToken, st, (bool) (st->member.access == ACCESS_PRIVATE),
1043 TAG_EVENT);
1044 else if (isValidTypeSpecifier (st->declaration))
1045 {
1046 if (st->notVariable)
1047 ;
1048 else if (isMember (st))
1049 {
1050 if (st->scope == SCOPE_GLOBAL || st->scope == SCOPE_STATIC)
1051 corkIndex = makeTag (nameToken, st, true, TAG_MEMBER);
1052 }
1053 else
1054 {
1055 if (st->scope == SCOPE_EXTERN || ! st->haveQualifyingName)
1056 corkIndex = makeTag (nameToken, st, false, TAG_EXTERN_VAR);
1057 else if (st->inFunction)
1058 corkIndex = makeTag (nameToken, st, (bool) (st->scope == SCOPE_STATIC),
1059 TAG_LOCAL);
1060 else
1061 corkIndex = makeTag (nameToken, st, (bool) (st->scope == SCOPE_STATIC),
1062 TAG_VARIABLE);
1063 }
1064 }
1065 return corkIndex;
1066 }
1067
1068 /*
1069 * Parsing functions
1070 */
1071
1072
1073 /* Skip to the next non-white character.
1074 */
skipToNonWhite(void)1075 static int skipToNonWhite (void)
1076 {
1077 bool found = false;
1078 int c;
1079
1080 #if 0
1081 do
1082 c = cppGetc ();
1083 while (cppIsspace (c));
1084 #else
1085 while (1)
1086 {
1087 c = cppGetc ();
1088 if (cppIsspace (c))
1089 found = true;
1090 else
1091 break;
1092 }
1093 if (CollectingSignature && found)
1094 vStringPut (Signature, ' ');
1095 #endif
1096
1097 return c;
1098 }
1099
1100 /* Skips to the next brace in column 1. This is intended for cases where
1101 * preprocessor constructs result in unbalanced braces.
1102 */
skipToFormattedBraceMatch(void)1103 static void skipToFormattedBraceMatch (void)
1104 {
1105 int c, next;
1106
1107 c = cppGetc ();
1108 next = cppGetc ();
1109 while (c != EOF && (c != '\n' || next != '}'))
1110 {
1111 c = next;
1112 next = cppGetc ();
1113 }
1114 }
1115
1116 /* Skip to the matching character indicated by the pair string. If skipping
1117 * to a matching brace and any brace is found within a different level of a
1118 * #if conditional statement while brace formatting is in effect, we skip to
1119 * the brace matched by its formatting. It is assumed that we have already
1120 * read the character which starts the group (i.e. the first character of
1121 * "pair").
1122 */
skipToMatch(const char * const pair)1123 static void skipToMatch (const char *const pair)
1124 {
1125 const bool braceMatching = (bool) (strcmp ("{}", pair) == 0);
1126 const bool braceFormatting = (bool) (cppIsBraceFormat () && braceMatching);
1127 const unsigned int initialLevel = cppGetDirectiveNestLevel ();
1128 const int begin = pair [0], end = pair [1];
1129 const unsigned long inputLineNumber = getInputLineNumber ();
1130 int matchLevel = 1;
1131 int c = '\0';
1132
1133 while (matchLevel > 0 && (c = skipToNonWhite ()) != EOF)
1134 {
1135 if (CollectingSignature)
1136 vStringPut (Signature, c);
1137 if (c == begin)
1138 {
1139 ++matchLevel;
1140 if (braceFormatting && cppGetDirectiveNestLevel () != initialLevel)
1141 {
1142 skipToFormattedBraceMatch ();
1143 break;
1144 }
1145 }
1146 else if (c == end)
1147 {
1148 --matchLevel;
1149 if (braceFormatting && cppGetDirectiveNestLevel () != initialLevel)
1150 {
1151 skipToFormattedBraceMatch ();
1152 break;
1153 }
1154 }
1155 }
1156 if (c == EOF)
1157 {
1158 verbose ("%s: failed to find match for '%c' at line %lu\n",
1159 getInputFileName (), begin, inputLineNumber);
1160 if (braceMatching)
1161 longjmp (Exception, (int) ExceptionBraceFormattingError);
1162 else
1163 longjmp (Exception, (int) ExceptionFormattingError);
1164 }
1165 }
1166
analyzeKeyword(const char * const name)1167 static keywordId analyzeKeyword (const char *const name)
1168 {
1169 const keywordId id = (keywordId) lookupKeyword (name, getInputLanguage ());
1170 return id;
1171 }
1172
analyzeIdentifier(tokenInfo * const token)1173 static void analyzeIdentifier (tokenInfo *const token)
1174 {
1175 const char * name = vStringValue (token->name);
1176
1177 vString * replacement = NULL;
1178
1179 // C: check for ignored token
1180 // (FIXME: java doesn't support -I... but maybe it should?)
1181 const cppMacroInfo * macro = cppFindMacro(name);
1182
1183 if(macro)
1184 {
1185 if(macro->hasParameterList)
1186 {
1187 // This old parser does not support macro parameters: we simply assume them to be empty
1188 int c = skipToNonWhite ();
1189
1190 if (c == '(')
1191 skipToMatch ("()");
1192 }
1193
1194 if(macro->replacements)
1195 {
1196 // There is a replacement: analyze it
1197 replacement = cppBuildMacroReplacement(macro,NULL,0);
1198 name = replacement ? vStringValue(replacement) : NULL;
1199 } else {
1200 // There is no replacement: just ignore
1201 name = NULL;
1202 }
1203 }
1204
1205 if(!name)
1206 {
1207 initToken(token);
1208 if(replacement)
1209 vStringDelete(replacement);
1210 return;
1211 }
1212
1213 token->keyword = analyzeKeyword (name);
1214
1215 if (token->keyword == KEYWORD_NONE)
1216 token->type = TOKEN_NAME;
1217 else
1218 token->type = TOKEN_KEYWORD;
1219
1220 if(replacement)
1221 vStringDelete(replacement);
1222 }
1223
readIdentifier(tokenInfo * const token,const int firstChar)1224 static void readIdentifier (tokenInfo *const token, const int firstChar)
1225 {
1226 vString *const name = token->name;
1227 int c = firstChar;
1228 bool first = true;
1229
1230 initToken (token);
1231
1232 do
1233 {
1234 vStringPut (name, c);
1235 if (CollectingSignature)
1236 {
1237 if (!first)
1238 vStringPut (Signature, c);
1239 first = false;
1240 }
1241 c = cppGetc ();
1242 } while (cppIsident (c));
1243 cppUngetc (c); /* unget non-identifier character */
1244
1245 analyzeIdentifier (token);
1246 }
1247
processName(statementInfo * const st)1248 static void processName (statementInfo *const st)
1249 {
1250 Assert (isType (activeToken (st), TOKEN_NAME));
1251 if (st->gotName && st->declaration == DECL_NONE)
1252 st->declaration = DECL_BASE;
1253 st->gotName = true;
1254 st->haveQualifyingName = true;
1255 }
1256
copyToken(tokenInfo * const dest,const tokenInfo * const src)1257 static void copyToken (tokenInfo *const dest, const tokenInfo *const src)
1258 {
1259 dest->type = src->type;
1260 dest->keyword = src->keyword;
1261 dest->filePosition = src->filePosition;
1262 dest->lineNumber = src->lineNumber;
1263 vStringCopy (dest->name, src->name);
1264 }
1265
setAccess(statementInfo * const st,const accessType access)1266 static void setAccess (statementInfo *const st, const accessType access)
1267 {
1268 if (isMember (st))
1269 {
1270 st->member.access = access;
1271 }
1272 }
1273
addParentClass(statementInfo * const st,tokenInfo * const token)1274 static void addParentClass (statementInfo *const st, tokenInfo *const token)
1275 {
1276 if (vStringLength (token->name) > 0 &&
1277 vStringLength (st->parentClasses) > 0)
1278 {
1279 vStringPut (st->parentClasses, ',');
1280 }
1281 vStringCat (st->parentClasses, token->name);
1282 }
1283
readParents(statementInfo * const st,const int qualifier)1284 static void readParents (statementInfo *const st, const int qualifier)
1285 {
1286 tokenInfo *const token = newToken ();
1287 tokenInfo *const parent = newToken ();
1288 int c;
1289
1290 do
1291 {
1292 c = skipToNonWhite ();
1293 if (cppIsident1 (c))
1294 {
1295 readIdentifier (token, c);
1296 if (isType (token, TOKEN_NAME))
1297 vStringCat (parent->name, token->name);
1298 else
1299 {
1300 addParentClass (st, parent);
1301 initToken (parent);
1302 }
1303 }
1304 else if (c == qualifier)
1305 vStringPut (parent->name, c);
1306 else if (c == '<')
1307 skipToMatch ("<>");
1308 else if (isType (token, TOKEN_NAME))
1309 {
1310 addParentClass (st, parent);
1311 initToken (parent);
1312 }
1313 } while (c != '{' && c != EOF);
1314 cppUngetc (c);
1315 deleteToken (parent);
1316 deleteToken (token);
1317 }
1318
processInterface(statementInfo * const st)1319 static void processInterface (statementInfo *const st)
1320 {
1321 st->declaration = DECL_INTERFACE;
1322 }
1323
checkIsClassEnum(statementInfo * const st,const declType decl)1324 static void checkIsClassEnum (statementInfo *const st, const declType decl)
1325 {
1326 st->declaration = decl;
1327 }
1328
processToken(tokenInfo * const token,statementInfo * const st)1329 static void processToken (tokenInfo *const token, statementInfo *const st)
1330 {
1331 switch ((int)token->keyword) /* is it a reserved word? */
1332 {
1333 default: break;
1334
1335 case KEYWORD_NONE: processName (st); break;
1336 case KEYWORD_BIND: st->declaration = DECL_BASE; break;
1337 case KEYWORD_BIT: st->declaration = DECL_BASE; break;
1338 case KEYWORD_CLASS: checkIsClassEnum (st, DECL_CLASS); break;
1339 case KEYWORD_ENUM: st->declaration = DECL_ENUM; break;
1340 case KEYWORD_EXTENDS: readParents (st, '.');
1341 setToken (st, TOKEN_NONE); break;
1342 case KEYWORD_FUNCTION: st->declaration = DECL_BASE; break;
1343 case KEYWORD_INTEGER: st->declaration = DECL_BASE; break;
1344 case KEYWORD_INTERFACE: processInterface (st); break;
1345 case KEYWORD_LOCAL: setAccess (st, ACCESS_LOCAL); break;
1346 case KEYWORD_PROGRAM: st->declaration = DECL_PROGRAM; break;
1347 case KEYWORD_PROTECTED: setAccess (st, ACCESS_PROTECTED); break;
1348 case KEYWORD_PUBLIC: setAccess (st, ACCESS_PUBLIC); break;
1349 case KEYWORD_STRING: st->declaration = DECL_BASE; break;
1350 case KEYWORD_TASK: st->declaration = DECL_TASK; break;
1351 case KEYWORD_VOID: st->declaration = DECL_BASE; break;
1352 case KEYWORD_VIRTUAL: st->implementation = IMP_VIRTUAL; break;
1353
1354 case KEYWORD_EVENT:
1355 break;
1356
1357 case KEYWORD_TYPEDEF:
1358 reinitStatement (st, false);
1359 st->scope = SCOPE_TYPEDEF;
1360 break;
1361
1362 case KEYWORD_EXTERN:
1363 reinitStatement (st, false);
1364 st->scope = SCOPE_EXTERN;
1365 st->declaration = DECL_BASE;
1366 break;
1367
1368 case KEYWORD_STATIC:
1369 reinitStatement (st, false);
1370 st->scope = SCOPE_STATIC;
1371 st->declaration = DECL_BASE;
1372 break;
1373 }
1374 }
1375
1376 /*
1377 * Parenthesis handling functions
1378 */
1379
restartStatement(statementInfo * const st)1380 static void restartStatement (statementInfo *const st)
1381 {
1382 tokenInfo *const save = newToken ();
1383 tokenInfo *token = activeToken (st);
1384
1385 copyToken (save, token);
1386 DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>");)
1387 reinitStatement (st, false);
1388 token = activeToken (st);
1389 copyToken (token, save);
1390 deleteToken (save);
1391 processToken (token, st);
1392 }
1393
1394 /* Skips over a mem-initializer-list of a ctor-initializer, defined as:
1395 *
1396 * mem-initializer-list:
1397 * mem-initializer, mem-initializer-list
1398 *
1399 * mem-initializer:
1400 * [::] [nested-name-spec] class-name (...)
1401 * identifier
1402 */
skipMemIntializerList(tokenInfo * const token)1403 static void skipMemIntializerList (tokenInfo *const token)
1404 {
1405 int c;
1406
1407 do
1408 {
1409 c = skipToNonWhite ();
1410 while (cppIsident1 (c) || c == ':')
1411 {
1412 if (c != ':')
1413 readIdentifier (token, c);
1414 c = skipToNonWhite ();
1415 }
1416 if (c == '<')
1417 {
1418 skipToMatch ("<>");
1419 c = skipToNonWhite ();
1420 }
1421 if (c == '(')
1422 {
1423 skipToMatch ("()");
1424 c = skipToNonWhite ();
1425 }
1426 } while (c == ',');
1427 cppUngetc (c);
1428 }
1429
skipMacro(statementInfo * const st)1430 static void skipMacro (statementInfo *const st)
1431 {
1432 tokenInfo *const prev2 = prevToken (st, 2);
1433
1434 if (isType (prev2, TOKEN_NAME))
1435 retardToken (st);
1436 skipToMatch ("()");
1437 }
1438
1439 /* Skips over characters following the parameter list.
1440 * Originally written for C++, may contain unnecessary stuff.
1441 *
1442 * C#:
1443 * public C(double x) : base(x) {}
1444 */
skipPostArgumentStuff(statementInfo * const st,parenInfo * const info)1445 static bool skipPostArgumentStuff (
1446 statementInfo *const st, parenInfo *const info)
1447 {
1448 tokenInfo *const token = activeToken (st);
1449 unsigned int parameters = info->parameterCount;
1450 unsigned int elementCount = 0;
1451 bool restart = false;
1452 bool end = false;
1453 int c = skipToNonWhite ();
1454
1455 do
1456 {
1457 switch (c)
1458 {
1459 case ')': break;
1460 case ':': skipMemIntializerList (token);break; /* ctor-initializer */
1461 case '[': skipToMatch ("[]"); break;
1462 case '=': cppUngetc (c); end = true; break;
1463 case '{': cppUngetc (c); end = true; break;
1464 case '}': cppUngetc (c); end = true; break;
1465
1466 case '(':
1467 if (elementCount > 0)
1468 ++elementCount;
1469 skipToMatch ("()");
1470 break;
1471
1472 case ';':
1473 if (parameters == 0 || elementCount < 2)
1474 {
1475 cppUngetc (c);
1476 end = true;
1477 }
1478 else if (--parameters == 0)
1479 end = true;
1480 break;
1481
1482 default:
1483 if (cppIsident1 (c))
1484 {
1485 readIdentifier (token, c);
1486 switch (token->keyword)
1487 {
1488 case KEYWORD_CLASS:
1489 case KEYWORD_EXTERN:
1490 case KEYWORD_NEWCOV:
1491 case KEYWORD_PROTECTED:
1492 case KEYWORD_PUBLIC:
1493 case KEYWORD_STATIC:
1494 case KEYWORD_TYPEDEF:
1495 case KEYWORD_VIRTUAL:
1496 /* Never allowed within parameter declarations. */
1497 restart = true;
1498 end = true;
1499 break;
1500
1501 default:
1502 if (isType (token, TOKEN_NONE))
1503 ;
1504 else
1505 {
1506 /* If we encounter any other identifier immediately
1507 * following an empty parameter list, this is almost
1508 * certainly one of those Microsoft macro "thingies"
1509 * that the automatic source code generation sticks
1510 * in. Terminate the current statement.
1511 */
1512 restart = true;
1513 end = true;
1514 }
1515 break;
1516 }
1517 }
1518 }
1519 if (! end)
1520 {
1521 c = skipToNonWhite ();
1522 if (c == EOF)
1523 end = true;
1524 }
1525 } while (! end);
1526
1527 if (restart)
1528 restartStatement (st);
1529 else
1530 setToken (st, TOKEN_NONE);
1531
1532 return (bool) (c != EOF);
1533 }
1534
analyzePostParens(statementInfo * const st,parenInfo * const info)1535 static void analyzePostParens (statementInfo *const st, parenInfo *const info)
1536 {
1537 const unsigned long inputLineNumber = getInputLineNumber ();
1538 int c = skipToNonWhite ();
1539
1540 cppUngetc (c);
1541 if (isOneOf (c, "{;,="))
1542 ;
1543 else {
1544 if (! skipPostArgumentStuff (st, info))
1545 {
1546 verbose (
1547 "%s: confusing argument declarations beginning at line %lu\n",
1548 getInputFileName (), inputLineNumber);
1549 longjmp (Exception, (int) ExceptionFormattingError);
1550 }
1551 }
1552 }
1553
processAngleBracket(void)1554 static void processAngleBracket (void)
1555 {
1556 int c = cppGetc ();
1557 if (c == '>') {
1558 /* already found match for template */
1559 } else if (c == '<') {
1560 /* skip "<<" or "<<=". */
1561 c = cppGetc ();
1562 if (c != '=') {
1563 cppUngetc (c);
1564 }
1565 } else {
1566 cppUngetc (c);
1567 }
1568 }
1569
parseParens(statementInfo * const st,parenInfo * const info)1570 static int parseParens (statementInfo *const st, parenInfo *const info)
1571 {
1572 tokenInfo *const token = activeToken (st);
1573 unsigned int identifierCount = 0;
1574 unsigned int depth = 1;
1575 bool firstChar = true;
1576 int nextChar = '\0';
1577
1578 CollectingSignature = true;
1579 vStringClear (Signature);
1580 vStringPut (Signature, '(');
1581 info->parameterCount = 1;
1582 do
1583 {
1584 int c = skipToNonWhite ();
1585 vStringPut (Signature, c);
1586
1587 switch (c)
1588 {
1589 case '^':
1590 break;
1591
1592 case '&':
1593 case '*':
1594 info->isPointer = true;
1595 if (identifierCount == 0)
1596 info->isParamList = false;
1597 initToken (token);
1598 break;
1599
1600 case ':':
1601 break;
1602
1603 case '.':
1604 info->isNameCandidate = false;
1605 c = cppGetc ();
1606 if (c != '.')
1607 cppUngetc (c);
1608 else
1609 {
1610 c = cppGetc ();
1611 if (c != '.')
1612 cppUngetc (c);
1613 else
1614 vStringCatS (Signature, "..."); /* variable arg list */
1615 }
1616 break;
1617
1618 case ',':
1619 info->isNameCandidate = false;
1620 break;
1621
1622 case '=':
1623 info->isNameCandidate = false;
1624 if (firstChar)
1625 {
1626 info->isParamList = false;
1627 skipMacro (st);
1628 depth = 0;
1629 }
1630 break;
1631
1632 case '[':
1633 skipToMatch ("[]");
1634 break;
1635
1636 case '<':
1637 processAngleBracket ();
1638 break;
1639
1640 case ')':
1641 if (firstChar)
1642 info->parameterCount = 0;
1643 --depth;
1644 break;
1645
1646 case '(':
1647 if (firstChar)
1648 {
1649 info->isNameCandidate = false;
1650 cppUngetc (c);
1651 vStringClear (Signature);
1652 skipMacro (st);
1653 depth = 0;
1654 vStringChop (Signature);
1655 }
1656 else if (isType (token, TOKEN_PAREN_NAME))
1657 {
1658 c = skipToNonWhite ();
1659 if (c == '*') /* check for function pointer */
1660 {
1661 skipToMatch ("()");
1662 c = skipToNonWhite ();
1663 if (c == '(')
1664 skipToMatch ("()");
1665 else
1666 cppUngetc (c);
1667 }
1668 else
1669 {
1670 cppUngetc (c);
1671 cppUngetc ('(');
1672 info->nestedArgs = true;
1673 }
1674 }
1675 else
1676 ++depth;
1677 break;
1678
1679 default:
1680 if (cppIsident1 (c))
1681 {
1682 readIdentifier (token, c);
1683 if (isType (token, TOKEN_NAME) && info->isNameCandidate)
1684 token->type = TOKEN_PAREN_NAME;
1685 else if (isType (token, TOKEN_KEYWORD))
1686 {
1687 info->isNameCandidate = false;
1688 }
1689 }
1690 else
1691 {
1692 info->isParamList = false;
1693 info->isNameCandidate = false;
1694 info->invalidContents = true;
1695 }
1696 break;
1697 }
1698 firstChar = false;
1699 } while (! info->nestedArgs && depth > 0 && info->isNameCandidate);
1700
1701 if (! info->nestedArgs) while (depth > 0)
1702 {
1703 skipToMatch ("()");
1704 --depth;
1705 }
1706
1707 if (! info->isNameCandidate)
1708 initToken (token);
1709
1710 CollectingSignature = false;
1711 return nextChar;
1712 }
1713
initParenInfo(parenInfo * const info)1714 static void initParenInfo (parenInfo *const info)
1715 {
1716 info->isPointer = false;
1717 info->isParamList = true;
1718 info->isNameCandidate = true;
1719 info->invalidContents = false;
1720 info->nestedArgs = false;
1721 info->parameterCount = 0;
1722 }
1723
analyzeParens(statementInfo * const st)1724 static void analyzeParens (statementInfo *const st)
1725 {
1726 tokenInfo *const prev = prevToken (st, 1);
1727
1728 if (st->inFunction && !st->assignment)
1729 st->notVariable = true;
1730
1731 if (! isType (prev, TOKEN_NONE)) /* in case of ignored enclosing macros */
1732 {
1733 tokenInfo *const token = activeToken (st);
1734 parenInfo info;
1735 int c;
1736
1737 initParenInfo (&info);
1738 parseParens (st, &info);
1739 c = skipToNonWhite ();
1740 cppUngetc (c);
1741 if (info.invalidContents)
1742 {
1743 /* FIXME: This breaks parsing of variable instantiations that have
1744 constants as parameters: Type var(0) or Type var("..."). */
1745 reinitStatement (st, false);
1746 }
1747 else if (info.isNameCandidate && isType (token, TOKEN_PAREN_NAME) &&
1748 ! st->gotParenName &&
1749 (! info.isParamList || ! st->haveQualifyingName ||
1750 c == '(' ||
1751 (c == '=' && st->implementation != IMP_VIRTUAL) ||
1752 (st->declaration == DECL_NONE && isOneOf (c, ",;"))))
1753 {
1754 token->type = TOKEN_NAME;
1755 processName (st);
1756 st->gotParenName = true;
1757 if (! (c == '(' && info.nestedArgs))
1758 st->isPointer = info.isPointer;
1759 }
1760 else if (! st->gotArgs && info.isParamList)
1761 {
1762 st->gotArgs = true;
1763 setToken (st, TOKEN_ARGS);
1764 advanceToken (st);
1765 if (st->scope != SCOPE_TYPEDEF)
1766 analyzePostParens (st, &info);
1767 }
1768 else
1769 setToken (st, TOKEN_NONE);
1770 }
1771 }
1772
1773 /*
1774 * Token parsing functions
1775 */
1776
addContext(statementInfo * const st,const tokenInfo * const token)1777 static void addContext (statementInfo *const st, const tokenInfo* const token)
1778 {
1779 if (isType (token, TOKEN_NAME))
1780 {
1781 vStringCat (st->context->name, token->name);
1782 st->context->type = TOKEN_NAME;
1783 }
1784 }
1785
processColon(statementInfo * const st)1786 static void processColon (statementInfo *const st)
1787 {
1788 int c = skipToNonWhite ();
1789 const bool doubleColon = (bool) (c == ':');
1790
1791 if (doubleColon)
1792 {
1793 setToken (st, TOKEN_DOUBLE_COLON);
1794 st->haveQualifyingName = false;
1795 }
1796 else
1797 {
1798 const tokenInfo *const prev = prevToken (st, 1);
1799 cppUngetc (c);
1800 if (st->parent != NULL)
1801 {
1802 makeTag (prev, st, false, TAG_LABEL);
1803 reinitStatement (st, false);
1804 }
1805 }
1806 }
1807
1808 /* Skips over any initializing value which may follow an '=' character in a
1809 * variable definition.
1810 */
skipInitializer(statementInfo * const st)1811 static int skipInitializer (statementInfo *const st)
1812 {
1813 bool done = false;
1814 int c;
1815
1816 while (! done)
1817 {
1818 c = skipToNonWhite ();
1819
1820 if (c == EOF)
1821 longjmp (Exception, (int) ExceptionFormattingError);
1822 else switch (c)
1823 {
1824 case ',':
1825 case ';': done = true; break;
1826
1827 case '0':
1828 if (st->implementation == IMP_VIRTUAL)
1829 st->implementation = IMP_PURE_VIRTUAL;
1830 break;
1831
1832 case '[': skipToMatch ("[]"); break;
1833 case '(': skipToMatch ("()"); break;
1834 case '{': skipToMatch ("{}"); break;
1835 case '<': processAngleBracket(); break;
1836
1837 case '}':
1838 if (insideEnumBody (st))
1839 done = true;
1840 else if (! cppIsBraceFormat ())
1841 {
1842 verbose ("%s: unexpected closing brace at line %lu\n",
1843 getInputFileName (), getInputLineNumber ());
1844 longjmp (Exception, (int) ExceptionBraceFormattingError);
1845 }
1846 break;
1847
1848 default: break;
1849 }
1850 }
1851 return c;
1852 }
1853
processInitializer(statementInfo * const st)1854 static void processInitializer (statementInfo *const st)
1855 {
1856 const bool inEnumBody = insideEnumBody (st);
1857 int c = cppGetc ();
1858
1859 if (c != '=')
1860 {
1861 cppUngetc (c);
1862 c = skipInitializer (st);
1863 st->assignment = true;
1864 if (c == ';')
1865 setToken (st, TOKEN_SEMICOLON);
1866 else if (c == ',')
1867 setToken (st, TOKEN_COMMA);
1868 else if (c == '}' && inEnumBody)
1869 {
1870 cppUngetc (c);
1871 setToken (st, TOKEN_COMMA);
1872 }
1873 if (st->scope == SCOPE_EXTERN)
1874 st->scope = SCOPE_GLOBAL;
1875 }
1876 }
1877
parseIdentifier(statementInfo * const st,const int c)1878 static void parseIdentifier (statementInfo *const st, const int c)
1879 {
1880 tokenInfo *const token = activeToken (st);
1881
1882 readIdentifier (token, c);
1883 if (! isType (token, TOKEN_NONE))
1884 processToken (token, st);
1885 }
1886
parseGeneralToken(statementInfo * const st,const int c)1887 static void parseGeneralToken (statementInfo *const st, const int c)
1888 {
1889 const tokenInfo *const prev = prevToken (st, 1);
1890
1891 if (cppIsident1 (c))
1892 {
1893
1894 parseIdentifier (st, c);
1895 if (isType (st->context, TOKEN_NAME) &&
1896 isType (activeToken (st), TOKEN_NAME) && isType (prev, TOKEN_NAME))
1897 {
1898 initToken (st->context);
1899 }
1900 }
1901 else if (c == '.' || c == '-')
1902 {
1903 if (! st->assignment)
1904 st->notVariable = true;
1905 if (c == '-')
1906 {
1907 int c2 = cppGetc ();
1908 if (c2 != '>')
1909 cppUngetc (c2);
1910 }
1911 }
1912 else if (c == '!' || c == '>')
1913 {
1914 int c2 = cppGetc ();
1915 if (c2 != '=')
1916 cppUngetc (c2);
1917 }
1918 else if (c == STRING_SYMBOL) {
1919 setToken(st, TOKEN_NONE);
1920 }
1921 }
1922
1923 /* Reads characters from the pre-processor and assembles tokens, setting
1924 * the current statement state.
1925 */
nextToken(statementInfo * const st)1926 static void nextToken (statementInfo *const st)
1927 {
1928 tokenInfo *token;
1929 do
1930 {
1931 int c = skipToNonWhite ();
1932 switch (c)
1933 {
1934 case EOF: longjmp (Exception, (int) ExceptionEOF); break;
1935 case '(': analyzeParens (st); break;
1936 case '<': processAngleBracket (); break;
1937 case '*': st->haveQualifyingName = false; break;
1938 case ',': setToken (st, TOKEN_COMMA); break;
1939 case ':': processColon (st); break;
1940 case ';': setToken (st, TOKEN_SEMICOLON); break;
1941 case '=': processInitializer (st); break;
1942 case '[': skipToMatch ("[]"); break;
1943 case '{': setToken (st, TOKEN_BRACE_OPEN); break;
1944 case '}': setToken (st, TOKEN_BRACE_CLOSE); break;
1945 default: parseGeneralToken (st, c); break;
1946 }
1947 token = activeToken (st);
1948 } while (isType (token, TOKEN_NONE));
1949 }
1950
1951 /*
1952 * Scanning support functions
1953 */
1954
1955 static statementInfo *CurrentStatement = NULL;
1956
newStatement(statementInfo * const parent)1957 static statementInfo *newStatement (statementInfo *const parent)
1958 {
1959 statementInfo *const st = xMalloc (1, statementInfo);
1960 unsigned int i;
1961
1962 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
1963 st->token [i] = newToken ();
1964
1965 st->context = newToken ();
1966 st->blockName = newToken ();
1967 st->parentClasses = vStringNew ();
1968
1969 initStatement (st, parent);
1970 CurrentStatement = st;
1971
1972 return st;
1973 }
1974
deleteStatement(void)1975 static void deleteStatement (void)
1976 {
1977 statementInfo *const st = CurrentStatement;
1978 statementInfo *const parent = st->parent;
1979 unsigned int i;
1980
1981 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
1982 {
1983 deleteToken (st->token [i]); st->token [i] = NULL;
1984 }
1985 deleteToken (st->blockName); st->blockName = NULL;
1986 deleteToken (st->context); st->context = NULL;
1987 vStringDelete (st->parentClasses); st->parentClasses = NULL;
1988 eFree (st);
1989 CurrentStatement = parent;
1990 }
1991
deleteAllStatements(void)1992 static void deleteAllStatements (void)
1993 {
1994 while (CurrentStatement != NULL)
1995 deleteStatement ();
1996 }
1997
isStatementEnd(const statementInfo * const st)1998 static bool isStatementEnd (const statementInfo *const st)
1999 {
2000 const tokenInfo *const token = activeToken (st);
2001 bool isEnd;
2002
2003 if (isType (token, TOKEN_SEMICOLON))
2004 isEnd = true;
2005 else if (isType (token, TOKEN_BRACE_CLOSE))
2006 isEnd = ! isContextualStatement (st);
2007 else
2008 isEnd = false;
2009
2010 return isEnd;
2011 }
2012
checkStatementEnd(statementInfo * const st,int corkIndex)2013 static void checkStatementEnd (statementInfo *const st, int corkIndex)
2014 {
2015 const tokenInfo *const token = activeToken (st);
2016
2017 tagEntryInfo *e = getEntryInCorkQueue (corkIndex);
2018 if (e)
2019 e->extensionFields.endLine = token->lineNumber;
2020
2021 if (isType (token, TOKEN_COMMA))
2022 reinitStatement (st, true);
2023 else if (isStatementEnd (st))
2024 {
2025 DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>"); )
2026 reinitStatement (st, false);
2027 cppEndStatement ();
2028 }
2029 else
2030 {
2031 cppBeginStatement ();
2032 advanceToken (st);
2033 }
2034 }
2035
nest(statementInfo * const st,const unsigned int nestLevel)2036 static void nest (statementInfo *const st, const unsigned int nestLevel)
2037 {
2038 switch (st->declaration)
2039 {
2040 case DECL_CLASS:
2041 case DECL_ENUM:
2042 case DECL_INTERFACE:
2043 createTags (nestLevel, st);
2044 break;
2045
2046 case DECL_FUNCTION:
2047 case DECL_TASK:
2048 st->inFunction = true;
2049 /* fall through */
2050 default:
2051 if (includeTag (TAG_LOCAL, false) || includeTag (TAG_LABEL, false))
2052 createTags (nestLevel, st);
2053 else
2054 skipToMatch ("{}");
2055 break;
2056 }
2057 advanceToken (st);
2058 setToken (st, TOKEN_BRACE_CLOSE);
2059 }
2060
tagCheck(statementInfo * const st)2061 static int tagCheck (statementInfo *const st)
2062 {
2063 const tokenInfo *const token = activeToken (st);
2064 const tokenInfo *const prev = prevToken (st, 1);
2065 const tokenInfo *const prev2 = prevToken (st, 2);
2066 int corkIndex = CORK_NIL;
2067
2068 switch (token->type)
2069 {
2070 case TOKEN_NAME:
2071 if (insideEnumBody (st))
2072 corkIndex = qualifyEnumeratorTag (st, token);
2073 if (insideInterfaceBody (st))
2074 {
2075 /* Quoted from
2076 http://www.asic-world.com/vera/hdl1.html#Interface_Declaration
2077 ------------------------------------------------
2078 interface interface_name
2079 {
2080 signal_direction [signal_width] signal_name signal_type
2081 [skew] [depth value][vca q_value][force][hdl_node "hdl_path"];
2082 }
2083 Where
2084 signal_direction : This can be one of the following
2085 input : ...
2086 output : ...
2087 inout : ...
2088 signal_width : The signal_width is a range specifying the width of
2089 a vector signal. It must be in the form [msb:lsb].
2090 Interface signals can have any integer lsb value,
2091 even a negative value. The default width is 1.
2092 signal_name : The signal_name identifies the signal being defined.
2093 It is the Vera name for the HDL signal being connected.
2094 signal_type : There are many signals types, most commonly used one are
2095 NHOLD : ...
2096 PHOLD : ...
2097 PHOLD NHOLD : ...
2098 NSAMPLE : ...
2099 PSAMPLE : ...
2100 PSAMPLE NSAMPLE : ...
2101 CLOCK : ...
2102 PSAMPLE PHOLD : ...
2103 NSAMPLE NHOLD : ...
2104 PSAMPLE PHOLD NSAMPLE NHOLD : ...
2105 ------------------------------------------------
2106 We want to capture "signal_name" here.
2107 */
2108 if (( isType (prev, TOKEN_KEYWORD)
2109 && isSignalDirection(prev) ) ||
2110 ( isType (prev2, TOKEN_KEYWORD)
2111 && isSignalDirection(prev) ))
2112 corkIndex = makeTag (token, st, false, TAG_SIGNAL);
2113 }
2114 break;
2115 case TOKEN_BRACE_OPEN:
2116 if (isType (prev, TOKEN_ARGS))
2117 {
2118 if (st->haveQualifyingName)
2119 {
2120 if (isType (prev2, TOKEN_NAME))
2121 copyToken (st->blockName, prev2);
2122
2123 corkIndex = qualifyFunctionTag (st, prev2);
2124 }
2125 }
2126 else if (isContextualStatement (st) ||
2127 st->declaration == DECL_PROGRAM)
2128 {
2129 const tokenInfo *name_token = prev;
2130
2131 if (isType (name_token, TOKEN_NAME))
2132 copyToken (st->blockName, name_token);
2133 else
2134 {
2135 /* For an anonymous struct or union we use a unique ID
2136 * a number, so that the members can be found.
2137 */
2138 char buf [20]; /* length of "_anon" + digits + null */
2139 sprintf (buf, "__anon%d", ++AnonymousID);
2140 vStringCopyS (st->blockName->name, buf);
2141 st->blockName->type = TOKEN_NAME;
2142 st->blockName->keyword = KEYWORD_NONE;
2143 }
2144 corkIndex = qualifyBlockTag (st, name_token);
2145 }
2146 break;
2147
2148 case TOKEN_KEYWORD:
2149 break;
2150
2151 case TOKEN_SEMICOLON:
2152 case TOKEN_COMMA:
2153 if (insideEnumBody (st))
2154 ;
2155 else if (isType (prev, TOKEN_NAME))
2156 {
2157 if (isContextualKeyword (prev2))
2158 corkIndex = makeTag (prev, st, true, TAG_EXTERN_VAR);
2159 else
2160 corkIndex = qualifyVariableTag (st, prev);
2161 }
2162 else if (isType (prev, TOKEN_ARGS) && isType (prev2, TOKEN_NAME))
2163 {
2164 if (st->isPointer || st->inFunction)
2165 {
2166 /* If it looks like a pointer or we are in a function body then
2167 it's far more likely to be a variable. */
2168 corkIndex = qualifyVariableTag (st, prev2);
2169 }
2170 else
2171 corkIndex = qualifyFunctionDeclTag (st, prev2);
2172 }
2173 break;
2174
2175 default: break;
2176 }
2177
2178 return corkIndex;
2179 }
2180
2181 /* Parses the current file and decides whether to write out and tags that
2182 * are discovered.
2183 */
createTags(const unsigned int nestLevel,statementInfo * const parent)2184 static void createTags (const unsigned int nestLevel,
2185 statementInfo *const parent)
2186 {
2187 statementInfo *const st = newStatement (parent);
2188
2189 DebugStatement ( if (nestLevel > 0) debugParseNest (true, nestLevel); )
2190 while (true)
2191 {
2192 tokenInfo *token;
2193
2194 nextToken (st);
2195 token = activeToken (st);
2196 if (isType (token, TOKEN_BRACE_CLOSE))
2197 {
2198 if (nestLevel > 0)
2199 break;
2200 else
2201 {
2202 verbose ("%s: unexpected closing brace at line %lu\n",
2203 getInputFileName (), getInputLineNumber ());
2204 longjmp (Exception, (int) ExceptionBraceFormattingError);
2205 }
2206 }
2207 else if (isType (token, TOKEN_DOUBLE_COLON))
2208 {
2209 addContext (st, prevToken (st, 1));
2210 advanceToken (st);
2211 }
2212 else
2213 {
2214 int corkIndex = tagCheck (st);
2215 if (isType (token, TOKEN_BRACE_OPEN))
2216 nest (st, nestLevel + 1);
2217 checkStatementEnd (st, corkIndex);
2218 }
2219 }
2220 deleteStatement ();
2221 DebugStatement ( if (nestLevel > 0) debugParseNest (false, nestLevel - 1); )
2222 }
2223
findCTags(const unsigned int passCount)2224 static rescanReason findCTags (const unsigned int passCount)
2225 {
2226 exception_t exception;
2227 rescanReason rescan;
2228 int kind_for_define = VK_DEFINE;
2229 int kind_for_header = VK_HEADER;
2230 int kind_for_param = VK_MACRO_PARAM;
2231 int role_for_macro_undef = VR_MACRO_UNDEF;
2232 int role_for_macro_condition = VR_MACRO_CONDITION;
2233 int role_for_header_system = VR_HEADER_SYSTEM;
2234 int role_for_header_local = VR_HEADER_LOCAL;
2235
2236 Assert (passCount < 3);
2237
2238 AnonymousID = 0;
2239
2240 cppInit ((bool) (passCount > 1), false, false,
2241 true,
2242 kind_for_define, role_for_macro_undef, role_for_macro_condition, kind_for_param,
2243 kind_for_header, role_for_header_system, role_for_header_local,
2244 FIELD_UNKNOWN);
2245
2246 Signature = vStringNew ();
2247
2248 exception = (exception_t) setjmp (Exception);
2249 rescan = RESCAN_NONE;
2250 if (exception == ExceptionNone)
2251 createTags (0, NULL);
2252 else
2253 {
2254 deleteAllStatements ();
2255 if (exception == ExceptionBraceFormattingError && passCount == 1)
2256 {
2257 rescan = RESCAN_FAILED;
2258 verbose ("%s: retrying file with fallback brace matching algorithm\n",
2259 getInputFileName ());
2260 }
2261 }
2262 vStringDelete (Signature);
2263 cppTerminate ();
2264 return rescan;
2265 }
2266
buildKeywordHash(const langType language,unsigned int idx)2267 static void buildKeywordHash (const langType language, unsigned int idx)
2268 {
2269 const size_t count = ARRAY_SIZE (KeywordTable);
2270 size_t i;
2271 for (i = 0 ; i < count ; ++i)
2272 {
2273 const keywordDesc* const p = &KeywordTable [i];
2274 addKeyword (p->name, language, (int) p->id);
2275 }
2276 }
2277
initializeVeraParser(const langType language)2278 static void initializeVeraParser (const langType language)
2279 {
2280 Lang_vera = language;
2281 buildKeywordHash (language, 0);
2282 }
2283
VeraParser(void)2284 extern parserDefinition* VeraParser (void)
2285 {
2286 static const char *const extensions [] = { "vr", "vri", "vrh", NULL };
2287 parserDefinition* def = parserNew ("Vera");
2288 def->kindTable = VeraKinds;
2289 def->kindCount = ARRAY_SIZE (VeraKinds);
2290 def->extensions = extensions;
2291 def->parser2 = findCTags;
2292 def->initialize = initializeVeraParser;
2293 // end: field is not tested.
2294
2295 /* cpreprocessor wants corkQueue. */
2296 def->useCork = CORK_QUEUE;
2297
2298 return def;
2299 }
2300