[cfe-commits] r38874 - in /cfe/cfe/trunk: Parse/ParseExpr.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:23 PDT 2007


Author: sabre
Date: Wed Jul 11 11:25:23 2007
New Revision: 38874

URL: http://llvm.org/viewvc/llvm-project?rev=38874&view=rev
Log:
Implement a first cut at binary expression parsing using a simple operator
precedence-based parser.

Modified:
    cfe/cfe/trunk/Parse/ParseExpr.cpp
    cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def
    cfe/cfe/trunk/include/clang/Parse/Parser.h

Modified: cfe/cfe/trunk/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/cfe/trunk/Parse/ParseExpr.cpp?rev=38874&r1=38873&r2=38874&view=diff

==============================================================================
--- cfe/cfe/trunk/Parse/ParseExpr.cpp (original)
+++ cfe/cfe/trunk/Parse/ParseExpr.cpp Wed Jul 11 11:25:23 2007
@@ -7,7 +7,15 @@
 //
 //===----------------------------------------------------------------------===//
 //
-//  This file implements the Expression parsing implementation.
+// This file implements the Expression parsing implementation.  Expressions in
+// C99 basically consist of a bunch of binary operators with unary operators and
+// other random stuff at the leaves.
+//
+// In the C99 grammar, these unary operators bind tightest and are represented
+// as the 'cast-expression' production.  Everything else is either a binary
+// operator (e.g. '/') or a trinary operator ("?:").  The unary leaves are
+// handled by ParseCastExpression, the higher level pieces are handled by
+// ParseBinaryExpression.
 //
 //===----------------------------------------------------------------------===//
 
@@ -38,7 +46,7 @@
 
 
 Parser::ExprResult Parser::ParseExpression() {
-  return ParseCastExpression(false);
+  return ParseBinaryExpression();
 }
 
 // Expr that doesn't include commas.
@@ -46,6 +54,232 @@
   return ParseExpression();
 }
 
