Implement a first cut at binary expression parsing using a simple operator

precedence-based parser.

llvm-svn: 38874
This commit is contained in:
Chris Lattner 2006-08-12 08:13:25 +00:00
parent 89c50c65af
commit cde626ae9b
3 changed files with 242 additions and 2 deletions

View File

@ -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::ParseInitializer() {
Parser::ExprResult Parser::ParseExpression() {
return ParseCastExpression(false);
return ParseBinaryExpression();
}
// Expr that doesn't include commas.
@ -46,6 +54,232 @@ Parser::ExprResult Parser::ParseAssignmentExpression() {
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.
///

View File

@ -262,6 +262,8 @@ DIAG(ext_gnu_address_of_label, EXTENSION,
"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 @@ DIAG(err_expected_colon_after, ERROR,
"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

View File

@ -180,6 +180,8 @@ private:
//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();