Commit c33b5553 authored by Erik Verbruggen's avatar Erik Verbruggen
Browse files

Extended operator precedence parsing.

It now includes comma expressions, conditionals and assignment
expressions.
parent 5878a895
......@@ -107,8 +107,7 @@ inline bool lookAtAssignmentOperator(int tokenKind)
} // switch
}
namespace Prec { // operator-precedence
namespace Prec {
enum {
Unknown = 0,
Comma = 1,
......@@ -126,46 +125,53 @@ enum {
Multiplicative = 13,
PointerToMember = 14
};
} // end of namespace Precedece
inline int precedence(int tokenKind, bool templateArguments)
{
// ### this will/might need some tuning for C++0x
// (see: [temp.names]p3)
if (templateArguments && tokenKind == T_GREATER)
return -1;
if (lookAtAssignmentOperator(tokenKind))
return Assignment;
return Prec::Assignment;
switch (tokenKind) {
case T_COMMA: return Comma;
case T_QUESTION: return Conditional;
case T_PIPE_PIPE: return LogicalOr;
case T_AMPER_AMPER: return LogicalAnd;
case T_PIPE: return InclusiveOr;
case T_CARET: return ExclusiveOr;
case T_AMPER: return And;
case T_COMMA: return Prec::Comma;
case T_QUESTION: return Prec::Conditional;
case T_PIPE_PIPE: return Prec::LogicalOr;
case T_AMPER_AMPER: return Prec::LogicalAnd;
case T_PIPE: return Prec::InclusiveOr;
case T_CARET: return Prec::ExclusiveOr;
case T_AMPER: return Prec::And;
case T_EQUAL_EQUAL:
case T_EXCLAIM_EQUAL: return Equality;
case T_EXCLAIM_EQUAL: return Prec::Equality;
case T_GREATER:
case T_LESS:
case T_LESS_EQUAL:
case T_GREATER_EQUAL: return Relational;
case T_GREATER_EQUAL: return Prec::Relational;
case T_LESS_LESS:
case T_GREATER_GREATER: return ExclusiveOr;
case T_GREATER_GREATER: return Prec::ExclusiveOr;
case T_PLUS:
case T_MINUS: return Additive;
case T_MINUS: return Prec::Additive;
case T_STAR:
case T_SLASH:
case T_PERCENT: return Multiplicative;
case T_PERCENT: return Prec::Multiplicative;
case T_ARROW_STAR:
case T_DOT_STAR: return PointerToMember;
default: return Unknown;
case T_DOT_STAR: return Prec::PointerToMember;
default: return Prec::Unknown;
}
}
} // end of namespace Precedece
inline bool isBinaryOperator(int tokenKind)
{ return Prec::precedence(tokenKind, false) != Prec::Unknown; }
{ return precedence(tokenKind, false) != Prec::Unknown; }
inline bool isRightAssociative(int tokenKind)
{
const int prec = precedence(tokenKind, false);
return prec == Prec::Conditional || prec == Prec::Assignment;
}
} // end of anonymous namespace
......@@ -4250,76 +4256,62 @@ bool Parser::parseCastExpression(ExpressionAST *&node)
bool Parser::parsePmExpression(ExpressionAST *&node)
{
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::precedence(T_ARROW_STAR, _templateArguments))
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::PointerToMember)
}
bool Parser::parseMultiplicativeExpression(ExpressionAST *&node)
{
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::precedence(T_STAR, _templateArguments))
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::Multiplicative)
}
bool Parser::parseAdditiveExpression(ExpressionAST *&node)
{
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::precedence(T_PLUS, _templateArguments))
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::Additive)
}
bool Parser::parseShiftExpression(ExpressionAST *&node)
{
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::precedence(T_LESS_LESS, _templateArguments))
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::Shift)
}
bool Parser::parseRelationalExpression(ExpressionAST *&node)
{
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::precedence(T_LESS, _templateArguments))
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::Relational)
}
bool Parser::parseEqualityExpression(ExpressionAST *&node)
{
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::precedence(T_EQUAL_EQUAL, _templateArguments))
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::Equality)
}
bool Parser::parseAndExpression(ExpressionAST *&node)
{
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::precedence(T_AMPER, _templateArguments))
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::And)
}
bool Parser::parseExclusiveOrExpression(ExpressionAST *&node)
{
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::precedence(T_CARET, _templateArguments))
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::ExclusiveOr)
}
bool Parser::parseInclusiveOrExpression(ExpressionAST *&node)
{
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::precedence(T_PIPE, _templateArguments))
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::InclusiveOr)
}
bool Parser::parseLogicalAndExpression(ExpressionAST *&node)
{
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::precedence(T_AMPER_AMPER, _templateArguments))
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::LogicalAnd)
}
bool Parser::parseLogicalOrExpression(ExpressionAST *&node)
{
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::precedence(T_PIPE_PIPE, _templateArguments))
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::LogicalOr)
}
bool Parser::parseConditionalExpression(ExpressionAST *&node)
{
DEBUG_THIS_RULE();
if (! parseLogicalOrExpression(node))
return false;
if (LA() != T_QUESTION)
return true;
ConditionalExpressionAST *ast = new (_pool) ConditionalExpressionAST;
ast->condition = node;
ast->question_token = consumeToken();
parseAssignmentExpression(ast->left_expression);
match(T_COLON, &ast->colon_token);
parseAssignmentExpression(ast->right_expression);
node = ast;
return true;
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::Conditional)
}
bool Parser::parseAssignmentExpression(ExpressionAST *&node)
......@@ -4327,27 +4319,8 @@ bool Parser::parseAssignmentExpression(ExpressionAST *&node)
DEBUG_THIS_RULE();
if (LA() == T_THROW)
return parseThrowExpression(node);
else if (! parseConditionalExpression(node))
return false;
if (lookAtAssignmentOperator(LA())) {
unsigned op = consumeToken();
ExpressionAST *rightExpr = 0;
if (! parseAssignmentExpression(rightExpr)) {
_translationUnit->error(op, "expected expression after token `%s'",
_translationUnit->spell(op));
return false;
}
BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
ast->binary_op_token = op;
ast->left_expression = node;
ast->right_expression = rightExpr;
node = ast;
}
return true;
else
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::Assignment)
}
bool Parser::parseQtMethod(ExpressionAST *&node)
......@@ -4390,47 +4363,61 @@ void Parser::parseExpressionWithOperatorPrecedence(ExpressionAST *&lhs, int minP
{
DEBUG_THIS_RULE();
while (Prec::precedence(tok().kind(), _templateArguments) >= minPrecedence) {
const int operPrecedence = Prec::precedence(tok().kind(), _templateArguments);
while (precedence(tok().kind(), _templateArguments) >= minPrecedence) {
const int operPrecedence = precedence(tok().kind(), _templateArguments);
const int oper = consumeToken();
ConditionalExpressionAST *condExpr = 0;
if (operPrecedence == Prec::Conditional) {
condExpr = new (_pool) ConditionalExpressionAST;
condExpr->question_token = oper;
if (oper == T_COLON) {
// GNU extension:
// logical-or-expression '?' ':' conditional-expression
condExpr->left_expression = 0;
} else {
parseExpression(condExpr->left_expression);
}
match(T_COLON, &condExpr->colon_token);
}
ExpressionAST *rhs = 0;
if (!parseCastExpression(rhs))
return;
const bool isCPlusPlus = true;
if (operPrecedence <= Prec::Conditional && isCPlusPlus) {
// in C++ you can put a throw in the right-most expression of a conditional expression,
// or an assignment, so some special handling:
if (!parseAssignmentExpression(rhs))
return;
} else {
// for C & all other expressions:
if (!parseCastExpression(rhs))
return;
}
for (int tokenKindAhead = tok().kind(), precedenceAhead = Prec::precedence(tokenKindAhead, _templateArguments);
precedenceAhead > operPrecedence && isBinaryOperator(tokenKindAhead);
tokenKindAhead = tok().kind(), precedenceAhead = Prec::precedence(tokenKindAhead, _templateArguments)) {
for (int tokenKindAhead = tok().kind(), precedenceAhead = precedence(tokenKindAhead, _templateArguments);
precedenceAhead > operPrecedence && isBinaryOperator(tokenKindAhead)
|| precedenceAhead == operPrecedence && isRightAssociative(tokenKindAhead);
tokenKindAhead = tok().kind(), precedenceAhead = precedence(tokenKindAhead, _templateArguments)) {
parseExpressionWithOperatorPrecedence(rhs, precedenceAhead);
}
BinaryExpressionAST *expr = new (_pool) BinaryExpressionAST;
expr->left_expression = lhs;
expr->binary_op_token = oper;
expr->right_expression = rhs;
lhs = expr;
if (condExpr) { // we were parsing a ternairy conditional expression
condExpr->condition = lhs;
condExpr->right_expression = rhs;
lhs = condExpr;
} else {
BinaryExpressionAST *expr = new (_pool) BinaryExpressionAST;
expr->left_expression = lhs;
expr->binary_op_token = oper;
expr->right_expression = rhs;
lhs = expr;
}
}
}
bool Parser::parseCommaExpression(ExpressionAST *&node)
{
DEBUG_THIS_RULE();
if (! parseAssignmentExpression(node))
return false;
while (LA() == T_COMMA) {
unsigned op = consumeToken();
ExpressionAST *rightExpr = 0;
if (! parseAssignmentExpression(rightExpr))
return false;
BinaryExpressionAST *ast = new (_pool) BinaryExpressionAST;
ast->binary_op_token = op;
ast->left_expression = node;
ast->right_expression = rightExpr;
node = ast;
}
return true;
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::Comma)
}
bool Parser::parseThrowExpression(ExpressionAST *&node)
......
......@@ -50,6 +50,7 @@ private slots:
void new_expression_2();
void condition_1();
void init_1();
void conditional_1();
// statements
void if_statement_1();
......@@ -248,6 +249,98 @@ void tst_AST::init_1()
QVERIFY(ast != 0);
}
void tst_AST::conditional_1()
{
QSharedPointer<TranslationUnit> unit(parseExpression("\n"
"(x < 0 && y > (int) a) ? x == 1 : y = 1"
));
AST *ast = unit->ast();
QVERIFY(ast != 0);
ConditionalExpressionAST *conditional = ast->asConditionalExpression();
QVERIFY(conditional);
QVERIFY(conditional->condition);
QVERIFY(conditional->left_expression);
QVERIFY(conditional->right_expression);
NestedExpressionAST *nestedExpr = conditional->condition->asNestedExpression();
QVERIFY(nestedExpr);
QVERIFY(nestedExpr->expression);
BinaryExpressionAST *andExpr = nestedExpr->expression->asBinaryExpression();
QVERIFY(andExpr);
QCOMPARE(unit->tokenKind(andExpr->binary_op_token), (int) T_AMPER_AMPER);
QVERIFY(andExpr->left_expression);
QVERIFY(andExpr->right_expression);
BinaryExpressionAST *ltExpr = andExpr->left_expression->asBinaryExpression();
QVERIFY(ltExpr);
QCOMPARE(unit->tokenKind(ltExpr->binary_op_token), (int) T_LESS);
QVERIFY(ltExpr->left_expression);
QVERIFY(ltExpr->right_expression);
SimpleNameAST *x = ltExpr->left_expression->asSimpleName();
QVERIFY(x);
QCOMPARE(unit->spell(x->identifier_token), "x");
NumericLiteralAST *zero = ltExpr->right_expression->asNumericLiteral();
QVERIFY(zero);
QCOMPARE(unit->spell(zero->literal_token), "0");
BinaryExpressionAST *gtExpr = andExpr->right_expression->asBinaryExpression();
QVERIFY(gtExpr);
QCOMPARE(unit->tokenKind(gtExpr->binary_op_token), (int) T_GREATER);
QVERIFY(gtExpr->left_expression);
QVERIFY(gtExpr->right_expression);
SimpleNameAST *y = gtExpr->left_expression->asSimpleName();
QVERIFY(y);
QCOMPARE(unit->spell(y->identifier_token), "y");
CastExpressionAST *cast = gtExpr->right_expression->asCastExpression();
QVERIFY(cast);
QVERIFY(cast->type_id);
QVERIFY(cast->expression);
TypeIdAST *intType = cast->type_id->asTypeId();
QVERIFY(intType);
QVERIFY(! (intType->declarator));
QVERIFY(intType->type_specifier_list);
QVERIFY(! (intType->type_specifier_list->next));
QVERIFY(intType->type_specifier_list->value);
SimpleSpecifierAST *intSpec = intType->type_specifier_list->value->asSimpleSpecifier();
QVERIFY(intSpec);
QCOMPARE(unit->spell(intSpec->specifier_token), "int");
SimpleNameAST *a = cast->expression->asSimpleName();
QVERIFY(a);
QCOMPARE(unit->spell(a->identifier_token), "a");
BinaryExpressionAST *equals = conditional->left_expression->asBinaryExpression();
QVERIFY(equals);
QCOMPARE(unit->tokenKind(equals->binary_op_token), (int) T_EQUAL_EQUAL);
x = equals->left_expression->asSimpleName();
QVERIFY(x);
QCOMPARE(unit->spell(x->identifier_token), "x");
NumericLiteralAST *one = equals->right_expression->asNumericLiteral();
QVERIFY(one);
QCOMPARE(unit->spell(one->literal_token), "1");
BinaryExpressionAST *assignment = conditional->right_expression->asBinaryExpression();
QVERIFY(assignment);
QCOMPARE(unit->tokenKind(assignment->binary_op_token), (int) T_EQUAL);
y = assignment->left_expression->asSimpleName();
QVERIFY(y);
QCOMPARE(unit->spell(y->identifier_token), "y");
one = assignment->right_expression->asNumericLiteral();
QVERIFY(one);
QCOMPARE(unit->spell(one->literal_token), "1");
}
void tst_AST::function_call_1()
{
QSharedPointer<TranslationUnit> unit(parseStatement("retranslateUi(blah);"));
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment