From: Francis De Brabandere <francisdb@gmail.com> The Not operator was only reachable from the NotExpression grammar rule, which sat above EqualityExpression in the precedence chain. This meant expressions like "a <> Not b" caused a syntax error because the right-hand side of a comparison could not contain Not. Fold Not directly into EqualityExpression as a unary prefix and use bison precedence declarations to resolve the resulting ambiguity: %right tNOT at lower precedence than %left comparison operators ensures "Not 1 = 2" parses as "Not(1 = 2)" while "a <> Not b = c" correctly lets Not capture the comparison on its right. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55093 --- dlls/vbscript/parser.y | 30 +++++++++++++++--------------- dlls/vbscript/tests/lang.vbs | 12 ++++++++++++ 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/dlls/vbscript/parser.y b/dlls/vbscript/parser.y index 42df9afaf8f..b499df747e2 100644 --- a/dlls/vbscript/parser.y +++ b/dlls/vbscript/parser.y @@ -136,11 +136,14 @@ static statement_t *link_statements(statement_t*,statement_t*); %token <dbl> tDouble %token <date> tDate +%right tNOT +%left '=' tNEQ '>' '<' tGTEQ tLTEQ tIS + %type <statement> Statement SimpleStatement StatementNl StatementsNl StatementsNl_opt BodyStatements IfStatement Else_opt %type <statement> GlobalDimDeclaration StatementsBody StatementsBody_opt %type <expression> Expression LiteralExpression PrimaryExpression EqualityExpression CallExpression ExpressionNl_opt %type <expression> ConcatExpression AdditiveExpression ModExpression IntdivExpression MultiplicativeExpression ExpExpression -%type <expression> NotExpression UnaryExpression AndExpression OrExpression XorExpression EqvExpression SignExpression +%type <expression> UnaryExpression AndExpression OrExpression XorExpression EqvExpression SignExpression %type <expression> ConstExpression NumericLiteralExpression %type <member> MemberExpression %type <expression> Arguments ArgumentList ArgumentList_opt Step_opt ExpressionList @@ -391,22 +394,19 @@ OrExpression | OrExpression tOR AndExpression { $$ = new_binary_expression(ctx, EXPR_OR, $1, $3); CHECK_ERROR; } AndExpression - : NotExpression { $$ = $1; } - | AndExpression tAND NotExpression { $$ = new_binary_expression(ctx, EXPR_AND, $1, $3); CHECK_ERROR; } - -NotExpression - : EqualityExpression { $$ = $1; } - | tNOT NotExpression { $$ = new_unary_expression(ctx, EXPR_NOT, $2); CHECK_ERROR; } + : EqualityExpression { $$ = $1; } + | AndExpression tAND EqualityExpression { $$ = new_binary_expression(ctx, EXPR_AND, $1, $3); CHECK_ERROR; } EqualityExpression - : ConcatExpression { $$ = $1; } - | EqualityExpression '=' ConcatExpression { $$ = new_binary_expression(ctx, EXPR_EQUAL, $1, $3); CHECK_ERROR; } - | EqualityExpression tNEQ ConcatExpression { $$ = new_binary_expression(ctx, EXPR_NEQUAL, $1, $3); CHECK_ERROR; } - | EqualityExpression '>' ConcatExpression { $$ = new_binary_expression(ctx, EXPR_GT, $1, $3); CHECK_ERROR; } - | EqualityExpression '<' ConcatExpression { $$ = new_binary_expression(ctx, EXPR_LT, $1, $3); CHECK_ERROR; } - | EqualityExpression tGTEQ ConcatExpression { $$ = new_binary_expression(ctx, EXPR_GTEQ, $1, $3); CHECK_ERROR; } - | EqualityExpression tLTEQ ConcatExpression { $$ = new_binary_expression(ctx, EXPR_LTEQ, $1, $3); CHECK_ERROR; } - | EqualityExpression tIS ConcatExpression { $$ = new_binary_expression(ctx, EXPR_IS, $1, $3); CHECK_ERROR; } + : ConcatExpression { $$ = $1; } + | tNOT EqualityExpression { $$ = new_unary_expression(ctx, EXPR_NOT, $2); CHECK_ERROR; } + | EqualityExpression '=' EqualityExpression { $$ = new_binary_expression(ctx, EXPR_EQUAL, $1, $3); CHECK_ERROR; } + | EqualityExpression tNEQ EqualityExpression { $$ = new_binary_expression(ctx, EXPR_NEQUAL, $1, $3); CHECK_ERROR; } + | EqualityExpression '>' EqualityExpression { $$ = new_binary_expression(ctx, EXPR_GT, $1, $3); CHECK_ERROR; } + | EqualityExpression '<' EqualityExpression { $$ = new_binary_expression(ctx, EXPR_LT, $1, $3); CHECK_ERROR; } + | EqualityExpression tGTEQ EqualityExpression { $$ = new_binary_expression(ctx, EXPR_GTEQ, $1, $3); CHECK_ERROR; } + | EqualityExpression tLTEQ EqualityExpression { $$ = new_binary_expression(ctx, EXPR_LTEQ, $1, $3); CHECK_ERROR; } + | EqualityExpression tIS EqualityExpression { $$ = new_binary_expression(ctx, EXPR_IS, $1, $3); CHECK_ERROR; } ConcatExpression : AdditiveExpression { $$ = $1; } diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index 4374d7b1f25..84dafe61f7a 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -92,6 +92,18 @@ Call ok(not(false = true = ""), "false = true = """" is true") Call ok(not (false = false <> false = false), "false = false <> false = false is true") Call ok(not ("" <> false = false), """"" <> false = false is true") +Call ok(true <> Not true, "true <> Not true should be true") +Call ok(false <> Not false, "false <> Not false should be true") +Call ok(true = Not false, "true = Not false should be true") +Call ok(Not false = true, "Not false = true should be true") +Call ok(Not true <> true, "Not true <> true should be true") +Call ok(Not true = false, "Not true = false should be true") +Call ok(Not 1 > 2, "Not 1 > 2 should be true") +Call ok(1 <> Not 0 = 0, "1 <> Not 0 = 0 should be true") +Call ok(0 = Not 1 = 1, "0 = Not 1 = 1 should be true") +Call ok(1 > Not 5 > 3, "1 > Not 5 > 3 should be true") +Call ok(Not false And false = false, "Not false And false should be false") + Call ok(getVT(false) = "VT_BOOL", "getVT(false) is not VT_BOOL") Call ok(getVT(true) = "VT_BOOL", "getVT(true) is not VT_BOOL") Call ok(getVT("") = "VT_BSTR", "getVT("""") is not VT_BSTR") -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10317