📄 parse.c
字号:
#if 0
/* Skip to the next occurance of the specified character.
*/
static int skipToCharacter( findchar )
const int findchar;
{
int c;
do
c = cppGetc();
while (c != EOF && c != findchar);
return c;
}
#endif
/* Skips to the next brace in column 1. This is intended for cases where
* preprocessor constructs result in unbalanced braces.
*/
static void skipToFormattedBraceMatch()
{
int c, next;
c = cppGetc();
next = cppGetc();
while (c != EOF && (c != '\n' || next != '}'))
{
c = next;
next = cppGetc();
}
}
/* Skip to the matching character indicated by the pair string. If skipping
* to a matching brace and any brace is found within a different level of a
* #if conditional statement while brace formatting is in effect, we skip to
* the brace matched by its formatting. It is assumed that we have already
* read the character which starts the group (i.e. the first character of
* "pair").
*/
static boolean skipToMatch( pair )
const char *const pair;
{
const int begin = pair[0], end = pair[1];
const unsigned int initialLevel = Cpp.directive.nestLevel;
const boolean braceFormatting = (boolean)(Option.braceFormat &&
strcmp("{}", pair) == 0);
boolean ok = TRUE;
int matchLevel = 1;
int c = '\0';
while (matchLevel > 0 && (c = cppGetc()) != EOF)
{
if (c == begin)
{
++matchLevel;
if (braceFormatting && Cpp.directive.nestLevel != initialLevel)
{
skipToFormattedBraceMatch();
break;
}
}
else if (c == end)
{
--matchLevel;
if (braceFormatting && Cpp.directive.nestLevel != initialLevel)
{
skipToFormattedBraceMatch();
break;
}
}
}
if (c == EOF)
ok = FALSE;
return ok;
}
/* Read a C identifier beginning with "firstChar" and places it into "name".
*/
static void readIdentifier( firstChar, name )
const int firstChar;
char *const name;
{
int c, i;
name[0] = firstChar;
for (i = 1, c = cppGetc() ;
i < (int)MaxNameLength - 1 && isident(c) ;
i++, c = cppGetc())
{
name[i] = c;
}
name[i] = '\0'; /* null terminate name */
cppUngetc(c); /* unget non-identifier character */
}
/* Read a C++ operator and appends to "name" (which should contain "operator").
*/
static void readOperator( firstChar, name )
const int firstChar;
char *const name;
{
int c, i;
for (c = firstChar, i = strlen(name) ;
i < (int)MaxNameLength - 1 && ! isspace(c) && c != '(' ;
i++, c = cppGetc())
{
name[i] = c;
}
if (i > 0)
name[i] = '\0'; /* null terminate operator */
cppUngetc(c); /* unget non-operator character */
}
/* Analyzes the identifier contained in a statement described by the
* statement structure and adjusts the structure according the significance
* of the identifier.
*/
static keywordId analyzeKeyword( name )
const char *const name;
{
keywordId id = KEYWORD_UNKNOWN;
if (name[0] == '_' || islower(name[0]))
{
const short hash = KeywordHash[hashIndex(name[0])];
if (hash >= 0)
{
unsigned int i;
for (i = hash ; i < KeywordTableSize ; ++i)
{
const keywordDesc *pKw = &KeywordTable[i];
if (pKw->name[0] != name[0])
break;
if (pKw->isValid[File.language] && strcmp(pKw->name, name) == 0)
{
id = pKw->id;
break;
}
}
}
}
return id;
}
static void processKeyword( st, keyword )
statementInfo *const st;
keywordId keyword;
{
st->token = TOK_SPEC; /* default unless otherwise */
switch (keyword) /* is it a reserved word? */
{
default: st->token = TOK_IGNORE; break;
case KEYWORD_CHAR: st->declaration = DECL_BASE; break;
case KEYWORD_CLASS: st->declaration = DECL_CLASS; break;
case KEYWORD_DOUBLE: st->declaration = DECL_BASE; break;
case KEYWORD_ENUM: st->declaration = DECL_ENUM; break;
case KEYWORD_EXTERN: st->scope = SCOPE_EXTERN; break;
case KEYWORD_FLOAT: st->declaration = DECL_BASE; break;
case KEYWORD_FRIEND: st->scope = SCOPE_FRIEND; break;
case KEYWORD_IMPORT: st->declaration = DECL_IGNORE; break;
case KEYWORD_INT: st->declaration = DECL_BASE; break;
case KEYWORD_INTERFACE: st->declaration = DECL_INTERFACE; break;
case KEYWORD_LONG: st->declaration = DECL_BASE; break;
case KEYWORD_NAMESPACE: st->declaration = DECL_NAMESPACE; break;
case KEYWORD_PACKAGE: st->declaration = DECL_IGNORE; break;
case KEYWORD_PRIVATE: st->member.visibility = VIS_PRIVATE; break;
case KEYWORD_PROTECTED: st->member.visibility = VIS_PROTECTED; break;
case KEYWORD_PUBLIC: st->member.visibility = VIS_PUBLIC; break;
case KEYWORD_SHORT: st->declaration = DECL_BASE; break;
case KEYWORD_SIGNED: st->declaration = DECL_BASE; break;
case KEYWORD_STRUCT: st->declaration = DECL_STRUCT; break;
case KEYWORD_TYPEDEF: st->scope = SCOPE_TYPEDEF; break;
case KEYWORD_UNION: st->declaration = DECL_UNION; break;
case KEYWORD_UNSIGNED: st->declaration = DECL_BASE; break;
case KEYWORD_VOID: st->declaration = DECL_BASE; break;
case KEYWORD_ATTRIBUTE:
{
const int c = skipToNonWhite();
if (c == '(')
skipToMatch("()");
else
cppUngetc(c);
st->token = TOK_IGNORE;
break;
}
case KEYWORD_EXTENDS:
case KEYWORD_IMPLEMENTS:
case KEYWORD_THROWS:
{
char *const name = activeName(st);
int c = skipToNonWhite();
/* Read and discard interface or class type-list (ident[, ident]).
*/
while (isident1(c))
{
readIdentifier(c, name);
c = skipToNonWhite();
if (c == '.' || c == ',')
c = skipToNonWhite();
}
cppUngetc(c);
st->token = TOK_IGNORE;
break;
}
case KEYWORD_STATIC:
if (File.language != LANG_JAVA)
st->scope = SCOPE_STATIC;
break;
case KEYWORD_OPERATOR:
{
char *const name = activeName(st);
const int c = skipToNonWhite();
if (isident1(c))
readIdentifier(c, name);
else
readOperator(c, name);
} /* fall through to unknown keyword case */
case KEYWORD_UNKNOWN:
{
tagInfo *const tag = &activeTag(st);
st->token = TOK_NAME;
st->gotName = TRUE;
tag->location = File.seek;
tag->lineNumber = File.lineNumber;
if (st->declaration == DECL_CLASS && st->class.name[0] == '\0')
{
strcpy(st->class.name, tag->name);
st->class.location = tag->location;
st->class.lineNumber = tag->lineNumber;
}
break;
}
}
}
/* Skips over characters following the parameter list. This might be non-ANSI
* style function declarations, a C++ exception specification, or another C++
* construct that I don't yet understand (e.g. "void Class::foo(int a):
* attr(v1), attr(v2)").
*/
static int skipPostArgumentStuff( c, st, emptyArgList )
int c;
statementInfo *const st;
const boolean emptyArgList;
{
boolean end = FALSE, firstSemicolon = TRUE;
boolean skipCPlusStuff = (boolean)(c == ':');
unsigned int tokenCount = 0;
while (c != EOF && ! end)
{
if (skipCPlusStuff)
{
if (c == '{' || c == ';')
break;
}
else if (isident1(c))
{
char name[MaxNameLength];
keywordId keyword;
readIdentifier(c, name);
++tokenCount;
keyword = analyzeKeyword(name);
switch (keyword)
{
/* These words are explicitly allowed following the closing
* parenthesis in C++.
*/
case KEYWORD_CONST:
break;
case KEYWORD_THROW:
skipCPlusStuff = TRUE;
break;
/* These words are never allowed within parameter declarations.
*/
case KEYWORD_CLASS:
case KEYWORD_EXTERN:
case KEYWORD_STATIC:
case KEYWORD_TYPEDEF:
DebugStatement( if (debug(DEBUG_PARSE)) printf("<ES>"); )
reinitStatement(st);
processKeyword(st, keyword);
c = skipToNonWhite();
end = TRUE;
continue; /* skip read of next character */
case KEYWORD_ATTRIBUTE:
{
c = skipToNonWhite();
if (c == '(' && ! skipToMatch("()"))
c = EOF;
}
break;
default:
/* If we encounter any other identifier immediately following
* an empty parameter list, this is almost certainly one of
* those Microsoft macro "thingies" that the automatic source
* code generation sticks in. Terminate the current statement.
*/
if (emptyArgList)
{
DebugStatement( if (debug(DEBUG_PARSE)) printf("<ES>"); )
reinitStatement(st);
processKeyword(st, keyword);
c = skipToNonWhite();
end = TRUE;
continue; /* skip read of next character */
}
break;
}
}
else switch (c)
{
default: break; /* ignore */
case ';':
/* A lone word is most likely a preprocessor qualifier.
*/
if (firstSemicolon && tokenCount == 1)
{
end = TRUE;
continue;
}
else
{
tokenCount = 0;
firstSemicolon = FALSE;
break;
}
case '(':
++tokenCount;
if (! skipToMatch("()"))
c = EOF;
break;
case '[': if (! skipToMatch("[]")) c = EOF; break;
case '{':
case '}': end = TRUE;
continue; /* skip read of next character */
}
if (c != EOF)
c = cppGetc();
}
return c;
}
static boolean analyzePostParens( st, paren, emptyArgList )
statementInfo *const st;
const parenInfo *const paren;
const boolean emptyArgList;
{
boolean ok = TRUE;
int c;
/* At this point we should be at the character following the
* closing parenthesis.
*/
c = skipToNonWhite();
if (st->gotName)
{
if (strchr("{;,", c) != NULL)
{
st->token = TOK_ARGS; /* parameter list to a func. */
st->declaration = DECL_BASE; /* clear any other decl. */
}
else if (isident1(c) || c == ':')
{
st->token = TOK_ARGS; /* parameter list to a func. */
st->declaration = DECL_BASE; /* clear any other decl. */
if (File.language != LANG_JAVA)
c = skipPostArgumentStuff(c, st, emptyArgList);
}
else
st->token = TOK_IGNORE;
}
/* The name inside the parentheses must have been a function or
* variable name.
*/
else if (paren->gotName)
{
tagInfo *const tag = &activeTag(st);
st->gotName = TRUE;
st->token = TOK_NAME;
tag->location = paren->location;
tag->lineNumber = paren->lineNumber;
strcpy(tag->name, paren->name);
}
else
st->token = TOK_IGNORE;
if (c == EOF)
ok = FALSE;
else
cppUngetc(c);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -