xref: /Universal-ctags/parsers/vera.c (revision 4861e8e6fd525dd4aacee07861a817897ffba73c)
12683f446SJiří Techet /*
22683f446SJiří Techet *   Copyright (c) 1996-2003, Darren Hiebert
32683f446SJiří Techet *
42683f446SJiří Techet *   This source code is released for free distribution under the terms of the
52683f446SJiří Techet *   GNU General Public License version 2 or (at your option) any later version.
62683f446SJiří Techet *
701dc7f65SJiří Techet *   This module contains functions for parsing and scanning Vera
82683f446SJiří Techet *   source files.
92683f446SJiří Techet */
102683f446SJiří Techet 
112683f446SJiří Techet /*
122683f446SJiří Techet *   INCLUDE FILES
132683f446SJiří Techet */
142683f446SJiří Techet #include "general.h"        /* must always come first */
152683f446SJiří Techet 
162683f446SJiří Techet #include <string.h>
172683f446SJiří Techet #include <setjmp.h>
182683f446SJiří Techet 
192683f446SJiří Techet #include "debug.h"
202683f446SJiří Techet #include "entry.h"
212683f446SJiří Techet #include "cpreprocessor.h"
222683f446SJiří Techet #include "keyword.h"
232683f446SJiří Techet #include "options.h"
242683f446SJiří Techet #include "parse.h"
252683f446SJiří Techet #include "read.h"
262683f446SJiří Techet #include "routines.h"
272683f446SJiří Techet #include "selectors.h"
282683f446SJiří Techet #include "xtag.h"
292683f446SJiří Techet 
302683f446SJiří Techet /*
312683f446SJiří Techet *   MACROS
322683f446SJiří Techet */
332683f446SJiří Techet 
342683f446SJiří Techet #define activeToken(st)     ((st)->token [(int) (st)->tokenIndex])
352683f446SJiří Techet #define parentDecl(st)      ((st)->parent == NULL ? \
362683f446SJiří Techet                             DECL_NONE : (st)->parent->declaration)
372683f446SJiří Techet #define isType(token,t)     (bool) ((token)->type == (t))
382683f446SJiří Techet #define insideEnumBody(st)  ((st)->parent == NULL ? false : \
392683f446SJiří Techet                             (bool) ((st)->parent->declaration == DECL_ENUM))
402683f446SJiří Techet #define insideInterfaceBody(st) ((st)->parent == NULL ? false : \
412683f446SJiří Techet                             (bool) ((st)->parent->declaration == DECL_INTERFACE))
422683f446SJiří Techet #define isSignalDirection(token) (bool)(( (token)->keyword == KEYWORD_INPUT  ) ||\
432683f446SJiří Techet 					   ( (token)->keyword == KEYWORD_OUTPUT ) ||\
442683f446SJiří Techet 					   ( (token)->keyword == KEYWORD_INOUT  )  )
452683f446SJiří Techet 
462683f446SJiří Techet #define isOneOf(c,s)        (bool) (strchr ((s), (c)) != NULL)
472683f446SJiří Techet 
482683f446SJiří Techet 
492683f446SJiří Techet /*
502683f446SJiří Techet *   DATA DECLARATIONS
512683f446SJiří Techet */
522683f446SJiří Techet 
532683f446SJiří Techet enum { NumTokens = 3 };
542683f446SJiří Techet 
552683f446SJiří Techet typedef enum eException {
562683f446SJiří Techet 	ExceptionNone, ExceptionEOF, ExceptionFormattingError,
572683f446SJiří Techet 	ExceptionBraceFormattingError
582683f446SJiří Techet } exception_t;
592683f446SJiří Techet 
602683f446SJiří Techet /*  Used to specify type of keyword.
612683f446SJiří Techet  */
622683f446SJiří Techet enum eKeywordId {
637bdd792eSJiří Techet 	KEYWORD_BAD_STATE, KEYWORD_BAD_TRANS,
642683f446SJiří Techet 	KEYWORD_BIND, KEYWORD_BIND_VAR, KEYWORD_BIT,
657bdd792eSJiří Techet 	KEYWORD_CLASS, KEYWORD_CLOCK,
662683f446SJiří Techet 	KEYWORD_CONSTRAINT, KEYWORD_COVERAGE_BLOCK, KEYWORD_COVERAGE_DEF,
677bdd792eSJiří Techet 	KEYWORD_ENUM, KEYWORD_EXTERN,
682683f446SJiří Techet 	KEYWORD_EXTENDS, KEYWORD_EVENT,
697bdd792eSJiří Techet 	KEYWORD_FUNCTION,
702683f446SJiří Techet 	KEYWORD_HDL_NODE,
712683f446SJiří Techet 	KEYWORD_INOUT, KEYWORD_INPUT, KEYWORD_INTEGER, KEYWORD_INTERFACE,
727bdd792eSJiří Techet 	KEYWORD_LOCAL,
732683f446SJiří Techet 	KEYWORD_M_BAD_STATE, KEYWORD_M_BAD_TRANS, KEYWORD_M_STATE, KEYWORD_M_TRANS,
747bdd792eSJiří Techet 	KEYWORD_NEWCOV,
752683f446SJiří Techet 	KEYWORD_NHOLD, KEYWORD_NSAMPLE,
767bdd792eSJiří Techet 	KEYWORD_OUTPUT,
777bdd792eSJiří Techet 	KEYWORD_PACKED, KEYWORD_PORT, KEYWORD_PHOLD,
782683f446SJiří Techet 	KEYWORD_PROGRAM, KEYWORD_PROTECTED, KEYWORD_PSAMPLE, KEYWORD_PUBLIC,
792683f446SJiří Techet 	KEYWORD_SHADOW, KEYWORD_STATE,
807bdd792eSJiří Techet 	KEYWORD_STATIC, KEYWORD_STRING,
817bdd792eSJiří Techet 	KEYWORD_TASK,
827bdd792eSJiří Techet 	KEYWORD_TRANS, KEYWORD_TRANSITION,
837bdd792eSJiří Techet 	KEYWORD_TYPEDEF,
847bdd792eSJiří Techet 	KEYWORD_VIRTUAL, KEYWORD_VOID
852683f446SJiří Techet };
862683f446SJiří Techet typedef int keywordId; /* to allow KEYWORD_NONE */
872683f446SJiří Techet 
882683f446SJiří Techet /*  Used to determine whether keyword is valid for the current language and
892683f446SJiří Techet  *  what its ID is.
902683f446SJiří Techet  */
912683f446SJiří Techet typedef struct sKeywordDesc {
922683f446SJiří Techet 	const char *name;
932683f446SJiří Techet 	keywordId id;
942683f446SJiří Techet } keywordDesc;
952683f446SJiří Techet 
962683f446SJiří Techet /*  Used for reporting the type of object parsed by nextToken ().
972683f446SJiří Techet  */
982683f446SJiří Techet typedef enum eTokenType {
992683f446SJiří Techet 	TOKEN_NONE,          /* none */
1002683f446SJiří Techet 	TOKEN_ARGS,          /* a parenthetical pair and its contents */
1012683f446SJiří Techet 	TOKEN_BRACE_CLOSE,
1022683f446SJiří Techet 	TOKEN_BRACE_OPEN,
1032683f446SJiří Techet 	TOKEN_COLON,         /* the colon character */
1042683f446SJiří Techet 	TOKEN_COMMA,         /* the comma character */
1052683f446SJiří Techet 	TOKEN_DOUBLE_COLON,  /* double colon indicates nested-name-specifier */
1062683f446SJiří Techet 	TOKEN_KEYWORD,
1072683f446SJiří Techet 	TOKEN_NAME,          /* an unknown name */
1082683f446SJiří Techet 	TOKEN_PAREN_NAME,    /* a single name in parentheses */
1092683f446SJiří Techet 	TOKEN_SEMICOLON,     /* the semicolon character */
1102683f446SJiří Techet 	TOKEN_COUNT
1112683f446SJiří Techet } tokenType;
1122683f446SJiří Techet 
1132683f446SJiří Techet /*  This describes the scoping of the current statement.
1142683f446SJiří Techet  */
1152683f446SJiří Techet typedef enum eTagScope {
1162683f446SJiří Techet 	SCOPE_GLOBAL,        /* no storage class specified */
1172683f446SJiří Techet 	SCOPE_STATIC,        /* static storage class */
1182683f446SJiří Techet 	SCOPE_EXTERN,        /* external storage class */
1192683f446SJiří Techet 	SCOPE_TYPEDEF,       /* scoping depends upon context */
1202683f446SJiří Techet 	SCOPE_COUNT
1212683f446SJiří Techet } tagScope;
1222683f446SJiří Techet 
1232683f446SJiří Techet typedef enum eDeclaration {
1242683f446SJiří Techet 	DECL_NONE,
1252683f446SJiří Techet 	DECL_BASE,           /* base type (default) */
1262683f446SJiří Techet 	DECL_CLASS,
1272683f446SJiří Techet 	DECL_ENUM,
1282683f446SJiří Techet 	DECL_EVENT,
1292683f446SJiří Techet 	DECL_FUNCTION,
1302683f446SJiří Techet 	DECL_INTERFACE,
13101dc7f65SJiří Techet 	DECL_PROGRAM,
13201dc7f65SJiří Techet 	DECL_TASK,
1332683f446SJiří Techet 	DECL_COUNT
1342683f446SJiří Techet } declType;
1352683f446SJiří Techet 
1362683f446SJiří Techet typedef enum eVisibilityType {
1372683f446SJiří Techet 	ACCESS_UNDEFINED,
1382683f446SJiří Techet 	ACCESS_LOCAL,
1392683f446SJiří Techet 	ACCESS_PRIVATE,
1402683f446SJiří Techet 	ACCESS_PROTECTED,
1412683f446SJiří Techet 	ACCESS_PUBLIC,
1422683f446SJiří Techet 	ACCESS_COUNT
1432683f446SJiří Techet } accessType;
1442683f446SJiří Techet 
1452683f446SJiří Techet /*  Information about the parent class of a member (if any).
1462683f446SJiří Techet  */
1472683f446SJiří Techet typedef struct sMemberInfo {
1482683f446SJiří Techet 	accessType access;           /* access of current statement */
1492683f446SJiří Techet 	accessType accessDefault;    /* access default for current statement */
1502683f446SJiří Techet } memberInfo;
1512683f446SJiří Techet 
1522683f446SJiří Techet typedef struct sTokenInfo {
1532683f446SJiří Techet 	tokenType     type;
1542683f446SJiří Techet 	keywordId     keyword;
1552683f446SJiří Techet 	vString*      name;          /* the name of the token */
1562683f446SJiří Techet 	unsigned long lineNumber;    /* line number of tag */
1572683f446SJiří Techet 	MIOPos        filePosition;  /* file position of line containing name */
1582683f446SJiří Techet } tokenInfo;
1592683f446SJiří Techet 
1602683f446SJiří Techet typedef enum eImplementation {
1612683f446SJiří Techet 	IMP_DEFAULT,
1622683f446SJiří Techet 	IMP_VIRTUAL,
1632683f446SJiří Techet 	IMP_PURE_VIRTUAL,
1642683f446SJiří Techet 	IMP_COUNT
1652683f446SJiří Techet } impType;
1662683f446SJiří Techet 
1672683f446SJiří Techet /*  Describes the statement currently undergoing analysis.
1682683f446SJiří Techet  */
1692683f446SJiří Techet typedef struct sStatementInfo {
1702683f446SJiří Techet 	tagScope	scope;
1712683f446SJiří Techet 	declType	declaration;    /* specifier associated with TOKEN_SPEC */
1722683f446SJiří Techet 	bool		gotName;        /* was a name parsed yet? */
1732683f446SJiří Techet 	bool		haveQualifyingName;  /* do we have a name we are considering? */
1742683f446SJiří Techet 	bool		gotParenName;   /* was a name inside parentheses parsed yet? */
1752683f446SJiří Techet 	bool		gotArgs;        /* was a list of parameters parsed yet? */
1762683f446SJiří Techet 	bool		isPointer;      /* is 'name' a pointer? */
1772683f446SJiří Techet 	bool     inFunction;     /* are we inside of a function? */
1782683f446SJiří Techet 	bool		assignment;     /* have we handled an '='? */
1792683f446SJiří Techet 	bool		notVariable;    /* has a variable declaration been disqualified ? */
1802683f446SJiří Techet 	impType		implementation; /* abstract or concrete implementation? */
1812683f446SJiří Techet 	unsigned int tokenIndex;    /* currently active token */
1822683f446SJiří Techet 	tokenInfo*	token [(int) NumTokens];
1832683f446SJiří Techet 	tokenInfo*	context;        /* accumulated scope of current statement */
1842683f446SJiří Techet 	tokenInfo*	blockName;      /* name of current block */
1852683f446SJiří Techet 	memberInfo	member;         /* information regarding parent class/struct */
1862683f446SJiří Techet 	vString*	parentClasses;  /* parent classes */
1872683f446SJiří Techet 	struct sStatementInfo *parent;  /* statement we are nested within */
1882683f446SJiří Techet } statementInfo;
1892683f446SJiří Techet 
1902683f446SJiří Techet /*  Describes the type of tag being generated.
1912683f446SJiří Techet  */
1922683f446SJiří Techet typedef enum eTagType {
1932683f446SJiří Techet 	TAG_UNDEFINED,
1942683f446SJiří Techet 	TAG_CLASS,       /* class name */
1952683f446SJiří Techet 	TAG_ENUM,        /* enumeration name */
1962683f446SJiří Techet 	TAG_ENUMERATOR,  /* enumerator (enumeration value) */
1972683f446SJiří Techet 	TAG_EVENT,       /* event */
1982683f446SJiří Techet 	TAG_FUNCTION,    /* function definition */
1992683f446SJiří Techet 	TAG_INTERFACE,   /* interface declaration */
2002683f446SJiří Techet 	TAG_LOCAL,       /* local variable definition */
2012683f446SJiří Techet 	TAG_MEMBER,      /* structure, class or interface member */
2022683f446SJiří Techet 	TAG_PROGRAM,     /* program name */
2032683f446SJiří Techet 	TAG_PROTOTYPE,   /* function prototype or declaration */
204b9c6970bSJiří Techet 	TAG_SIGNAL,      /* signal name */
2052683f446SJiří Techet 	TAG_TASK,        /* task name */
2062683f446SJiří Techet 	TAG_TYPEDEF,     /* typedef name / D alias name */
2072683f446SJiří Techet 	TAG_VARIABLE,    /* variable definition */
2082683f446SJiří Techet 	TAG_EXTERN_VAR,  /* external variable declaration */
2092683f446SJiří Techet 	TAG_LABEL,       /* goto label */
2102683f446SJiří Techet 	TAG_COUNT        /* must be last */
2112683f446SJiří Techet } tagType;
2122683f446SJiří Techet 
2132683f446SJiří Techet typedef struct sParenInfo {
2142683f446SJiří Techet 	bool isPointer;
2152683f446SJiří Techet 	bool isParamList;
2162683f446SJiří Techet 	bool isNameCandidate;
2172683f446SJiří Techet 	bool invalidContents;
2182683f446SJiří Techet 	bool nestedArgs;
2192683f446SJiří Techet 	unsigned int parameterCount;
2202683f446SJiří Techet } parenInfo;
2212683f446SJiří Techet 
2222683f446SJiří Techet /*
2232683f446SJiří Techet *   DATA DEFINITIONS
2242683f446SJiří Techet */
2252683f446SJiří Techet 
2262683f446SJiří Techet static jmp_buf Exception;
2272683f446SJiří Techet 
2282683f446SJiří Techet static langType Lang_vera;
2292683f446SJiří Techet static vString *Signature;
2302683f446SJiří Techet static bool CollectingSignature;
2312683f446SJiří Techet 
2322683f446SJiří Techet /* Number used to uniquely identify anonymous structs and unions. */
2332683f446SJiří Techet static int AnonymousID = 0;
2342683f446SJiří Techet 
2352683f446SJiří Techet #define COMMONK_UNDEFINED -1
2362683f446SJiří Techet 
2372683f446SJiří Techet 
2382683f446SJiří Techet /* Used to index into the VeraKinds table. */
2392683f446SJiří Techet typedef enum {
2402683f446SJiří Techet 	VR_MACRO_UNDEF,
2412683f446SJiří Techet 	VR_MACRO_CONDITION,
2422683f446SJiří Techet } veraMacroRole;
2432683f446SJiří Techet 
2442683f446SJiří Techet static roleDefinition VeraMacroRoles [] = {
2452683f446SJiří Techet 	RoleTemplateUndef,
2462683f446SJiří Techet 	RoleTemplateCondition,
2472683f446SJiří Techet };
2482683f446SJiří Techet 
2492683f446SJiří Techet 
2502683f446SJiří Techet typedef enum {
2512683f446SJiří Techet 	VR_HEADER_SYSTEM,
2522683f446SJiří Techet 	VR_HEADER_LOCAL,
2532683f446SJiří Techet } veraHeaderRole;
2542683f446SJiří Techet 
2552683f446SJiří Techet static roleDefinition VeraHeaderRoles [] = {
2562683f446SJiří Techet 	RoleTemplateSystem,
2572683f446SJiří Techet 	RoleTemplateLocal,
2582683f446SJiří Techet };
2592683f446SJiří Techet 
2602683f446SJiří Techet typedef enum {
2612683f446SJiří Techet 	VK_UNDEFINED = COMMONK_UNDEFINED,
2622683f446SJiří Techet 	VK_CLASS, VK_DEFINE, VK_ENUMERATOR, VK_FUNCTION,
2632683f446SJiří Techet 	VK_ENUMERATION, VK_INTERFACE, VK_LOCAL, VK_MEMBER, VK_PROGRAM, VK_PROTOTYPE,
2642683f446SJiří Techet 	VK_SIGNAL, VK_TASK, VK_TYPEDEF, VK_VARIABLE,
2652683f446SJiří Techet 	VK_EXTERN_VARIABLE, VK_HEADER, VK_MACRO_PARAM,
2662683f446SJiří Techet } veraKind;
2672683f446SJiří Techet 
2682683f446SJiří Techet static kindDefinition VeraKinds [] = {
2692683f446SJiří Techet 	{ true,  'c', "class",      "classes"},
2702683f446SJiří Techet 	{ true,  'd', "macro",      "macro definitions",
2712683f446SJiří Techet 	  .referenceOnly = false, ATTACH_ROLES(VeraMacroRoles)},
2722683f446SJiří Techet 	{ true,  'e', "enumerator", "enumerators (values inside an enumeration)"},
2732683f446SJiří Techet 	{ true,  'f', "function",   "function definitions"},
2742683f446SJiří Techet 	{ true,  'g', "enum",       "enumeration names"},
2752683f446SJiří Techet 	{ true,  'i', "interface",  "interfaces"},
2762683f446SJiří Techet 	{ false, 'l', "local",      "local variables"},
2772683f446SJiří Techet 	{ true,  'm', "member",     "class, struct, and union members"},
2782683f446SJiří Techet 	{ true,  'p', "program",    "programs"},
2792683f446SJiří Techet 	{ false, 'P', "prototype",  "function prototypes"},
2802683f446SJiří Techet 	{ true,  's', "signal",     "signals"},
2812683f446SJiří Techet 	{ true,  't', "task",       "tasks"},
2822683f446SJiří Techet 	{ true,  'T', "typedef",    "typedefs"},
2832683f446SJiří Techet 	{ true,  'v', "variable",   "variable definitions"},
2842683f446SJiří Techet 	{ false, 'x', "externvar",  "external variable declarations"},
2852683f446SJiří Techet 	{ true,  'h', "header",     "included header files",
2862683f446SJiří Techet 	  .referenceOnly = true, ATTACH_ROLES(VeraHeaderRoles)},
2872683f446SJiří Techet 	{ false, 'D', "macroParameter", "cpp macro parameters"},
2882683f446SJiří Techet };
2892683f446SJiří Techet 
2902683f446SJiří Techet static const keywordDesc KeywordTable [] = {
291*eb1b3c1bSJiří Techet      { "bad_state",       KEYWORD_BAD_STATE,      },
292*eb1b3c1bSJiří Techet      { "bad_trans",       KEYWORD_BAD_TRANS,      },
293*eb1b3c1bSJiří Techet      { "bind",            KEYWORD_BIND,           },
294*eb1b3c1bSJiří Techet      { "bind_var",        KEYWORD_BIND_VAR,       },
295*eb1b3c1bSJiří Techet      { "bit",             KEYWORD_BIT,            },
296*eb1b3c1bSJiří Techet      { "class",           KEYWORD_CLASS,          },
297*eb1b3c1bSJiří Techet      { "CLOCK",           KEYWORD_CLOCK,          },
298*eb1b3c1bSJiří Techet      { "constraint",      KEYWORD_CONSTRAINT,     },
299*eb1b3c1bSJiří Techet      { "coverage_block",  KEYWORD_COVERAGE_BLOCK, },
300*eb1b3c1bSJiří Techet      { "coverage_def",    KEYWORD_COVERAGE_DEF,   },
301*eb1b3c1bSJiří Techet      { "enum",            KEYWORD_ENUM,           },
302*eb1b3c1bSJiří Techet      { "event",           KEYWORD_EVENT,          },
303*eb1b3c1bSJiří Techet      { "extends",         KEYWORD_EXTENDS,        },
304*eb1b3c1bSJiří Techet      { "extern",          KEYWORD_EXTERN,         },
305*eb1b3c1bSJiří Techet      { "function",        KEYWORD_FUNCTION,       },
306*eb1b3c1bSJiří Techet      { "hdl_node",        KEYWORD_HDL_NODE,       },
307*eb1b3c1bSJiří Techet      { "inout",           KEYWORD_INOUT,          },
308*eb1b3c1bSJiří Techet      { "input",           KEYWORD_INPUT,          },
309*eb1b3c1bSJiří Techet      { "integer",         KEYWORD_INTEGER,        },
310*eb1b3c1bSJiří Techet      { "interface",       KEYWORD_INTERFACE,      },
311*eb1b3c1bSJiří Techet      { "local",           KEYWORD_LOCAL,          },
312*eb1b3c1bSJiří Techet      { "m_bad_state",     KEYWORD_M_BAD_STATE,    },
313*eb1b3c1bSJiří Techet      { "m_bad_trans",     KEYWORD_M_BAD_TRANS,    },
314*eb1b3c1bSJiří Techet      { "m_state",         KEYWORD_M_STATE,        },
315*eb1b3c1bSJiří Techet      { "m_trans",         KEYWORD_M_TRANS,        },
316*eb1b3c1bSJiří Techet      { "newcov",          KEYWORD_NEWCOV,         },
317*eb1b3c1bSJiří Techet      { "NHOLD",           KEYWORD_NHOLD,          },
318*eb1b3c1bSJiří Techet      { "NSAMPLE",         KEYWORD_NSAMPLE,        },
319*eb1b3c1bSJiří Techet      { "output",          KEYWORD_OUTPUT,         },
320*eb1b3c1bSJiří Techet      { "packed",          KEYWORD_PACKED,         },
321*eb1b3c1bSJiří Techet      { "PHOLD",           KEYWORD_PHOLD,          },
322*eb1b3c1bSJiří Techet      { "port",            KEYWORD_PORT,           },
323*eb1b3c1bSJiří Techet      { "program",         KEYWORD_PROGRAM,        },
324*eb1b3c1bSJiří Techet      { "protected",       KEYWORD_PROTECTED,      },
325*eb1b3c1bSJiří Techet      { "PSAMPLE",         KEYWORD_PSAMPLE,        },
326*eb1b3c1bSJiří Techet      { "public",          KEYWORD_PUBLIC,         },
327*eb1b3c1bSJiří Techet      { "shadow",          KEYWORD_SHADOW,         },
328*eb1b3c1bSJiří Techet      { "state",           KEYWORD_STATE,          },
329*eb1b3c1bSJiří Techet      { "static",          KEYWORD_STATIC,         },
330*eb1b3c1bSJiří Techet      { "string",          KEYWORD_STRING,         },
331*eb1b3c1bSJiří Techet      { "task",            KEYWORD_TASK,           },
332*eb1b3c1bSJiří Techet      { "trans",           KEYWORD_TRANS,          },
333*eb1b3c1bSJiří Techet      { "transition",      KEYWORD_TRANSITION,     },
334*eb1b3c1bSJiří Techet      { "typedef",         KEYWORD_TYPEDEF,        },
335*eb1b3c1bSJiří Techet      { "virtual",         KEYWORD_VIRTUAL,        },
336*eb1b3c1bSJiří Techet      { "void",            KEYWORD_VOID,           },
3372683f446SJiří Techet };
3382683f446SJiří Techet 
3392683f446SJiří Techet /*
3402683f446SJiří Techet *   FUNCTION PROTOTYPES
3412683f446SJiří Techet */
3422683f446SJiří Techet static void createTags (const unsigned int nestLevel, statementInfo *const parent);
3432683f446SJiří Techet 
3442683f446SJiří Techet /*
3452683f446SJiří Techet *   FUNCTION DEFINITIONS
3462683f446SJiří Techet */
3472683f446SJiří Techet 
3482683f446SJiří Techet /*
3492683f446SJiří Techet *   Token management
3502683f446SJiří Techet */
3512683f446SJiří Techet 
initToken(tokenInfo * const token)3522683f446SJiří Techet static void initToken (tokenInfo* const token)
3532683f446SJiří Techet {
3542683f446SJiří Techet 	token->type			= TOKEN_NONE;
3552683f446SJiří Techet 	token->keyword		= KEYWORD_NONE;
3562683f446SJiří Techet 	token->lineNumber	= getInputLineNumber ();
3572683f446SJiří Techet 	token->filePosition	= getInputFilePosition ();
3582683f446SJiří Techet 	vStringClear (token->name);
3592683f446SJiří Techet }
3602683f446SJiří Techet 
advanceToken(statementInfo * const st)3612683f446SJiří Techet static void advanceToken (statementInfo* const st)
3622683f446SJiří Techet {
3632683f446SJiří Techet 	if (st->tokenIndex >= (unsigned int) NumTokens - 1)
3642683f446SJiří Techet 		st->tokenIndex = 0;
3652683f446SJiří Techet 	else
3662683f446SJiří Techet 		++st->tokenIndex;
3672683f446SJiří Techet 	initToken (st->token [st->tokenIndex]);
3682683f446SJiří Techet }
3692683f446SJiří Techet 
prevToken(const statementInfo * const st,unsigned int n)3702683f446SJiří Techet static tokenInfo *prevToken (const statementInfo *const st, unsigned int n)
3712683f446SJiří Techet {
3722683f446SJiří Techet 	unsigned int tokenIndex;
3732683f446SJiří Techet 	unsigned int num = (unsigned int) NumTokens;
3742683f446SJiří Techet 	Assert (n < num);
3752683f446SJiří Techet 	tokenIndex = (st->tokenIndex + num - n) % num;
3762683f446SJiří Techet 	return st->token [tokenIndex];
3772683f446SJiří Techet }
3782683f446SJiří Techet 
setToken(statementInfo * const st,const tokenType type)3792683f446SJiří Techet static void setToken (statementInfo *const st, const tokenType type)
3802683f446SJiří Techet {
3812683f446SJiří Techet 	tokenInfo *token;
3822683f446SJiří Techet 	token = activeToken (st);
3832683f446SJiří Techet 	initToken (token);
3842683f446SJiří Techet 	token->type = type;
3852683f446SJiří Techet }
3862683f446SJiří Techet 
retardToken(statementInfo * const st)3872683f446SJiří Techet static void retardToken (statementInfo *const st)
3882683f446SJiří Techet {
3892683f446SJiří Techet 	if (st->tokenIndex == 0)
3902683f446SJiří Techet 		st->tokenIndex = (unsigned int) NumTokens - 1;
3912683f446SJiří Techet 	else
3922683f446SJiří Techet 		--st->tokenIndex;
3932683f446SJiří Techet 	setToken (st, TOKEN_NONE);
3942683f446SJiří Techet }
3952683f446SJiří Techet 
newToken(void)3962683f446SJiří Techet static tokenInfo *newToken (void)
3972683f446SJiří Techet {
3982683f446SJiří Techet 	tokenInfo *const token = xMalloc (1, tokenInfo);
3992683f446SJiří Techet 	token->name = vStringNew ();
4002683f446SJiří Techet 	initToken (token);
4012683f446SJiří Techet 	return token;
4022683f446SJiří Techet }
4032683f446SJiří Techet 
deleteToken(tokenInfo * const token)4042683f446SJiří Techet static void deleteToken (tokenInfo *const token)
4052683f446SJiří Techet {
4062683f446SJiří Techet 	if (token != NULL)
4072683f446SJiří Techet 	{
4082683f446SJiří Techet 		vStringDelete (token->name);
4092683f446SJiří Techet 		eFree (token);
4102683f446SJiří Techet 	}
4112683f446SJiří Techet }
4122683f446SJiří Techet 
accessString(const accessType access)4132683f446SJiří Techet static const char *accessString (const accessType access)
4142683f446SJiří Techet {
4152683f446SJiří Techet 	static const char *const names [] = {
416b9c6970bSJiří Techet 		"?", "local", "private", "protected", "public"
4172683f446SJiří Techet 	};
4182683f446SJiří Techet 	Assert (ARRAY_SIZE (names) == ACCESS_COUNT);
4192683f446SJiří Techet 	Assert ((int) access < ACCESS_COUNT);
4202683f446SJiří Techet 	return names [(int) access];
4212683f446SJiří Techet }
4222683f446SJiří Techet 
4232683f446SJiří Techet /*
4242683f446SJiří Techet *   Debugging functions
4252683f446SJiří Techet */
4262683f446SJiří Techet 
4272683f446SJiří Techet #ifdef DEBUG
4282683f446SJiří Techet 
4292683f446SJiří Techet #define boolString(c)   ((c) ? "true" : "false")
4302683f446SJiří Techet 
tokenString(const tokenType type)4312683f446SJiří Techet static const char *tokenString (const tokenType type)
4322683f446SJiří Techet {
4332683f446SJiří Techet 	static const char *const names [] = {
4342683f446SJiří Techet 		"none", "args", "}", "{", "colon", "comma", "double colon", "keyword",
43501dc7f65SJiří Techet 		"name", "paren-name", "semicolon"
4362683f446SJiří Techet 	};
4372683f446SJiří Techet 	Assert (ARRAY_SIZE (names) == TOKEN_COUNT);
4382683f446SJiří Techet 	Assert ((int) type < TOKEN_COUNT);
4392683f446SJiří Techet 	return names [(int) type];
4402683f446SJiří Techet }
4412683f446SJiří Techet 
scopeString(const tagScope scope)4422683f446SJiří Techet static const char *scopeString (const tagScope scope)
4432683f446SJiří Techet {
4442683f446SJiří Techet 	static const char *const names [] = {
44501dc7f65SJiří Techet 		"global", "static", "extern", "typedef"
4462683f446SJiří Techet 	};
4472683f446SJiří Techet 	Assert (ARRAY_SIZE (names) == SCOPE_COUNT);
4482683f446SJiří Techet 	Assert ((int) scope < SCOPE_COUNT);
4492683f446SJiří Techet 	return names [(int) scope];
4502683f446SJiří Techet }
4512683f446SJiří Techet 
declString(const declType declaration)4522683f446SJiří Techet static const char *declString (const declType declaration)
4532683f446SJiří Techet {
4542683f446SJiří Techet 	static const char *const names [] = {
45501dc7f65SJiří Techet 		"?", "base", "class", "enum", "event", "function",
45601dc7f65SJiří Techet 		"interface",
45701dc7f65SJiří Techet 		"program", "task"
4582683f446SJiří Techet 	};
4592683f446SJiří Techet 	Assert (ARRAY_SIZE (names) == DECL_COUNT);
4602683f446SJiří Techet 	Assert ((int) declaration < DECL_COUNT);
4612683f446SJiří Techet 	return names [(int) declaration];
4622683f446SJiří Techet }
4632683f446SJiří Techet 
keywordString(const keywordId keyword)4642683f446SJiří Techet static const char *keywordString (const keywordId keyword)
4652683f446SJiří Techet {
4662683f446SJiří Techet 	const size_t count = ARRAY_SIZE (KeywordTable);
4672683f446SJiří Techet 	const char *name = "none";
4682683f446SJiří Techet 	size_t i;
4692683f446SJiří Techet 	for (i = 0  ;  i < count  ;  ++i)
4702683f446SJiří Techet 	{
4712683f446SJiří Techet 		const keywordDesc *p = &KeywordTable [i];
4722683f446SJiří Techet 		if (p->id == keyword)
4732683f446SJiří Techet 		{
4742683f446SJiří Techet 			name = p->name;
4752683f446SJiří Techet 			break;
4762683f446SJiří Techet 		}
4772683f446SJiří Techet 	}
4782683f446SJiří Techet 	return name;
4792683f446SJiří Techet }
4802683f446SJiří Techet 
pt(tokenInfo * const token)4812683f446SJiří Techet static void CTAGS_ATTR_UNUSED pt (tokenInfo *const token)
4822683f446SJiří Techet {
4832683f446SJiří Techet 	if (isType (token, TOKEN_NAME))
4842683f446SJiří Techet 		printf ("type: %-12s: %-13s   line: %lu\n",
4852683f446SJiří Techet 			tokenString (token->type), vStringValue (token->name),
4862683f446SJiří Techet 			token->lineNumber);
4872683f446SJiří Techet 	else if (isType (token, TOKEN_KEYWORD))
4882683f446SJiří Techet 		printf ("type: %-12s: %-13s   line: %lu\n",
4892683f446SJiří Techet 			tokenString (token->type), keywordString (token->keyword),
4902683f446SJiří Techet 			token->lineNumber);
4912683f446SJiří Techet 	else
4922683f446SJiří Techet 		printf ("type: %-12s                  line: %lu\n",
4932683f446SJiří Techet 			tokenString (token->type), token->lineNumber);
4942683f446SJiří Techet }
4952683f446SJiří Techet 
ps(statementInfo * const st)4962683f446SJiří Techet static void CTAGS_ATTR_UNUSED ps (statementInfo *const st)
4972683f446SJiří Techet {
4982683f446SJiří Techet #define P	"[%-7u]"
4992683f446SJiří Techet 	static unsigned int id = 0;
5002683f446SJiří Techet 	unsigned int i;
5012683f446SJiří Techet 	printf (P"scope: %s   decl: %s   gotName: %s   gotParenName: %s\n", id,
5022683f446SJiří Techet 		scopeString (st->scope), declString (st->declaration),
5032683f446SJiří Techet 		boolString (st->gotName), boolString (st->gotParenName));
5042683f446SJiří Techet 	printf (P"haveQualifyingName: %s\n", id, boolString (st->haveQualifyingName));
5052683f446SJiří Techet 	printf (P"access: %s   default: %s\n", id, accessString (st->member.access),
5062683f446SJiří Techet 		accessString (st->member.accessDefault));
5072683f446SJiří Techet 	printf (P"token  : ", id);
5082683f446SJiří Techet 	pt (activeToken (st));
5092683f446SJiří Techet 	for (i = 1  ;  i < (unsigned int) NumTokens  ;  ++i)
5102683f446SJiří Techet 	{
5112683f446SJiří Techet 		printf (P"prev %u : ", id, i);
5122683f446SJiří Techet 		pt (prevToken (st, i));
5132683f446SJiří Techet 	}
5142683f446SJiří Techet 	printf (P"context: ", id);
5152683f446SJiří Techet 	pt (st->context);
5162683f446SJiří Techet 	id++;
5172683f446SJiří Techet #undef P
5182683f446SJiří Techet }
5192683f446SJiří Techet 
5202683f446SJiří Techet #endif
5212683f446SJiří Techet 
5222683f446SJiří Techet /*
5232683f446SJiří Techet *   Statement management
5242683f446SJiří Techet */
5252683f446SJiří Techet 
isContextualKeyword(const tokenInfo * const token)5262683f446SJiří Techet static bool isContextualKeyword (const tokenInfo *const token)
5272683f446SJiří Techet {
5282683f446SJiří Techet 	bool result;
5292683f446SJiří Techet 	switch (token->keyword)
5302683f446SJiří Techet 	{
5312683f446SJiří Techet 		case KEYWORD_CLASS:
5322683f446SJiří Techet 		case KEYWORD_ENUM:
5332683f446SJiří Techet 		case KEYWORD_INTERFACE:
5342683f446SJiří Techet 			result = true;
5352683f446SJiří Techet 			break;
5362683f446SJiří Techet 
5372683f446SJiří Techet 		default: result = false; break;
5382683f446SJiří Techet 	}
5392683f446SJiří Techet 	return result;
5402683f446SJiří Techet }
5412683f446SJiří Techet 
isContextualStatement(const statementInfo * const st)5422683f446SJiří Techet static bool isContextualStatement (const statementInfo *const st)
5432683f446SJiří Techet {
5442683f446SJiří Techet 	bool result = false;
5452683f446SJiří Techet 	if (st != NULL) switch (st->declaration)
5462683f446SJiří Techet 	{
5472683f446SJiří Techet 		case DECL_CLASS:
5482683f446SJiří Techet 		case DECL_ENUM:
5492683f446SJiří Techet 		case DECL_INTERFACE:
5502683f446SJiří Techet 			result = true;
5512683f446SJiří Techet 			break;
5522683f446SJiří Techet 
5532683f446SJiří Techet 		default: result = false; break;
5542683f446SJiří Techet 	}
5552683f446SJiří Techet 	return result;
5562683f446SJiří Techet }
5572683f446SJiří Techet 
isMember(const statementInfo * const st)5582683f446SJiří Techet static bool isMember (const statementInfo *const st)
5592683f446SJiří Techet {
5602683f446SJiří Techet 	bool result;
5612683f446SJiří Techet 	if (isType (st->context, TOKEN_NAME))
5622683f446SJiří Techet 		result = true;
5632683f446SJiří Techet 	else
5642683f446SJiří Techet 		result = (bool)
5652683f446SJiří Techet 			(st->parent != NULL && isContextualStatement (st->parent));
5662683f446SJiří Techet 	return result;
5672683f446SJiří Techet }
5682683f446SJiří Techet 
initMemberInfo(statementInfo * const st)5692683f446SJiří Techet static void initMemberInfo (statementInfo *const st)
5702683f446SJiří Techet {
5712683f446SJiří Techet 	accessType accessDefault = ACCESS_UNDEFINED;
5722683f446SJiří Techet 	if (st->parent != NULL) switch (st->parent->declaration)
5732683f446SJiří Techet 	{
5742683f446SJiří Techet 		case DECL_ENUM:
57523c6e73eSJiří Techet 			accessDefault = ACCESS_UNDEFINED;
5762683f446SJiří Techet 			break;
5772683f446SJiří Techet 
5782683f446SJiří Techet 		case DECL_CLASS:
5792683f446SJiří Techet 			accessDefault = ACCESS_PRIVATE;
5802683f446SJiří Techet 			break;
5812683f446SJiří Techet 
5822683f446SJiří Techet 		case DECL_INTERFACE:
5832683f446SJiří Techet 			accessDefault = ACCESS_PUBLIC;
5842683f446SJiří Techet 			break;
5852683f446SJiří Techet 
5862683f446SJiří Techet 		default: break;
5872683f446SJiří Techet 	}
5882683f446SJiří Techet 	st->member.accessDefault = accessDefault;
5892683f446SJiří Techet 	st->member.access		 = accessDefault;
5902683f446SJiří Techet }
5912683f446SJiří Techet 
reinitStatement(statementInfo * const st,const bool partial)5922683f446SJiří Techet static void reinitStatement (statementInfo *const st, const bool partial)
5932683f446SJiří Techet {
5942683f446SJiří Techet 	unsigned int i;
5952683f446SJiří Techet 
5962683f446SJiří Techet 	if (! partial)
5972683f446SJiří Techet 	{
5982683f446SJiří Techet 		st->scope = SCOPE_GLOBAL;
5992683f446SJiří Techet 		if (isContextualStatement (st->parent))
6002683f446SJiří Techet 			st->declaration = DECL_BASE;
6012683f446SJiří Techet 		else
6022683f446SJiří Techet 			st->declaration = DECL_NONE;
6032683f446SJiří Techet 	}
6042683f446SJiří Techet 	st->gotParenName	= false;
6052683f446SJiří Techet 	st->isPointer		= false;
6062683f446SJiří Techet 	st->inFunction		= false;
6072683f446SJiří Techet 	st->assignment		= false;
6082683f446SJiří Techet 	st->notVariable		= false;
6092683f446SJiří Techet 	st->implementation	= IMP_DEFAULT;
6102683f446SJiří Techet 	st->gotArgs			= false;
6112683f446SJiří Techet 	st->gotName			= false;
6122683f446SJiří Techet 	st->haveQualifyingName = false;
6132683f446SJiří Techet 	st->tokenIndex		= 0;
6142683f446SJiří Techet 
6152683f446SJiří Techet 	if (st->parent != NULL)
6162683f446SJiří Techet 		st->inFunction = st->parent->inFunction;
6172683f446SJiří Techet 
6182683f446SJiří Techet 	for (i = 0  ;  i < (unsigned int) NumTokens  ;  ++i)
6192683f446SJiří Techet 		initToken (st->token [i]);
6202683f446SJiří Techet 
6212683f446SJiří Techet 	initToken (st->context);
6222683f446SJiří Techet 
6232683f446SJiří Techet 	/*	Keep the block name, so that a variable following after a comma will
6242683f446SJiří Techet 	 *	still have the structure name.
6252683f446SJiří Techet 	 */
6262683f446SJiří Techet 	if (! partial)
6272683f446SJiří Techet 		initToken (st->blockName);
6282683f446SJiří Techet 
6292683f446SJiří Techet 	vStringClear (st->parentClasses);
6302683f446SJiří Techet 
6312683f446SJiří Techet 	/*  Init member info.
6322683f446SJiří Techet 	 */
6332683f446SJiří Techet 	if (! partial)
6342683f446SJiří Techet 		st->member.access = st->member.accessDefault;
6352683f446SJiří Techet }
6362683f446SJiří Techet 
initStatement(statementInfo * const st,statementInfo * const parent)6372683f446SJiří Techet static void initStatement (statementInfo *const st, statementInfo *const parent)
6382683f446SJiří Techet {
6392683f446SJiří Techet 	st->parent = parent;
6402683f446SJiří Techet 	initMemberInfo (st);
6412683f446SJiří Techet 	reinitStatement (st, false);
6422683f446SJiří Techet }
6432683f446SJiří Techet 
6442683f446SJiří Techet /*
6452683f446SJiří Techet *   Tag generation functions
6462683f446SJiří Techet */
6472683f446SJiří Techet #define veraTagKind(type) veraTagKindFull(type, true)
6482683f446SJiří Techet #define veraTagKindNoAssert(type) veraTagKindFull(type, false)
veraTagKindFull(const tagType type,bool with_assert)6492683f446SJiří Techet static veraKind veraTagKindFull (const tagType type, bool with_assert) {
6502683f446SJiří Techet 	veraKind result = VK_UNDEFINED;
6512683f446SJiří Techet 	switch (type)
6522683f446SJiří Techet 	{
6532683f446SJiří Techet 		case TAG_CLASS:      result = VK_CLASS;           break;
6542683f446SJiří Techet 		case TAG_ENUM:       result = VK_ENUMERATION;     break;
6552683f446SJiří Techet 		case TAG_ENUMERATOR: result = VK_ENUMERATOR;      break;
6562683f446SJiří Techet 		case TAG_FUNCTION:   result = VK_FUNCTION;        break;
6572683f446SJiří Techet 		case TAG_INTERFACE:  result = VK_INTERFACE;       break;
6582683f446SJiří Techet 		case TAG_LOCAL:      result = VK_LOCAL;           break;
6592683f446SJiří Techet 		case TAG_MEMBER:     result = VK_MEMBER;          break;
6602683f446SJiří Techet 		case TAG_PROGRAM:    result = VK_PROGRAM;         break;
6612683f446SJiří Techet 		case TAG_PROTOTYPE:  result = VK_PROTOTYPE;       break;
6622683f446SJiří Techet 		case TAG_SIGNAL:     result = VK_SIGNAL;          break;
6632683f446SJiří Techet 		case TAG_TASK:       result = VK_TASK;            break;
6642683f446SJiří Techet 		case TAG_TYPEDEF:    result = VK_TYPEDEF;         break;
6652683f446SJiří Techet 		case TAG_VARIABLE:   result = VK_VARIABLE;        break;
6662683f446SJiří Techet 		case TAG_EXTERN_VAR: result = VK_EXTERN_VARIABLE; break;
6672683f446SJiří Techet 
6682683f446SJiří Techet 		default: if (with_assert) Assert ("Bad Vera tag type" == NULL); break;
6692683f446SJiří Techet 	}
6702683f446SJiří Techet 	return result;
6712683f446SJiří Techet }
6722683f446SJiří Techet 
kindIndexForType(const tagType type)6732683f446SJiří Techet static int kindIndexForType (const tagType type)
6742683f446SJiří Techet {
67523c6e73eSJiří Techet 	return veraTagKind (type);
6762683f446SJiří Techet }
6772683f446SJiří Techet 
tagName(const tagType type)6782683f446SJiří Techet static const char *tagName (const tagType type)
6792683f446SJiří Techet {
68023c6e73eSJiří Techet 	return VeraKinds [veraTagKind (type)].name;
6812683f446SJiří Techet }
6822683f446SJiří Techet 
includeTag(const tagType type,const bool isFileScope)6832683f446SJiří Techet static bool includeTag (const tagType type, const bool isFileScope)
6842683f446SJiří Techet {
6852683f446SJiří Techet 	bool result;
6862683f446SJiří Techet 	int k = COMMONK_UNDEFINED;
6872683f446SJiří Techet 
6882683f446SJiří Techet 	if (isFileScope && !isXtagEnabled(XTAG_FILE_SCOPE))
6892683f446SJiří Techet 		return false;
6902683f446SJiří Techet 
69123c6e73eSJiří Techet 	k = veraTagKindNoAssert (type);
6922683f446SJiří Techet 	if (k == COMMONK_UNDEFINED)
6932683f446SJiří Techet 		result = false;
6942683f446SJiří Techet 	else
6952683f446SJiří Techet 		result = isInputLanguageKindEnabled (k);
6962683f446SJiří Techet 
6972683f446SJiří Techet 	return result;
6982683f446SJiří Techet }
6992683f446SJiří Techet 
declToTagType(const declType declaration)7002683f446SJiří Techet static tagType declToTagType (const declType declaration)
7012683f446SJiří Techet {
7022683f446SJiří Techet 	tagType type = TAG_UNDEFINED;
7032683f446SJiří Techet 
7042683f446SJiří Techet 	switch (declaration)
7052683f446SJiří Techet 	{
7062683f446SJiří Techet 		case DECL_CLASS:        type = TAG_CLASS;       break;
7072683f446SJiří Techet 		case DECL_ENUM:         type = TAG_ENUM;        break;
7082683f446SJiří Techet 		case DECL_EVENT:        type = TAG_EVENT;       break;
7092683f446SJiří Techet 		case DECL_FUNCTION:     type = TAG_FUNCTION;    break;
7102683f446SJiří Techet 		case DECL_INTERFACE:    type = TAG_INTERFACE;   break;
7112683f446SJiří Techet 		case DECL_PROGRAM:      type = TAG_PROGRAM;     break;
7122683f446SJiří Techet 		case DECL_TASK:         type = TAG_TASK;        break;
7132683f446SJiří Techet 
7142683f446SJiří Techet 		default: Assert ("Unexpected declaration" == NULL); break;
7152683f446SJiří Techet 	}
7162683f446SJiří Techet 	return type;
7172683f446SJiří Techet }
7182683f446SJiří Techet 
accessField(const statementInfo * const st)7192683f446SJiří Techet static const char* accessField (const statementInfo *const st)
7202683f446SJiří Techet {
7212683f446SJiří Techet 	const char* result = NULL;
7222683f446SJiří Techet 	if (st->member.access != ACCESS_UNDEFINED)
7232683f446SJiří Techet 		result = accessString (st->member.access);
7242683f446SJiří Techet 	return result;
7252683f446SJiří Techet }
7262683f446SJiří Techet 
addOtherFields(tagEntryInfo * const tag,const tagType type,const statementInfo * const st,vString * const scope,vString * const typeRef)7272683f446SJiří Techet static void addOtherFields (tagEntryInfo* const tag, const tagType type,
7282683f446SJiří Techet 							const statementInfo *const st,
7292683f446SJiří Techet 							vString *const scope, vString *const typeRef)
7302683f446SJiří Techet {
7312683f446SJiří Techet 	/*  For selected tag types, append an extension flag designating the
7322683f446SJiří Techet 	 *  parent object in which the tag is defined.
7332683f446SJiří Techet 	 */
7342683f446SJiří Techet 	switch (type)
7352683f446SJiří Techet 	{
7362683f446SJiří Techet 		default: break;
7372683f446SJiří Techet 
7382683f446SJiří Techet 		case TAG_FUNCTION:
7392683f446SJiří Techet 		case TAG_PROTOTYPE:
7402683f446SJiří Techet 			if (vStringLength (Signature) > 0)
7412683f446SJiří Techet 				tag->extensionFields.signature = vStringValue (Signature);
7422683f446SJiří Techet 		case TAG_CLASS:
7432683f446SJiří Techet 		case TAG_ENUM:
7442683f446SJiří Techet 		case TAG_ENUMERATOR:
7452683f446SJiří Techet 		case TAG_EVENT:
7462683f446SJiří Techet 		case TAG_INTERFACE:
7472683f446SJiří Techet 		case TAG_MEMBER:
7482683f446SJiří Techet 		case TAG_SIGNAL:
7492683f446SJiří Techet 		case TAG_TASK:
7502683f446SJiří Techet 		case TAG_TYPEDEF:
75101dc7f65SJiří Techet 			if (vStringLength (scope) > 0  &&  isMember (st))
7522683f446SJiří Techet 			{
7532683f446SJiří Techet 				tagType ptype;
7542683f446SJiří Techet 
7552683f446SJiří Techet 				if (isType (st->context, TOKEN_NAME))
7562683f446SJiří Techet 				{
7572683f446SJiří Techet 					tag->extensionFields.scopeKindIndex = kindIndexForType (TAG_CLASS);
7582683f446SJiří Techet 					tag->extensionFields.scopeName = vStringValue (scope);
7592683f446SJiří Techet 				}
7602683f446SJiří Techet 				else if ((ptype = declToTagType (parentDecl (st))) &&
7612683f446SJiří Techet 					 includeTag (ptype, isXtagEnabled(XTAG_FILE_SCOPE)))
7622683f446SJiří Techet 				{
7632683f446SJiří Techet 					tag->extensionFields.scopeKindIndex = kindIndexForType (ptype);
7642683f446SJiří Techet 					tag->extensionFields.scopeName = vStringValue (scope);
7652683f446SJiří Techet 				}
7662683f446SJiří Techet 			}
767b9c6970bSJiří Techet 			if ((type == TAG_CLASS  ||  type == TAG_INTERFACE) &&
768b9c6970bSJiří Techet 				 vStringLength (st->parentClasses) > 0)
7692683f446SJiří Techet 			{
7702683f446SJiří Techet 
7712683f446SJiří Techet 				tag->extensionFields.inheritance =
7722683f446SJiří Techet 						vStringValue (st->parentClasses);
7732683f446SJiří Techet 			}
7742683f446SJiří Techet 			if (isMember (st))
7752683f446SJiří Techet 			{
7762683f446SJiří Techet 				tag->extensionFields.access = accessField (st);
7772683f446SJiří Techet 			}
7782683f446SJiří Techet 			break;
7792683f446SJiří Techet 	}
7802683f446SJiří Techet 
7812683f446SJiří Techet 	/* Add typename info, type of the tag and name of struct/union/etc. */
7822683f446SJiří Techet 	if ((type == TAG_TYPEDEF || type == TAG_VARIABLE || type == TAG_MEMBER)
7832683f446SJiří Techet 			&& isContextualStatement(st))
7842683f446SJiří Techet 	{
7852683f446SJiří Techet 		char *p;
7862683f446SJiří Techet 
7872683f446SJiří Techet 		tag->extensionFields.typeRef [0] =
7882683f446SJiří Techet 						tagName (declToTagType (st->declaration));
7892683f446SJiří Techet 		p = vStringValue (st->blockName->name);
7902683f446SJiří Techet 
7912683f446SJiří Techet 		/*  If there was no {} block get the name from the token before the
7922683f446SJiří Techet 		 *  name (current token is ';' or ',', previous token is the name).
7932683f446SJiří Techet 		 */
7942683f446SJiří Techet 		if (p == NULL || *p == '\0')
7952683f446SJiří Techet 		{
7962683f446SJiří Techet 			tokenInfo *const prev2 = prevToken (st, 2);
7972683f446SJiří Techet 			if (isType (prev2, TOKEN_NAME))
7982683f446SJiří Techet 				p = vStringValue (prev2->name);
7992683f446SJiří Techet 		}
8002683f446SJiří Techet 
8012683f446SJiří Techet 		/* Prepend the scope name if there is one. */
8022683f446SJiří Techet 		if (vStringLength (scope) > 0)
8032683f446SJiří Techet 		{
8042683f446SJiří Techet 			vStringCopy(typeRef, scope);
8052683f446SJiří Techet 			vStringCatS(typeRef, p);
8062683f446SJiří Techet 			p = vStringValue (typeRef);
8072683f446SJiří Techet 		}
8082683f446SJiří Techet 		tag->extensionFields.typeRef [1] = p;
8092683f446SJiří Techet 	}
8102683f446SJiří Techet }
8112683f446SJiří Techet 
findScopeHierarchy(vString * const string,const statementInfo * const st)8122683f446SJiří Techet static bool findScopeHierarchy (vString *const string, const statementInfo *const st)
8132683f446SJiří Techet {
8142683f446SJiří Techet 	bool found = false;
8152683f446SJiří Techet 
8162683f446SJiří Techet 	vStringClear (string);
8172683f446SJiří Techet 
8182683f446SJiří Techet 	if (isType (st->context, TOKEN_NAME))
8192683f446SJiří Techet 	{
8202683f446SJiří Techet 		vStringCopy (string, st->context->name);
8212683f446SJiří Techet 		found = true;
8222683f446SJiří Techet 	}
8232683f446SJiří Techet 
8242683f446SJiří Techet 	if (st->parent != NULL)
8252683f446SJiří Techet 	{
8262683f446SJiří Techet 		vString *temp = vStringNew ();
8272683f446SJiří Techet 		const statementInfo *s;
8282683f446SJiří Techet 		for (s = st->parent  ;  s != NULL  ;  s = s->parent)
8292683f446SJiří Techet 		{
8302683f446SJiří Techet 			if (isContextualStatement (s) ||
8312683f446SJiří Techet 				s->declaration == DECL_PROGRAM)
8322683f446SJiří Techet 			{
8332683f446SJiří Techet 				found = true;
8342683f446SJiří Techet 				vStringCopy (temp, string);
8352683f446SJiří Techet 				vStringClear (string);
8362683f446SJiří Techet 				if (isType (s->blockName, TOKEN_NAME))
8372683f446SJiří Techet 				{
8382683f446SJiří Techet 					if (isType (s->context, TOKEN_NAME) &&
8392683f446SJiří Techet 					    vStringLength (s->context->name) > 0)
8402683f446SJiří Techet 					{
8412683f446SJiří Techet 						vStringCat (string, s->context->name);
8422683f446SJiří Techet 					}
8432683f446SJiří Techet 					vStringCat (string, s->blockName->name);
8442683f446SJiří Techet 					vStringCat (string, temp);
8452683f446SJiří Techet 				}
8462683f446SJiří Techet 				else
8472683f446SJiří Techet 				{
8482683f446SJiří Techet 					/* Information for building scope string
8492683f446SJiří Techet 					   is lacking. Maybe input is broken. */
8502683f446SJiří Techet 					found = false;
8512683f446SJiří Techet 				}
8522683f446SJiří Techet 			}
8532683f446SJiří Techet 		}
8542683f446SJiří Techet 		vStringDelete (temp);
8552683f446SJiří Techet 	}
8562683f446SJiří Techet 	return found;
8572683f446SJiří Techet }
8582683f446SJiří Techet 
makeExtraTagEntry(const tagType type,tagEntryInfo * const e,vString * const scope)8592683f446SJiří Techet static void makeExtraTagEntry (const tagType type, tagEntryInfo *const e,
8602683f446SJiří Techet 							   vString *const scope)
8612683f446SJiří Techet {
8622683f446SJiří Techet 	if (isXtagEnabled(XTAG_QUALIFIED_TAGS)  &&
8632683f446SJiří Techet 		scope != NULL  &&  vStringLength (scope) > 0)
8642683f446SJiří Techet 	{
8652683f446SJiří Techet 		vString *const scopedName = vStringNew ();
8662683f446SJiří Techet 
8672683f446SJiří Techet 		if (type != TAG_ENUMERATOR)
8682683f446SJiří Techet 			vStringCopy (scopedName, scope);
8692683f446SJiří Techet 		else
8702683f446SJiří Techet 		{
8712683f446SJiří Techet 			/* remove last component (i.e. enumeration name) from scope */
8722683f446SJiří Techet 			const char* const sc = vStringValue (scope);
8732683f446SJiří Techet 			const char* colon = strrchr (sc, ':');
8742683f446SJiří Techet 			if (colon != NULL)
8752683f446SJiří Techet 			{
8762683f446SJiří Techet 				while (*colon == ':'  &&  colon > sc)
8772683f446SJiří Techet 					--colon;
8782683f446SJiří Techet 				vStringNCopy (scopedName, scope, colon + 1 - sc);
8792683f446SJiří Techet 			}
8802683f446SJiří Techet 		}
8812683f446SJiří Techet 		if (vStringLength (scopedName) > 0)
8822683f446SJiří Techet 		{
8832683f446SJiří Techet 			vStringCatS (scopedName, e->name);
8842683f446SJiří Techet 			e->name = vStringValue (scopedName);
8852683f446SJiří Techet 			markTagExtraBit (e, XTAG_QUALIFIED_TAGS);
8862683f446SJiří Techet 			makeTagEntry (e);
8872683f446SJiří Techet 		}
8882683f446SJiří Techet 		vStringDelete (scopedName);
8892683f446SJiří Techet 	}
8902683f446SJiří Techet }
8912683f446SJiří Techet 
makeTag(const tokenInfo * const token,const statementInfo * const st,bool isFileScope,const tagType type)8922683f446SJiří Techet static int makeTag (const tokenInfo *const token,
8932683f446SJiří Techet 					 const statementInfo *const st,
8942683f446SJiří Techet 					 bool isFileScope, const tagType type)
8952683f446SJiří Techet {
8962683f446SJiří Techet 	int corkIndex = CORK_NIL;
8972683f446SJiří Techet 	/*  Nothing is really of file scope when it appears in a header file.
8982683f446SJiří Techet 	 */
8992683f446SJiří Techet 	isFileScope = (bool) (isFileScope && ! isInputHeaderFile ());
9002683f446SJiří Techet 
9012683f446SJiří Techet 	if (isType (token, TOKEN_NAME)  &&  vStringLength (token->name) > 0  &&
9022683f446SJiří Techet 		includeTag (type, isFileScope))
9032683f446SJiří Techet 	{
9042683f446SJiří Techet 		vString *scope;
9052683f446SJiří Techet 		vString *typeRef;
9062683f446SJiří Techet 		bool isScopeBuilt;
9072683f446SJiří Techet 		/* Use "typeRef" to store the typename from addOtherFields() until
9082683f446SJiří Techet 		 * it's used in makeTagEntry().
9092683f446SJiří Techet 		 */
9102683f446SJiří Techet 		tagEntryInfo e;
9112683f446SJiří Techet 		int kind;
9122683f446SJiří Techet 
9132683f446SJiří Techet 		scope  = vStringNew ();
9142683f446SJiří Techet 		typeRef = vStringNew ();
9152683f446SJiří Techet 
9162683f446SJiří Techet 		kind  = kindIndexForType(type);
9172683f446SJiří Techet 		initTagEntry (&e, vStringValue (token->name), kind);
9182683f446SJiří Techet 
9192683f446SJiří Techet 		e.lineNumber	= token->lineNumber;
9202683f446SJiří Techet 		e.filePosition	= token->filePosition;
9212683f446SJiří Techet 		e.isFileScope	= isFileScope;
9222683f446SJiří Techet 		if (e.isFileScope)
9232683f446SJiří Techet 			markTagExtraBit (&e, XTAG_FILE_SCOPE);
9242683f446SJiří Techet 
9252683f446SJiří Techet 		isScopeBuilt = findScopeHierarchy (scope, st);
9262683f446SJiří Techet 		addOtherFields (&e, type, st, scope, typeRef);
9272683f446SJiří Techet 
9282683f446SJiří Techet 		corkIndex = makeTagEntry (&e);
9292683f446SJiří Techet 		if (isScopeBuilt)
9302683f446SJiří Techet 			makeExtraTagEntry (type, &e, scope);
9312683f446SJiří Techet 		vStringDelete (scope);
9322683f446SJiří Techet 		vStringDelete (typeRef);
9332683f446SJiří Techet 	}
9342683f446SJiří Techet 	return corkIndex;
9352683f446SJiří Techet }
9362683f446SJiří Techet 
isValidTypeSpecifier(const declType declaration)9372683f446SJiří Techet static bool isValidTypeSpecifier (const declType declaration)
9382683f446SJiří Techet {
9392683f446SJiří Techet 	bool result;
9402683f446SJiří Techet 	switch (declaration)
9412683f446SJiří Techet 	{
9422683f446SJiří Techet 		case DECL_BASE:
9432683f446SJiří Techet 		case DECL_CLASS:
9442683f446SJiří Techet 		case DECL_ENUM:
9452683f446SJiří Techet 		case DECL_EVENT:
9462683f446SJiří Techet 			result = true;
9472683f446SJiří Techet 			break;
9482683f446SJiří Techet 
9492683f446SJiří Techet 		default:
9502683f446SJiří Techet 			result = false;
9512683f446SJiří Techet 			break;
9522683f446SJiří Techet 	}
9532683f446SJiří Techet 	return result;
9542683f446SJiří Techet }
9552683f446SJiří Techet 
qualifyEnumeratorTag(const statementInfo * const st,const tokenInfo * const nameToken)9562683f446SJiří Techet static int qualifyEnumeratorTag (const statementInfo *const st,
9572683f446SJiří Techet 								 const tokenInfo *const nameToken)
9582683f446SJiří Techet {
9592683f446SJiří Techet 	int corkIndex = CORK_NIL;
9602683f446SJiří Techet 	if (isType (nameToken, TOKEN_NAME))
9612683f446SJiří Techet 		corkIndex = makeTag (nameToken, st, true, TAG_ENUMERATOR);
9622683f446SJiří Techet 	return corkIndex;
9632683f446SJiří Techet }
9642683f446SJiří Techet 
qualifyFunctionTag(const statementInfo * const st,const tokenInfo * const nameToken)9652683f446SJiří Techet static int qualifyFunctionTag (const statementInfo *const st,
9662683f446SJiří Techet 								const tokenInfo *const nameToken)
9672683f446SJiří Techet {
9682683f446SJiří Techet 	int corkIndex = CORK_NIL;
9692683f446SJiří Techet 	if (isType (nameToken, TOKEN_NAME))
9702683f446SJiří Techet 	{
9712683f446SJiří Techet 		tagType type;
9722683f446SJiří Techet 		const bool isFileScope =
9732683f446SJiří Techet 						(bool) (st->member.access == ACCESS_PRIVATE ||
9742683f446SJiří Techet 						(!isMember (st)  &&  st->scope == SCOPE_STATIC));
97523c6e73eSJiří Techet 		if (st->declaration == DECL_TASK)
9762683f446SJiří Techet 			type = TAG_TASK;
9772683f446SJiří Techet 		else
9782683f446SJiří Techet 			type = TAG_FUNCTION;
9792683f446SJiří Techet 		corkIndex = makeTag (nameToken, st, isFileScope, type);
9802683f446SJiří Techet 	}
9812683f446SJiří Techet 	return corkIndex;
9822683f446SJiří Techet }
9832683f446SJiří Techet 
qualifyFunctionDeclTag(const statementInfo * const st,const tokenInfo * const nameToken)9842683f446SJiří Techet static int qualifyFunctionDeclTag (const statementInfo *const st,
9852683f446SJiří Techet 									const tokenInfo *const nameToken)
9862683f446SJiří Techet {
9872683f446SJiří Techet 	int corkIndex = CORK_NIL;
9882683f446SJiří Techet 	if (! isType (nameToken, TOKEN_NAME))
9892683f446SJiří Techet 		;
9902683f446SJiří Techet 	else if (st->scope == SCOPE_TYPEDEF)
9912683f446SJiří Techet 		corkIndex = makeTag (nameToken, st, true, TAG_TYPEDEF);
99223c6e73eSJiří Techet 	else if (isValidTypeSpecifier (st->declaration))
9932683f446SJiří Techet 		corkIndex = makeTag (nameToken, st, true, TAG_PROTOTYPE);
9942683f446SJiří Techet 	return corkIndex;
9952683f446SJiří Techet }
9962683f446SJiří Techet 
qualifyCompoundTag(const statementInfo * const st,const tokenInfo * const nameToken)9972683f446SJiří Techet static int qualifyCompoundTag (const statementInfo *const st,
9982683f446SJiří Techet 								const tokenInfo *const nameToken)
9992683f446SJiří Techet {
10002683f446SJiří Techet 	int corkIndex = CORK_NIL;
10012683f446SJiří Techet 	if (isType (nameToken, TOKEN_NAME))
10022683f446SJiří Techet 	{
10032683f446SJiří Techet 		const tagType type = declToTagType (st->declaration);
10042683f446SJiří Techet 
10052683f446SJiří Techet 		if (type != TAG_UNDEFINED)
100623c6e73eSJiří Techet 			corkIndex = makeTag (nameToken, st, false, type);
10072683f446SJiří Techet 	}
10082683f446SJiří Techet 	return corkIndex;
10092683f446SJiří Techet }
10102683f446SJiří Techet 
qualifyBlockTag(statementInfo * const st,const tokenInfo * const nameToken)10112683f446SJiří Techet static int qualifyBlockTag (statementInfo *const st,
10122683f446SJiří Techet 							 const tokenInfo *const nameToken)
10132683f446SJiří Techet {
10142683f446SJiří Techet 	int corkIndex = CORK_NIL;
10152683f446SJiří Techet 	switch (st->declaration)
10162683f446SJiří Techet 	{
10172683f446SJiří Techet 
10182683f446SJiří Techet 		case DECL_CLASS:
10192683f446SJiří Techet 		case DECL_ENUM:
10202683f446SJiří Techet 		case DECL_INTERFACE:
10212683f446SJiří Techet 		case DECL_PROGRAM:
10222683f446SJiří Techet 			corkIndex = qualifyCompoundTag (st, nameToken);
10232683f446SJiří Techet 			break;
10242683f446SJiří Techet 		default: break;
10252683f446SJiří Techet 	}
10262683f446SJiří Techet 	return corkIndex;
10272683f446SJiří Techet }
10282683f446SJiří Techet 
qualifyVariableTag(const statementInfo * const st,const tokenInfo * const nameToken)10292683f446SJiří Techet static int qualifyVariableTag (const statementInfo *const st,
10302683f446SJiří Techet 								const tokenInfo *const nameToken)
10312683f446SJiří Techet {
10322683f446SJiří Techet 	int corkIndex = CORK_NIL;
10332683f446SJiří Techet 	/*	We have to watch that we do not interpret a declaration of the
10342683f446SJiří Techet 	 *	form "struct tag;" as a variable definition. In such a case, the
10352683f446SJiří Techet 	 *	token preceding the name will be a keyword.
10362683f446SJiří Techet 	 */
10372683f446SJiří Techet 	if (! isType (nameToken, TOKEN_NAME))
10382683f446SJiří Techet 		;
10392683f446SJiří Techet 	else if (st->scope == SCOPE_TYPEDEF)
10402683f446SJiří Techet 		corkIndex = makeTag (nameToken, st, true, TAG_TYPEDEF);
10412683f446SJiří Techet 	else if (st->declaration == DECL_EVENT)
10422683f446SJiří Techet 		corkIndex = makeTag (nameToken, st, (bool) (st->member.access == ACCESS_PRIVATE),
10432683f446SJiří Techet 							 TAG_EVENT);
10442683f446SJiří Techet 	else if (isValidTypeSpecifier (st->declaration))
10452683f446SJiří Techet 	{
10462683f446SJiří Techet 		if (st->notVariable)
10472683f446SJiří Techet 			;
10482683f446SJiří Techet 		else if (isMember (st))
10492683f446SJiří Techet 		{
105023c6e73eSJiří Techet 			if (st->scope == SCOPE_GLOBAL  ||  st->scope == SCOPE_STATIC)
10512683f446SJiří Techet 				corkIndex = makeTag (nameToken, st, true, TAG_MEMBER);
10522683f446SJiří Techet 		}
10532683f446SJiří Techet 		else
10542683f446SJiří Techet 		{
10552683f446SJiří Techet 			if (st->scope == SCOPE_EXTERN  ||  ! st->haveQualifyingName)
10562683f446SJiří Techet 				corkIndex = makeTag (nameToken, st, false, TAG_EXTERN_VAR);
10572683f446SJiří Techet 			else if (st->inFunction)
10582683f446SJiří Techet 				corkIndex = makeTag (nameToken, st, (bool) (st->scope == SCOPE_STATIC),
10592683f446SJiří Techet 									 TAG_LOCAL);
10602683f446SJiří Techet 			else
10612683f446SJiří Techet 				corkIndex = makeTag (nameToken, st, (bool) (st->scope == SCOPE_STATIC),
10622683f446SJiří Techet 									 TAG_VARIABLE);
10632683f446SJiří Techet 		}
10642683f446SJiří Techet 	}
10652683f446SJiří Techet 	return corkIndex;
10662683f446SJiří Techet }
10672683f446SJiří Techet 
10682683f446SJiří Techet /*
10692683f446SJiří Techet *   Parsing functions
10702683f446SJiří Techet */
10712683f446SJiří Techet 
10722683f446SJiří Techet 
10732683f446SJiří Techet /*  Skip to the next non-white character.
10742683f446SJiří Techet  */
skipToNonWhite(void)10752683f446SJiří Techet static int skipToNonWhite (void)
10762683f446SJiří Techet {
10772683f446SJiří Techet 	bool found = false;
10782683f446SJiří Techet 	int c;
10792683f446SJiří Techet 
10802683f446SJiří Techet #if 0
10812683f446SJiří Techet 	do
10822683f446SJiří Techet 		c = cppGetc ();
10832683f446SJiří Techet 	while (cppIsspace (c));
10842683f446SJiří Techet #else
10852683f446SJiří Techet 	while (1)
10862683f446SJiří Techet 	{
10872683f446SJiří Techet 		c = cppGetc ();
10882683f446SJiří Techet 		if (cppIsspace (c))
10892683f446SJiří Techet 			found = true;
10902683f446SJiří Techet 		else
10912683f446SJiří Techet 			break;
10922683f446SJiří Techet 	}
10932683f446SJiří Techet 	if (CollectingSignature && found)
10942683f446SJiří Techet 		vStringPut (Signature, ' ');
10952683f446SJiří Techet #endif
10962683f446SJiří Techet 
10972683f446SJiří Techet 	return c;
10982683f446SJiří Techet }
10992683f446SJiří Techet 
11002683f446SJiří Techet /*  Skips to the next brace in column 1. This is intended for cases where
11012683f446SJiří Techet  *  preprocessor constructs result in unbalanced braces.
11022683f446SJiří Techet  */
skipToFormattedBraceMatch(void)11032683f446SJiří Techet static void skipToFormattedBraceMatch (void)
11042683f446SJiří Techet {
11052683f446SJiří Techet 	int c, next;
11062683f446SJiří Techet 
11072683f446SJiří Techet 	c = cppGetc ();
11082683f446SJiří Techet 	next = cppGetc ();
11092683f446SJiří Techet 	while (c != EOF  &&  (c != '\n'  ||  next != '}'))
11102683f446SJiří Techet 	{
11112683f446SJiří Techet 		c = next;
11122683f446SJiří Techet 		next = cppGetc ();
11132683f446SJiří Techet 	}
11142683f446SJiří Techet }
11152683f446SJiří Techet 
11162683f446SJiří Techet /*  Skip to the matching character indicated by the pair string. If skipping
11172683f446SJiří Techet  *  to a matching brace and any brace is found within a different level of a
11182683f446SJiří Techet  *  #if conditional statement while brace formatting is in effect, we skip to
11192683f446SJiří Techet  *  the brace matched by its formatting. It is assumed that we have already
11202683f446SJiří Techet  *  read the character which starts the group (i.e. the first character of
11212683f446SJiří Techet  *  "pair").
11222683f446SJiří Techet  */
skipToMatch(const char * const pair)11232683f446SJiří Techet static void skipToMatch (const char *const pair)
11242683f446SJiří Techet {
11252683f446SJiří Techet 	const bool braceMatching = (bool) (strcmp ("{}", pair) == 0);
11262683f446SJiří Techet 	const bool braceFormatting = (bool) (cppIsBraceFormat () && braceMatching);
11272683f446SJiří Techet 	const unsigned int initialLevel = cppGetDirectiveNestLevel ();
11282683f446SJiří Techet 	const int begin = pair [0], end = pair [1];
11292683f446SJiří Techet 	const unsigned long inputLineNumber = getInputLineNumber ();
11302683f446SJiří Techet 	int matchLevel = 1;
11312683f446SJiří Techet 	int c = '\0';
11322683f446SJiří Techet 
11332683f446SJiří Techet 	while (matchLevel > 0  &&  (c = skipToNonWhite ()) != EOF)
11342683f446SJiří Techet 	{
11352683f446SJiří Techet 		if (CollectingSignature)
11362683f446SJiří Techet 			vStringPut (Signature, c);
11372683f446SJiří Techet 		if (c == begin)
11382683f446SJiří Techet 		{
11392683f446SJiří Techet 			++matchLevel;
11402683f446SJiří Techet 			if (braceFormatting  &&  cppGetDirectiveNestLevel () != initialLevel)
11412683f446SJiří Techet 			{
11422683f446SJiří Techet 				skipToFormattedBraceMatch ();
11432683f446SJiří Techet 				break;
11442683f446SJiří Techet 			}
11452683f446SJiří Techet 		}
11462683f446SJiří Techet 		else if (c == end)
11472683f446SJiří Techet 		{
11482683f446SJiří Techet 			--matchLevel;
11492683f446SJiří Techet 			if (braceFormatting  &&  cppGetDirectiveNestLevel () != initialLevel)
11502683f446SJiří Techet 			{
11512683f446SJiří Techet 				skipToFormattedBraceMatch ();
11522683f446SJiří Techet 				break;
11532683f446SJiří Techet 			}
11542683f446SJiří Techet 		}
11552683f446SJiří Techet 	}
11562683f446SJiří Techet 	if (c == EOF)
11572683f446SJiří Techet 	{
11582683f446SJiří Techet 		verbose ("%s: failed to find match for '%c' at line %lu\n",
11592683f446SJiří Techet 				getInputFileName (), begin, inputLineNumber);
11602683f446SJiří Techet 		if (braceMatching)
11612683f446SJiří Techet 			longjmp (Exception, (int) ExceptionBraceFormattingError);
11622683f446SJiří Techet 		else
11632683f446SJiří Techet 			longjmp (Exception, (int) ExceptionFormattingError);
11642683f446SJiří Techet 	}
11652683f446SJiří Techet }
11662683f446SJiří Techet 
analyzeKeyword(const char * const name)11672683f446SJiří Techet static keywordId analyzeKeyword (const char *const name)
11682683f446SJiří Techet {
11692683f446SJiří Techet 	const keywordId id = (keywordId) lookupKeyword (name, getInputLanguage ());
11702683f446SJiří Techet 	return id;
11712683f446SJiří Techet }
11722683f446SJiří Techet 
analyzeIdentifier(tokenInfo * const token)11732683f446SJiří Techet static void analyzeIdentifier (tokenInfo *const token)
11742683f446SJiří Techet {
11752683f446SJiří Techet 	const char * name = vStringValue (token->name);
11762683f446SJiří Techet 
11772683f446SJiří Techet 	vString * replacement = NULL;
11782683f446SJiří Techet 
11792683f446SJiří Techet 	// C: check for ignored token
11802683f446SJiří Techet 	// (FIXME: java doesn't support -I... but maybe it should?)
11812683f446SJiří Techet 	const cppMacroInfo * macro = cppFindMacro(name);
11822683f446SJiří Techet 
11832683f446SJiří Techet 	if(macro)
11842683f446SJiří Techet 	{
11852683f446SJiří Techet 		if(macro->hasParameterList)
11862683f446SJiří Techet 		{
11872683f446SJiří Techet 			// This old parser does not support macro parameters: we simply assume them to be empty
11882683f446SJiří Techet 			int c = skipToNonWhite ();
11892683f446SJiří Techet 
11902683f446SJiří Techet 			if (c == '(')
11912683f446SJiří Techet 				skipToMatch ("()");
11922683f446SJiří Techet 		}
11932683f446SJiří Techet 
11942683f446SJiří Techet 		if(macro->replacements)
11952683f446SJiří Techet 		{
11962683f446SJiří Techet 			// There is a replacement: analyze it
11972683f446SJiří Techet 			replacement = cppBuildMacroReplacement(macro,NULL,0);
11982683f446SJiří Techet 			name = replacement ? vStringValue(replacement) : NULL;
11992683f446SJiří Techet 		} else {
12002683f446SJiří Techet 			// There is no replacement: just ignore
12012683f446SJiří Techet 			name = NULL;
12022683f446SJiří Techet 		}
12032683f446SJiří Techet 	}
12042683f446SJiří Techet 
12052683f446SJiří Techet 	if(!name)
12062683f446SJiří Techet 	{
12072683f446SJiří Techet 		initToken(token);
12082683f446SJiří Techet 		if(replacement)
12092683f446SJiří Techet 			vStringDelete(replacement);
12102683f446SJiří Techet 		return;
12112683f446SJiří Techet 	}
12122683f446SJiří Techet 
12132683f446SJiří Techet 	token->keyword = analyzeKeyword (name);
12142683f446SJiří Techet 
12152683f446SJiří Techet 	if (token->keyword == KEYWORD_NONE)
12162683f446SJiří Techet 		token->type = TOKEN_NAME;
12172683f446SJiří Techet 	else
12182683f446SJiří Techet 		token->type = TOKEN_KEYWORD;
12192683f446SJiří Techet 
12202683f446SJiří Techet 	if(replacement)
12212683f446SJiří Techet 		vStringDelete(replacement);
12222683f446SJiří Techet }
12232683f446SJiří Techet 
readIdentifier(tokenInfo * const token,const int firstChar)12242683f446SJiří Techet static void readIdentifier (tokenInfo *const token, const int firstChar)
12252683f446SJiří Techet {
12262683f446SJiří Techet 	vString *const name = token->name;
12272683f446SJiří Techet 	int c = firstChar;
12282683f446SJiří Techet 	bool first = true;
12292683f446SJiří Techet 
12302683f446SJiří Techet 	initToken (token);
12312683f446SJiří Techet 
12322683f446SJiří Techet 	do
12332683f446SJiří Techet 	{
12342683f446SJiří Techet 		vStringPut (name, c);
12352683f446SJiří Techet 		if (CollectingSignature)
12362683f446SJiří Techet 		{
12372683f446SJiří Techet 			if (!first)
12382683f446SJiří Techet 				vStringPut (Signature, c);
12392683f446SJiří Techet 			first = false;
12402683f446SJiří Techet 		}
12412683f446SJiří Techet 		c = cppGetc ();
124223c6e73eSJiří Techet 	} while (cppIsident (c));
12432683f446SJiří Techet 	cppUngetc (c);        /* unget non-identifier character */
12442683f446SJiří Techet 
12452683f446SJiří Techet 	analyzeIdentifier (token);
12462683f446SJiří Techet }
12472683f446SJiří Techet 
processName(statementInfo * const st)12482683f446SJiří Techet static void processName (statementInfo *const st)
12492683f446SJiří Techet {
12502683f446SJiří Techet 	Assert (isType (activeToken (st), TOKEN_NAME));
12512683f446SJiří Techet 	if (st->gotName  &&  st->declaration == DECL_NONE)
12522683f446SJiří Techet 		st->declaration = DECL_BASE;
12532683f446SJiří Techet 	st->gotName = true;
12542683f446SJiří Techet 	st->haveQualifyingName = true;
12552683f446SJiří Techet }
12562683f446SJiří Techet 
copyToken(tokenInfo * const dest,const tokenInfo * const src)12572683f446SJiří Techet static void copyToken (tokenInfo *const dest, const tokenInfo *const src)
12582683f446SJiří Techet {
12592683f446SJiří Techet 	dest->type         = src->type;
12602683f446SJiří Techet 	dest->keyword      = src->keyword;
12612683f446SJiří Techet 	dest->filePosition = src->filePosition;
12622683f446SJiří Techet 	dest->lineNumber   = src->lineNumber;
12632683f446SJiří Techet 	vStringCopy (dest->name, src->name);
12642683f446SJiří Techet }
12652683f446SJiří Techet 
setAccess(statementInfo * const st,const accessType access)12662683f446SJiří Techet static void setAccess (statementInfo *const st, const accessType access)
12672683f446SJiří Techet {
12682683f446SJiří Techet 	if (isMember (st))
12692683f446SJiří Techet 	{
12702683f446SJiří Techet 		st->member.access = access;
12712683f446SJiří Techet 	}
12722683f446SJiří Techet }
12732683f446SJiří Techet 
addParentClass(statementInfo * const st,tokenInfo * const token)12742683f446SJiří Techet static void addParentClass (statementInfo *const st, tokenInfo *const token)
12752683f446SJiří Techet {
12762683f446SJiří Techet 	if (vStringLength (token->name) > 0  &&
12772683f446SJiří Techet 		vStringLength (st->parentClasses) > 0)
12782683f446SJiří Techet 	{
12792683f446SJiří Techet 		vStringPut (st->parentClasses, ',');
12802683f446SJiří Techet 	}
12812683f446SJiří Techet 	vStringCat (st->parentClasses, token->name);
12822683f446SJiří Techet }
12832683f446SJiří Techet 
readParents(statementInfo * const st,const int qualifier)12842683f446SJiří Techet static void readParents (statementInfo *const st, const int qualifier)
12852683f446SJiří Techet {
12862683f446SJiří Techet 	tokenInfo *const token = newToken ();
12872683f446SJiří Techet 	tokenInfo *const parent = newToken ();
12882683f446SJiří Techet 	int c;
12892683f446SJiří Techet 
12902683f446SJiří Techet 	do
12912683f446SJiří Techet 	{
12922683f446SJiří Techet 		c = skipToNonWhite ();
12932683f446SJiří Techet 		if (cppIsident1 (c))
12942683f446SJiří Techet 		{
12952683f446SJiří Techet 			readIdentifier (token, c);
12962683f446SJiří Techet 			if (isType (token, TOKEN_NAME))
12972683f446SJiří Techet 				vStringCat (parent->name, token->name);
12982683f446SJiří Techet 			else
12992683f446SJiří Techet 			{
13002683f446SJiří Techet 				addParentClass (st, parent);
13012683f446SJiří Techet 				initToken (parent);
13022683f446SJiří Techet 			}
13032683f446SJiří Techet 		}
13042683f446SJiří Techet 		else if (c == qualifier)
13052683f446SJiří Techet 			vStringPut (parent->name, c);
13062683f446SJiří Techet 		else if (c == '<')
13072683f446SJiří Techet 			skipToMatch ("<>");
13082683f446SJiří Techet 		else if (isType (token, TOKEN_NAME))
13092683f446SJiří Techet 		{
13102683f446SJiří Techet 			addParentClass (st, parent);
13112683f446SJiří Techet 			initToken (parent);
13122683f446SJiří Techet 		}
13132683f446SJiří Techet 	} while (c != '{'  &&  c != EOF);
13142683f446SJiří Techet 	cppUngetc (c);
13152683f446SJiří Techet 	deleteToken (parent);
13162683f446SJiří Techet 	deleteToken (token);
13172683f446SJiří Techet }
13182683f446SJiří Techet 
processInterface(statementInfo * const st)13192683f446SJiří Techet static void processInterface (statementInfo *const st)
13202683f446SJiří Techet {
13212683f446SJiří Techet 	st->declaration = DECL_INTERFACE;
13222683f446SJiří Techet }
13232683f446SJiří Techet 
checkIsClassEnum(statementInfo * const st,const declType decl)13242683f446SJiří Techet static void checkIsClassEnum (statementInfo *const st, const declType decl)
13252683f446SJiří Techet {
13262683f446SJiří Techet 	st->declaration = decl;
13272683f446SJiří Techet }
13282683f446SJiří Techet 
processToken(tokenInfo * const token,statementInfo * const st)13292683f446SJiří Techet static void processToken (tokenInfo *const token, statementInfo *const st)
13302683f446SJiří Techet {
13312683f446SJiří Techet 	switch ((int)token->keyword)        /* is it a reserved word? */
13322683f446SJiří Techet 	{
13332683f446SJiří Techet 		default: break;
13342683f446SJiří Techet 
13352683f446SJiří Techet 		case KEYWORD_NONE:      processName (st);                       break;
13362683f446SJiří Techet 		case KEYWORD_BIND:      st->declaration = DECL_BASE;            break;
13372683f446SJiří Techet 		case KEYWORD_BIT:       st->declaration = DECL_BASE;            break;
13382683f446SJiří Techet 		case KEYWORD_CLASS:     checkIsClassEnum (st, DECL_CLASS);      break;
13392683f446SJiří Techet 		case KEYWORD_ENUM:      st->declaration = DECL_ENUM;            break;
13402683f446SJiří Techet 		case KEYWORD_EXTENDS:   readParents (st, '.');
13412683f446SJiří Techet 		                        setToken (st, TOKEN_NONE);              break;
13422683f446SJiří Techet 		case KEYWORD_FUNCTION:  st->declaration = DECL_BASE;            break;
13432683f446SJiří Techet 		case KEYWORD_INTEGER:   st->declaration = DECL_BASE;            break;
13442683f446SJiří Techet 		case KEYWORD_INTERFACE: processInterface (st);                  break;
13452683f446SJiří Techet 		case KEYWORD_LOCAL:     setAccess (st, ACCESS_LOCAL);           break;
13462683f446SJiří Techet 		case KEYWORD_PROGRAM:   st->declaration = DECL_PROGRAM;         break;
13472683f446SJiří Techet 		case KEYWORD_PROTECTED: setAccess (st, ACCESS_PROTECTED);       break;
13482683f446SJiří Techet 		case KEYWORD_PUBLIC:    setAccess (st, ACCESS_PUBLIC);          break;
13492683f446SJiří Techet 		case KEYWORD_STRING:    st->declaration = DECL_BASE;            break;
13502683f446SJiří Techet 		case KEYWORD_TASK:      st->declaration = DECL_TASK;            break;
13512683f446SJiří Techet 		case KEYWORD_VOID:      st->declaration = DECL_BASE;            break;
13522683f446SJiří Techet 		case KEYWORD_VIRTUAL:   st->implementation = IMP_VIRTUAL;       break;
13532683f446SJiří Techet 
13542683f446SJiří Techet 		case KEYWORD_EVENT:
13552683f446SJiří Techet 			break;
13562683f446SJiří Techet 
13572683f446SJiří Techet 		case KEYWORD_TYPEDEF:
13582683f446SJiří Techet 			reinitStatement (st, false);
13592683f446SJiří Techet 			st->scope = SCOPE_TYPEDEF;
13602683f446SJiří Techet 			break;
13612683f446SJiří Techet 
13622683f446SJiří Techet 		case KEYWORD_EXTERN:
13632683f446SJiří Techet 			reinitStatement (st, false);
13642683f446SJiří Techet 			st->scope = SCOPE_EXTERN;
13652683f446SJiří Techet 			st->declaration = DECL_BASE;
13662683f446SJiří Techet 			break;
13672683f446SJiří Techet 
13682683f446SJiří Techet 		case KEYWORD_STATIC:
13692683f446SJiří Techet 			reinitStatement (st, false);
13702683f446SJiří Techet 			st->scope = SCOPE_STATIC;
13712683f446SJiří Techet 			st->declaration = DECL_BASE;
13722683f446SJiří Techet 			break;
13732683f446SJiří Techet 	}
13742683f446SJiří Techet }
13752683f446SJiří Techet 
13762683f446SJiří Techet /*
13772683f446SJiří Techet *   Parenthesis handling functions
13782683f446SJiří Techet */
13792683f446SJiří Techet 
restartStatement(statementInfo * const st)13802683f446SJiří Techet static void restartStatement (statementInfo *const st)
13812683f446SJiří Techet {
13822683f446SJiří Techet 	tokenInfo *const save = newToken ();
13832683f446SJiří Techet 	tokenInfo *token = activeToken (st);
13842683f446SJiří Techet 
13852683f446SJiří Techet 	copyToken (save, token);
13862683f446SJiří Techet 	DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>");)
13872683f446SJiří Techet 	reinitStatement (st, false);
13882683f446SJiří Techet 	token = activeToken (st);
13892683f446SJiří Techet 	copyToken (token, save);
13902683f446SJiří Techet 	deleteToken (save);
13912683f446SJiří Techet 	processToken (token, st);
13922683f446SJiří Techet }
13932683f446SJiří Techet 
13942683f446SJiří Techet /*  Skips over a mem-initializer-list of a ctor-initializer, defined as:
13952683f446SJiří Techet  *
13962683f446SJiří Techet  *  mem-initializer-list:
13972683f446SJiří Techet  *    mem-initializer, mem-initializer-list
13982683f446SJiří Techet  *
13992683f446SJiří Techet  *  mem-initializer:
14002683f446SJiří Techet  *    [::] [nested-name-spec] class-name (...)
14012683f446SJiří Techet  *    identifier
14022683f446SJiří Techet  */
skipMemIntializerList(tokenInfo * const token)14032683f446SJiří Techet static void skipMemIntializerList (tokenInfo *const token)
14042683f446SJiří Techet {
14052683f446SJiří Techet 	int c;
14062683f446SJiří Techet 
14072683f446SJiří Techet 	do
14082683f446SJiří Techet 	{
14092683f446SJiří Techet 		c = skipToNonWhite ();
14102683f446SJiří Techet 		while (cppIsident1 (c)  ||  c == ':')
14112683f446SJiří Techet 		{
14122683f446SJiří Techet 			if (c != ':')
14132683f446SJiří Techet 				readIdentifier (token, c);
14142683f446SJiří Techet 			c = skipToNonWhite ();
14152683f446SJiří Techet 		}
14162683f446SJiří Techet 		if (c == '<')
14172683f446SJiří Techet 		{
14182683f446SJiří Techet 			skipToMatch ("<>");
14192683f446SJiří Techet 			c = skipToNonWhite ();
14202683f446SJiří Techet 		}
14212683f446SJiří Techet 		if (c == '(')
14222683f446SJiří Techet 		{
14232683f446SJiří Techet 			skipToMatch ("()");
14242683f446SJiří Techet 			c = skipToNonWhite ();
14252683f446SJiří Techet 		}
14262683f446SJiří Techet 	} while (c == ',');
14272683f446SJiří Techet 	cppUngetc (c);
14282683f446SJiří Techet }
14292683f446SJiří Techet 
skipMacro(statementInfo * const st)14302683f446SJiří Techet static void skipMacro (statementInfo *const st)
14312683f446SJiří Techet {
14322683f446SJiří Techet 	tokenInfo *const prev2 = prevToken (st, 2);
14332683f446SJiří Techet 
14342683f446SJiří Techet 	if (isType (prev2, TOKEN_NAME))
14352683f446SJiří Techet 		retardToken (st);
14362683f446SJiří Techet 	skipToMatch ("()");
14372683f446SJiří Techet }
14382683f446SJiří Techet 
14392683f446SJiří Techet /*  Skips over characters following the parameter list.
14402683f446SJiří Techet  *  Originally written for C++, may contain unnecessary stuff.
14412683f446SJiří Techet  *
14422683f446SJiří Techet  *  C#:
14432683f446SJiří Techet  *    public C(double x) : base(x) {}
14442683f446SJiří Techet  */
skipPostArgumentStuff(statementInfo * const st,parenInfo * const info)14452683f446SJiří Techet static bool skipPostArgumentStuff (
14462683f446SJiří Techet 		statementInfo *const st, parenInfo *const info)
14472683f446SJiří Techet {
14482683f446SJiří Techet 	tokenInfo *const token = activeToken (st);
14492683f446SJiří Techet 	unsigned int parameters = info->parameterCount;
14502683f446SJiří Techet 	unsigned int elementCount = 0;
14512683f446SJiří Techet 	bool restart = false;
14522683f446SJiří Techet 	bool end = false;
14532683f446SJiří Techet 	int c = skipToNonWhite ();
14542683f446SJiří Techet 
14552683f446SJiří Techet 	do
14562683f446SJiří Techet 	{
14572683f446SJiří Techet 		switch (c)
14582683f446SJiří Techet 		{
14592683f446SJiří Techet 		case ')':                               break;
14602683f446SJiří Techet 		case ':': skipMemIntializerList (token);break;  /* ctor-initializer */
14612683f446SJiří Techet 		case '[': skipToMatch ("[]");           break;
14622683f446SJiří Techet 		case '=': cppUngetc (c); end = true;    break;
14632683f446SJiří Techet 		case '{': cppUngetc (c); end = true;    break;
14642683f446SJiří Techet 		case '}': cppUngetc (c); end = true;    break;
14652683f446SJiří Techet 
14662683f446SJiří Techet 		case '(':
14672683f446SJiří Techet 			if (elementCount > 0)
14682683f446SJiří Techet 				++elementCount;
14692683f446SJiří Techet 			skipToMatch ("()");
14702683f446SJiří Techet 			break;
14712683f446SJiří Techet 
14722683f446SJiří Techet 		case ';':
14732683f446SJiří Techet 			if (parameters == 0  ||  elementCount < 2)
14742683f446SJiří Techet 			{
14752683f446SJiří Techet 				cppUngetc (c);
14762683f446SJiří Techet 				end = true;
14772683f446SJiří Techet 			}
14782683f446SJiří Techet 			else if (--parameters == 0)
14792683f446SJiří Techet 				end = true;
14802683f446SJiří Techet 			break;
14812683f446SJiří Techet 
14822683f446SJiří Techet 		default:
14832683f446SJiří Techet 			if (cppIsident1 (c))
14842683f446SJiří Techet 			{
14852683f446SJiří Techet 				readIdentifier (token, c);
14862683f446SJiří Techet 				switch (token->keyword)
14872683f446SJiří Techet 				{
14882683f446SJiří Techet 				case KEYWORD_CLASS:
14892683f446SJiří Techet 				case KEYWORD_EXTERN:
14902683f446SJiří Techet 				case KEYWORD_NEWCOV:
14912683f446SJiří Techet 				case KEYWORD_PROTECTED:
14922683f446SJiří Techet 				case KEYWORD_PUBLIC:
14932683f446SJiří Techet 				case KEYWORD_STATIC:
14942683f446SJiří Techet 				case KEYWORD_TYPEDEF:
14952683f446SJiří Techet 				case KEYWORD_VIRTUAL:
14962683f446SJiří Techet 					/* Never allowed within parameter declarations. */
14972683f446SJiří Techet 					restart = true;
14982683f446SJiří Techet 					end = true;
14992683f446SJiří Techet 					break;
15002683f446SJiří Techet 
15012683f446SJiří Techet 				default:
15022683f446SJiří Techet 					if (isType (token, TOKEN_NONE))
15032683f446SJiří Techet 						;
15042683f446SJiří Techet 					else
15052683f446SJiří Techet 					{
15062683f446SJiří Techet 						/*  If we encounter any other identifier immediately
15072683f446SJiří Techet 						 *  following an empty parameter list, this is almost
15082683f446SJiří Techet 						 *  certainly one of those Microsoft macro "thingies"
15092683f446SJiří Techet 						 *  that the automatic source code generation sticks
15102683f446SJiří Techet 						 *  in. Terminate the current statement.
15112683f446SJiří Techet 						 */
15122683f446SJiří Techet 						restart = true;
15132683f446SJiří Techet 						end = true;
15142683f446SJiří Techet 					}
15152683f446SJiří Techet 					break;
15162683f446SJiří Techet 				}
15172683f446SJiří Techet 			}
15182683f446SJiří Techet 		}
15192683f446SJiří Techet 		if (! end)
15202683f446SJiří Techet 		{
15212683f446SJiří Techet 			c = skipToNonWhite ();
15222683f446SJiří Techet 			if (c == EOF)
15232683f446SJiří Techet 				end = true;
15242683f446SJiří Techet 		}
15252683f446SJiří Techet 	} while (! end);
15262683f446SJiří Techet 
15272683f446SJiří Techet 	if (restart)
15282683f446SJiří Techet 		restartStatement (st);
15292683f446SJiří Techet 	else
15302683f446SJiří Techet 		setToken (st, TOKEN_NONE);
15312683f446SJiří Techet 
15322683f446SJiří Techet 	return (bool) (c != EOF);
15332683f446SJiří Techet }
15342683f446SJiří Techet 
analyzePostParens(statementInfo * const st,parenInfo * const info)15352683f446SJiří Techet static void analyzePostParens (statementInfo *const st, parenInfo *const info)
15362683f446SJiří Techet {
15372683f446SJiří Techet 	const unsigned long inputLineNumber = getInputLineNumber ();
15382683f446SJiří Techet 	int c = skipToNonWhite ();
15392683f446SJiří Techet 
15402683f446SJiří Techet 	cppUngetc (c);
15412683f446SJiří Techet 	if (isOneOf (c, "{;,="))
15422683f446SJiří Techet 		;
154323c6e73eSJiří Techet 	else {
15442683f446SJiří Techet 		if (! skipPostArgumentStuff (st, info))
15452683f446SJiří Techet 		{
15462683f446SJiří Techet 			verbose (
15472683f446SJiří Techet 				"%s: confusing argument declarations beginning at line %lu\n",
15482683f446SJiří Techet 				getInputFileName (), inputLineNumber);
15492683f446SJiří Techet 			longjmp (Exception, (int) ExceptionFormattingError);
15502683f446SJiří Techet 		}
15512683f446SJiří Techet 	}
15522683f446SJiří Techet }
15532683f446SJiří Techet 
processAngleBracket(void)15542683f446SJiří Techet static void processAngleBracket (void)
15552683f446SJiří Techet {
15562683f446SJiří Techet 	int c = cppGetc ();
15572683f446SJiří Techet 	if (c == '>') {
15582683f446SJiří Techet 		/* already found match for template */
15592683f446SJiří Techet 	} else if (c == '<') {
15602683f446SJiří Techet 		/* skip "<<" or "<<=". */
15612683f446SJiří Techet 		c = cppGetc ();
15622683f446SJiří Techet 		if (c != '=') {
15632683f446SJiří Techet 			cppUngetc (c);
15642683f446SJiří Techet 		}
15652683f446SJiří Techet 	} else {
15662683f446SJiří Techet 		cppUngetc (c);
15672683f446SJiří Techet 	}
15682683f446SJiří Techet }
15692683f446SJiří Techet 
parseParens(statementInfo * const st,parenInfo * const info)15702683f446SJiří Techet static int parseParens (statementInfo *const st, parenInfo *const info)
15712683f446SJiří Techet {
15722683f446SJiří Techet 	tokenInfo *const token = activeToken (st);
15732683f446SJiří Techet 	unsigned int identifierCount = 0;
15742683f446SJiří Techet 	unsigned int depth = 1;
15752683f446SJiří Techet 	bool firstChar = true;
15762683f446SJiří Techet 	int nextChar = '\0';
15772683f446SJiří Techet 
15782683f446SJiří Techet 	CollectingSignature = true;
15792683f446SJiří Techet 	vStringClear (Signature);
15802683f446SJiří Techet 	vStringPut (Signature, '(');
15812683f446SJiří Techet 	info->parameterCount = 1;
15822683f446SJiří Techet 	do
15832683f446SJiří Techet 	{
15842683f446SJiří Techet 		int c = skipToNonWhite ();
15852683f446SJiří Techet 		vStringPut (Signature, c);
15862683f446SJiří Techet 
15872683f446SJiří Techet 		switch (c)
15882683f446SJiří Techet 		{
15892683f446SJiří Techet 			case '^':
15902683f446SJiří Techet 				break;
15912683f446SJiří Techet 
15922683f446SJiří Techet 			case '&':
15932683f446SJiří Techet 			case '*':
15942683f446SJiří Techet 				info->isPointer = true;
15952683f446SJiří Techet 				if (identifierCount == 0)
15962683f446SJiří Techet 					info->isParamList = false;
15972683f446SJiří Techet 				initToken (token);
15982683f446SJiří Techet 				break;
15992683f446SJiří Techet 
16002683f446SJiří Techet 			case ':':
16012683f446SJiří Techet 				break;
16022683f446SJiří Techet 
16032683f446SJiří Techet 			case '.':
16042683f446SJiří Techet 				info->isNameCandidate = false;
16052683f446SJiří Techet 				c = cppGetc ();
16062683f446SJiří Techet 				if (c != '.')
16072683f446SJiří Techet 					cppUngetc (c);
16082683f446SJiří Techet 				else
16092683f446SJiří Techet 				{
16102683f446SJiří Techet 					c = cppGetc ();
16112683f446SJiří Techet 					if (c != '.')
16122683f446SJiří Techet 						cppUngetc (c);
16132683f446SJiří Techet 					else
16142683f446SJiří Techet 						vStringCatS (Signature, "..."); /* variable arg list */
16152683f446SJiří Techet 				}
16162683f446SJiří Techet 				break;
16172683f446SJiří Techet 
16182683f446SJiří Techet 			case ',':
16192683f446SJiří Techet 				info->isNameCandidate = false;
16202683f446SJiří Techet 				break;
16212683f446SJiří Techet 
16222683f446SJiří Techet 			case '=':
16232683f446SJiří Techet 				info->isNameCandidate = false;
16242683f446SJiří Techet 				if (firstChar)
16252683f446SJiří Techet 				{
16262683f446SJiří Techet 					info->isParamList = false;
16272683f446SJiří Techet 					skipMacro (st);
16282683f446SJiří Techet 					depth = 0;
16292683f446SJiří Techet 				}
16302683f446SJiří Techet 				break;
16312683f446SJiří Techet 
16322683f446SJiří Techet 			case '[':
16332683f446SJiří Techet 				skipToMatch ("[]");
16342683f446SJiří Techet 				break;
16352683f446SJiří Techet 
16362683f446SJiří Techet 			case '<':
16372683f446SJiří Techet 				processAngleBracket ();
16382683f446SJiří Techet 				break;
16392683f446SJiří Techet 
16402683f446SJiří Techet 			case ')':
16412683f446SJiří Techet 				if (firstChar)
16422683f446SJiří Techet 					info->parameterCount = 0;
16432683f446SJiří Techet 				--depth;
16442683f446SJiří Techet 				break;
16452683f446SJiří Techet 
16462683f446SJiří Techet 			case '(':
16472683f446SJiří Techet 				if (firstChar)
16482683f446SJiří Techet 				{
16492683f446SJiří Techet 					info->isNameCandidate = false;
16502683f446SJiří Techet 					cppUngetc (c);
16512683f446SJiří Techet 					vStringClear (Signature);
16522683f446SJiří Techet 					skipMacro (st);
16532683f446SJiří Techet 					depth = 0;
16542683f446SJiří Techet 					vStringChop (Signature);
16552683f446SJiří Techet 				}
16562683f446SJiří Techet 				else if (isType (token, TOKEN_PAREN_NAME))
16572683f446SJiří Techet 				{
16582683f446SJiří Techet 					c = skipToNonWhite ();
16592683f446SJiří Techet 					if (c == '*')        /* check for function pointer */
16602683f446SJiří Techet 					{
16612683f446SJiří Techet 						skipToMatch ("()");
16622683f446SJiří Techet 						c = skipToNonWhite ();
16632683f446SJiří Techet 						if (c == '(')
16642683f446SJiří Techet 							skipToMatch ("()");
16652683f446SJiří Techet 						else
16662683f446SJiří Techet 							cppUngetc (c);
16672683f446SJiří Techet 					}
16682683f446SJiří Techet 					else
16692683f446SJiří Techet 					{
16702683f446SJiří Techet 						cppUngetc (c);
16712683f446SJiří Techet 						cppUngetc ('(');
16722683f446SJiří Techet 						info->nestedArgs = true;
16732683f446SJiří Techet 					}
16742683f446SJiří Techet 				}
16752683f446SJiří Techet 				else
16762683f446SJiří Techet 					++depth;
16772683f446SJiří Techet 				break;
16782683f446SJiří Techet 
16792683f446SJiří Techet 			default:
168023c6e73eSJiří Techet 				if (cppIsident1 (c))
16812683f446SJiří Techet 				{
16822683f446SJiří Techet 					readIdentifier (token, c);
16832683f446SJiří Techet 					if (isType (token, TOKEN_NAME)  &&  info->isNameCandidate)
16842683f446SJiří Techet 						token->type = TOKEN_PAREN_NAME;
16852683f446SJiří Techet 					else if (isType (token, TOKEN_KEYWORD))
16862683f446SJiří Techet 					{
16872683f446SJiří Techet 						info->isNameCandidate = false;
16882683f446SJiří Techet 					}
16892683f446SJiří Techet 				}
16902683f446SJiří Techet 				else
16912683f446SJiří Techet 				{
16922683f446SJiří Techet 					info->isParamList     = false;
16932683f446SJiří Techet 					info->isNameCandidate = false;
16942683f446SJiří Techet 					info->invalidContents = true;
16952683f446SJiří Techet 				}
16962683f446SJiří Techet 				break;
16972683f446SJiří Techet 		}
16982683f446SJiří Techet 		firstChar = false;
16992683f446SJiří Techet 	} while (! info->nestedArgs  &&  depth > 0  &&  info->isNameCandidate);
17002683f446SJiří Techet 
17012683f446SJiří Techet 	if (! info->nestedArgs) while (depth > 0)
17022683f446SJiří Techet 	{
17032683f446SJiří Techet 		skipToMatch ("()");
17042683f446SJiří Techet 		--depth;
17052683f446SJiří Techet 	}
17062683f446SJiří Techet 
17072683f446SJiří Techet 	if (! info->isNameCandidate)
17082683f446SJiří Techet 		initToken (token);
17092683f446SJiří Techet 
17102683f446SJiří Techet 	CollectingSignature = false;
17112683f446SJiří Techet 	return nextChar;
17122683f446SJiří Techet }
17132683f446SJiří Techet 
initParenInfo(parenInfo * const info)17142683f446SJiří Techet static void initParenInfo (parenInfo *const info)
17152683f446SJiří Techet {
17162683f446SJiří Techet 	info->isPointer				= false;
17172683f446SJiří Techet 	info->isParamList			= true;
17182683f446SJiří Techet 	info->isNameCandidate		= true;
17192683f446SJiří Techet 	info->invalidContents		= false;
17202683f446SJiří Techet 	info->nestedArgs			= false;
17212683f446SJiří Techet 	info->parameterCount		= 0;
17222683f446SJiří Techet }
17232683f446SJiří Techet 
analyzeParens(statementInfo * const st)17242683f446SJiří Techet static void analyzeParens (statementInfo *const st)
17252683f446SJiří Techet {
17262683f446SJiří Techet 	tokenInfo *const prev = prevToken (st, 1);
17272683f446SJiří Techet 
17282683f446SJiří Techet 	if (st->inFunction && !st->assignment)
17292683f446SJiří Techet 		st->notVariable = true;
17302683f446SJiří Techet 
17312683f446SJiří Techet 	if (! isType (prev, TOKEN_NONE))  /* in case of ignored enclosing macros */
17322683f446SJiří Techet 	{
17332683f446SJiří Techet 		tokenInfo *const token = activeToken (st);
17342683f446SJiří Techet 		parenInfo info;
17352683f446SJiří Techet 		int c;
17362683f446SJiří Techet 
17372683f446SJiří Techet 		initParenInfo (&info);
17382683f446SJiří Techet 		parseParens (st, &info);
17392683f446SJiří Techet 		c = skipToNonWhite ();
17402683f446SJiří Techet 		cppUngetc (c);
17412683f446SJiří Techet 		if (info.invalidContents)
17422683f446SJiří Techet 		{
17432683f446SJiří Techet 			/* FIXME: This breaks parsing of variable instantiations that have
17442683f446SJiří Techet 			   constants as parameters: Type var(0) or Type var("..."). */
17452683f446SJiří Techet 			reinitStatement (st, false);
17462683f446SJiří Techet 		}
17472683f446SJiří Techet 		else if (info.isNameCandidate  &&  isType (token, TOKEN_PAREN_NAME)  &&
17482683f446SJiří Techet 				 ! st->gotParenName  &&
17492683f446SJiří Techet 				 (! info.isParamList || ! st->haveQualifyingName  ||
17502683f446SJiří Techet 				  c == '('  ||
17512683f446SJiří Techet 				  (c == '='  &&  st->implementation != IMP_VIRTUAL) ||
17522683f446SJiří Techet 				  (st->declaration == DECL_NONE  &&  isOneOf (c, ",;"))))
17532683f446SJiří Techet 		{
17542683f446SJiří Techet 			token->type = TOKEN_NAME;
17552683f446SJiří Techet 			processName (st);
17562683f446SJiří Techet 			st->gotParenName = true;
17572683f446SJiří Techet 			if (! (c == '('  &&  info.nestedArgs))
17582683f446SJiří Techet 				st->isPointer = info.isPointer;
17592683f446SJiří Techet 		}
17602683f446SJiří Techet 		else if (! st->gotArgs  &&  info.isParamList)
17612683f446SJiří Techet 		{
17622683f446SJiří Techet 			st->gotArgs = true;
17632683f446SJiří Techet 			setToken (st, TOKEN_ARGS);
17642683f446SJiří Techet 			advanceToken (st);
17652683f446SJiří Techet 			if (st->scope != SCOPE_TYPEDEF)
17662683f446SJiří Techet 				analyzePostParens (st, &info);
17672683f446SJiří Techet 		}
17682683f446SJiří Techet 		else
17692683f446SJiří Techet 			setToken (st, TOKEN_NONE);
17702683f446SJiří Techet 	}
17712683f446SJiří Techet }
17722683f446SJiří Techet 
17732683f446SJiří Techet /*
17742683f446SJiří Techet *   Token parsing functions
17752683f446SJiří Techet */
17762683f446SJiří Techet 
addContext(statementInfo * const st,const tokenInfo * const token)17772683f446SJiří Techet static void addContext (statementInfo *const st, const tokenInfo* const token)
17782683f446SJiří Techet {
17792683f446SJiří Techet 	if (isType (token, TOKEN_NAME))
17802683f446SJiří Techet 	{
17812683f446SJiří Techet 		vStringCat (st->context->name, token->name);
17822683f446SJiří Techet 		st->context->type = TOKEN_NAME;
17832683f446SJiří Techet 	}
17842683f446SJiří Techet }
17852683f446SJiří Techet 
processColon(statementInfo * const st)17862683f446SJiří Techet static void processColon (statementInfo *const st)
17872683f446SJiří Techet {
17882683f446SJiří Techet 	int c = skipToNonWhite ();
17892683f446SJiří Techet 	const bool doubleColon = (bool) (c == ':');
17902683f446SJiří Techet 
17912683f446SJiří Techet 	if (doubleColon)
17922683f446SJiří Techet 	{
17932683f446SJiří Techet 		setToken (st, TOKEN_DOUBLE_COLON);
17942683f446SJiří Techet 		st->haveQualifyingName = false;
17952683f446SJiří Techet 	}
17962683f446SJiří Techet 	else
17972683f446SJiří Techet 	{
17982683f446SJiří Techet 		const tokenInfo *const prev  = prevToken (st, 1);
179901dc7f65SJiří Techet 		cppUngetc (c);
18007bdd792eSJiří Techet 		if (st->parent != NULL)
18012683f446SJiří Techet 		{
18022683f446SJiří Techet 			makeTag (prev, st, false, TAG_LABEL);
18032683f446SJiří Techet 			reinitStatement (st, false);
18042683f446SJiří Techet 		}
18052683f446SJiří Techet 	}
18062683f446SJiří Techet }
18072683f446SJiří Techet 
18082683f446SJiří Techet /*  Skips over any initializing value which may follow an '=' character in a
18092683f446SJiří Techet  *  variable definition.
18102683f446SJiří Techet  */
skipInitializer(statementInfo * const st)18112683f446SJiří Techet static int skipInitializer (statementInfo *const st)
18122683f446SJiří Techet {
18132683f446SJiří Techet 	bool done = false;
18142683f446SJiří Techet 	int c;
18152683f446SJiří Techet 
18162683f446SJiří Techet 	while (! done)
18172683f446SJiří Techet 	{
18182683f446SJiří Techet 		c = skipToNonWhite ();
18192683f446SJiří Techet 
18202683f446SJiří Techet 		if (c == EOF)
18212683f446SJiří Techet 			longjmp (Exception, (int) ExceptionFormattingError);
18222683f446SJiří Techet 		else switch (c)
18232683f446SJiří Techet 		{
18242683f446SJiří Techet 			case ',':
18252683f446SJiří Techet 			case ';': done = true; break;
18262683f446SJiří Techet 
18272683f446SJiří Techet 			case '0':
18282683f446SJiří Techet 				if (st->implementation == IMP_VIRTUAL)
18292683f446SJiří Techet 					st->implementation = IMP_PURE_VIRTUAL;
18302683f446SJiří Techet 				break;
18312683f446SJiří Techet 
18322683f446SJiří Techet 			case '[': skipToMatch ("[]"); break;
18332683f446SJiří Techet 			case '(': skipToMatch ("()"); break;
18342683f446SJiří Techet 			case '{': skipToMatch ("{}"); break;
18352683f446SJiří Techet 			case '<': processAngleBracket(); break;
18362683f446SJiří Techet 
18372683f446SJiří Techet 			case '}':
18382683f446SJiří Techet 				if (insideEnumBody (st))
18392683f446SJiří Techet 					done = true;
18402683f446SJiří Techet 				else if (! cppIsBraceFormat ())
18412683f446SJiří Techet 				{
18422683f446SJiří Techet 					verbose ("%s: unexpected closing brace at line %lu\n",
18432683f446SJiří Techet 							getInputFileName (), getInputLineNumber ());
18442683f446SJiří Techet 					longjmp (Exception, (int) ExceptionBraceFormattingError);
18452683f446SJiří Techet 				}
18462683f446SJiří Techet 				break;
18472683f446SJiří Techet 
18482683f446SJiří Techet 			default: break;
18492683f446SJiří Techet 		}
18502683f446SJiří Techet 	}
18512683f446SJiří Techet 	return c;
18522683f446SJiří Techet }
18532683f446SJiří Techet 
processInitializer(statementInfo * const st)18542683f446SJiří Techet static void processInitializer (statementInfo *const st)
18552683f446SJiří Techet {
18562683f446SJiří Techet 	const bool inEnumBody = insideEnumBody (st);
18572683f446SJiří Techet 	int c = cppGetc ();
18582683f446SJiří Techet 
18592683f446SJiří Techet 	if (c != '=')
18602683f446SJiří Techet 	{
18612683f446SJiří Techet 		cppUngetc (c);
18622683f446SJiří Techet 		c = skipInitializer (st);
18632683f446SJiří Techet 		st->assignment = true;
18642683f446SJiří Techet 		if (c == ';')
18652683f446SJiří Techet 			setToken (st, TOKEN_SEMICOLON);
18662683f446SJiří Techet 		else if (c == ',')
18672683f446SJiří Techet 			setToken (st, TOKEN_COMMA);
18682683f446SJiří Techet 		else if (c == '}'  &&  inEnumBody)
18692683f446SJiří Techet 		{
18702683f446SJiří Techet 			cppUngetc (c);
18712683f446SJiří Techet 			setToken (st, TOKEN_COMMA);
18722683f446SJiří Techet 		}
18732683f446SJiří Techet 		if (st->scope == SCOPE_EXTERN)
18742683f446SJiří Techet 			st->scope = SCOPE_GLOBAL;
18752683f446SJiří Techet 	}
18762683f446SJiří Techet }
18772683f446SJiří Techet 
parseIdentifier(statementInfo * const st,const int c)18782683f446SJiří Techet static void parseIdentifier (statementInfo *const st, const int c)
18792683f446SJiří Techet {
18802683f446SJiří Techet 	tokenInfo *const token = activeToken (st);
18812683f446SJiří Techet 
18822683f446SJiří Techet 	readIdentifier (token, c);
18832683f446SJiří Techet 	if (! isType (token, TOKEN_NONE))
18842683f446SJiří Techet 		processToken (token, st);
18852683f446SJiří Techet }
18862683f446SJiří Techet 
parseGeneralToken(statementInfo * const st,const int c)18872683f446SJiří Techet static void parseGeneralToken (statementInfo *const st, const int c)
18882683f446SJiří Techet {
18892683f446SJiří Techet 	const tokenInfo *const prev = prevToken (st, 1);
18902683f446SJiří Techet 
189123c6e73eSJiří Techet 	if (cppIsident1 (c))
18922683f446SJiří Techet 	{
18932683f446SJiří Techet 
18942683f446SJiří Techet 		parseIdentifier (st, c);
18952683f446SJiří Techet 		if (isType (st->context, TOKEN_NAME) &&
18962683f446SJiří Techet 			isType (activeToken (st), TOKEN_NAME) && isType (prev, TOKEN_NAME))
18972683f446SJiří Techet 		{
18982683f446SJiří Techet 			initToken (st->context);
18992683f446SJiří Techet 		}
19002683f446SJiří Techet 	}
19012683f446SJiří Techet 	else if (c == '.' || c == '-')
19022683f446SJiří Techet 	{
19032683f446SJiří Techet 		if (! st->assignment)
19042683f446SJiří Techet 			st->notVariable = true;
19052683f446SJiří Techet 		if (c == '-')
19062683f446SJiří Techet 		{
19072683f446SJiří Techet 			int c2 = cppGetc ();
19082683f446SJiří Techet 			if (c2 != '>')
19092683f446SJiří Techet 				cppUngetc (c2);
19102683f446SJiří Techet 		}
19112683f446SJiří Techet 	}
19122683f446SJiří Techet 	else if (c == '!' || c == '>')
19132683f446SJiří Techet 	{
19142683f446SJiří Techet 		int c2 = cppGetc ();
19152683f446SJiří Techet 		if (c2 != '=')
19162683f446SJiří Techet 			cppUngetc (c2);
19172683f446SJiří Techet 	}
19182683f446SJiří Techet 	else if (c == STRING_SYMBOL) {
19192683f446SJiří Techet 		setToken(st, TOKEN_NONE);
19202683f446SJiří Techet 	}
19212683f446SJiří Techet }
19222683f446SJiří Techet 
19232683f446SJiří Techet /*  Reads characters from the pre-processor and assembles tokens, setting
19242683f446SJiří Techet  *  the current statement state.
19252683f446SJiří Techet  */
nextToken(statementInfo * const st)19262683f446SJiří Techet static void nextToken (statementInfo *const st)
19272683f446SJiří Techet {
19282683f446SJiří Techet 	tokenInfo *token;
19292683f446SJiří Techet 	do
19302683f446SJiří Techet 	{
19312683f446SJiří Techet 		int c = skipToNonWhite ();
19322683f446SJiří Techet 		switch (c)
19332683f446SJiří Techet 		{
19342683f446SJiří Techet 			case EOF: longjmp (Exception, (int) ExceptionEOF);  break;
19352683f446SJiří Techet 			case '(': analyzeParens (st);                       break;
19362683f446SJiří Techet 			case '<': processAngleBracket ();                   break;
19372683f446SJiří Techet 			case '*': st->haveQualifyingName = false;           break;
19382683f446SJiří Techet 			case ',': setToken (st, TOKEN_COMMA);               break;
19392683f446SJiří Techet 			case ':': processColon (st);                        break;
19402683f446SJiří Techet 			case ';': setToken (st, TOKEN_SEMICOLON);           break;
19412683f446SJiří Techet 			case '=': processInitializer (st);                  break;
19422683f446SJiří Techet 			case '[': skipToMatch ("[]");                       break;
19432683f446SJiří Techet 			case '{': setToken (st, TOKEN_BRACE_OPEN);          break;
19442683f446SJiří Techet 			case '}': setToken (st, TOKEN_BRACE_CLOSE);         break;
19452683f446SJiří Techet 			default:  parseGeneralToken (st, c);                break;
19462683f446SJiří Techet 		}
19472683f446SJiří Techet 		token = activeToken (st);
19482683f446SJiří Techet 	} while (isType (token, TOKEN_NONE));
19492683f446SJiří Techet }
19502683f446SJiří Techet 
19512683f446SJiří Techet /*
19522683f446SJiří Techet *   Scanning support functions
19532683f446SJiří Techet */
19542683f446SJiří Techet 
19552683f446SJiří Techet static statementInfo *CurrentStatement = NULL;
19562683f446SJiří Techet 
newStatement(statementInfo * const parent)19572683f446SJiří Techet static statementInfo *newStatement (statementInfo *const parent)
19582683f446SJiří Techet {
19592683f446SJiří Techet 	statementInfo *const st = xMalloc (1, statementInfo);
19602683f446SJiří Techet 	unsigned int i;
19612683f446SJiří Techet 
19622683f446SJiří Techet 	for (i = 0  ;  i < (unsigned int) NumTokens  ;  ++i)
19632683f446SJiří Techet 		st->token [i] = newToken ();
19642683f446SJiří Techet 
19652683f446SJiří Techet 	st->context = newToken ();
19662683f446SJiří Techet 	st->blockName = newToken ();
19672683f446SJiří Techet 	st->parentClasses = vStringNew ();
19682683f446SJiří Techet 
19692683f446SJiří Techet 	initStatement (st, parent);
19702683f446SJiří Techet 	CurrentStatement = st;
19712683f446SJiří Techet 
19722683f446SJiří Techet 	return st;
19732683f446SJiří Techet }
19742683f446SJiří Techet 
deleteStatement(void)19752683f446SJiří Techet static void deleteStatement (void)
19762683f446SJiří Techet {
19772683f446SJiří Techet 	statementInfo *const st = CurrentStatement;
19782683f446SJiří Techet 	statementInfo *const parent = st->parent;
19792683f446SJiří Techet 	unsigned int i;
19802683f446SJiří Techet 
19812683f446SJiří Techet 	for (i = 0  ;  i < (unsigned int) NumTokens  ;  ++i)
19822683f446SJiří Techet 	{
19832683f446SJiří Techet 		deleteToken (st->token [i]);       st->token [i] = NULL;
19842683f446SJiří Techet 	}
19852683f446SJiří Techet 	deleteToken (st->blockName);           st->blockName = NULL;
19862683f446SJiří Techet 	deleteToken (st->context);             st->context = NULL;
19872683f446SJiří Techet 	vStringDelete (st->parentClasses);     st->parentClasses = NULL;
19882683f446SJiří Techet 	eFree (st);
19892683f446SJiří Techet 	CurrentStatement = parent;
19902683f446SJiří Techet }
19912683f446SJiří Techet 
deleteAllStatements(void)19922683f446SJiří Techet static void deleteAllStatements (void)
19932683f446SJiří Techet {
19942683f446SJiří Techet 	while (CurrentStatement != NULL)
19952683f446SJiří Techet 		deleteStatement ();
19962683f446SJiří Techet }
19972683f446SJiří Techet 
isStatementEnd(const statementInfo * const st)19982683f446SJiří Techet static bool isStatementEnd (const statementInfo *const st)
19992683f446SJiří Techet {
20002683f446SJiří Techet 	const tokenInfo *const token = activeToken (st);
20012683f446SJiří Techet 	bool isEnd;
20022683f446SJiří Techet 
20032683f446SJiří Techet 	if (isType (token, TOKEN_SEMICOLON))
20042683f446SJiří Techet 		isEnd = true;
20052683f446SJiří Techet 	else if (isType (token, TOKEN_BRACE_CLOSE))
200623c6e73eSJiří Techet 		isEnd = ! isContextualStatement (st);
20072683f446SJiří Techet 	else
20082683f446SJiří Techet 		isEnd = false;
20092683f446SJiří Techet 
20102683f446SJiří Techet 	return isEnd;
20112683f446SJiří Techet }
20122683f446SJiří Techet 
checkStatementEnd(statementInfo * const st,int corkIndex)20132683f446SJiří Techet static void checkStatementEnd (statementInfo *const st, int corkIndex)
20142683f446SJiří Techet {
20152683f446SJiří Techet 	const tokenInfo *const token = activeToken (st);
20162683f446SJiří Techet 
20172683f446SJiří Techet 	tagEntryInfo *e = getEntryInCorkQueue (corkIndex);
20182683f446SJiří Techet 	if (e)
20192683f446SJiří Techet 		e->extensionFields.endLine = token->lineNumber;
20202683f446SJiří Techet 
20212683f446SJiří Techet 	if (isType (token, TOKEN_COMMA))
20222683f446SJiří Techet 		reinitStatement (st, true);
20232683f446SJiří Techet 	else if (isStatementEnd (st))
20242683f446SJiří Techet 	{
20252683f446SJiří Techet 		DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>"); )
20262683f446SJiří Techet 		reinitStatement (st, false);
20272683f446SJiří Techet 		cppEndStatement ();
20282683f446SJiří Techet 	}
20292683f446SJiří Techet 	else
20302683f446SJiří Techet 	{
20312683f446SJiří Techet 		cppBeginStatement ();
20322683f446SJiří Techet 		advanceToken (st);
20332683f446SJiří Techet 	}
20342683f446SJiří Techet }
20352683f446SJiří Techet 
nest(statementInfo * const st,const unsigned int nestLevel)20362683f446SJiří Techet static void nest (statementInfo *const st, const unsigned int nestLevel)
20372683f446SJiří Techet {
20382683f446SJiří Techet 	switch (st->declaration)
20392683f446SJiří Techet 	{
20402683f446SJiří Techet 		case DECL_CLASS:
20412683f446SJiří Techet 		case DECL_ENUM:
20422683f446SJiří Techet 		case DECL_INTERFACE:
20432683f446SJiří Techet 			createTags (nestLevel, st);
20442683f446SJiří Techet 			break;
20452683f446SJiří Techet 
20462683f446SJiří Techet 		case DECL_FUNCTION:
20472683f446SJiří Techet 		case DECL_TASK:
20482683f446SJiří Techet 			st->inFunction = true;
20492683f446SJiří Techet 			/* fall through */
20502683f446SJiří Techet 		default:
20512683f446SJiří Techet 			if (includeTag (TAG_LOCAL, false) || includeTag (TAG_LABEL, false))
20522683f446SJiří Techet 				createTags (nestLevel, st);
20532683f446SJiří Techet 			else
20542683f446SJiří Techet 				skipToMatch ("{}");
20552683f446SJiří Techet 			break;
20562683f446SJiří Techet 	}
20572683f446SJiří Techet 	advanceToken (st);
20582683f446SJiří Techet 	setToken (st, TOKEN_BRACE_CLOSE);
20592683f446SJiří Techet }
20602683f446SJiří Techet 
tagCheck(statementInfo * const st)20612683f446SJiří Techet static int tagCheck (statementInfo *const st)
20622683f446SJiří Techet {
20632683f446SJiří Techet 	const tokenInfo *const token = activeToken (st);
20642683f446SJiří Techet 	const tokenInfo *const prev  = prevToken (st, 1);
20652683f446SJiří Techet 	const tokenInfo *const prev2 = prevToken (st, 2);
20662683f446SJiří Techet 	int corkIndex = CORK_NIL;
20672683f446SJiří Techet 
20682683f446SJiří Techet 	switch (token->type)
20692683f446SJiří Techet 	{
20702683f446SJiří Techet 		case TOKEN_NAME:
20712683f446SJiří Techet 			if (insideEnumBody (st))
20722683f446SJiří Techet 				corkIndex = qualifyEnumeratorTag (st, token);
207323c6e73eSJiří Techet 			if (insideInterfaceBody (st))
20742683f446SJiří Techet 			{
20752683f446SJiří Techet 				/* Quoted from
20762683f446SJiří Techet 				   http://www.asic-world.com/vera/hdl1.html#Interface_Declaration
20772683f446SJiří Techet 				   ------------------------------------------------
20782683f446SJiří Techet 				   interface interface_name
20792683f446SJiří Techet 				   {
20802683f446SJiří Techet 				   signal_direction [signal_width] signal_name signal_type
20812683f446SJiří Techet 				   [skew] [depth value][vca q_value][force][hdl_node "hdl_path"];
20822683f446SJiří Techet 				   }
20832683f446SJiří Techet 				   Where
20842683f446SJiří Techet 				   signal_direction : This can be one of the following
20852683f446SJiří Techet 				        input : ...
20862683f446SJiří Techet 				        output : ...
20872683f446SJiří Techet 				        inout : ...
20882683f446SJiří Techet 				   signal_width : The signal_width is a range specifying the width of
20892683f446SJiří Techet 				                  a vector signal. It must be in the form [msb:lsb].
20902683f446SJiří Techet 						  Interface signals can have any integer lsb value,
20912683f446SJiří Techet 						  even a negative value. The default width is 1.
20922683f446SJiří Techet 				   signal_name : The signal_name identifies the signal being defined.
20932683f446SJiří Techet 				                 It is the Vera name for the HDL signal being connected.
20942683f446SJiří Techet 				   signal_type : There are many signals types, most commonly used one are
20952683f446SJiří Techet 					NHOLD : ...
20962683f446SJiří Techet 					PHOLD : ...
20972683f446SJiří Techet 					PHOLD NHOLD : ...
20982683f446SJiří Techet 					NSAMPLE : ...
20992683f446SJiří Techet 					PSAMPLE : ...
21002683f446SJiří Techet 					PSAMPLE NSAMPLE : ...
21012683f446SJiří Techet 					CLOCK : ...
21022683f446SJiří Techet 					PSAMPLE PHOLD : ...
21032683f446SJiří Techet 					NSAMPLE NHOLD : ...
21042683f446SJiří Techet 					PSAMPLE PHOLD NSAMPLE NHOLD : ...
21052683f446SJiří Techet 				   ------------------------------------------------
21062683f446SJiří Techet 				   We want to capture "signal_name" here.
21072683f446SJiří Techet 				*/
21082683f446SJiří Techet 				if (( isType (prev, TOKEN_KEYWORD)
21092683f446SJiří Techet 				      && isSignalDirection(prev) ) ||
21102683f446SJiří Techet 				    ( isType (prev2, TOKEN_KEYWORD)
21112683f446SJiří Techet 				      && isSignalDirection(prev) ))
21122683f446SJiří Techet 					corkIndex = makeTag (token, st, false, TAG_SIGNAL);
21132683f446SJiří Techet 			}
21142683f446SJiří Techet 			break;
21152683f446SJiří Techet 		case TOKEN_BRACE_OPEN:
21162683f446SJiří Techet 			if (isType (prev, TOKEN_ARGS))
21172683f446SJiří Techet 			{
211801dc7f65SJiří Techet 				if (st->haveQualifyingName)
21192683f446SJiří Techet 				{
21202683f446SJiří Techet 					if (isType (prev2, TOKEN_NAME))
21212683f446SJiří Techet 						copyToken (st->blockName, prev2);
21222683f446SJiří Techet 
21232683f446SJiří Techet 					corkIndex = qualifyFunctionTag (st, prev2);
21242683f446SJiří Techet 				}
21252683f446SJiří Techet 			}
21262683f446SJiří Techet 			else if (isContextualStatement (st) ||
21272683f446SJiří Techet 					st->declaration == DECL_PROGRAM)
21282683f446SJiří Techet 			{
21292683f446SJiří Techet 				const tokenInfo *name_token = prev;
21302683f446SJiří Techet 
21312683f446SJiří Techet 				if (isType (name_token, TOKEN_NAME))
21322683f446SJiří Techet 					copyToken (st->blockName, name_token);
21332683f446SJiří Techet 				else
21342683f446SJiří Techet 				{
21352683f446SJiří Techet 					/*  For an anonymous struct or union we use a unique ID
21362683f446SJiří Techet 					 *  a number, so that the members can be found.
21372683f446SJiří Techet 					 */
21382683f446SJiří Techet 					char buf [20];  /* length of "_anon" + digits  + null */
21392683f446SJiří Techet 					sprintf (buf, "__anon%d", ++AnonymousID);
21402683f446SJiří Techet 					vStringCopyS (st->blockName->name, buf);
21412683f446SJiří Techet 					st->blockName->type = TOKEN_NAME;
21422683f446SJiří Techet 					st->blockName->keyword = KEYWORD_NONE;
21432683f446SJiří Techet 				}
21442683f446SJiří Techet 				corkIndex = qualifyBlockTag (st, name_token);
21452683f446SJiří Techet 			}
21462683f446SJiří Techet 			break;
21472683f446SJiří Techet 
21482683f446SJiří Techet 		case TOKEN_KEYWORD:
21492683f446SJiří Techet 			break;
21502683f446SJiří Techet 
21512683f446SJiří Techet 		case TOKEN_SEMICOLON:
21522683f446SJiří Techet 		case TOKEN_COMMA:
21532683f446SJiří Techet 			if (insideEnumBody (st))
21542683f446SJiří Techet 				;
21552683f446SJiří Techet 			else if (isType (prev, TOKEN_NAME))
21562683f446SJiří Techet 			{
21572683f446SJiří Techet 				if (isContextualKeyword (prev2))
21582683f446SJiří Techet 					corkIndex = makeTag (prev, st, true, TAG_EXTERN_VAR);
21592683f446SJiří Techet 				else
21602683f446SJiří Techet 					corkIndex = qualifyVariableTag (st, prev);
21612683f446SJiří Techet 			}
21622683f446SJiří Techet 			else if (isType (prev, TOKEN_ARGS)  &&  isType (prev2, TOKEN_NAME))
21632683f446SJiří Techet 			{
21642683f446SJiří Techet 				if (st->isPointer || st->inFunction)
21652683f446SJiří Techet 				{
21662683f446SJiří Techet 					/* If it looks like a pointer or we are in a function body then
21672683f446SJiří Techet 					   it's far more likely to be a variable. */
21682683f446SJiří Techet 					corkIndex = qualifyVariableTag (st, prev2);
21692683f446SJiří Techet 				}
21702683f446SJiří Techet 				else
21712683f446SJiří Techet 					corkIndex = qualifyFunctionDeclTag (st, prev2);
21722683f446SJiří Techet 			}
21732683f446SJiří Techet 			break;
21742683f446SJiří Techet 
21752683f446SJiří Techet 		default: break;
21762683f446SJiří Techet 	}
21772683f446SJiří Techet 
21782683f446SJiří Techet 	return corkIndex;
21792683f446SJiří Techet }
21802683f446SJiří Techet 
21812683f446SJiří Techet /*  Parses the current file and decides whether to write out and tags that
21822683f446SJiří Techet  *  are discovered.
21832683f446SJiří Techet  */
createTags(const unsigned int nestLevel,statementInfo * const parent)21842683f446SJiří Techet static void createTags (const unsigned int nestLevel,
21852683f446SJiří Techet 						statementInfo *const parent)
21862683f446SJiří Techet {
21872683f446SJiří Techet 	statementInfo *const st = newStatement (parent);
21882683f446SJiří Techet 
21892683f446SJiří Techet 	DebugStatement ( if (nestLevel > 0) debugParseNest (true, nestLevel); )
21902683f446SJiří Techet 	while (true)
21912683f446SJiří Techet 	{
21922683f446SJiří Techet 		tokenInfo *token;
21932683f446SJiří Techet 
21942683f446SJiří Techet 		nextToken (st);
21952683f446SJiří Techet 		token = activeToken (st);
21962683f446SJiří Techet 		if (isType (token, TOKEN_BRACE_CLOSE))
21972683f446SJiří Techet 		{
21982683f446SJiří Techet 			if (nestLevel > 0)
21992683f446SJiří Techet 				break;
22002683f446SJiří Techet 			else
22012683f446SJiří Techet 			{
22022683f446SJiří Techet 				verbose ("%s: unexpected closing brace at line %lu\n",
22032683f446SJiří Techet 						getInputFileName (), getInputLineNumber ());
22042683f446SJiří Techet 				longjmp (Exception, (int) ExceptionBraceFormattingError);
22052683f446SJiří Techet 			}
22062683f446SJiří Techet 		}
22072683f446SJiří Techet 		else if (isType (token, TOKEN_DOUBLE_COLON))
22082683f446SJiří Techet 		{
22092683f446SJiří Techet 			addContext (st, prevToken (st, 1));
22102683f446SJiří Techet 			advanceToken (st);
22112683f446SJiří Techet 		}
22122683f446SJiří Techet 		else
22132683f446SJiří Techet 		{
22142683f446SJiří Techet 			int corkIndex = tagCheck (st);
22152683f446SJiří Techet 			if (isType (token, TOKEN_BRACE_OPEN))
22162683f446SJiří Techet 				nest (st, nestLevel + 1);
22172683f446SJiří Techet 			checkStatementEnd (st, corkIndex);
22182683f446SJiří Techet 		}
22192683f446SJiří Techet 	}
22202683f446SJiří Techet 	deleteStatement ();
22212683f446SJiří Techet 	DebugStatement ( if (nestLevel > 0) debugParseNest (false, nestLevel - 1); )
22222683f446SJiří Techet }
22232683f446SJiří Techet 
findCTags(const unsigned int passCount)22242683f446SJiří Techet static rescanReason findCTags (const unsigned int passCount)
22252683f446SJiří Techet {
22262683f446SJiří Techet 	exception_t exception;
22272683f446SJiří Techet 	rescanReason rescan;
222823c6e73eSJiří Techet 	int kind_for_define = VK_DEFINE;
222923c6e73eSJiří Techet 	int kind_for_header = VK_HEADER;
223023c6e73eSJiří Techet 	int kind_for_param  = VK_MACRO_PARAM;
223123c6e73eSJiří Techet 	int role_for_macro_undef = VR_MACRO_UNDEF;
223223c6e73eSJiří Techet 	int role_for_macro_condition = VR_MACRO_CONDITION;
223323c6e73eSJiří Techet 	int role_for_header_system   = VR_HEADER_SYSTEM;
223423c6e73eSJiří Techet 	int role_for_header_local   = VR_HEADER_LOCAL;
22352683f446SJiří Techet 
22362683f446SJiří Techet 	Assert (passCount < 3);
22372683f446SJiří Techet 
22382683f446SJiří Techet 	AnonymousID = 0;
22392683f446SJiří Techet 
224023c6e73eSJiří Techet 	cppInit ((bool) (passCount > 1), false, false,
224123c6e73eSJiří Techet 		 true,
22422683f446SJiří Techet 		 kind_for_define, role_for_macro_undef, role_for_macro_condition, kind_for_param,
22432683f446SJiří Techet 		 kind_for_header, role_for_header_system, role_for_header_local,
22442683f446SJiří Techet 		 FIELD_UNKNOWN);
22452683f446SJiří Techet 
22462683f446SJiří Techet 	Signature = vStringNew ();
22472683f446SJiří Techet 
22482683f446SJiří Techet 	exception = (exception_t) setjmp (Exception);
22492683f446SJiří Techet 	rescan = RESCAN_NONE;
22502683f446SJiří Techet 	if (exception == ExceptionNone)
22512683f446SJiří Techet 		createTags (0, NULL);
22522683f446SJiří Techet 	else
22532683f446SJiří Techet 	{
22542683f446SJiří Techet 		deleteAllStatements ();
22552683f446SJiří Techet 		if (exception == ExceptionBraceFormattingError  &&  passCount == 1)
22562683f446SJiří Techet 		{
22572683f446SJiří Techet 			rescan = RESCAN_FAILED;
22582683f446SJiří Techet 			verbose ("%s: retrying file with fallback brace matching algorithm\n",
22592683f446SJiří Techet 					getInputFileName ());
22602683f446SJiří Techet 		}
22612683f446SJiří Techet 	}
22622683f446SJiří Techet 	vStringDelete (Signature);
22632683f446SJiří Techet 	cppTerminate ();
22642683f446SJiří Techet 	return rescan;
22652683f446SJiří Techet }
22662683f446SJiří Techet 
buildKeywordHash(const langType language,unsigned int idx)22672683f446SJiří Techet static void buildKeywordHash (const langType language, unsigned int idx)
22682683f446SJiří Techet {
22692683f446SJiří Techet 	const size_t count = ARRAY_SIZE (KeywordTable);
22702683f446SJiří Techet 	size_t i;
22712683f446SJiří Techet 	for (i = 0  ;  i < count  ;  ++i)
22722683f446SJiří Techet 	{
22732683f446SJiří Techet 		const keywordDesc* const p = &KeywordTable [i];
22742683f446SJiří Techet 		addKeyword (p->name, language, (int) p->id);
22752683f446SJiří Techet 	}
22762683f446SJiří Techet }
22772683f446SJiří Techet 
initializeVeraParser(const langType language)22782683f446SJiří Techet static void initializeVeraParser (const langType language)
22792683f446SJiří Techet {
22802683f446SJiří Techet 	Lang_vera = language;
228123c6e73eSJiří Techet 	buildKeywordHash (language, 0);
22822683f446SJiří Techet }
22832683f446SJiří Techet 
VeraParser(void)22842683f446SJiří Techet extern parserDefinition* VeraParser (void)
22852683f446SJiří Techet {
22862683f446SJiří Techet 	static const char *const extensions [] = { "vr", "vri", "vrh", NULL };
22872683f446SJiří Techet 	parserDefinition* def = parserNew ("Vera");
22882683f446SJiří Techet 	def->kindTable      = VeraKinds;
22892683f446SJiří Techet 	def->kindCount  = ARRAY_SIZE (VeraKinds);
22902683f446SJiří Techet 	def->extensions = extensions;
22912683f446SJiří Techet 	def->parser2    = findCTags;
22922683f446SJiří Techet 	def->initialize = initializeVeraParser;
22932683f446SJiří Techet 	// end: field is not tested.
22942683f446SJiří Techet 
22952683f446SJiří Techet 	/* cpreprocessor wants corkQueue. */
22962683f446SJiří Techet 	def->useCork    = CORK_QUEUE;
22972683f446SJiří Techet 
22982683f446SJiří Techet 	return def;
22992683f446SJiří Techet }
2300