+/// PrecedenceLevels - These are precedences for the binary/trinary operators in
+/// the C99 grammar.  These have been named to relate with the C99 grammar
+/// productions.  Low precedences numbers bind more weakly than high numbers.
+namespace prec {
+  enum Level {
+    Unknown        = 0,    // Not binary operator.
+    Comma          = 1,    // ,
+    Assignment     = 2,    // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=
+    Conditional    = 3,    // ?
+    LogicalOr      = 4,    // ||
+    LogicalAnd     = 5,    // &&
+    InclusiveOr    = 6,    // |
+    ExclusiveOr    = 7,    // ^
+    And            = 8,    // &
+    MinMax         = 9,   // <?, >?           min, max (GCC extensions)
+    Equality       = 10,   // ==, !=
+    Relational     = 11,   //  >=, <=, >, <
+    Shift          = 12,   // <<, >>
+    Additive       = 13,   // -, +
+    Multiplicative = 14    // *, /, %
+  };
+}
+
+
+/// getBinOpPrecedence - Return the precedence of the specified binary operator
+/// token.  This returns:
+///
+static prec::Level getBinOpPrecedence(tok::TokenKind Kind) {
+  switch (Kind) {
+  default:                        return prec::Unknown;
+  case tok::comma:                return prec::Comma;
+  case tok::equal:
+  case tok::starequal:
+  case tok::slashequal:
+  case tok::percentequal:
+  case tok::plusequal:
+  case tok::minusequal:
+  case tok::lesslessequal:
+  case tok::greatergreaterequal:
+  case tok::ampequal:
+  case tok::caretequal:
+  case tok::pipeequal:            return prec::Assignment;
+  case tok::question:             return prec::Conditional;
+  case tok::pipepipe:             return prec::LogicalOr;
+  case tok::ampamp:               return prec::LogicalAnd;
+  case tok::pipe:                 return prec::InclusiveOr;
+  case tok::caret:                return prec::ExclusiveOr;
+  case tok::amp:                  return prec::And;
+  case tok::lessquestion:
+  case tok::greaterquestion:      return prec::MinMax;
+  case tok::exclaimequal:
+  case tok::equalequal:           return prec::Equality;
+  case tok::lessequal:
+  case tok::less:
+  case tok::greaterequal:
+  case tok::greater:              return prec::Relational;
+  case tok::lessless:
+  case tok::greatergreater:       return prec::Shift;
+  case tok::plus:
+  case tok::minus:                return prec::Additive;
+  case tok::percent:
+  case tok::slash:
+  case tok::star:                 return prec::Multiplicative;
+  }
+}
+
+
+/// ParseBinaryExpression - Simple precedence-based parser for binary/trinary
+/// operators.
+///
+///       multiplicative-expression: [C99 6.5.5]
+///         cast-expression
+///         multiplicative-expression '*' cast-expression
+///         multiplicative-expression '/' cast-expression
+///         multiplicative-expression '%' cast-expression
+///
+///       additive-expression: [C99 6.5.6]
+///         multiplicative-expression
+///         additive-expression '+' multiplicative-expression
+///         additive-expression '-' multiplicative-expression
+///
+///       shift-expression: [C99 6.5.7]
+///         additive-expression
+///         shift-expression '<<' additive-expression
+///         shift-expression '>>' additive-expression
+///
+///       relational-expression: [C99 6.5.8]
+///         shift-expression
+///         relational-expression '<' shift-expression
+///         relational-expression '>' shift-expression
+///         relational-expression '<=' shift-expression
+///         relational-expression '>=' shift-expression
+///
+///       equality-expression: [C99 6.5.9]
+///         relational-expression
+///         equality-expression '==' relational-expression
+///         equality-expression '!=' relational-expression
+///
+///       AND-expression: [C99 6.5.10]
+///         equality-expression
+///         AND-expression '&' equality-expression
+///
+///       exclusive-OR-expression: [C99 6.5.11]
+///         AND-expression
+///         exclusive-OR-expression '^' AND-expression
+///
+///       inclusive-OR-expression: [C99 6.5.12]
+///         exclusive-OR-expression
+///         inclusive-OR-expression '|' exclusive-OR-expression
+///
+///       logical-AND-expression: [C99 6.5.13]
+///         inclusive-OR-expression
+///         logical-AND-expression '&&' inclusive-OR-expression
+///
+///       logical-OR-expression: [C99 6.5.14]
+///         logical-AND-expression
+///         logical-OR-expression '||' logical-AND-expression
+///
+///       conditional-expression: [C99 6.5.15]
+///         logical-OR-expression
+///         logical-OR-expression '?' expression ':' conditional-expression
+/// [GNU]   logical-OR-expression '?' ':' conditional-expression
+///
+///       assignment-expression: [C99 6.5.16]
+///         conditional-expression
+///         unary-expression assignment-operator assignment-expression
+///
+///       assignment-operator: one of
+///         = *= /= %= += -= <<= >>= &= ^= |=
+///
+///       expression: [C99 6.5.17]
+///         assignment-expression
+///         expression ',' assignment-expression
+///
+Parser::ExprResult Parser::ParseBinaryExpression() {
+  ExprResult LHS = ParseCastExpression(false);
+  if (LHS.isInvalid) return LHS;
+  
+  return ParseRHSOfBinaryExpression(LHS, prec::Comma);
+}
+
+/// ParseRHSOfBinaryExpression - Parse a binary expression that starts with
+/// LHS and has a precedence of at least MinPrec.
+Parser::ExprResult
+Parser::ParseRHSOfBinaryExpression(ExprResult LHS, unsigned MinPrec) {
+  unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind());
+  
+  while (1) {
+    // If this token has a lower precedence than we are allowed to parse (e.g.
+    // because we are called recursively, or because the token is not a binop),
+    // then we are done!
+    if (NextTokPrec < MinPrec)
+      return LHS;
+
+    // Consume the operator, saving the operator token for error reporting.
+    LexerToken OpToken = Tok;
+    ConsumeToken();
+    
+    // Parse the RHS of the operator.
+    ExprResult RHS;
+    
+    // Special case handling of "X ? Y : Z" were Y is empty.  This is a GCC
+    // extension.
+    if (OpToken.getKind() != tok::question || Tok.getKind() != tok::colon) {
+      RHS = ParseCastExpression(false);
+      if (RHS.isInvalid) return RHS;
+    } else {
+      RHS = ExprResult(false);
+      Diag(Tok, diag::ext_gnu_conditional_expr);
+    }
+
+    // Remember the precedence of this operator and get the precedence of the
+    // operator immediately to the right of the RHS.
+    unsigned ThisPrec = NextTokPrec;
+    NextTokPrec = getBinOpPrecedence(Tok.getKind());
+    
+    // FIXME: ASSIGNMENT IS RIGHT ASSOCIATIVE.
+    // FIXME: do we want to handle assignment here??
+    // ASSIGNMENT: Parse LHS as conditional expr, then catch errors in semantic
+    // analysis.
+    bool isRightAssoc = OpToken.getKind() == tok::question;
+
+    // Get the precedence of the operator to the right of the RHS.  If it binds
+    // more tightly with RHS than we do, evaluate it completely first.
+
+    // FIXME: Is this enough for '?:' operators?  The second term is suppsed to
+    // be 'expression', not 'assignment'.
+    if (ThisPrec < NextTokPrec ||
+        (ThisPrec == NextTokPrec && isRightAssoc)) {
+      RHS = ParseRHSOfBinaryExpression(RHS, ThisPrec+1);
+      if (RHS.isInvalid) return RHS;
+
+      NextTokPrec = getBinOpPrecedence(Tok.getKind());
+    }
+    assert(NextTokPrec <= ThisPrec && "Recursion didn't work!");
+  
+    // Handle the special case of our one trinary operator here.
+    if (OpToken.getKind() == tok::question) {
+      if (Tok.getKind() != tok::colon) {
+        Diag(Tok, diag::err_expected_colon);
+        Diag(OpToken, diag::err_matching, "?");
+        return ExprResult(true);
+      }
+      
+      // Eat the colon.
+      ConsumeToken();
+      
+      // Parse the value of the colon.
+      ExprResult AfterColonVal = ParseCastExpression(false);
+      if (AfterColonVal.isInvalid) return AfterColonVal;
+      
+      // Parse anything after the RRHS that has a higher precedence than ?.
+      AfterColonVal = ParseRHSOfBinaryExpression(AfterColonVal, ThisPrec+1);
+      if (AfterColonVal.isInvalid) return AfterColonVal;
+      
+      // TODO: Combine LHS = LHS ? RHS : AfterColonVal.
+      
+      // Figure out the precedence of the token after the : part.
+      NextTokPrec = getBinOpPrecedence(Tok.getKind());
+    } else {
+      // TODO: combine the LHS and RHS into the LHS (e.g. build AST).
+    }
+  }
+}
+
+
 /// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is
 /// true, parse a unary-expression.
 ///

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=38874&r1=38873&r2=38874&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/cfe/trunk/include/clang/Basic/DiagnosticKinds.def Wed Jul 11 11:25:23 2007
@@ -262,6 +262,8 @@
      "use of GNU address-of-label extension")
 DIAG(ext_gnu_statement_expr, EXTENSION,
      "use of GNU statement expression extension")
+DIAG(ext_gnu_conditional_expr, EXTENSION,
+     "use of GNU ?: expression extension, eliding middle term")
      
 // Generic errors.
 DIAG(err_parse_error, ERROR,
@@ -300,6 +302,8 @@
      "expected ':' after %s")
 DIAG(err_label_end_of_compound_statement, ERROR,
      "label at end of compound statement: expected statement")
+DIAG(err_expected_colon, 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

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=38874&r1=38873&r2=38874&view=diff

==============================================================================
--- cfe/cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/cfe/trunk/include/clang/Parse/Parser.h Wed Jul 11 11:25:23 2007
@@ -180,6 +180,8 @@
   //ExprResult ParseExpression();  // Above.
   ExprResult ParseAssignmentExpression();  // Expr that doesn't include commas.
 
+  ExprResult ParseBinaryExpression();
+  ExprResult ParseRHSOfBinaryExpression(ExprResult LHS, unsigned MinPrec);
   ExprResult ParseCastExpression(bool isUnaryExpression);
   ExprResult ParseSizeofAlignofExpression();
   





More information about the cfe-commits mailing list