forked from qt-creator/qt-creator
Changed binary expression parsing to use precedence parsing.
This commit is contained in:
@@ -59,6 +59,7 @@
|
||||
#endif
|
||||
|
||||
#define CPLUSPLUS_NO_DEBUG_RULE
|
||||
#define MAX_EXPRESSION_DEPTH 100
|
||||
|
||||
using namespace CPlusPlus;
|
||||
|
||||
@@ -85,6 +86,73 @@ public:
|
||||
|
||||
int DebugRule::depth = 0;
|
||||
|
||||
inline int precedence(int tokenKind, bool templateArguments)
|
||||
{
|
||||
if (templateArguments && tokenKind == T_GREATER)
|
||||
return -1;
|
||||
|
||||
switch (tokenKind) {
|
||||
case T_PIPE_PIPE: return 0;
|
||||
case T_AMPER_AMPER: return 1;
|
||||
case T_PIPE: return 2;
|
||||
case T_CARET: return 3;
|
||||
case T_AMPER: return 4;
|
||||
case T_EQUAL_EQUAL:
|
||||
case T_EXCLAIM_EQUAL: return 5;
|
||||
case T_GREATER:
|
||||
case T_LESS:
|
||||
case T_LESS_EQUAL:
|
||||
case T_GREATER_EQUAL: return 6;
|
||||
case T_LESS_LESS:
|
||||
case T_GREATER_GREATER: return 7;
|
||||
case T_PLUS:
|
||||
case T_MINUS: return 8;
|
||||
case T_STAR:
|
||||
case T_SLASH:
|
||||
case T_PERCENT: return 9;
|
||||
case T_ARROW_STAR:
|
||||
case T_DOT_STAR: return 10;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool isBinaryOperator(int tokenKind)
|
||||
{
|
||||
switch (tokenKind) {
|
||||
case T_PIPE_PIPE:
|
||||
case T_AMPER_AMPER:
|
||||
case T_PIPE:
|
||||
case T_CARET:
|
||||
case T_AMPER:
|
||||
case T_EQUAL_EQUAL:
|
||||
case T_EXCLAIM_EQUAL:
|
||||
case T_GREATER:
|
||||
case T_LESS:
|
||||
case T_LESS_EQUAL:
|
||||
case T_GREATER_EQUAL:
|
||||
case T_LESS_LESS:
|
||||
case T_GREATER_GREATER:
|
||||
case T_PLUS:
|
||||
case T_MINUS:
|
||||
case T_STAR:
|
||||
case T_SLASH:
|
||||
case T_PERCENT:
|
||||
case T_ARROW_STAR:
|
||||
case T_DOT_STAR:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool isRightAssoc(int /*tokenKind*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
||||
#ifndef CPLUSPLUS_NO_DEBUG_RULE
|
||||
@@ -93,6 +161,14 @@ int DebugRule::depth = 0;
|
||||
# define DEBUG_THIS_RULE() do {} while (0)
|
||||
#endif
|
||||
|
||||
#define PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, minPrecedence) { \
|
||||
if (!parseCastExpression(node)) \
|
||||
return false; \
|
||||
\
|
||||
parseExpressionWithOperatorPrecedence(node, minPrecedence); \
|
||||
return true; \
|
||||
}
|
||||
|
||||
class Parser::Rewind
|
||||
{
|
||||
Parser *_parser;
|
||||
@@ -127,7 +203,7 @@ Parser::Parser(TranslationUnit *unit)
|
||||
_objCEnabled(false),
|
||||
_inFunctionBody(false),
|
||||
_inObjCImplementationContext(false),
|
||||
depth(0)
|
||||
_expressionDepth(0)
|
||||
{ }
|
||||
|
||||
Parser::~Parser()
|
||||
@@ -4145,280 +4221,57 @@ bool Parser::parseCastExpression(ExpressionAST *&node)
|
||||
|
||||
bool Parser::parsePmExpression(ExpressionAST *&node)
|
||||
{
|
||||
DEBUG_THIS_RULE();
|
||||
if (! parseCastExpression(node))
|
||||
return false;
|
||||
|
||||
while (LA() == T_ARROW_STAR || LA() == T_DOT_STAR) {
|
||||
unsigned op = consumeToken();
|
||||
|
||||
ExpressionAST *rightExpr = 0;
|
||||
if (! parseCastExpression(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;
|
||||
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, precedence(T_ARROW_STAR, _templateArguments))
|
||||
}
|
||||
|
||||
bool Parser::parseMultiplicativeExpression(ExpressionAST *&node)
|
||||
{
|
||||
DEBUG_THIS_RULE();
|
||||
if (! parsePmExpression(node))
|
||||
return false;
|
||||
|
||||
while (LA() == T_STAR || LA() == T_SLASH || LA() == T_PERCENT) {
|
||||
unsigned op = consumeToken();
|
||||
|
||||
ExpressionAST *rightExpr = 0;
|
||||
if (! parsePmExpression(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;
|
||||
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, precedence(T_STAR, _templateArguments))
|
||||
}
|
||||
|
||||
bool Parser::parseAdditiveExpression(ExpressionAST *&node)
|
||||
{
|
||||
DEBUG_THIS_RULE();
|
||||
if (! parseMultiplicativeExpression(node))
|
||||
return false;
|
||||
|
||||
while (LA() == T_PLUS || LA() == T_MINUS) {
|
||||
unsigned op = consumeToken();
|
||||
|
||||
ExpressionAST *rightExpr = 0;
|
||||
if (! parseMultiplicativeExpression(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;
|
||||
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, precedence(T_PLUS, _templateArguments))
|
||||
}
|
||||
|
||||
bool Parser::parseShiftExpression(ExpressionAST *&node)
|
||||
{
|
||||
DEBUG_THIS_RULE();
|
||||
if (! parseAdditiveExpression(node))
|
||||
return false;
|
||||
|
||||
while (LA() == T_LESS_LESS || LA() == T_GREATER_GREATER) {
|
||||
unsigned op = consumeToken();
|
||||
|
||||
ExpressionAST *rightExpr = 0;
|
||||
if (! parseAdditiveExpression(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;
|
||||
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, precedence(T_LESS_LESS, _templateArguments))
|
||||
}
|
||||
|
||||
bool Parser::parseRelationalExpression(ExpressionAST *&node)
|
||||
{
|
||||
DEBUG_THIS_RULE();
|
||||
if (! parseShiftExpression(node))
|
||||
return false;
|
||||
|
||||
while (LA() == T_LESS || (LA() == T_GREATER && ! _templateArguments) ||
|
||||
LA() == T_LESS_EQUAL || LA() == T_GREATER_EQUAL) {
|
||||
unsigned op = consumeToken();
|
||||
|
||||
ExpressionAST *rightExpr = 0;
|
||||
if (! parseShiftExpression(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;
|
||||
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, precedence(T_LESS, _templateArguments))
|
||||
}
|
||||
|
||||
bool Parser::parseEqualityExpression(ExpressionAST *&node)
|
||||
{
|
||||
DEBUG_THIS_RULE();
|
||||
if (! parseRelationalExpression(node))
|
||||
return false;
|
||||
|
||||
while (LA() == T_EQUAL_EQUAL || LA() == T_EXCLAIM_EQUAL) {
|
||||
unsigned op = consumeToken();
|
||||
|
||||
ExpressionAST *rightExpr = 0;
|
||||
if (! parseRelationalExpression(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;
|
||||
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, precedence(T_EQUAL_EQUAL, _templateArguments))
|
||||
}
|
||||
|
||||
bool Parser::parseAndExpression(ExpressionAST *&node)
|
||||
{
|
||||
DEBUG_THIS_RULE();
|
||||
if (! parseEqualityExpression(node))
|
||||
return false;
|
||||
|
||||
while (LA() == T_AMPER) {
|
||||
unsigned op = consumeToken();
|
||||
|
||||
ExpressionAST *rightExpr = 0;
|
||||
if (! parseEqualityExpression(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;
|
||||
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, precedence(T_AMPER, _templateArguments))
|
||||
}
|
||||
|
||||
bool Parser::parseExclusiveOrExpression(ExpressionAST *&node)
|
||||
{
|
||||
DEBUG_THIS_RULE();
|
||||
if (! parseAndExpression(node))
|
||||
return false;
|
||||
|
||||
while (LA() == T_CARET) {
|
||||
unsigned op = consumeToken();
|
||||
|
||||
ExpressionAST *rightExpr = 0;
|
||||
if (! parseAndExpression(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;
|
||||
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, precedence(T_CARET, _templateArguments))
|
||||
}
|
||||
|
||||
bool Parser::parseInclusiveOrExpression(ExpressionAST *&node)
|
||||
{
|
||||
DEBUG_THIS_RULE();
|
||||
if (! parseExclusiveOrExpression(node))
|
||||
return false;
|
||||
|
||||
while (LA() == T_PIPE) {
|
||||
unsigned op = consumeToken();
|
||||
|
||||
ExpressionAST *rightExpr = 0;
|
||||
if (! parseExclusiveOrExpression(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;
|
||||
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, precedence(T_PIPE, _templateArguments))
|
||||
}
|
||||
|
||||
bool Parser::parseLogicalAndExpression(ExpressionAST *&node)
|
||||
{
|
||||
DEBUG_THIS_RULE();
|
||||
if (! parseInclusiveOrExpression(node))
|
||||
return false;
|
||||
|
||||
while (LA() == T_AMPER_AMPER) {
|
||||
unsigned op = consumeToken();
|
||||
|
||||
ExpressionAST *rightExpr = 0;
|
||||
if (! parseInclusiveOrExpression(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;
|
||||
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, precedence(T_AMPER_AMPER, _templateArguments))
|
||||
}
|
||||
|
||||
bool Parser::parseLogicalOrExpression(ExpressionAST *&node)
|
||||
{
|
||||
DEBUG_THIS_RULE();
|
||||
if (! parseLogicalAndExpression(node))
|
||||
return false;
|
||||
|
||||
while (LA() == T_PIPE_PIPE) {
|
||||
unsigned op = consumeToken();
|
||||
|
||||
ExpressionAST *rightExpr = 0;
|
||||
if (! parseLogicalAndExpression(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;
|
||||
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, precedence(T_PIPE_PIPE, _templateArguments))
|
||||
}
|
||||
|
||||
bool Parser::parseConditionalExpression(ExpressionAST *&node)
|
||||
@@ -4515,13 +4368,40 @@ bool Parser::parseConstantExpression(ExpressionAST *&node)
|
||||
bool Parser::parseExpression(ExpressionAST *&node)
|
||||
{
|
||||
DEBUG_THIS_RULE();
|
||||
if (depth > 100)
|
||||
|
||||
if (_expressionDepth > MAX_EXPRESSION_DEPTH)
|
||||
return false;
|
||||
|
||||
++depth;
|
||||
bool result = parseCommaExpression(node);
|
||||
--depth;
|
||||
return result;
|
||||
++_expressionDepth;
|
||||
bool success = parseCommaExpression(node);
|
||||
--_expressionDepth;
|
||||
return success;
|
||||
}
|
||||
|
||||
void Parser::parseExpressionWithOperatorPrecedence(ExpressionAST *&lhs, int minPrecedence)
|
||||
{
|
||||
DEBUG_THIS_RULE();
|
||||
|
||||
while (precedence(tok().kind(), _templateArguments) >= minPrecedence) {
|
||||
const int operPrecedence = precedence(tok().kind(), _templateArguments);
|
||||
const int oper = consumeToken();
|
||||
ExpressionAST *rhs = 0;
|
||||
if (!parseCastExpression(rhs))
|
||||
return;
|
||||
|
||||
for (int tokenKindAhead = tok().kind(), precedenceAhead = precedence(tokenKindAhead, _templateArguments);
|
||||
precedenceAhead > operPrecedence && isBinaryOperator(tokenKindAhead)
|
||||
|| precedenceAhead == operPrecedence && isRightAssoc(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;
|
||||
}
|
||||
}
|
||||
|
||||
bool Parser::parseCommaExpression(ExpressionAST *&node)
|
||||
|
||||
@@ -214,6 +214,8 @@ public:
|
||||
bool parseUsingDirective(DeclarationAST *&node);
|
||||
bool parseWhileStatement(StatementAST *&node);
|
||||
|
||||
void parseExpressionWithOperatorPrecedence(ExpressionAST *&lhs, int minPrecedence);
|
||||
|
||||
// Qt MOC run
|
||||
bool parseQtMethod(ExpressionAST *&node);
|
||||
|
||||
@@ -313,8 +315,7 @@ private:
|
||||
bool _objCEnabled: 1;
|
||||
bool _inFunctionBody: 1;
|
||||
bool _inObjCImplementationContext: 1;
|
||||
|
||||
int depth;
|
||||
int _expressionDepth;
|
||||
|
||||
std::map<unsigned, TemplateArgumentListEntry> _templateArgumentList;
|
||||
|
||||
|
||||
@@ -185,11 +185,56 @@ void tst_AST::new_expression_2()
|
||||
void tst_AST::condition_1()
|
||||
{
|
||||
QSharedPointer<TranslationUnit> unit(parseExpression("\n"
|
||||
"(x < 0 && y > (int) a)"
|
||||
"(x < 0 && y > (int) a)"
|
||||
));
|
||||
|
||||
AST *ast = unit->ast();
|
||||
QVERIFY(ast != 0);
|
||||
NestedExpressionAST *nestedExpr = ast->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);
|
||||
// ### here we could check if the type is an actual int
|
||||
|
||||
SimpleNameAST *a = cast->expression->asSimpleName();
|
||||
QVERIFY(a);
|
||||
QCOMPARE(unit->spell(a->identifier_token), "a");
|
||||
}
|
||||
|
||||
void tst_AST::init_1()
|
||||
|
||||
Reference in New Issue
Block a user