[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