xref: /Universal-ctags/parsers/vera.c (revision 4861e8e6fd525dd4aacee07861a817897ffba73c)
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