[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: KDE/kdevelop/languages/cpp/parser
From: Hamish Rodda <rodda () kde ! org>
Date: 2008-07-10 1:14:36
Message-ID: 1215652476.093265.25284.nullmailer () svn ! kde ! org
[Download RAW message or body]
SVN commit 830250 by rodda:
Parser improvements, merged from a patch by Robert Knight (thanks!)
- parse jump/goto/break
- report errors that were held back in expression or declaration parsing
- parse initializer lists
- adjust visitors appropriately
CCMAIL:robertknight@gmail.com
M +18 -0 ast.h
M +6 -0 default_visitor.cpp
M +1 -0 default_visitor.h
M +149 -54 parser.cpp
M +24 -3 parser.h
M +3 -1 visitor.cpp
M +1 -0 visitor.h
--- trunk/KDE/kdevelop/languages/cpp/parser/ast.h #830249:830250
@@ -190,6 +190,7 @@
Kind_WhileStatement, // 73
Kind_WinDeclSpec, // 74
Kind_Comment, // 75
+ Kind_JumpStatement, // 76
NODE_KIND_COUNT
};
@@ -496,7 +497,12 @@
{
DECLARE_AST_NODE(InitializerClause)
+ // either 'expression' or 'initializer_list' or neither are used.
+ // neither are used when the clause represents the empty initializer "{}"
+
+ // assignment expression
ExpressionAST *expression;
+ const ListNode<InitializerClauseAST*> *initializer_list;
};
struct LabeledStatementAST: public StatementAST
@@ -672,6 +678,18 @@
DECLARE_AST_NODE(PtrToMember)
};
+struct JumpStatementAST : public StatementAST
+{
+ DECLARE_AST_NODE(JumpStatement)
+
+ // index of operator token which describes the jump, one of
+ // 'break', 'continue' or 'goto. Return statements are handled by
+ // ReturnStatementAST
+ std::size_t op;
+ // identifier for 'goto' statements
+ std::size_t identifier;
+};
+
struct ReturnStatementAST: public StatementAST
{
DECLARE_AST_NODE(ReturnStatement)
--- trunk/KDE/kdevelop/languages/cpp/parser/default_visitor.cpp #830249:830250
@@ -202,8 +202,14 @@
void DefaultVisitor::visitInitializerClause(InitializerClauseAST *node)
{
visit(node->expression);
+ visitNodes(this, node->initializer_list);
}
+void DefaultVisitor::visitJumpStatement(JumpStatementAST *)
+{
+ // nothing to do
+}
+
void DefaultVisitor::visitLabeledStatement(LabeledStatementAST *node)
{
visit(node->expression);
--- trunk/KDE/kdevelop/languages/cpp/parser/default_visitor.h #830249:830250
@@ -59,6 +59,7 @@
virtual void visitInitDeclarator(InitDeclaratorAST *);
virtual void visitInitializer(InitializerAST *);
virtual void visitInitializerClause(InitializerClauseAST *);
+ virtual void visitJumpStatement(JumpStatementAST *);
virtual void visitLabeledStatement(LabeledStatementAST *);
virtual void visitLinkageBody(LinkageBodyAST *);
virtual void visitLinkageSpecification(LinkageSpecificationAST *);
--- trunk/KDE/kdevelop/languages/cpp/parser/parser.cpp #830249:830250
@@ -85,7 +85,7 @@
: control(c), lexer(control), session(0), _M_last_valid_token(0), _M_last_parsed_comment(0)
{
_M_max_problem_count = 5;
- _M_block_errors = false;
+ _M_hold_errors = false;
}
Parser::~Parser()
@@ -181,7 +181,7 @@
TranslationUnitAST *Parser::parse(ParseSession* _session)
{
- _M_block_errors = false;
+ _M_hold_errors = false;
session = _session;
if (!session->token_stream)
@@ -197,7 +197,7 @@
StatementAST *Parser::parseStatement(ParseSession* _session)
{
- _M_block_errors = false;
+ _M_hold_errors = false;
session = _session;
if (!session->token_stream)
@@ -213,7 +213,7 @@
AST *Parser::parseTypeOrExpression(ParseSession* _session, bool forceExpression)
{
- _M_block_errors = false;
+ _M_hold_errors = false;
session = _session;
if (!session->token_stream)
@@ -276,31 +276,62 @@
{
QString err;
- err += "expected token ";
- err += "``";
+ err += "Expected token ";
+ err += '\'';
err += token_name(token);
- err += "'' found ``";
+ err += "\' after \'";
+ err += token_name(session->token_stream->lookAhead(-1));
+ err += "\' found \'";
err += token_name(session->token_stream->lookAhead());
- err += "''";
+ err += '\'';
reportError(err);
}
void Parser::syntaxError()
{
+ std::size_t cursor = session->token_stream->cursor();
+ std::size_t kind = session->token_stream->lookAhead();
+
+ if (m_syntaxErrorTokens.contains(cursor))
+ return; // syntax error at this point has already been reported
+
+ m_syntaxErrorTokens.insert(cursor);
+
QString err;
- err += "unexpected token ";
- err += "``";
- err += token_name(session->token_stream->lookAhead());
- err += "''";
+ if (kind == Token_EOF)
+ err += "Unexpected end of file";
+ else
+ {
+ err += "Unexpected token ";
+ err += '\'';
+ err += token_name(kind);
+ err += '\'';
+ }
reportError(err);
}
+void Parser::reportPendingErrors()
+{
+ bool hold = holdErrors(false);
+
+ std::size_t start = session->token_stream->cursor();
+ while (m_pendingErrors.count() > 0)
+ {
+ PendingError error = m_pendingErrors.dequeue();
+ session->token_stream->rewind(error.cursor);
+ reportError(error.message);
+ }
+ rewind(start);
+
+ holdErrors(hold);
+}
+
void Parser::reportError(const QString& msg)
{
- if (!_M_block_errors && _M_problem_count < _M_max_problem_count)
+ if (!_M_hold_errors && _M_problem_count < _M_max_problem_count)
{
++_M_problem_count;
@@ -316,6 +347,13 @@
control->reportProblem(p);
}
+ else if (_M_hold_errors)
+ {
+ PendingError pending;
+ pending.message = msg;
+ pending.cursor = session->token_stream->cursor();
+ m_pendingErrors.enqueue(pending);
+ }
}
bool Parser::skipUntil(int token)
@@ -764,7 +802,7 @@
}
else
{
- reportError(("namespace expected"));
+ reportError(("Namespace expected"));
return false;
}
}
@@ -994,7 +1032,7 @@
DeclarationAST *declaration = 0;
if (!parseDeclaration(declaration))
{
- reportError(("expected a declaration"));
+ reportError(("Expected a declaration"));
}
TemplateDeclarationAST *ast = CreateNode<TemplateDeclarationAST>(session->mempool);
@@ -2461,6 +2499,27 @@
return true;
}
+bool Parser::parseInitializerList(const ListNode<InitializerClauseAST*> *&node)
+{
+ const ListNode<InitializerClauseAST*> *list = 0;
+ do
+ {
+ if (list)
+ advance(); // skip ',' separator between clauses
+
+ InitializerClauseAST *init_clause = 0;
+ if (!parseInitializerClause(init_clause))
+ {
+ return false;
+ }
+ list = snoc(list,init_clause,session->mempool);
+ } while (session->token_stream->lookAhead() == ',');
+
+ node = list;
+
+ return true;
+}
+
bool Parser::parseInitializerClause(InitializerClauseAST *&node)
{
std::size_t start = session->token_stream->cursor();
@@ -2469,19 +2528,23 @@
if (session->token_stream->lookAhead() == '{')
{
-#if defined(__GNUC__)
-#warning "implement me"
-#endif
- if (skip('{','}'))
- advance();
- else
- reportError(("} missing"));
+ advance();
+ const ListNode<InitializerClauseAST*> *initializer_list = 0;
+ if (session->token_stream->lookAhead() != '}' &&
+ !parseInitializerList(initializer_list))
+ {
+ return false;
+ }
+ ADVANCE('}',"}");
+
+ ast->initializer_list = initializer_list;
}
else
{
if (!parseAssignmentExpression(ast->expression))
{
- //reportError(("Expression expected"));
+ reportError("Expression expected");
+ return false;
}
}
@@ -2638,6 +2701,32 @@
return true;
}
+bool Parser::parseJumpStatement(StatementAST *&node)
+{
+ std::size_t op = session->token_stream->cursor();
+ std::size_t kind = session->token_stream->lookAhead();
+ std::size_t identifier = 0;
+
+ if (kind != Token_break && kind != Token_continue && kind != Token_goto)
+ return false;
+
+ advance();
+ if (kind == Token_goto)
+ {
+ ADVANCE(Token_identifier,"label");
+ identifier = op+1;
+ }
+ ADVANCE(';',";");
+
+ JumpStatementAST* ast = CreateNode<JumpStatementAST>(session->mempool);
+ ast->op = op;
+ ast->identifier = identifier;
+
+ UPDATE_POS(ast,ast->op,_M_last_valid_token+1);
+ node = ast;
+ return true;
+}
+
bool Parser::parseStatement(StatementAST *&node)
{
std::size_t start = session->token_stream->cursor();
@@ -2668,21 +2757,8 @@
case Token_break:
case Token_continue:
-#if defined(__GNUC__)
-#warning "implement me"
-#endif
- advance();
- ADVANCE(';', ";");
- return true;
-
case Token_goto:
-#if defined(__GNUC__)
-#warning "implement me"
-#endif
- advance();
- ADVANCE(Token_identifier, "identifier");
- ADVANCE(';', ";");
- return true;
+ return parseJumpStatement(node);
case Token_return:
{
@@ -2715,7 +2791,9 @@
bool Parser::parseExpressionOrDeclarationStatement(StatementAST *&node)
{
- bool blocked = block_errors(true);
+ // hold any errors while the expression/declaration ambiguity is resolved
+ // for this statement
+ bool hold = holdErrors(true);
std::size_t start = session->token_stream->cursor();
@@ -2724,6 +2802,13 @@
bool maybe_amb = parseDeclarationStatement(decl_ast);
maybe_amb &= session->token_stream->kind(session->token_stream->cursor() - 1) == ';';
+ // if parsing as a declaration succeeded, then any pending errors are genuine.
+ // Otherwise this is not a declaration so ignore the errors.
+ if (decl_ast)
+ reportPendingErrors();
+ else
+ m_pendingErrors.clear();
+
std::size_t end = session->token_stream->cursor();
rewind(start);
@@ -2731,6 +2816,13 @@
maybe_amb &= parseExpressionStatement(expr_ast);
maybe_amb &= session->token_stream->kind(session->token_stream->cursor() - 1) == ';';
+ // if parsing as an expression succeeded, then any pending errors are genuine.
+ // Otherwise this is not an expression so ignore the errors.
+ if (expr_ast)
+ reportPendingErrors();
+ else
+ m_pendingErrors.clear();
+
if (maybe_amb)
{
Q_ASSERT(decl_ast != 0 && expr_ast != 0);
@@ -2751,7 +2843,7 @@
node = expr_ast;
}
- block_errors(blocked);
+ holdErrors(hold);
if (!node)
syntaxError();
@@ -2820,7 +2912,7 @@
ConditionAST *cond = 0;
if (!parseCondition(cond))
{
- reportError(("condition expected"));
+ reportError("Condition expected");
return false;
}
ADVANCE(')', ")");
@@ -2828,7 +2920,7 @@
StatementAST *body = 0;
if (!parseStatement(body))
{
- reportError(("statement expected"));
+ reportError("Statement expected");
return false;
}
@@ -2851,7 +2943,7 @@
StatementAST *body = 0;
if (!parseStatement(body))
{
- reportError(("statement expected"));
+ reportError(("Statement expected"));
//return false;
}
@@ -2861,7 +2953,7 @@
ExpressionAST *expr = 0;
if (!parseCommaExpression(expr))
{
- reportError(("expression expected"));
+ reportError(("Expression expected"));
//return false;
}
@@ -2888,7 +2980,7 @@
StatementAST *init = 0;
if (!parseForInitStatement(init))
{
- reportError(("for initialization expected"));
+ reportError(("'for' initialization expected"));
return false;
}
@@ -2975,7 +3067,7 @@
ConditionAST *cond = 0;
if (!parseCondition(cond))
{
- reportError(("condition expected"));
+ reportError(("Condition expected"));
return false;
}
ADVANCE(')', ")");
@@ -2983,7 +3075,7 @@
StatementAST *stmt = 0;
if (!parseStatement(stmt))
{
- reportError(("statement expected"));
+ reportError(("Statement expected"));
return false;
}
@@ -2996,7 +3088,7 @@
if (!parseStatement(ast->else_statement))
{
- reportError(("statement expected"));
+ reportError(("Statement expected"));
return false;
}
}
@@ -3017,7 +3109,7 @@
ConditionAST *cond = 0;
if (!parseCondition(cond))
{
- reportError(("condition expected"));
+ reportError(("Condition expected"));
return false;
}
ADVANCE(')', ")");
@@ -3067,7 +3159,7 @@
ExpressionAST *expr = 0;
if (!parseConstantExpression(expr))
{
- reportError(("expression expected"));
+ reportError(("Expression expected"));
}
else if (session->token_stream->lookAhead() == Token_ellipsis)
{
@@ -3075,7 +3167,7 @@
if (!parseConstantExpression(expr))
{
- reportError(("expression expected"));
+ reportError(("Expression expected"));
}
}
ADVANCE(':', ":");
@@ -3456,6 +3548,8 @@
bool Parser::parseTryBlockStatement(StatementAST *&node)
{
+ std::size_t start = session->token_stream->cursor();
+
CHECK(Token_try);
TryBlockStatementAST *ast = CreateNode<TryBlockStatementAST>(session->mempool);
@@ -3470,7 +3564,7 @@
if (session->token_stream->lookAhead() != Token_catch)
{
- reportError(("catch expected"));
+ reportError(("'catch' expected after try block"));
return false;
}
@@ -3505,6 +3599,7 @@
}
node = ast;
+ UPDATE_POS(ast, start, _M_last_valid_token+1);
return true;
}
@@ -4505,10 +4600,10 @@
return true;
}
-bool Parser::block_errors(bool block)
+bool Parser::holdErrors(bool hold)
{
- bool current = _M_block_errors;
- _M_block_errors = block;
+ bool current = _M_hold_errors;
+ _M_hold_errors = hold;
return current;
}
--- trunk/KDE/kdevelop/languages/cpp/parser/parser.h #830249:830250
@@ -23,6 +23,8 @@
#include "lexer.h"
#include "commentparser.h"
+#include <QtCore/QQueue>
+#include <QtCore/QSet>
#include <QtCore/QString>
#include <cppparserexport.h>
@@ -132,6 +134,8 @@
bool parseInitDeclaratorList(const ListNode<InitDeclaratorAST*> *&node);
bool parseInitializer(InitializerAST *&node);
bool parseInitializerClause(InitializerClauseAST *&node);
+ bool parseInitializerList(const ListNode<InitializerClauseAST*> *&node);
+ bool parseJumpStatement(StatementAST *&node);
bool parseLabeledStatement(StatementAST *&node);
bool parseLinkageBody(LinkageBodyAST *&node);
bool parseLinkageSpecification(DeclarationAST *&node);
@@ -207,8 +211,6 @@
// private:
TokenStream* token_stream;
- bool block_errors(bool block);
-
// private:
Control *control;
Lexer lexer;
@@ -223,15 +225,34 @@
void processComment( int offset = 0, int line = -1 );
void clearComment( );
+ bool holdErrors(bool hold);
+ void reportPendingErrors();
+
Comment m_currentComment;
CommentStore m_commentStore;
int _M_problem_count;
int _M_max_problem_count;
ParseSession* session;
- bool _M_block_errors;
+ bool _M_hold_errors;
size_t _M_last_valid_token; //Last encountered token that was not a comment
size_t _M_last_parsed_comment;
+
+ // keeps track of tokens where a syntax error has been found
+ // so that the same error is not reported twice for a token
+ QSet<std::size_t> m_syntaxErrorTokens;
+
+ // when _M_hold_errors is true, reported errors are held in m_pendingErrors
+ // rather than being reported to the Control immediately.
+ //
+ // this is used, for example, when parsing ambiguous statements.
+ struct PendingError
+ {
+ QString message;
+ std::size_t cursor;
+ };
+ QQueue<PendingError> m_pendingErrors;
+
private:
Parser(const Parser& source);
void operator = (const Parser& source);
--- trunk/KDE/kdevelop/languages/cpp/parser/visitor.cpp #830249:830250
@@ -93,7 +93,9 @@
reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitUsing),
reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitUsingDirective),
reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitWhileStatement),
- reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitWinDeclSpec)
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitWinDeclSpec),
+ 0,
+ reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitJumpStatement)
};
Visitor::Visitor()
--- trunk/KDE/kdevelop/languages/cpp/parser/visitor.h #830249:830250
@@ -62,6 +62,7 @@
virtual void visitInitDeclarator(InitDeclaratorAST *) {}
virtual void visitInitializer(InitializerAST *) {}
virtual void visitInitializerClause(InitializerClauseAST *) {}
+ virtual void visitJumpStatement(JumpStatementAST *) {}
virtual void visitLabeledStatement(LabeledStatementAST *) {}
virtual void visitLinkageBody(LinkageBodyAST *) {}
virtual void visitLinkageSpecification(LinkageSpecificationAST *) {}
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic