2006-08-11 02:43:39 +08:00
|
|
|
//===--- Parser.cpp - C Language Family Parser ----------------------------===//
|
2006-07-31 09:59:18 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file was developed by Chris Lattner and is distributed under
|
|
|
|
// the University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the Parser interfaces.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "clang/Parse/Parser.h"
|
2006-08-04 12:39:53 +08:00
|
|
|
#include "clang/Parse/Declarations.h"
|
2006-08-06 06:46:42 +08:00
|
|
|
#include "clang/Parse/Scope.h"
|
2006-07-31 09:59:18 +08:00
|
|
|
using namespace llvm;
|
|
|
|
using namespace clang;
|
|
|
|
|
|
|
|
Parser::Parser(Preprocessor &pp, ParserActions &actions)
|
2006-08-06 06:46:42 +08:00
|
|
|
: PP(pp), Actions(actions), Diags(PP.getDiagnostics()) {
|
2006-08-07 01:24:14 +08:00
|
|
|
Tok.SetKind(tok::eof);
|
2006-08-14 08:15:05 +08:00
|
|
|
CurScope = 0;
|
2006-08-07 05:55:29 +08:00
|
|
|
|
|
|
|
ParenCount = BracketCount = BraceCount = 0;
|
2006-08-06 06:46:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Parser::~Parser() {
|
2006-08-14 08:15:05 +08:00
|
|
|
// If we still have scopes active, delete the scope tree.
|
2006-08-06 06:46:42 +08:00
|
|
|
delete CurScope;
|
|
|
|
}
|
|
|
|
|
2006-08-14 08:15:05 +08:00
|
|
|
/// Out-of-line virtual destructor to provide home for ParserActions class.
|
|
|
|
ParserActions::~ParserActions() {}
|
|
|
|
|
2006-07-31 09:59:18 +08:00
|
|
|
|
2006-08-04 12:39:53 +08:00
|
|
|
void Parser::Diag(SourceLocation Loc, unsigned DiagID,
|
2006-07-31 09:59:18 +08:00
|
|
|
const std::string &Msg) {
|
2006-08-04 12:39:53 +08:00
|
|
|
Diags.Report(Loc, DiagID, Msg);
|
2006-07-31 09:59:18 +08:00
|
|
|
}
|
|
|
|
|
2006-08-11 07:14:52 +08:00
|
|
|
/// MatchRHSPunctuation - For punctuation with a LHS and RHS (e.g. '['/']'),
|
|
|
|
/// this helper function matches and consumes the specified RHS token if
|
|
|
|
/// present. If not present, it emits the specified diagnostic indicating
|
|
|
|
/// that the parser failed to match the RHS of the token at LHSLoc. LHSName
|
|
|
|
/// should be the name of the unmatched LHS token.
|
|
|
|
void Parser::MatchRHSPunctuation(tok::TokenKind RHSTok, SourceLocation LHSLoc,
|
|
|
|
const char *LHSName, unsigned DiagID) {
|
|
|
|
|
|
|
|
if (Tok.getKind() == RHSTok) {
|
2006-08-13 03:26:13 +08:00
|
|
|
ConsumeAnyToken();
|
2006-08-11 07:14:52 +08:00
|
|
|
} else {
|
|
|
|
Diag(Tok, DiagID);
|
|
|
|
Diag(LHSLoc, diag::err_matching, LHSName);
|
|
|
|
SkipUntil(RHSTok);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-08-13 03:26:13 +08:00
|
|
|
/// ExpectAndConsume - The parser expects that 'ExpectedTok' is next in the
|
|
|
|
/// input. If so, it is consumed and false is returned.
|
|
|
|
///
|
|
|
|
/// If the input is malformed, this emits the specified diagnostic. Next, if
|
|
|
|
/// SkipToTok is specified, it calls SkipUntil(SkipToTok). Finally, true is
|
|
|
|
/// returned.
|
|
|
|
bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID,
|
|
|
|
tok::TokenKind SkipToTok) {
|
|
|
|
if (Tok.getKind() == ExpectedTok) {
|
|
|
|
ConsumeToken();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Diag(Tok, DiagID);
|
|
|
|
if (SkipToTok != tok::unknown)
|
|
|
|
SkipUntil(SkipToTok);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2006-08-07 05:55:29 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Error recovery.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
/// SkipUntil - Read tokens until we get to the specified token, then consume
|
|
|
|
/// it (unless DontConsume is false). Because we cannot guarantee that the
|
|
|
|
/// token will ever occur, this skips to the next token, or to some likely
|
|
|
|
/// good stopping point. If StopAtSemi is true, skipping will stop at a ';'
|
|
|
|
/// character.
|
|
|
|
///
|
|
|
|
/// If SkipUntil finds the specified token, it returns true, otherwise it
|
|
|
|
/// returns false.
|
|
|
|
bool Parser::SkipUntil(tok::TokenKind T, bool StopAtSemi, bool DontConsume) {
|
2006-08-11 14:40:25 +08:00
|
|
|
// We always want this function to skip at least one token if the first token
|
|
|
|
// isn't T and if not at EOF.
|
|
|
|
bool isFirstTokenSkipped = true;
|
2006-08-07 05:55:29 +08:00
|
|
|
while (1) {
|
|
|
|
// If we found the token, stop and return true.
|
|
|
|
if (Tok.getKind() == T) {
|
|
|
|
if (DontConsume) {
|
|
|
|
// Noop, don't consume the token.
|
|
|
|
} else {
|
2006-08-13 03:26:13 +08:00
|
|
|
ConsumeAnyToken();
|
2006-08-07 05:55:29 +08:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (Tok.getKind()) {
|
|
|
|
case tok::eof:
|
|
|
|
// Ran out of tokens.
|
|
|
|
return false;
|
|
|
|
|
|
|
|
case tok::l_paren:
|
|
|
|
// Recursively skip properly-nested parens.
|
|
|
|
ConsumeParen();
|
2006-08-11 14:40:25 +08:00
|
|
|
SkipUntil(tok::r_paren, false);
|
2006-08-07 05:55:29 +08:00
|
|
|
break;
|
|
|
|
case tok::l_square:
|
|
|
|
// Recursively skip properly-nested square brackets.
|
|
|
|
ConsumeBracket();
|
2006-08-11 14:40:25 +08:00
|
|
|
SkipUntil(tok::r_square, false);
|
2006-08-07 05:55:29 +08:00
|
|
|
break;
|
|
|
|
case tok::l_brace:
|
|
|
|
// Recursively skip properly-nested braces.
|
|
|
|
ConsumeBrace();
|
2006-08-11 14:40:25 +08:00
|
|
|
SkipUntil(tok::r_brace, false);
|
2006-08-07 05:55:29 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
// Okay, we found a ']' or '}' or ')', which we think should be balanced.
|
|
|
|
// Since the user wasn't looking for this token (if they were, it would
|
|
|
|
// already be handled), this isn't balanced. If there is a LHS token at a
|
|
|
|
// higher level, we will assume that this matches the unbalanced token
|
|
|
|
// and return it. Otherwise, this is a spurious RHS token, which we skip.
|
|
|
|
case tok::r_paren:
|
2006-08-11 14:40:25 +08:00
|
|
|
if (ParenCount && !isFirstTokenSkipped)
|
|
|
|
return false; // Matches something.
|
2006-08-07 05:55:29 +08:00
|
|
|
ConsumeParen();
|
|
|
|
break;
|
|
|
|
case tok::r_square:
|
2006-08-11 14:40:25 +08:00
|
|
|
if (BracketCount && !isFirstTokenSkipped)
|
|
|
|
return false; // Matches something.
|
2006-08-07 05:55:29 +08:00
|
|
|
ConsumeBracket();
|
|
|
|
break;
|
|
|
|
case tok::r_brace:
|
2006-08-11 14:40:25 +08:00
|
|
|
if (BraceCount && !isFirstTokenSkipped)
|
|
|
|
return false; // Matches something.
|
2006-08-07 05:55:29 +08:00
|
|
|
ConsumeBrace();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case tok::string_literal:
|
|
|
|
ConsumeStringToken();
|
|
|
|
break;
|
|
|
|
case tok::semi:
|
|
|
|
if (StopAtSemi)
|
|
|
|
return false;
|
|
|
|
// FALL THROUGH.
|
|
|
|
default:
|
|
|
|
// Skip this token.
|
|
|
|
ConsumeToken();
|
|
|
|
break;
|
|
|
|
}
|
2006-08-11 14:40:25 +08:00
|
|
|
isFirstTokenSkipped = false;
|
2006-08-07 05:55:29 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-08-14 08:15:05 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Scope manipulation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
/// EnterScope - Start a new scope.
|
|
|
|
void Parser::EnterScope() {
|
|
|
|
// TODO: Inform actions?
|
|
|
|
CurScope = new Scope(CurScope);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ExitScope - Pop a scope off the scope stack.
|
|
|
|
void Parser::ExitScope() {
|
|
|
|
assert(CurScope && "Scope imbalance!");
|
|
|
|
|
|
|
|
// Inform the actions module that this scope is going away.
|
|
|
|
Actions.PopScope(Tok.getLocation(), CurScope);
|
|
|
|
|
|
|
|
Scope *Old = CurScope;
|
|
|
|
CurScope = Old->getParent();
|
|
|
|
delete Old;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2006-07-31 13:09:04 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// C99 6.9: External Definitions.
|
|
|
|
//===----------------------------------------------------------------------===//
|
2006-07-31 09:59:18 +08:00
|
|
|
|
|
|
|
/// ParseTranslationUnit:
|
2006-07-31 13:09:04 +08:00
|
|
|
/// translation-unit: [C99 6.9]
|
2006-07-31 09:59:18 +08:00
|
|
|
/// external-declaration
|
|
|
|
/// translation-unit external-declaration
|
|
|
|
void Parser::ParseTranslationUnit() {
|
2006-08-14 08:15:05 +08:00
|
|
|
// Prime the lexer look-ahead.
|
|
|
|
ConsumeToken();
|
|
|
|
|
|
|
|
// Create the global scope, install it as the current scope.
|
|
|
|
assert(CurScope == 0 && "A scope is already active?");
|
|
|
|
EnterScope();
|
2006-07-31 09:59:18 +08:00
|
|
|
|
|
|
|
if (Tok.getKind() == tok::eof) // Empty source file is an extension.
|
|
|
|
Diag(diag::ext_empty_source_file);
|
|
|
|
|
|
|
|
while (Tok.getKind() != tok::eof)
|
|
|
|
ParseExternalDeclaration();
|
2006-08-14 08:15:05 +08:00
|
|
|
|
|
|
|
ExitScope();
|
|
|
|
assert(CurScope == 0 && "Scope imbalance!");
|
2006-07-31 09:59:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseExternalDeclaration:
|
2006-07-31 13:09:04 +08:00
|
|
|
/// external-declaration: [C99 6.9]
|
2006-07-31 09:59:18 +08:00
|
|
|
/// function-definition [TODO]
|
|
|
|
/// declaration [TODO]
|
|
|
|
/// [EXT] ';'
|
|
|
|
/// [GNU] asm-definition [TODO]
|
|
|
|
/// [GNU] __extension__ external-declaration [TODO]
|
|
|
|
/// [OBJC] objc-class-definition [TODO]
|
|
|
|
/// [OBJC] objc-class-declaration [TODO]
|
|
|
|
/// [OBJC] objc-alias-declaration [TODO]
|
|
|
|
/// [OBJC] objc-protocol-definition [TODO]
|
|
|
|
/// [OBJC] objc-method-definition [TODO]
|
|
|
|
/// [OBJC] @end [TODO]
|
|
|
|
///
|
|
|
|
void Parser::ParseExternalDeclaration() {
|
|
|
|
switch (Tok.getKind()) {
|
|
|
|
case tok::semi:
|
|
|
|
Diag(diag::ext_top_level_semi);
|
|
|
|
ConsumeToken();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// We can't tell whether this is a function-definition or declaration yet.
|
|
|
|
ParseDeclarationOrFunctionDefinition();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseDeclarationOrFunctionDefinition - Parse either a function-definition or
|
2006-07-31 13:09:04 +08:00
|
|
|
/// a declaration. We can't tell which we have until we read up to the
|
|
|
|
/// compound-statement in function-definition.
|
2006-07-31 09:59:18 +08:00
|
|
|
///
|
2006-07-31 13:09:04 +08:00
|
|
|
/// function-definition: [C99 6.9.1]
|
|
|
|
/// declaration-specifiers[opt] declarator declaration-list[opt]
|
|
|
|
/// compound-statement [TODO]
|
|
|
|
/// declaration: [C99 6.7]
|
2006-07-31 09:59:18 +08:00
|
|
|
/// declaration-specifiers init-declarator-list[opt] ';' [TODO]
|
2006-08-05 14:26:47 +08:00
|
|
|
/// [!C99] init-declarator-list ';' [TODO]
|
2006-07-31 13:09:04 +08:00
|
|
|
/// [OMP] threadprivate-directive [TODO]
|
|
|
|
///
|
2006-07-31 09:59:18 +08:00
|
|
|
void Parser::ParseDeclarationOrFunctionDefinition() {
|
2006-07-31 13:09:04 +08:00
|
|
|
// Parse the common declaration-specifiers piece.
|
2006-08-04 12:39:53 +08:00
|
|
|
DeclSpec DS;
|
|
|
|
ParseDeclarationSpecifiers(DS);
|
2006-08-05 16:09:44 +08:00
|
|
|
|
|
|
|
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
|
2006-08-10 13:19:57 +08:00
|
|
|
// declaration-specifiers init-declarator-list[opt] ';'
|
2006-08-14 03:58:17 +08:00
|
|
|
if (Tok.getKind() == tok::semi) {
|
|
|
|
// TODO: emit error on 'int;' or 'const enum foo;'.
|
|
|
|
// if (!DS.isMissingDeclaratorOk()) Diag(...);
|
|
|
|
|
|
|
|
ConsumeToken();
|
|
|
|
return;
|
|
|
|
}
|
2006-07-31 13:09:04 +08:00
|
|
|
|
2006-08-07 14:31:38 +08:00
|
|
|
// Parse the first declarator.
|
|
|
|
Declarator DeclaratorInfo(DS, Declarator::FileContext);
|
|
|
|
ParseDeclarator(DeclaratorInfo);
|
|
|
|
// Error parsing the declarator?
|
|
|
|
if (DeclaratorInfo.getIdentifier() == 0) {
|
|
|
|
// If so, skip until the semi-colon or a }.
|
|
|
|
SkipUntil(tok::r_brace, true);
|
|
|
|
if (Tok.getKind() == tok::semi)
|
|
|
|
ConsumeToken();
|
|
|
|
return;
|
|
|
|
}
|
2006-07-31 13:09:04 +08:00
|
|
|
|
2006-08-07 14:31:38 +08:00
|
|
|
// If the declarator is the start of a function definition, handle it.
|
|
|
|
if (Tok.getKind() == tok::equal || // int X()= -> not a function def
|
|
|
|
Tok.getKind() == tok::comma || // int X(), -> not a function def
|
|
|
|
Tok.getKind() == tok::semi || // int X(); -> not a function def
|
|
|
|
Tok.getKind() == tok::kw_asm || // int X() __asm__ -> not a fn def
|
|
|
|
Tok.getKind() == tok::kw___attribute) {// int X() __attr__ -> not a fn def
|
|
|
|
// FALL THROUGH.
|
|
|
|
} else if (DeclaratorInfo.isInnermostFunctionType() &&
|
|
|
|
(Tok.getKind() == tok::l_brace || // int X() {}
|
|
|
|
isDeclarationSpecifier())) { // int X(f) int f; {}
|
|
|
|
ParseFunctionDefinition(DeclaratorInfo);
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
if (DeclaratorInfo.isInnermostFunctionType())
|
|
|
|
Diag(Tok, diag::err_expected_fn_body);
|
|
|
|
else
|
|
|
|
Diag(Tok, diag::err_expected_after_declarator);
|
2006-08-14 08:15:05 +08:00
|
|
|
SkipUntil(tok::semi);
|
2006-08-07 14:31:38 +08:00
|
|
|
return;
|
|
|
|
}
|
2006-08-05 14:26:47 +08:00
|
|
|
|
2006-08-10 13:19:57 +08:00
|
|
|
// Parse the init-declarator-list for a normal declaration.
|
|
|
|
ParseInitDeclaratorListAfterFirstDeclarator(DeclaratorInfo);
|
2006-07-31 13:09:04 +08:00
|
|
|
}
|
|
|
|
|
2006-08-07 14:31:38 +08:00
|
|
|
/// ParseFunctionDefinition - We parsed and verified that the specified
|
|
|
|
/// Declarator is well formed. If this is a K&R-style function, read the
|
|
|
|
/// parameters declaration-list, then start the compound-statement.
|
|
|
|
///
|
|
|
|
/// declaration-specifiers[opt] declarator declaration-list[opt]
|
|
|
|
/// compound-statement [TODO]
|
|
|
|
///
|
|
|
|
void Parser::ParseFunctionDefinition(Declarator &D) {
|
|
|
|
const DeclaratorTypeInfo &FnTypeInfo = D.getTypeObject(0);
|
|
|
|
assert(FnTypeInfo.Kind == DeclaratorTypeInfo::Function &&
|
|
|
|
"This isn't a function declarator!");
|
|
|
|
|
|
|
|
// If this declaration was formed with a K&R-style identifier list for the
|
|
|
|
// arguments, parse declarations for all of the args next.
|
|
|
|
// int foo(a,b) int a; float b; {}
|
|
|
|
if (!FnTypeInfo.Fun.hasPrototype && !FnTypeInfo.Fun.isEmpty) {
|
|
|
|
// Read all the argument declarations.
|
2006-08-10 13:19:57 +08:00
|
|
|
while (isDeclarationSpecifier())
|
|
|
|
ParseDeclaration(Declarator::KNRTypeListContext);
|
2006-08-07 14:31:38 +08:00
|
|
|
|
|
|
|
// Note, check that we got them all.
|
|
|
|
} else {
|
|
|
|
//if (isDeclarationSpecifier())
|
|
|
|
// Diag('k&r declspecs with prototype?');
|
|
|
|
|
2006-08-14 05:54:02 +08:00
|
|
|
// TODO: Install the arguments into the current scope.
|
2006-08-07 14:31:38 +08:00
|
|
|
}
|
|
|
|
|
2006-08-09 13:47:47 +08:00
|
|
|
// We should have an opening brace now.
|
|
|
|
if (Tok.getKind() != tok::l_brace) {
|
|
|
|
Diag(Tok, diag::err_expected_fn_body);
|
|
|
|
|
|
|
|
// Skip over garbage, until we get to '{'. Don't eat the '{'.
|
|
|
|
SkipUntil(tok::l_brace, true, true);
|
|
|
|
|
|
|
|
// If we didn't find the '{', bail out.
|
|
|
|
if (Tok.getKind() != tok::l_brace)
|
|
|
|
return;
|
|
|
|
}
|
2006-08-07 14:31:38 +08:00
|
|
|
|
2006-08-09 13:47:47 +08:00
|
|
|
ParseCompoundStatement();
|
2006-08-07 14:31:38 +08:00
|
|
|
}
|
|
|
|
|