2006-08-04 12:39:53 +08:00
|
|
|
//===--- Parse.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()) {
|
|
|
|
// Create the global scope, install it as the current scope.
|
|
|
|
CurScope = new Scope(0);
|
2006-08-07 01:24:14 +08:00
|
|
|
Tok.SetKind(tok::eof);
|
2006-08-07 05:55:29 +08:00
|
|
|
|
|
|
|
ParenCount = BracketCount = BraceCount = 0;
|
2006-08-06 06:46:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Parser::~Parser() {
|
|
|
|
delete CurScope;
|
|
|
|
}
|
|
|
|
|
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-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) {
|
|
|
|
while (1) {
|
|
|
|
// If we found the token, stop and return true.
|
|
|
|
if (Tok.getKind() == T) {
|
|
|
|
if (DontConsume) {
|
|
|
|
// Noop, don't consume the token.
|
|
|
|
} else if (isTokenParen()) {
|
|
|
|
ConsumeParen();
|
|
|
|
} else if (isTokenBracket()) {
|
|
|
|
ConsumeBracket();
|
|
|
|
} else if (isTokenBrace()) {
|
|
|
|
ConsumeBrace();
|
|
|
|
} else if (T == tok::string_literal) {
|
|
|
|
ConsumeStringToken();
|
|
|
|
} else {
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (Tok.getKind()) {
|
|
|
|
case tok::eof:
|
|
|
|
// Ran out of tokens.
|
|
|
|
return false;
|
|
|
|
|
|
|
|
case tok::l_paren:
|
|
|
|
// Recursively skip properly-nested parens.
|
|
|
|
ConsumeParen();
|
|
|
|
SkipUntil(tok::r_paren);
|
|
|
|
break;
|
|
|
|
case tok::l_square:
|
|
|
|
// Recursively skip properly-nested square brackets.
|
|
|
|
ConsumeBracket();
|
|
|
|
SkipUntil(tok::r_square);
|
|
|
|
break;
|
|
|
|
case tok::l_brace:
|
|
|
|
// Recursively skip properly-nested braces.
|
|
|
|
ConsumeBrace();
|
|
|
|
SkipUntil(tok::r_brace);
|
|
|
|
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:
|
|
|
|
if (ParenCount) return false; // Matches something.
|
|
|
|
ConsumeParen();
|
|
|
|
break;
|
|
|
|
case tok::r_square:
|
|
|
|
if (BracketCount) return false; // Matches something.
|
|
|
|
ConsumeBracket();
|
|
|
|
break;
|
|
|
|
case tok::r_brace:
|
|
|
|
if (BraceCount) return false; // Matches something.
|
|
|
|
ConsumeBrace();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case tok::string_literal:
|
|
|
|
ConsumeStringToken();
|
|
|
|
break;
|
|
|
|
case tok::semi:
|
|
|
|
if (StopAtSemi)
|
|
|
|
return false;
|
|
|
|
// FALL THROUGH.
|
|
|
|
default:
|
|
|
|
// Skip this token.
|
|
|
|
ConsumeToken();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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() {
|
|
|
|
|
|
|
|
if (Tok.getKind() == tok::eof) // Empty source file is an extension.
|
|
|
|
Diag(diag::ext_empty_source_file);
|
|
|
|
|
|
|
|
while (Tok.getKind() != tok::eof)
|
|
|
|
ParseExternalDeclaration();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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]
|
|
|
|
///
|
|
|
|
/// init-declarator-list: [C99 6.7]
|
|
|
|
/// init-declarator
|
|
|
|
/// init-declarator-list ',' init-declarator
|
|
|
|
/// init-declarator: [C99 6.7]
|
|
|
|
/// declarator
|
|
|
|
/// declarator '=' initializer
|
|
|
|
///
|
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 };"
|
|
|
|
if (Tok.getKind() == tok::semi)
|
|
|
|
assert(0 && "Unimp!");
|
|
|
|
|
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);
|
|
|
|
SkipUntil(tok::r_brace, true);
|
|
|
|
if (Tok.getKind() == tok::semi)
|
|
|
|
ConsumeToken();
|
|
|
|
return;
|
|
|
|
}
|
2006-08-05 14:26:47 +08:00
|
|
|
|
2006-08-07 14:31:38 +08:00
|
|
|
// At this point, we know that it is not a function definition. Parse the
|
|
|
|
// rest of the init-declarator-list.
|
|
|
|
while (1) {
|
2006-08-06 08:02:28 +08:00
|
|
|
// must be: decl-spec[opt] declarator init-declarator-list
|
|
|
|
// Parse declarator '=' initializer.
|
|
|
|
if (Tok.getKind() == tok::equal)
|
|
|
|
assert(0 && "cannot handle initializer yet!");
|
2006-08-05 14:26:47 +08:00
|
|
|
|
2006-08-07 14:31:38 +08:00
|
|
|
|
|
|
|
// TODO: install declarator.
|
|
|
|
|
|
|
|
// If we don't have a comma, it is either the end of the list (a ';') or an
|
|
|
|
// error, bail out.
|
|
|
|
if (Tok.getKind() != tok::comma)
|
|
|
|
break;
|
|
|
|
|
2006-08-05 14:26:47 +08:00
|
|
|
// Consume the comma.
|
|
|
|
ConsumeToken();
|
|
|
|
|
2006-08-07 14:31:38 +08:00
|
|
|
// Parse the next declarator.
|
|
|
|
DeclaratorInfo.clear();
|
2006-08-06 08:02:28 +08:00
|
|
|
ParseDeclarator(DeclaratorInfo);
|
2006-08-05 14:26:47 +08:00
|
|
|
}
|
2006-08-05 16:09:44 +08:00
|
|
|
|
|
|
|
if (Tok.getKind() == tok::semi) {
|
2006-07-31 13:09:04 +08:00
|
|
|
ConsumeToken();
|
2006-08-05 16:09:44 +08:00
|
|
|
} else {
|
|
|
|
Diag(Tok, diag::err_parse_error);
|
2006-08-07 05:55:29 +08:00
|
|
|
// Skip to end of block or statement
|
|
|
|
SkipUntil(tok::r_brace, true);
|
2006-08-05 16:09:44 +08:00
|
|
|
if (Tok.getKind() == tok::semi)
|
|
|
|
ConsumeToken();
|
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.
|
|
|
|
while (isDeclarationSpecifier()) {
|
|
|
|
// Parse the common declaration-specifiers piece.
|
|
|
|
DeclSpec DS;
|
|
|
|
ParseDeclarationSpecifiers(DS);
|
|
|
|
|
|
|
|
Declarator DeclaratorInfo(DS, Declarator::FileContext);
|
|
|
|
ParseDeclarator(DeclaratorInfo);
|
|
|
|
|
|
|
|
while (Tok.getKind() == tok::comma) {
|
|
|
|
// Consume the comma.
|
|
|
|
ConsumeToken();
|
|
|
|
|
|
|
|
// Parse the next declarator.
|
|
|
|
DeclaratorInfo.clear();
|
|
|
|
ParseDeclarator(DeclaratorInfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Tok.getKind() == tok::semi) {
|
|
|
|
ConsumeToken();
|
|
|
|
} else {
|
|
|
|
Diag(Tok, diag::err_expected_semi_knr_fn_body);
|
|
|
|
// Skip to end of block or statement
|
|
|
|
SkipUntil(tok::l_brace, true);
|
|
|
|
if (Tok.getKind() == tok::semi)
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Note, check that we got them all.
|
|
|
|
} else {
|
|
|
|
//if (isDeclarationSpecifier())
|
|
|
|
// Diag('k&r declspecs with prototype?');
|
|
|
|
|
|
|
|
// FIXME: Install the arguments into the current scope.
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|