📄 parse.c
字号:
return ok;
}
static void initParenInfo( paren )
parenInfo *const paren;
{
DebugStatement( clearString(paren->name, MaxNameLength); )
paren->gotName = FALSE;
paren->location = 0;
paren->lineNumber = 0;
}
static boolean saveParenInfo( paren, c )
parenInfo *const paren;
int c;
{
boolean ok = TRUE;
readIdentifier(c, paren->name);
c = skipToNonWhite();
if (c == ')') /* saved if only identifier in parentheses */
{
paren->gotName = TRUE;
paren->location = File.seek;
paren->lineNumber = File.lineNumber;
}
else
{
if (c == '(')
cppUngetc(c);
ok = skipToMatch("()");
}
return ok;
}
static boolean doubleParens( st )
statementInfo *const st;
{
/* A double parenthesis almost certainly means one of those conditional
* prototype macro thingies (e.g. __ARGS((void)) ). If found, we will use
* the previous name, if it is not empty.
*/
if (st->gotName && *st->tag[!st->buf1].name != '\0')
swapNameBuffers(st);
cppUngetc('('); /* put back for skipToMatch() */
return skipToMatch("()");
}
/* Analyzes the context and contents of parentheses.
*/
static boolean analyzeParens( st )
statementInfo *const st;
{
boolean ok = TRUE;
int c;
c = skipToNonWhite();
if (c == '*') /* this is a function pointer */
{
st->gotName = FALSE; /* invalidate previous name */
st->isFuncPtr = TRUE;
st->token = TOK_IGNORE;
}
if (! st->gotName)
{
st->token = TOK_IGNORE;
cppUngetc(c);
}
else
{
boolean terminate = FALSE, emptyArgList = FALSE;
parenInfo paren;
initParenInfo(&paren);
if (isident1(c))
ok = saveParenInfo(&paren, c);
else if (c == '(')
ok = doubleParens(st);
else if (c == ')') /* empty parentheses... */
emptyArgList = TRUE;
else
{
/* This is an invalid character to be inside a paren in this
* context. This must be a macro call. After we read to the
* end of the parenthesis seqence, force a termination of the
* current statement,
*/
st->token = TOK_NONE;
st->gotName = FALSE;
terminate = TRUE;
ok = skipToMatch("()");
}
if (ok && ! terminate)
ok = analyzePostParens(st, &paren, emptyArgList);
}
return ok;
}
/* Analyzes the identifier contained in a statement described by the
* statement structure and adjusts the structure according the significance
* of the identifier.
*/
static void analyzeIdentifier( st )
statementInfo *const st;
{
tagInfo *const tag = &activeTag(st);
char *const name = tag->name;
if (isIgnoreToken(name))
st->token = TOK_IGNORE;
else
processKeyword(st, analyzeKeyword(name));
if (st->token == TOK_IGNORE)
name[0] = '\0';
}
static void processIdentifier( st, c )
statementInfo *const st;
const int c;
{
if (st->gotName)
swapNameBuffers(st);
readIdentifier(c, activeName(st));
analyzeIdentifier(st);
if (st->gotName && st->token == TOK_IGNORE)
swapNameBuffers(st);
}
static void processColon( st )
statementInfo *const st;
{
if (st->declaration != DECL_CLASS)
{
const int c = skipToNonWhite();
if (c == ':') /* this is a method or static member definition */
{
st->member.type = MEMBER_CLASS;
strcpy(st->member.parent, activeName(st));
st->member.persistent = FALSE;
}
else
{
cppUngetc(c);
st->token = TOK_IGNORE;
}
}
}
/* Skips over any initializing value which may follow a '=' character in a
* variable definition.
*/
static int skipInitializer( enumInitializer )
const boolean enumInitializer;
{
boolean done = FALSE;
int c;
do
{
c = cppGetc();
if (c != EOF) switch (c)
{
case ',':
case ';': done = TRUE; break;
case '[': if (! skipToMatch("[]"))
c = EOF;
break;
case '(': if (! skipToMatch("()"))
c = EOF;
break;
case '{': if (! skipToMatch("{}"))
c = EOF;
break;
case '}': if (enumInitializer)
{
cppUngetc(c);
done = TRUE;
}
else if (! Option.braceFormat)
c = EOF;
break;
default: break;
}
} while (! done && c != EOF);
return c;
}
static boolean processInitializer( st )
statementInfo *const st;
{
boolean ok = TRUE;
const int c = skipInitializer(st->inEnumBody);
if (c == EOF)
ok = FALSE;
else if (c == ';')
st->token = TOK_SEMICOLON;
else if (c == ',')
st->token = TOK_COMMA;
else if ('}' && st->inEnumBody)
st->token = TOK_COMMA;
if (st->scope == SCOPE_EXTERN)
st->scope = SCOPE_GLOBAL;
return ok;
}
static boolean processArray( st )
statementInfo *const st;
{
st->token = TOK_IGNORE;
return skipToMatch("[]");
}
static boolean processTemplate( st )
statementInfo *const st;
{
st->token = TOK_IGNORE;
return skipToMatch("<>");
}
static boolean beginBlock( st, nesting )
statementInfo *const st;
const unsigned int nesting;
{
const tagScope declScope = (File.isHeader || File.language == LANG_JAVA) ?
SCOPE_GLOBAL : SCOPE_STATIC;
tagInfo *const tag = &activeTag(st);
boolean ok;
switch (st->declaration)
{
case DECL_CLASS:
qualifyBlockTag(st, &st->class, declScope);
ok = createTags(nesting + 1, st);
break;
case DECL_ENUM:
case DECL_INTERFACE:
case DECL_NAMESPACE:
case DECL_STRUCT:
case DECL_UNION:
qualifyBlockTag(st, tag, declScope);
ok = createTags(nesting + 1, st);
break;
case DECL_NOMANGLE:
ok = createTags(nesting + 1, st);
break;
default:
ok = skipToMatch("{}");
}
st->token = TOK_BODY;
return ok;
}
static boolean endBlock( st, nesting )
statementInfo *const st;
const unsigned int nesting;
{
boolean ok = TRUE;
if (nesting > 0)
st->token = TOK_EOF; /* fake out */
else
{
st->token = TOK_IGNORE;
ok = FALSE;
}
return ok;
}
/* Reads characters from the pre-processor and assembles tokens, setting
* the current statement state.
*/
static boolean nextToken( st, nesting )
statementInfo *const st;
const unsigned int nesting;
{
int c;
boolean ok = TRUE;
do
{
c = cppGetc();
switch (c)
{
case EOF: st->token = TOK_EOF; break;
case '(': ok = analyzeParens(st); break;
case '*': st->gotName = FALSE; break;
case ',': st->token = TOK_COMMA; break;
case ':': processColon(st); break;
case ';': st->token = TOK_SEMICOLON; break;
case '=': ok = processInitializer(st); break;
case '[': ok = processArray(st); break;
case '{': ok = beginBlock(st, nesting); break;
case '}': ok = endBlock(st, nesting); break;
case '<': ok = processTemplate(st); break;
default:
if (isident1(c))
processIdentifier(st, c);
else if (isExternCDecl(st, c))
{
st->declaration = DECL_NOMANGLE;
st->scope = SCOPE_GLOBAL;
}
else
st->token = TOK_IGNORE;
}
} while (ok && st->token == TOK_IGNORE);
return ok;
}
/*----------------------------------------------------------------------------
*- Scanning functions
----------------------------------------------------------------------------*/
/* Parses the current file and decides whether to write out and tags that
* are discovered.
*/
extern boolean createTags( nesting, parent )
const unsigned int nesting;
const void *const parent;
{
const tagScope declScope = File.isHeader ? SCOPE_GLOBAL : SCOPE_STATIC;
statementInfo *st;
boolean ok;
DebugStatement( if (nesting > 0) debugParseNest(TRUE, nesting); )
st = (statementInfo *)malloc(sizeof(statementInfo));
if (st == NULL)
error(FATAL | PERROR, "cannot allocate statement info");
initStatement(st, (const statementInfo *)parent);
while ((ok = nextToken(st, nesting)))
{
tagInfo *const tag = &activeTag(st);
if (st->token == TOK_EOF)
break;
else if (! st->gotName)
;
else if (st->inEnumBody)
qualifyEnumeratorTag(st, tag, declScope);
else if (st->token == TOK_BODY && st->prev[0] == TOK_ARGS)
qualifyFunctionTag(st, tag);
else if (st->token == TOK_SEMICOLON || st->token == TOK_COMMA)
{
if (st->scope == SCOPE_TYPEDEF)
makeTag(tag, &st->member, declScope, TAG_TYPEDEF);
else if (st->prev[0] == TOK_NAME || st->isFuncPtr)
qualifyVariableTag(st, tag);
else if (st->prev[0] == TOK_ARGS)
qualifyFunctionDeclTag(st, tag);
}
/* Reset after a semicolon, or BODY preceeded by ARGS (a function),
* a namspace definition, or an "extern" block.
*/
if (st->token == TOK_SEMICOLON || (st->token == TOK_BODY &&
(st->declaration == DECL_NAMESPACE ||
st->declaration == DECL_NOMANGLE ||
st->prev[0] == TOK_ARGS)))
{
DebugStatement( if (debug(DEBUG_PARSE)) printf("<ES>"); )
reinitStatement(st);
Cpp.resolveRequired = FALSE; /* end of statement */
}
else
Cpp.resolveRequired = TRUE; /* in middle of statement */
st->prev[1] = st->prev[0];
st->prev[0] = st->token;
}
DebugStatement( if (nesting > 0) debugParseNest(FALSE, nesting - 1); )
free(st);
return ok;
}
extern void buildKeywordHash()
{
int lastInitialChar = '\0';
size_t i;
/* Clear all hash entries.
*/
for (i = 0 ; i < sizeof(KeywordHash)/sizeof(KeywordHash[0]) ; ++i)
KeywordHash[i] = -1;
/* Set those hash entries corresponding to keywords.
*/
for (i = 0 ; i < KeywordTableSize ; ++i)
{
const unsigned char initialChar = KeywordTable[i].name[0];
if (initialChar != lastInitialChar)
{
KeywordHash[hashIndex(initialChar)] = i;
lastInitialChar = initialChar;
}
}
}
/* vi:set tabstop=8 shiftwidth=4: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -