parse.c
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:36k
源码类别:

编辑器/阅读器

开发平台:

DOS

  1. /*****************************************************************************
  2. *   $Id: parse.c,v 6.6 1998/08/20 04:50:36 darren Exp $
  3. *
  4. *   Copyright (c) 1996-1998, Darren Hiebert
  5. *
  6. *   This source code is released for free distribution under the terms of the
  7. *   GNU General Public License.
  8. *
  9. *   This module contains functions for parsing and scanning of a source file.
  10. *****************************************************************************/
  11. /*============================================================================
  12. =   Include files
  13. ============================================================================*/
  14. #ifdef HAVE_CONFIG_H
  15. # include <config.h>
  16. #endif
  17. #include "ctags.h"
  18. /*============================================================================
  19. =   Macros
  20. ============================================================================*/
  21. #define hashIndex(c) ((c) - '_')
  22. #define activeTag(st) ((st)->tag[(int)(st)->buf1])
  23. #define activeName(st) (activeTag(st).name)
  24. #define swapNameBuffers(st) ((st)->buf1 = (boolean)!(st)->buf1)
  25. #define isExternCDecl(st,c) ((c) == STRING_SYMBOL  &&  !(st)->gotName  && 
  26.  (st)->scope == SCOPE_EXTERN)
  27. /*============================================================================
  28. =   Data declarations
  29. ============================================================================*/
  30. /*  Used to specify type of keyword.
  31.  */
  32. typedef enum _keywordId {
  33.     KEYWORD_UNKNOWN,
  34.     KEYWORD_ABSTRACT, KEYWORD_ATTRIBUTE,
  35.     KEYWORD_BOOLEAN, KEYWORD_BYTE,
  36.     KEYWORD_CHAR, KEYWORD_CLASS, KEYWORD_CONST,
  37.     KEYWORD_DOUBLE,
  38.     KEYWORD_ENUM, KEYWORD_EXPLICIT, KEYWORD_EXTERN, KEYWORD_EXTENDS,
  39.     KEYWORD_FINAL, KEYWORD_FLOAT, KEYWORD_FRIEND,
  40.     KEYWORD_IMPLEMENTS, KEYWORD_IMPORT, KEYWORD_INLINE, KEYWORD_INT,
  41.     KEYWORD_INTERFACE,
  42.     KEYWORD_LONG,
  43.     KEYWORD_MUTABLE,
  44.     KEYWORD_NAMESPACE, KEYWORD_NEW, KEYWORD_NATIVE,
  45.     KEYWORD_OPERATOR, KEYWORD_OVERLOAD,
  46.     KEYWORD_PACKAGE, KEYWORD_PRIVATE, KEYWORD_PROTECTED, KEYWORD_PUBLIC,
  47.     KEYWORD_REGISTER,
  48.     KEYWORD_SHORT, KEYWORD_SIGNED, KEYWORD_STATIC, KEYWORD_STRUCT,
  49.     KEYWORD_SYNCHRONIZED,
  50.     KEYWORD_TEMPLATE, KEYWORD_THROW, KEYWORD_THROWS, KEYWORD_TRANSIENT,
  51.     KEYWORD_TYPEDEF, KEYWORD_TYPENAME,
  52.     KEYWORD_UNION, KEYWORD_UNSIGNED, KEYWORD_USING,
  53.     KEYWORD_VIRTUAL, KEYWORD_VOID, KEYWORD_VOLATILE,
  54.     KEYWORD_WCHAR_T
  55. } keywordId;
  56. /*  Used to determine whether keyword is valid for the current language and
  57.  *  what its ID is.
  58.  */
  59. typedef struct _keywordDesc {
  60.     const char *name;
  61.     keywordId id;
  62.     short isValid[LANG_COUNT]; /* indicates languages for which kw is valid */
  63. } keywordDesc;
  64. /*  Used for reporting the type of object parsed by nextToken().
  65.  */
  66. typedef enum _tokenType {
  67.     TOK_NONE, /* none */
  68.     TOK_ARGS, /* a parenthetical pair and its contents */
  69.     TOK_BODY, /* a brace enclosed block */
  70.     TOK_COMMA, /* the comma character */
  71.     TOK_IGNORE, /* a sequence not to be seen by createTags() */
  72.     TOK_ENUM_BODY_END, /* the beginning of a list of enumeration values */
  73.     TOK_EOF, /* end of file */
  74.     TOK_NAME, /* an unknown name */
  75.     TOK_SEMICOLON, /* the semicolon character */
  76.     TOK_SPEC /* a storage class specifier, qualifier, type, etc. */
  77. } tokenType;
  78. /*  Describes the statement currently undergoing analysis.
  79.  */
  80. typedef struct _statementInfo {
  81.     tagScope scope;
  82.     enum _declaration {
  83. DECL_BASE, /* base type (default) */
  84. DECL_CLASS, /* C++ class */
  85. DECL_ENUM, /* enumeration */
  86. DECL_IGNORE, /* non-taggable "declaration" */
  87. DECL_INTERFACE, /* interface */
  88. DECL_NAMESPACE, /* namespace */
  89. DECL_STRUCT, /* structure */
  90. DECL_UNION, /* union */
  91. DECL_NOMANGLE /* C++ name demangling block */
  92.     } declaration; /* describes specifier associated with TOK_SPEC */
  93.     tokenType token; /* the most recent type of token */
  94.     tokenType prev[2]; /* the previous tokens */
  95.     boolean gotName; /* was a name parsed yet? */
  96.     boolean isFuncPtr; /* is 'name' a pointer? */
  97.     boolean inEnumBody; /* currently within enumeration value list? */
  98.     boolean buf1; /* is tag[1] the primary buffer? */
  99.     tagInfo tag[2]; /* information regarding last 2 tag candidates */
  100.     tagInfo class; /* class declaration name info */
  101.     memberInfo member; /* information regarding parent class/struct */
  102. } statementInfo;
  103. /*  Information about an identifier within parentheses.
  104.  */
  105. typedef struct _parenInfo {
  106.     char name[MaxNameLength];
  107.     boolean gotName;
  108.     long location;
  109.     long lineNumber;
  110. } parenInfo;
  111. /*============================================================================
  112. =   Data definitions
  113. ============================================================================*/
  114. enum { HashSize = ('z' - '_' + 1) }; /* '_' through 'z' */
  115. static short KeywordHash[(int)HashSize];
  116. static const keywordDesc KeywordTable[] = {
  117.     /*      C++ */
  118.     /*       ANSI C  |  Java */
  119.     /* keyword keyword ID     |   /   */
  120.     { "__attribute__", KEYWORD_ATTRIBUTE, { 1, 1, 0 } },
  121.     { "abstract", KEYWORD_ABSTRACT, { 0, 0, 1 } },
  122.     { "boolean", KEYWORD_BOOLEAN, { 0, 0, 1 } },
  123.     { "byte", KEYWORD_BYTE, { 0, 0, 1 } },
  124.     { "char", KEYWORD_CHAR, { 1, 1, 1 } },
  125.     { "class", KEYWORD_CLASS, { 0, 1, 1 } },
  126.     { "const", KEYWORD_CONST, { 1, 1, 1 } },
  127.     { "double", KEYWORD_DOUBLE, { 1, 1, 1 } },
  128.     { "enum", KEYWORD_ENUM, { 1, 1, 0 } },
  129.     { "explicit", KEYWORD_EXPLICIT, { 0, 1, 0 } },
  130.     { "extends", KEYWORD_EXTENDS, { 0, 0, 1 } },
  131.     { "extern", KEYWORD_EXTERN, { 1, 1, 0 } },
  132.     { "final", KEYWORD_FINAL, { 0, 0, 1 } },
  133.     { "float", KEYWORD_FLOAT, { 1, 1, 1 } },
  134.     { "friend", KEYWORD_FRIEND, { 0, 1, 0 } },
  135.     { "implements", KEYWORD_IMPLEMENTS, { 0, 0, 1 } },
  136.     { "import", KEYWORD_IMPORT, { 0, 0, 1 } },
  137.     { "inline", KEYWORD_INLINE, { 0, 1, 0 } },
  138.     { "int", KEYWORD_INT, { 1, 1, 1 } },
  139.     { "interface", KEYWORD_INTERFACE, { 0, 0, 1 } },
  140.     { "long", KEYWORD_LONG, { 1, 1, 1 } },
  141.     { "mutable", KEYWORD_MUTABLE, { 0, 1, 0 } },
  142.     { "namespace", KEYWORD_NAMESPACE, { 0, 1, 0 } },
  143.     { "native", KEYWORD_NATIVE, { 0, 0, 1 } },
  144.     { "new", KEYWORD_NEW, { 0, 1, 1 } },
  145.     { "operator", KEYWORD_OPERATOR, { 0, 1, 0 } },
  146.     { "overload", KEYWORD_OVERLOAD, { 0, 1, 0 } },
  147.     { "package", KEYWORD_PACKAGE, { 0, 0, 1 } },
  148.     { "private", KEYWORD_PRIVATE, { 0, 1, 1 } },
  149.     { "protected", KEYWORD_PROTECTED, { 0, 1, 1 } },
  150.     { "public", KEYWORD_PUBLIC, { 0, 1, 1 } },
  151.     { "register", KEYWORD_REGISTER, { 1, 1, 0 } },
  152.     { "short", KEYWORD_SHORT, { 1, 1, 1 } },
  153.     { "signed", KEYWORD_SIGNED, { 1, 1, 0 } },
  154.     { "static", KEYWORD_STATIC, { 1, 1, 1 } },
  155.     { "struct", KEYWORD_STRUCT, { 1, 1, 0 } },
  156.     { "synchronized", KEYWORD_SYNCHRONIZED, { 0, 0, 1 } },
  157.     { "template", KEYWORD_TEMPLATE, { 0, 1, 0 } },
  158.     { "throw", KEYWORD_THROW, { 0, 1, 1 } },
  159.     { "throws", KEYWORD_THROWS, { 0, 0, 1 } },
  160.     { "transient", KEYWORD_TRANSIENT, { 0, 0, 1 } },
  161.     { "typedef", KEYWORD_TYPEDEF, { 1, 1, 0 } },
  162.     { "typename", KEYWORD_TYPENAME, { 0, 1, 0 } },
  163.     { "union", KEYWORD_UNION, { 1, 1, 0 } },
  164.     { "unsigned", KEYWORD_UNSIGNED, { 1, 1, 0 } },
  165.     { "using", KEYWORD_USING, { 0, 1, 0 } },
  166.     { "virtual", KEYWORD_VIRTUAL, { 0, 1, 0 } },
  167.     { "void", KEYWORD_VOID, { 1, 1, 1 } },
  168.     { "volatile", KEYWORD_VOLATILE, { 1, 1, 1 } },
  169.     { "wchar_t", KEYWORD_WCHAR_T, { 1, 1, 0 } }
  170. };
  171. static const size_t KeywordTableSize =
  172. sizeof(KeywordTable)/sizeof(KeywordTable[0]);
  173. /*============================================================================
  174. =   Function prototypes
  175. ============================================================================*/
  176. static void initTag __ARGS((tagInfo *const tag));
  177. static void initMemberInfo __ARGS((memberInfo *const pMember));
  178. static void reinitStatement __ARGS((statementInfo *const st));
  179. static void initStatement __ARGS((statementInfo *const st, const statementInfo *const parent));
  180. /*  Tag generation functions.
  181.  */
  182. static void qualifyBlockTag __ARGS((const statementInfo *const st, const tagInfo *const tag, const tagScope declScope));
  183. static void qualifyEnumeratorTag __ARGS((const statementInfo *const st, const tagInfo *const tag, const tagScope declScope));
  184. static void qualifyFunctionTag __ARGS((statementInfo *const st, const tagInfo *const tag));
  185. static void qualifyVariableTag __ARGS((const statementInfo *const st, const tagInfo *const tag));
  186. static void qualifyFunctionDeclTag __ARGS((const statementInfo *const st, const tagInfo *const tag));
  187. /*  Parsing functions.
  188.  */
  189. static int skipToNonWhite __ARGS((void));
  190. static void skipToFormattedBraceMatch __ARGS((void));
  191. static boolean skipToMatch __ARGS((const char *const pair));
  192. static void readIdentifier __ARGS((const int firstChar, char *const name));
  193. static void readOperator __ARGS((const int firstChar, char *const name));
  194. static keywordId analyzeKeyword __ARGS((const char *const name));
  195. static void processKeyword __ARGS((statementInfo *const st, keywordId keyword));
  196. static int skipPostArgumentStuff __ARGS((int c, statementInfo *const st, const boolean emptyArgList));
  197. static boolean analyzePostParens __ARGS((statementInfo *const st, const parenInfo *const paren, const boolean emptyArgList));
  198. static void initParenInfo __ARGS((parenInfo *const paren));
  199. static boolean saveParenInfo __ARGS((parenInfo *const paren, int c));
  200. static boolean doubleParens __ARGS((statementInfo *const st));
  201. static boolean analyzeParens __ARGS((statementInfo *const st));
  202. static void analyzeIdentifier __ARGS((statementInfo *const st));
  203. static boolean beginBlock __ARGS((statementInfo *const st, const unsigned int nesting));
  204. static boolean endBlock __ARGS((statementInfo *const st, const unsigned int nesting));
  205. static void processColon __ARGS((statementInfo *const st));
  206. static int skipInitializer __ARGS((const boolean inEnumBody));
  207. static boolean processInitializer __ARGS((statementInfo *const st));
  208. static boolean processArray __ARGS((statementInfo *const st));
  209. static boolean processTemplate __ARGS((statementInfo *const st));
  210. static void processIdentifier __ARGS((statementInfo *const st, const int c));
  211. static boolean nextToken __ARGS((statementInfo *const st, const unsigned int nesting));
  212. /*============================================================================
  213. =   Function definitions
  214. ============================================================================*/
  215. static void initTag( tag )
  216.     tagInfo *const tag;
  217. {
  218.     tag->location = 0;
  219.     tag->lineNumber = 0;
  220.     tag->name[0] = '';
  221.     DebugStatement( clearString(tag->name, MaxNameLength); )
  222. }
  223. static void initMemberInfo( pMember )
  224.     memberInfo *const pMember;
  225. {
  226.     pMember->type = MEMBER_NONE;
  227.     pMember->visibility = VIS_UNDEFINED;
  228.     pMember->parent[0] = '';
  229.     DebugStatement( clearString(pMember->parent, MaxNameLength); )
  230. }
  231. static void reinitStatement( st )
  232.     statementInfo *const st;
  233. {
  234.     int i;
  235.     st->scope = SCOPE_GLOBAL;
  236.     st->declaration = DECL_BASE;
  237.     st->token = TOK_NONE;
  238.     st->prev[0] = TOK_NONE;
  239.     st->prev[1] = TOK_NONE;
  240.     st->gotName = FALSE;
  241.     st->isFuncPtr = FALSE;
  242.     st->buf1 = FALSE;
  243.     for (i = 0  ;  i < 2  ;  ++i)
  244. initTag(&st->tag[i]);
  245.     initTag(&st->class);
  246.     if (st->member.type != MEMBER_NONE  &&  ! st->member.persistent)
  247. initMemberInfo(&st->member);
  248. }
  249. static void initStatement( st, parent )
  250.     statementInfo *const st;
  251.     const statementInfo *const parent;
  252. {
  253.     /*  Set the member information. If there is a parent statement, inherit
  254.      *  the parent member information from it.
  255.      */
  256.     if (parent == NULL)
  257.     {
  258. initMemberInfo(&st->member);
  259. st->inEnumBody = FALSE;
  260.     }
  261.     else
  262.     {
  263. st->inEnumBody = (boolean)(parent->declaration == DECL_ENUM);
  264. st->member.visibility = VIS_UNDEFINED;
  265. switch (parent->declaration)
  266. {
  267.     case DECL_ENUM: st->member.type = MEMBER_ENUM; break;
  268.     case DECL_CLASS: st->member.type = MEMBER_CLASS;
  269. st->member.visibility = VIS_PRIVATE; break;
  270.     case DECL_INTERFACE:st->member.type = MEMBER_INTERFACE; break;
  271.     case DECL_NAMESPACE:st->member.type = MEMBER_NAMESPACE; break;
  272.     case DECL_STRUCT: st->member.type = MEMBER_STRUCT;
  273. st->member.visibility = VIS_PUBLIC; break;
  274.     case DECL_UNION: st->member.type = MEMBER_UNION; break;
  275.     default: st->member.type = MEMBER_NONE; break;
  276. }
  277. DebugStatement( clearString(st->member.parent, MaxNameLength); )
  278. if (st->member.type != MEMBER_NONE)
  279. {
  280.     st->member.persistent = TRUE;
  281.     if (parent->declaration == DECL_CLASS)
  282. strcpy(st->member.parent, parent->class.name);
  283.     else
  284. strcpy(st->member.parent,
  285.        (parent->prev[0] == TOK_NAME) ? activeName(parent) : "");
  286. }
  287.     }
  288.     reinitStatement(st);
  289. }
  290. /*----------------------------------------------------------------------------
  291. *- Tag generation functions
  292. ----------------------------------------------------------------------------*/
  293. static void qualifyBlockTag( st, tag, declScope )
  294.     const statementInfo *const st;
  295.     const tagInfo *const tag;
  296.     const tagScope declScope;
  297. {
  298.     if (st->prev[0] == TOK_NAME)
  299.     {
  300. boolean ok = TRUE;
  301. tagType type = TAG_NUMTYPES; /* assignment to avoid warning */
  302. switch (st->declaration)
  303. {
  304.     case DECL_CLASS: type = TAG_CLASS; break;
  305.     case DECL_ENUM: type = TAG_ENUM; break;
  306.     case DECL_INTERFACE:type = TAG_INTERFACE; break;
  307.     case DECL_NAMESPACE:type = TAG_NAMESPACE; break;
  308.     case DECL_STRUCT: type = TAG_STRUCT; break;
  309.     case DECL_UNION: type = TAG_UNION; break;
  310.     default: ok = FALSE; break;
  311. }
  312. if (ok)
  313.     makeTag(tag, &st->member, declScope, type);
  314.     }
  315. }
  316. static void qualifyEnumeratorTag( st, tag, declScope )
  317.     const statementInfo *const st;
  318.     const tagInfo *const tag;
  319.     const tagScope declScope;
  320. {
  321.     if (st->token == TOK_NAME)
  322. makeTag(tag, &st->member, declScope, TAG_ENUMERATOR);
  323. }
  324. static void qualifyFunctionTag( st, tag )
  325.     statementInfo *const st;
  326.     const tagInfo *const tag;
  327. {
  328.     if (st->scope == SCOPE_EXTERN) /* allowed for func. def. */
  329. st->scope = SCOPE_GLOBAL;
  330.     makeTag(tag, &st->member, st->scope, TAG_FUNCTION);
  331. }
  332. static void qualifyVariableTag( st, tag )
  333.     const statementInfo *const st;
  334.     const tagInfo *const tag;
  335. {
  336.     /* We have to watch that we do not interpret a declaration of the
  337.      * form "struct tag;" as a variable definition. In such a case, the
  338.      * declaration will be either class, enum, struct or union, and prev[1]
  339.      * will be empty.
  340.      */
  341.     if (st->declaration == DECL_IGNORE)
  342. ;
  343.     else if (st->declaration == DECL_BASE  ||  st->prev[1] != TOK_SPEC)
  344.     {
  345. if (st->member.type == MEMBER_NONE)
  346. {
  347.     if (st->scope == SCOPE_EXTERN)
  348. makeTag(tag, &st->member, st->scope, TAG_EXTERN_VAR);
  349.     else
  350. makeTag(tag, &st->member, st->scope, TAG_VARIABLE);
  351. }
  352. else
  353. {
  354.     if (st->scope == SCOPE_GLOBAL)
  355. makeTag(tag, &st->member, st->scope, TAG_MEMBER);
  356.     else if (st->scope == SCOPE_STATIC)
  357. makeTag(tag, &st->member, SCOPE_EXTERN, TAG_MEMBER);
  358. }
  359.     }
  360. }
  361. static void qualifyFunctionDeclTag( st, tag )
  362.     const statementInfo *const st;
  363.     const tagInfo *const tag;
  364. {
  365.     if (! File.isHeader)
  366. makeTag(tag, &st->member, SCOPE_STATIC, TAG_FUNCDECL);
  367.     else if (st->scope == SCOPE_GLOBAL  ||  st->scope == SCOPE_EXTERN)
  368. makeTag(tag, &st->member, SCOPE_GLOBAL, TAG_FUNCDECL);
  369. }
  370. /*----------------------------------------------------------------------------
  371. *- Parsing functions
  372. ----------------------------------------------------------------------------*/
  373. /*  Skip to the next non-white character.
  374.  */
  375. static int skipToNonWhite()
  376. {
  377.     int c;
  378.     do
  379.     {
  380. c = cppGetc();
  381.     } while (c != EOF  &&  isspace(c));
  382.     return c;
  383. }
  384. #if 0
  385. /*  Skip to the next occurance of the specified character.
  386.  */
  387. static int skipToCharacter( findchar )
  388.     const int findchar;
  389. {
  390.     int c;
  391.     do
  392. c = cppGetc();
  393.     while (c != EOF  &&  c != findchar);
  394.     return c;
  395. }
  396. #endif
  397. /*  Skips to the next brace in column 1. This is intended for cases where
  398.  *  preprocessor constructs result in unbalanced braces.
  399.  */
  400. static void skipToFormattedBraceMatch()
  401. {
  402.     int c, next;
  403.     c = cppGetc();
  404.     next = cppGetc();
  405.     while (c != EOF  &&  (c != 'n'  ||  next != '}'))
  406.     {
  407. c = next;
  408. next = cppGetc();
  409.     }
  410. }
  411. /*  Skip to the matching character indicated by the pair string. If skipping
  412.  *  to a matching brace and any brace is found within a different level of a
  413.  *  #if conditional statement while brace formatting is in effect, we skip to
  414.  *  the brace matched by its formatting. It is assumed that we have already
  415.  *  read the character which starts the group (i.e. the first character of
  416.  *  "pair").
  417.  */
  418. static boolean skipToMatch( pair )
  419.     const char *const pair;
  420. {
  421.     const int begin = pair[0], end = pair[1];
  422.     const unsigned int initialLevel = Cpp.directive.nestLevel;
  423.     const boolean braceFormatting = (boolean)(Option.braceFormat &&
  424.       strcmp("{}", pair) == 0);
  425.     boolean ok = TRUE;
  426.     int matchLevel = 1;
  427.     int c = '';
  428.     while (matchLevel > 0  &&  (c = cppGetc()) != EOF)
  429.     {
  430. if (c == begin)
  431. {
  432.     ++matchLevel;
  433.     if (braceFormatting  &&  Cpp.directive.nestLevel != initialLevel)
  434.     {
  435. skipToFormattedBraceMatch();
  436. break;
  437.     }
  438. }
  439. else if (c == end)
  440. {
  441.     --matchLevel;
  442.     if (braceFormatting  &&  Cpp.directive.nestLevel != initialLevel)
  443.     {
  444. skipToFormattedBraceMatch();
  445. break;
  446.     }
  447. }
  448.     }
  449.     if (c == EOF)
  450. ok = FALSE;
  451.     return ok;
  452. }
  453. /*  Read a C identifier beginning with "firstChar" and places it into "name".
  454.  */
  455. static void readIdentifier( firstChar, name )
  456.     const int firstChar;
  457.     char *const name;
  458. {
  459.     int c, i;
  460.     name[0] = firstChar;
  461.     for (i = 1, c = cppGetc() ;
  462.  i < (int)MaxNameLength - 1  &&  isident(c) ;
  463.  i++, c = cppGetc())
  464.     {
  465. name[i] = c;
  466.     }
  467.     name[i] = ''; /* null terminate name */
  468.     cppUngetc(c); /* unget non-identifier character */
  469. }
  470. /*  Read a C++ operator and appends to "name" (which should contain "operator").
  471.  */
  472. static void readOperator( firstChar, name )
  473.     const int firstChar;
  474.     char *const name;
  475. {
  476.     int c, i;
  477.     for (c = firstChar, i = strlen(name) ;
  478.  i < (int)MaxNameLength - 1  &&  ! isspace(c)  &&  c != '(' ;
  479.  i++, c = cppGetc())
  480.     {
  481. name[i] = c;
  482.     }
  483.     if (i > 0)
  484. name[i] = ''; /* null terminate operator */
  485.     cppUngetc(c); /* unget non-operator character */
  486. }
  487. /*  Analyzes the identifier contained in a statement described by the
  488.  *  statement structure and adjusts the structure according the significance
  489.  *  of the identifier.
  490.  */
  491. static keywordId analyzeKeyword( name )
  492.     const char *const name;
  493. {
  494.     keywordId id = KEYWORD_UNKNOWN;
  495.     if (name[0] == '_'  ||  islower(name[0]))
  496.     {
  497. const short hash = KeywordHash[hashIndex(name[0])];
  498. if (hash >= 0)
  499. {
  500.     unsigned int i;
  501.     for (i = hash  ;  i < KeywordTableSize  ;  ++i)
  502.     {
  503. const keywordDesc *pKw = &KeywordTable[i];
  504. if (pKw->name[0] != name[0])
  505.     break;
  506. if (pKw->isValid[File.language] && strcmp(pKw->name, name) == 0)
  507. {
  508.     id = pKw->id;
  509.     break;
  510. }
  511.     }
  512. }
  513.     }
  514.     return id;
  515. }
  516. static void processKeyword( st, keyword )
  517.     statementInfo *const st;
  518.     keywordId keyword;
  519. {
  520.     st->token = TOK_SPEC; /* default unless otherwise */
  521.     switch (keyword) /* is it a reserved word? */
  522.     {
  523. default: st->token = TOK_IGNORE; break;
  524. case KEYWORD_CHAR: st->declaration = DECL_BASE; break;
  525. case KEYWORD_CLASS: st->declaration = DECL_CLASS; break;
  526. case KEYWORD_DOUBLE: st->declaration = DECL_BASE; break;
  527. case KEYWORD_ENUM: st->declaration = DECL_ENUM; break;
  528. case KEYWORD_EXTERN: st->scope = SCOPE_EXTERN; break;
  529. case KEYWORD_FLOAT: st->declaration = DECL_BASE; break;
  530. case KEYWORD_FRIEND: st->scope = SCOPE_FRIEND; break;
  531. case KEYWORD_IMPORT: st->declaration = DECL_IGNORE; break;
  532. case KEYWORD_INT: st->declaration = DECL_BASE; break;
  533. case KEYWORD_INTERFACE: st->declaration = DECL_INTERFACE; break;
  534. case KEYWORD_LONG: st->declaration = DECL_BASE; break;
  535. case KEYWORD_NAMESPACE: st->declaration = DECL_NAMESPACE; break;
  536. case KEYWORD_PACKAGE: st->declaration = DECL_IGNORE; break;
  537. case KEYWORD_PRIVATE: st->member.visibility = VIS_PRIVATE; break;
  538. case KEYWORD_PROTECTED: st->member.visibility = VIS_PROTECTED; break;
  539. case KEYWORD_PUBLIC: st->member.visibility = VIS_PUBLIC; break;
  540. case KEYWORD_SHORT: st->declaration = DECL_BASE; break;
  541. case KEYWORD_SIGNED: st->declaration = DECL_BASE; break;
  542. case KEYWORD_STRUCT: st->declaration = DECL_STRUCT; break;
  543. case KEYWORD_TYPEDEF: st->scope = SCOPE_TYPEDEF; break;
  544. case KEYWORD_UNION: st->declaration = DECL_UNION; break;
  545. case KEYWORD_UNSIGNED: st->declaration = DECL_BASE; break;
  546. case KEYWORD_VOID: st->declaration = DECL_BASE; break;
  547. case KEYWORD_ATTRIBUTE:
  548. {
  549.     const int c = skipToNonWhite();
  550.     if (c == '(')
  551. skipToMatch("()");
  552.     else
  553. cppUngetc(c);
  554.     st->token = TOK_IGNORE;
  555.     break;
  556. }
  557. case KEYWORD_EXTENDS:
  558. case KEYWORD_IMPLEMENTS:
  559. case KEYWORD_THROWS:
  560. {
  561.     char *const name = activeName(st);
  562.     int c = skipToNonWhite();
  563.     /*  Read and discard interface or class type-list (ident[, ident]).
  564.      */
  565.     while (isident1(c))
  566.     {
  567. readIdentifier(c, name);
  568. c = skipToNonWhite();
  569. if (c == '.'  ||  c == ',')
  570.     c = skipToNonWhite();
  571.     }
  572.     cppUngetc(c);
  573.     st->token = TOK_IGNORE;
  574.     break;
  575. }
  576. case KEYWORD_STATIC:
  577.     if (File.language != LANG_JAVA)
  578. st->scope = SCOPE_STATIC;
  579.     break;
  580. case KEYWORD_OPERATOR:
  581. {
  582.     char *const name = activeName(st);
  583.     const int c = skipToNonWhite();
  584.     if (isident1(c))
  585. readIdentifier(c, name);
  586.     else
  587. readOperator(c, name);
  588. } /* fall through to unknown keyword case */
  589. case KEYWORD_UNKNOWN:
  590. {
  591.     tagInfo *const tag = &activeTag(st);
  592.     st->token = TOK_NAME;
  593.     st->gotName = TRUE;
  594.     tag->location   = File.seek;
  595.     tag->lineNumber = File.lineNumber;
  596.     if (st->declaration == DECL_CLASS  &&  st->class.name[0] == '')
  597.     {
  598. strcpy(st->class.name, tag->name);
  599. st->class.location   = tag->location;
  600. st->class.lineNumber = tag->lineNumber;
  601.     }
  602.     break;
  603. }
  604.     }
  605. }
  606. /*  Skips over characters following the parameter list. This might be non-ANSI
  607.  *  style function declarations, a C++ exception specification, or another C++
  608.  *  construct that I don't yet understand (e.g. "void Class::foo(int a):
  609.  *  attr(v1), attr(v2)").
  610.  */
  611. static int skipPostArgumentStuff( c, st, emptyArgList )
  612.     int c;
  613.     statementInfo *const st;
  614.     const boolean emptyArgList;
  615. {
  616.     boolean end = FALSE, firstSemicolon = TRUE;
  617.     boolean skipCPlusStuff = (boolean)(c == ':');
  618.     unsigned int tokenCount = 0;
  619.     while (c != EOF  &&  ! end)
  620.     {
  621. if (skipCPlusStuff)
  622. {
  623.     if (c == '{'  ||  c == ';')
  624. break;
  625. }
  626. else if (isident1(c))
  627. {
  628.     char name[MaxNameLength];
  629.     keywordId keyword;
  630.     readIdentifier(c, name);
  631.     ++tokenCount;
  632.     keyword = analyzeKeyword(name);
  633.     switch (keyword)
  634.     {
  635.     /*  These words are explicitly allowed following the closing
  636.      *  parenthesis in C++.
  637.      */
  638.     case KEYWORD_CONST:
  639. break;
  640.     case KEYWORD_THROW:
  641. skipCPlusStuff = TRUE;
  642. break;
  643.     /*  These words are never allowed within parameter declarations.
  644.      */
  645.     case KEYWORD_CLASS:
  646.     case KEYWORD_EXTERN:
  647.     case KEYWORD_STATIC:
  648.     case KEYWORD_TYPEDEF:
  649. DebugStatement( if (debug(DEBUG_PARSE)) printf("<ES>"); )
  650. reinitStatement(st);
  651. processKeyword(st, keyword);
  652. c = skipToNonWhite();
  653. end = TRUE;
  654. continue; /* skip read of next character */
  655.     case KEYWORD_ATTRIBUTE:
  656. {
  657.     c = skipToNonWhite();
  658.     if (c == '('  &&  ! skipToMatch("()"))
  659. c = EOF;
  660. }
  661. break;
  662.     default:
  663. /*  If we encounter any other identifier immediately following
  664.  *  an empty parameter list, this is almost certainly one of
  665.  *  those Microsoft macro "thingies" that the automatic source
  666.  *  code generation sticks in. Terminate the current statement.
  667.  */
  668. if (emptyArgList)
  669. {
  670.     DebugStatement( if (debug(DEBUG_PARSE)) printf("<ES>"); )
  671.     reinitStatement(st);
  672.     processKeyword(st, keyword);
  673.     c = skipToNonWhite();
  674.     end = TRUE;
  675.     continue; /* skip read of next character */
  676. }
  677. break;
  678.     }
  679. }
  680. else switch (c)
  681. {
  682. default:    break; /* ignore */
  683. case ';':
  684.     /*  A lone word is most likely a preprocessor qualifier.
  685.      */
  686.     if (firstSemicolon  &&  tokenCount == 1)
  687.     {
  688. end = TRUE;
  689. continue;
  690.     }
  691.     else
  692.     {
  693. tokenCount = 0;
  694. firstSemicolon = FALSE;
  695. break;
  696.     }
  697. case '(':
  698.     ++tokenCount;
  699.     if (! skipToMatch("()"))
  700. c = EOF;
  701.     break;
  702. case '[':   if (! skipToMatch("[]"))  c = EOF; break;
  703. case '{':
  704. case '}':   end = TRUE;
  705.     continue; /* skip read of next character */
  706. }
  707. if (c != EOF)
  708.     c = cppGetc();
  709.     }
  710.     return c;
  711. }
  712. static boolean analyzePostParens( st, paren, emptyArgList )
  713.     statementInfo *const st;
  714.     const parenInfo *const paren;
  715.     const boolean emptyArgList;
  716. {
  717.     boolean ok = TRUE;
  718.     int c;
  719.     /* At this point we should be at the character following the
  720.      * closing parenthesis.
  721.      */
  722.     c = skipToNonWhite();
  723.     if (st->gotName)
  724.     {
  725. if (strchr("{;,", c) != NULL)
  726. {
  727.     st->token = TOK_ARGS; /* parameter list to a func. */
  728.     st->declaration = DECL_BASE; /* clear any other decl. */
  729. }
  730. else if (isident1(c)  ||  c == ':')
  731. {
  732.     st->token = TOK_ARGS; /* parameter list to a func. */
  733.     st->declaration = DECL_BASE; /* clear any other decl. */
  734.     if (File.language != LANG_JAVA)
  735. c = skipPostArgumentStuff(c, st, emptyArgList);
  736. }
  737. else
  738.     st->token = TOK_IGNORE;
  739.     }
  740.     /* The name inside the parentheses must have been a function or
  741.      * variable name.
  742.      */
  743.     else if (paren->gotName)
  744.     {
  745. tagInfo *const tag = &activeTag(st);
  746. st->gotName = TRUE;
  747. st->token = TOK_NAME;
  748. tag->location = paren->location;
  749. tag->lineNumber = paren->lineNumber;
  750. strcpy(tag->name, paren->name);
  751.     }
  752.     else
  753. st->token = TOK_IGNORE;
  754.     if (c == EOF)
  755. ok = FALSE;
  756.     else
  757. cppUngetc(c);
  758.     return ok;
  759. }
  760. static void initParenInfo( paren )
  761.     parenInfo *const paren;
  762. {
  763.     DebugStatement( clearString(paren->name, MaxNameLength); )
  764.     paren->gotName = FALSE;
  765.     paren->location = 0;
  766.     paren->lineNumber = 0;
  767. }
  768. static boolean saveParenInfo( paren, c )
  769.     parenInfo *const paren;
  770.     int c;
  771. {
  772.     boolean ok = TRUE;
  773.     readIdentifier(c, paren->name);
  774.     c = skipToNonWhite();
  775.     if (c == ')') /* saved if only identifier in parentheses */
  776.     {
  777. paren->gotName    = TRUE;
  778. paren->location   = File.seek;
  779. paren->lineNumber = File.lineNumber;
  780.     }
  781.     else
  782.     {
  783. if (c == '(')
  784.     cppUngetc(c);
  785. ok = skipToMatch("()");
  786.     }
  787.     return ok;
  788. }
  789. static boolean doubleParens( st )
  790.     statementInfo *const st;
  791. {
  792.     /* A double parenthesis almost certainly means one of those conditional
  793.      * prototype macro thingies (e.g. __ARGS((void)) ). If found, we will use
  794.      * the previous name, if it is not empty.
  795.      */
  796.     if (st->gotName  &&  *st->tag[!st->buf1].name != '')
  797. swapNameBuffers(st);
  798.     cppUngetc('('); /* put back for skipToMatch() */
  799.     return skipToMatch("()");
  800. }
  801. /*  Analyzes the context and contents of parentheses.
  802.  */
  803. static boolean analyzeParens( st )
  804.     statementInfo *const st;
  805. {
  806.     boolean ok = TRUE;
  807.     int c;
  808.     c = skipToNonWhite();
  809.     if (c == '*') /* this is a function pointer */
  810.     {
  811. st->gotName = FALSE; /* invalidate previous name */
  812. st->isFuncPtr = TRUE;
  813. st->token = TOK_IGNORE;
  814.     }
  815.     if (! st->gotName)
  816.     {
  817. st->token = TOK_IGNORE;
  818. cppUngetc(c);
  819.     }
  820.     else
  821.     {
  822. boolean terminate = FALSE, emptyArgList = FALSE;
  823. parenInfo paren;
  824. initParenInfo(&paren);
  825. if (isident1(c))
  826.     ok = saveParenInfo(&paren, c);
  827. else if (c == '(')
  828.     ok = doubleParens(st);
  829. else if (c == ')') /* empty parentheses... */
  830.     emptyArgList = TRUE;
  831. else
  832. {
  833.     /* This is an invalid character to be inside a paren in this
  834.      * context. This must be a macro call. After we read to the
  835.      * end of the parenthesis seqence, force a termination of the
  836.      * current statement,
  837.      */
  838.     st->token = TOK_NONE;
  839.     st->gotName = FALSE;
  840.     terminate = TRUE;
  841.     ok = skipToMatch("()");
  842. }
  843. if (ok  &&  ! terminate)
  844.     ok = analyzePostParens(st, &paren, emptyArgList);
  845.     }
  846.     return ok;
  847. }
  848. /*  Analyzes the identifier contained in a statement described by the
  849.  *  statement structure and adjusts the structure according the significance
  850.  *  of the identifier.
  851.  */
  852. static void analyzeIdentifier( st )
  853.     statementInfo *const st;
  854. {
  855.     tagInfo *const tag = &activeTag(st);
  856.     char *const name = tag->name;
  857.     if (isIgnoreToken(name))
  858. st->token = TOK_IGNORE;
  859.     else
  860. processKeyword(st, analyzeKeyword(name));
  861.     if (st->token == TOK_IGNORE)
  862. name[0] = '';
  863. }
  864. static void processIdentifier( st, c )
  865.     statementInfo *const st;
  866.     const int c;
  867. {
  868.     if (st->gotName)
  869. swapNameBuffers(st);
  870.     readIdentifier(c, activeName(st));
  871.     analyzeIdentifier(st);
  872.     if (st->gotName  &&  st->token == TOK_IGNORE)
  873. swapNameBuffers(st);
  874. }
  875. static void processColon( st )
  876.     statementInfo *const st;
  877. {
  878.     if (st->declaration != DECL_CLASS)
  879.     {
  880. const int c = skipToNonWhite();
  881. if (c == ':') /* this is a method or static member definition */
  882. {
  883.     st->member.type = MEMBER_CLASS;
  884.     strcpy(st->member.parent, activeName(st));
  885.     st->member.persistent = FALSE;
  886. }
  887. else
  888. {
  889.     cppUngetc(c);
  890.     st->token = TOK_IGNORE;
  891. }
  892.     }
  893. }
  894. /*  Skips over any initializing value which may follow a '=' character in a
  895.  *  variable definition.
  896.  */
  897. static int skipInitializer( enumInitializer )
  898.     const boolean enumInitializer;
  899. {
  900.     boolean done = FALSE;
  901.     int c;
  902.     do
  903.     {
  904. c = cppGetc();
  905. if (c != EOF) switch (c)
  906. {
  907.     case ',':
  908.     case ';':   done = TRUE; break;
  909.     case '[':   if (! skipToMatch("[]"))
  910.     c = EOF;
  911. break;
  912.     case '(':   if (! skipToMatch("()"))
  913.     c = EOF;
  914. break;
  915.     case '{':   if (! skipToMatch("{}"))
  916.     c = EOF;
  917. break;
  918.     case '}':   if (enumInitializer)
  919. {
  920.     cppUngetc(c);
  921.     done = TRUE;
  922. }
  923. else if (! Option.braceFormat)
  924.     c = EOF;
  925. break;
  926.     default:    break;
  927. }
  928.     } while (! done  &&  c != EOF);
  929.     return c;
  930. }
  931. static boolean processInitializer( st )
  932.     statementInfo *const st;
  933. {
  934.     boolean ok = TRUE;
  935.     const int c = skipInitializer(st->inEnumBody);
  936.     if (c == EOF)
  937. ok = FALSE;
  938.     else if (c == ';')
  939. st->token = TOK_SEMICOLON;
  940.     else if (c == ',')
  941. st->token = TOK_COMMA;
  942.     else if ('}'  &&  st->inEnumBody)
  943. st->token = TOK_COMMA;
  944.     if (st->scope == SCOPE_EXTERN)
  945. st->scope = SCOPE_GLOBAL;
  946.     return ok;
  947. }
  948. static boolean processArray( st )
  949.     statementInfo *const st;
  950. {
  951.     st->token = TOK_IGNORE;
  952.     return skipToMatch("[]");
  953. }
  954. static boolean processTemplate( st )
  955.     statementInfo *const st;
  956. {
  957.     st->token = TOK_IGNORE;
  958.     return skipToMatch("<>");
  959. }
  960. static boolean beginBlock( st, nesting )
  961.     statementInfo *const st;
  962.     const unsigned int nesting;
  963. {
  964.     const tagScope declScope = (File.isHeader || File.language == LANG_JAVA) ?
  965. SCOPE_GLOBAL : SCOPE_STATIC;
  966.     tagInfo *const tag = &activeTag(st);
  967.     boolean ok;
  968.     switch (st->declaration)
  969.     {
  970. case DECL_CLASS:
  971.     qualifyBlockTag(st, &st->class, declScope);
  972.     ok = createTags(nesting + 1, st);
  973.     break;
  974. case DECL_ENUM:
  975. case DECL_INTERFACE:
  976. case DECL_NAMESPACE:
  977. case DECL_STRUCT:
  978. case DECL_UNION:
  979.     qualifyBlockTag(st, tag, declScope);
  980.     ok = createTags(nesting + 1, st);
  981.     break;
  982. case DECL_NOMANGLE:
  983.     ok = createTags(nesting + 1, st);
  984.     break;
  985. default:
  986.     ok = skipToMatch("{}");
  987.     }
  988.     st->token = TOK_BODY;
  989.     return ok;
  990. }
  991. static boolean endBlock( st, nesting )
  992.     statementInfo *const st;
  993.     const unsigned int nesting;
  994. {
  995.     boolean ok = TRUE;
  996.     if (nesting > 0)
  997. st->token = TOK_EOF; /* fake out */
  998.     else
  999.     {
  1000. st->token = TOK_IGNORE;
  1001. ok = FALSE;
  1002.     }
  1003.     return ok;
  1004. }
  1005. /*  Reads characters from the pre-processor and assembles tokens, setting
  1006.  *  the current statement state.
  1007.  */
  1008. static boolean nextToken( st, nesting )
  1009.     statementInfo *const st;
  1010.     const unsigned int nesting;
  1011. {
  1012.     int c;
  1013.     boolean ok = TRUE;
  1014.     do
  1015.     {
  1016. c = cppGetc();
  1017. switch (c)
  1018. {
  1019.     case EOF:   st->token = TOK_EOF; break;
  1020.     case '(':   ok = analyzeParens(st); break;
  1021.     case '*':   st->gotName = FALSE; break;
  1022.     case ',':   st->token = TOK_COMMA; break;
  1023.     case ':':   processColon(st); break;
  1024.     case ';':   st->token = TOK_SEMICOLON; break;
  1025.     case '=':   ok = processInitializer(st); break;
  1026.     case '[':   ok = processArray(st); break;
  1027.     case '{':   ok = beginBlock(st, nesting); break;
  1028.     case '}':   ok = endBlock(st, nesting); break;
  1029.     case '<':   ok = processTemplate(st); break;
  1030.     default:
  1031. if (isident1(c))
  1032.     processIdentifier(st, c);
  1033. else if (isExternCDecl(st, c))
  1034. {
  1035.     st->declaration = DECL_NOMANGLE;
  1036.     st->scope = SCOPE_GLOBAL;
  1037. }
  1038. else
  1039.     st->token = TOK_IGNORE;
  1040. }
  1041.     } while (ok  &&  st->token == TOK_IGNORE);
  1042.     return ok;
  1043. }
  1044. /*----------------------------------------------------------------------------
  1045. *- Scanning functions
  1046. ----------------------------------------------------------------------------*/
  1047. /*  Parses the current file and decides whether to write out and tags that
  1048.  *  are discovered.
  1049.  */
  1050. extern boolean createTags( nesting, parent )
  1051.     const unsigned int nesting;
  1052.     const void *const parent;
  1053. {
  1054.     const tagScope declScope = File.isHeader ? SCOPE_GLOBAL : SCOPE_STATIC;
  1055.     statementInfo *st;
  1056.     boolean ok;
  1057.     DebugStatement( if (nesting > 0) debugParseNest(TRUE, nesting); )
  1058.     st = (statementInfo *)malloc(sizeof(statementInfo));
  1059.     if (st == NULL)
  1060. error(FATAL | PERROR, "cannot allocate statement info");
  1061.     initStatement(st, (const statementInfo *)parent);
  1062.     while ((ok = nextToken(st, nesting)))
  1063.     {
  1064. tagInfo *const tag = &activeTag(st);
  1065. if (st->token == TOK_EOF)
  1066.     break;
  1067. else if (! st->gotName)
  1068.     ;
  1069. else if (st->inEnumBody)
  1070.     qualifyEnumeratorTag(st, tag, declScope);
  1071. else if (st->token == TOK_BODY  &&  st->prev[0] == TOK_ARGS)
  1072.     qualifyFunctionTag(st, tag);
  1073. else if (st->token == TOK_SEMICOLON  ||  st->token == TOK_COMMA)
  1074. {
  1075.     if (st->scope == SCOPE_TYPEDEF)
  1076. makeTag(tag, &st->member, declScope, TAG_TYPEDEF);
  1077.     else if (st->prev[0] == TOK_NAME  ||  st->isFuncPtr)
  1078. qualifyVariableTag(st, tag);
  1079.     else if (st->prev[0] == TOK_ARGS)
  1080. qualifyFunctionDeclTag(st, tag);
  1081. }
  1082. /*  Reset after a semicolon, or BODY preceeded by ARGS (a function),
  1083.  *  a namspace definition, or an "extern" block.
  1084.  */
  1085. if (st->token == TOK_SEMICOLON  ||  (st->token == TOK_BODY  &&
  1086.      (st->declaration == DECL_NAMESPACE  ||
  1087.       st->declaration == DECL_NOMANGLE   ||
  1088.       st->prev[0] == TOK_ARGS)))
  1089. {
  1090.     DebugStatement( if (debug(DEBUG_PARSE)) printf("<ES>"); )
  1091.     reinitStatement(st);
  1092.     Cpp.resolveRequired = FALSE; /* end of statement */
  1093. }
  1094. else
  1095.     Cpp.resolveRequired = TRUE; /* in middle of statement */
  1096. st->prev[1] = st->prev[0];
  1097. st->prev[0] = st->token;
  1098.     }
  1099.     DebugStatement( if (nesting > 0) debugParseNest(FALSE, nesting - 1); )
  1100.     free(st);
  1101.     return ok;
  1102. }
  1103. extern void buildKeywordHash()
  1104. {
  1105.     int lastInitialChar = '';
  1106.     size_t i;
  1107.     /*  Clear all hash entries.
  1108.      */
  1109.     for (i = 0  ;  i < sizeof(KeywordHash)/sizeof(KeywordHash[0])  ;  ++i)
  1110. KeywordHash[i] = -1;
  1111.     /*  Set those hash entries corresponding to keywords.
  1112.      */
  1113.     for (i = 0  ;  i < KeywordTableSize  ;  ++i)
  1114.     {
  1115. const unsigned char initialChar = KeywordTable[i].name[0];
  1116. if (initialChar != lastInitialChar)
  1117. {
  1118.     KeywordHash[hashIndex(initialChar)] = i;
  1119.     lastInitialChar = initialChar;
  1120. }
  1121.     }
  1122. }
  1123. /* vi:set tabstop=8 shiftwidth=4: */