[cfe-commits] r38833 - in /cfe/cfe/trunk: Parse/ParseDecl.cpp Parse/Parser.cpp include/clang/Basic/DiagnosticKinds.def include/clang/Parse/Parser.h
sabre at cs.uiuc.edu
sabre at cs.uiuc.edu
Wed Jul 11 09:25:02 PDT 2007
Author: sabre
Date: Wed Jul 11 11:25:01 2007
New Revision: 38833
URL: http://llvm.org/viewvc/llvm-project?rev=38833&view=rev
Log:
Start implementing error recovery, this implements test/Parser/recovery-1.c
Modified:
cfe/cfe/trunk/Parse/ParseDecl.cpp
cfe/cfe/trunk/Parse/Parser.cpp
cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
cfe/cfe/trunk/include/clang/Parse/Parser.h
Modified: cfe/cfe/trunk/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Parse/ParseDecl.cpp?rev=38833&r1=38832&r2=38833&view=diff
==============================================================================
--- cfe/cfe/trunk/Parse/ParseDecl.cpp (original)
+++ cfe/cfe/trunk/Parse/ParseDecl.cpp Wed Jul 11 11:25:01 2007
@@ -332,22 +332,14 @@
// direct-declarator: '(' attributes declarator ')' [TODO]
// Example: 'char (*X)' or 'int (*XX)(void)'
ParseParenDeclarator(D);
- } else if (Tok.getKind() == tok::l_square &&
- D.mayOmitIdentifier()) {
- // direct-abstract-declarator[opt] '[' assignment-expression[opt] ']'
- // direct-abstract-declarator[opt] '[' '*' ']'
-
- // direct-abstract-declarator was not specified. Remember that this is the
- // place where the identifier would have been.
- D.SetIdentifier(0, Tok.getLocation());
- // Don't consume the '[', handle it below.
} else if (D.mayOmitIdentifier()) {
// This could be something simple like "int" (in which case the declarator
// portion is empty), if an abstract-declarator is allowed.
D.SetIdentifier(0, Tok.getLocation());
} else {
- // expected identifier or '(' or '['.
- assert(0 && "ERROR: should recover!");
+ // Expected identifier or '('.
+ Diag(Tok, diag::err_expected_ident_lparen);
+ D.SetIdentifier(0, Tok.getLocation());
}
assert(D.isPastIdentifier() &&
@@ -389,6 +381,7 @@
/// identifier-list ',' identifier
///
void Parser::ParseParenDeclarator(Declarator &D) {
+ SourceLocation LParenLoc = Tok.getLocation();
ConsumeParen();
// If we haven't past the identifier yet (or where the identifier would be
@@ -418,10 +411,14 @@
// direct-declarator: '(' attributes declarator ')' [TODO]
if (isGrouping) {
ParseDeclarator(D);
- // expected ')': skip until we find ')'.
- if (Tok.getKind() != tok::r_paren)
- assert(0 && "Recover!");
- ConsumeParen();
+ if (Tok.getKind() == tok::r_paren) {
+ ConsumeParen();
+ } else {
+ // expected ')': skip until we find ')'.
+ Diag(Tok, diag::err_expected_rparen);
+ Diag(LParenLoc, diag::err_matching);
+ SkipUntil(tok::r_paren);
+ }
return;
}
@@ -520,6 +517,7 @@
HasPrototype = true;
}
+ // FIXME: pop the scope.
// expected ')': skip until we find ')'.
if (Tok.getKind() != tok::r_paren)
@@ -535,7 +533,7 @@
/// [C99] direct-declarator '[' type-qual-list[opt] '*' ']'
void Parser::ParseBracketDeclarator(Declarator &D) {
SourceLocation StartLoc = Tok.getLocation();
- ConsumeSquare();
+ ConsumeBracket();
// If valid, this location is the position where we read the 'static' keyword.
SourceLocation StaticLoc;
@@ -570,15 +568,13 @@
Diag(StaticLoc, diag::err_unspecified_vla_size_with_static);
StaticLoc = SourceLocation(); // Drop the static.
isStar = true;
- ConsumeToken();
} else {
// Otherwise, the * must have been some expression (such as '*ptr') that
// started an assign-expr. We already consumed the token, but now we need
// to reparse it.
- // FIXME: There are two options here: first, we could push 'StarTok' and
- // Tok back into the preprocessor as a macro expansion context, so they
- // will be read again. Second, we could parse the rest of the assign-expr
- // then apply the dereference.
+ // FIXME: We must push 'StarTok' and Tok back into the preprocessor as a
+ // macro expansion context, so they will be read again. It is basically
+ // impossible to refudge the * in otherwise, due to cases like X[*p + 4].
assert(0 && "FIXME: int X[*p] unimplemented");
}
}
@@ -588,7 +584,7 @@
assert(0 && "expr parsing not impl yet!");
}
- ConsumeSquare();
+ ConsumeBracket();
// If C99 isn't enabled, emit an ext-warn if the arg list wasn't empty and if
// it was not a constant expression.
Modified: cfe/cfe/trunk/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Parse/Parser.cpp?rev=38833&r1=38832&r2=38833&view=diff
==============================================================================
--- cfe/cfe/trunk/Parse/Parser.cpp (original)
+++ cfe/cfe/trunk/Parse/Parser.cpp Wed Jul 11 11:25:01 2007
@@ -22,6 +22,8 @@
// Create the global scope, install it as the current scope.
CurScope = new Scope(0);
Tok.SetKind(tok::eof);
+
+ ParenCount = BracketCount = BraceCount = 0;
}
Parser::~Parser() {
@@ -35,6 +37,92 @@
}
//===----------------------------------------------------------------------===//
+// 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;
+ }
+ }
+}
+
+//===----------------------------------------------------------------------===//
// C99 6.9: External Definitions.
//===----------------------------------------------------------------------===//
@@ -140,9 +228,8 @@
ConsumeToken();
} else {
Diag(Tok, diag::err_parse_error);
- // FIXME: skip to end of block or statement
- while (Tok.getKind() != tok::semi && Tok.getKind() != tok::eof)
- ConsumeToken();
+ // Skip to end of block or statement
+ SkipUntil(tok::r_brace, true);
if (Tok.getKind() == tok::semi)
ConsumeToken();
}
Modified: cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=38833&r1=38832&r2=38833&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Jul 11 11:25:01 2007
@@ -255,8 +255,22 @@
DIAG(ext_c99_array_usage, EXTENSION,
"use of c99-specific array features")
+// Generic errors.
DIAG(err_parse_error, ERROR,
"parse error")
+DIAG(err_expected_ident_lparen, ERROR,
+ "expected identifier or '('")
+DIAG(err_expected_rparen, ERROR,
+ "expected ')'")
+
+/// err_matching - this is used as a continuation of a previous error, e.g. to
+/// specify the '(' when we expected a ')'. This should probably be some
+/// special sort of diagnostic kind to indicate that it is the second half of
+/// the previous diagnostic.
+DIAG(err_matching, ERROR,
+ "to match")
+
+
DIAG(err_invalid_decl_spec_combination, ERROR,
"cannot combine with previous '%s' declaration specifier")
DIAG(err_invalid_sign_spec, ERROR,
Modified: cfe/cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/include/clang/Parse/Parser.h?rev=38833&r1=38832&r2=38833&view=diff
==============================================================================
--- cfe/cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/cfe/trunk/include/clang/Parse/Parser.h Wed Jul 11 11:25:01 2007
@@ -33,6 +33,7 @@
ParserActions &Actions;
Diagnostic &Diags;
Scope *CurScope;
+ unsigned short ParenCount, BracketCount, BraceCount;
/// Tok - The current token we are peeking head. All parsing methods assume
/// that this is valid.
@@ -61,37 +62,95 @@
Diag(Tok, DiagID, Msg);
}
- /// ConsumeToken - Consume the current 'peek token', lexing a new one and
- /// returning the token kind. This does not work will all kinds of tokens,
- /// strings and parens must be consumed with custom methods below.
+ /// isTokenParen - Return true if the cur token is '(' or ')'.
+ bool isTokenParen() const {
+ return Tok.getKind() == tok::l_paren || Tok.getKind() == tok::r_paren;
+ }
+ /// isTokenBracket - Return true if the cur token is '[' or ']'.
+ bool isTokenBracket() const {
+ return Tok.getKind() == tok::l_square || Tok.getKind() == tok::r_square;
+ }
+ /// isTokenBrace - Return true if the cur token is '{' or '}'.
+ bool isTokenBrace() const {
+ return Tok.getKind() == tok::l_brace || Tok.getKind() == tok::r_brace;
+ }
+
+ /// ConsumeToken - Consume the current 'peek token' and lex the next one.
+ /// This does not work will all kinds of tokens: strings and specific other
+ /// tokens must be consumed with custom methods below.
void ConsumeToken() {
+ // Note: update Parser::SkipUntil if any other special tokens are added.
assert(Tok.getKind() != tok::string_literal &&
- Tok.getKind() != tok::l_paren &&
- Tok.getKind() != tok::r_paren &&
- Tok.getKind() != tok::l_square &&
- Tok.getKind() != tok::r_square &&
+ !isTokenParen() && !isTokenBracket() && !isTokenBrace() &&
"Should consume special tokens with Consume*Token");
PP.Lex(Tok);
}
- /// ConsumeParen - This consume method keeps the paren count up-to-date.
+ /// ConsumeParen - This consume method keeps the paren count up-to-date.
///
void ConsumeParen() {
- assert((Tok.getKind() == tok::l_paren ||
- Tok.getKind() == tok::r_paren) && "wrong consume method");
+ assert(isTokenParen() && "wrong consume method");
+ if (Tok.getKind() == tok::l_paren)
+ ++ParenCount;
+ else if (ParenCount)
+ --ParenCount; // Don't let unbalanced )'s drive the count negative.
PP.Lex(Tok);
}
-
- /// ConsumeSquare - This consume method keeps the bracket count up-to-date.
+
+ /// ConsumeBracket - This consume method keeps the bracket count up-to-date.
///
- void ConsumeSquare() {
- assert((Tok.getKind() == tok::l_square ||
- Tok.getKind() == tok::r_square) && "wrong consume method");
+ void ConsumeBracket() {
+ assert(isTokenBracket() && "wrong consume method");
+ if (Tok.getKind() == tok::l_square)
+ ++BracketCount;
+ else if (BracketCount)
+ --BracketCount; // Don't let unbalanced ]'s drive the count negative.
+
PP.Lex(Tok);
}
+
+ /// ConsumeBrace - This consume method keeps the brace count up-to-date.
+ ///
+ void ConsumeBrace() {
+ assert(isTokenBrace() && "wrong consume method");
+ if (Tok.getKind() == tok::l_brace)
+ ++BraceCount;
+ else if (BraceCount)
+ --BraceCount; // Don't let unbalanced }'s drive the count negative.
+
+ PP.Lex(Tok);
+ }
+
+
+ /// ConsumeStringToken - Consume the current 'peek token', lexing a new one
+ /// and returning the token kind. This method is specific to strings, as it
+ /// handles string literal concatenation, as per C99 5.1.1.2, translation
+ /// phase #6.
+ void ConsumeStringToken() {
+ assert(Tok.getKind() != tok::string_literal &&
+ "Should consume special tokens with Consume*Token");
+ // Due to string literal concatenation, all consequtive string literals are
+ // a single token.
+ while (Tok.getKind() == tok::string_literal)
+ PP.Lex(Tok);
+ }
private:
//===--------------------------------------------------------------------===//
+ // 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 SkipUntil(tok::TokenKind T, bool StopAtSemi = false,
+ bool DontConsume = false);
+
+ //===--------------------------------------------------------------------===//
// C99 6.9: External Definitions.
void ParseExternalDeclaration();
void ParseDeclarationOrFunctionDefinition();
More information about the cfe-commits
mailing list