diff options
author | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2008-06-24 22:12:16 +0000 |
---|---|---|
committer | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2008-06-24 22:12:16 +0000 |
commit | 4cc18a4d5222e04bd568b1e3e4d86127dbbcdf3f (patch) | |
tree | 64ba80f8bf12837a3a31ea24a4e5fc0acce67ccb /lib/Parse/ParseCXXInlineMethods.cpp | |
parent | 8fdf32822be2238aa7db62d40e75b168b637ab7d (diff) |
Add parsing support for C++ classes.
Note that Parser::ParseCXXMemberSpecification is temporarily disabled until the Sema support is in place.
Once ParseCXXMemberSpecification is enabled, the Parser/cxx-class.cpp test will pass.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@52694 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse/ParseCXXInlineMethods.cpp')
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp new file mode 100644 index 0000000000..b593f89668 --- /dev/null +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -0,0 +1,159 @@ +//===--- ParseCXXInlineMethods.cpp - C++ class inline methods parsing------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements parsing for C++ class inline methods. +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/Parser.h" +#include "clang/Parse/DeclSpec.h" +#include "clang/Parse/Scope.h" +using namespace clang; + +/// ParseInlineCXXMethodDef - We parsed and verified that the specified +/// Declarator is a well formed C++ inline method definition. Now lex its body +/// and store its tokens for parsing after the C++ class is complete. +Parser::DeclTy * +Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D) { + assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function && + "This isn't a function declarator!"); + + DeclTy *FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D, 0, 0, 0); + + // We should have an opening brace now. + if (Tok.isNot(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.isNot(tok::l_brace)) + return FnD; + } + + // Consume the tokens and store them for later parsing. + + getCurTopClassStack().push(LexedMethod(FnD)); + TokensTy &Toks = getCurTopClassStack().top().Toks; + + // Begin by storing the '{' token. + Toks.push_back(Tok); + ConsumeBrace(); + ConsumeAndStoreUntil(tok::r_brace, Toks); + + return FnD; +} + +/// ParseLexedMethodDefs - We finished parsing the member specification of a top +/// (non-nested) C++ class. Now go over the stack of lexed methods that were +/// collected during its parsing and parse them all. +void Parser::ParseLexedMethodDefs() { + while (!getCurTopClassStack().empty()) { + LexedMethod &LM = getCurTopClassStack().top(); + + assert(!LM.Toks.empty() && "Empty body!"); + // Append the current token at the end of the new token stream so that it + // doesn't get lost. + LM.Toks.push_back(Tok); + PP.EnterTokenStream(&LM.Toks.front(), LM.Toks.size(), true, false); + + // Consume the previously pushed token. + ConsumeAnyToken(); + assert(Tok.is(tok::l_brace) && "Inline method not starting with '{'"); + + // Parse the method body. Function body parsing code is similar enough + // to be re-used for method bodies as well. + EnterScope(Scope::FnScope|Scope::DeclScope); + Actions.ActOnStartOfFunctionDef(CurScope, LM.D); + + ParseFunctionStatementBody(LM.D, Tok.getLocation(), Tok.getLocation()); + + getCurTopClassStack().pop(); + } +} + +/// ConsumeAndStoreUntil - Consume and store the token at the passed token +/// container until the token 'T' is reached (which gets consumed/stored too). +/// Returns true if token 'T' was found. +/// NOTE: This is a specialized version of Parser::SkipUntil. +bool Parser::ConsumeAndStoreUntil(tok::TokenKind T, TokensTy &Toks) { + // We always want this function to consume at least one token if the first + // token isn't T and if not at EOF. + bool isFirstTokenConsumed = true; + while (1) { + // If we found one of the tokens, stop and return true. + if (Tok.is(T)) { + Toks.push_back(Tok); + ConsumeAnyToken(); + return true; + } + + switch (Tok.getKind()) { + case tok::eof: + // Ran out of tokens. + return false; + + case tok::l_paren: + // Recursively consume properly-nested parens. + Toks.push_back(Tok); + ConsumeParen(); + ConsumeAndStoreUntil(tok::r_paren, Toks); + break; + case tok::l_square: + // Recursively consume properly-nested square brackets. + Toks.push_back(Tok); + ConsumeBracket(); + ConsumeAndStoreUntil(tok::r_square, Toks); + break; + case tok::l_brace: + // Recursively consume properly-nested braces. + Toks.push_back(Tok); + ConsumeBrace(); + ConsumeAndStoreUntil(tok::r_brace, Toks); + 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 && !isFirstTokenConsumed) + return false; // Matches something. + Toks.push_back(Tok); + ConsumeParen(); + break; + case tok::r_square: + if (BracketCount && !isFirstTokenConsumed) + return false; // Matches something. + Toks.push_back(Tok); + ConsumeBracket(); + break; + case tok::r_brace: + if (BraceCount && !isFirstTokenConsumed) + return false; // Matches something. + Toks.push_back(Tok); + ConsumeBrace(); + break; + + case tok::string_literal: + case tok::wide_string_literal: + Toks.push_back(Tok); + ConsumeStringToken(); + break; + default: + // consume this token. + Toks.push_back(Tok); + ConsumeToken(); + break; + } + isFirstTokenConsumed = false; + } +} |