mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-22 05:40:01 -06:00
InputCommon/ExpressionParser: Add compound assignment operators.
This commit is contained in:
@ -25,6 +25,45 @@ using namespace ciface::Core;
|
|||||||
|
|
||||||
class ControlExpression;
|
class ControlExpression;
|
||||||
|
|
||||||
|
// Check if operator is usable with assignment, e.g. += -= *=
|
||||||
|
bool IsCompoundAssignmentUsableBinaryOperator(TokenType type)
|
||||||
|
{
|
||||||
|
return type >= TOK_COMPOUND_ASSIGN_OPS_BEGIN && type < TOK_COMPOUND_ASSIGN_OPS_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
TokenType GetBinaryOperatorTokenTypeFromChar(char c)
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '+':
|
||||||
|
return TOK_ADD;
|
||||||
|
case '-':
|
||||||
|
return TOK_SUB;
|
||||||
|
case '*':
|
||||||
|
return TOK_MUL;
|
||||||
|
case '/':
|
||||||
|
return TOK_DIV;
|
||||||
|
case '%':
|
||||||
|
return TOK_MOD;
|
||||||
|
case '=':
|
||||||
|
return TOK_ASSIGN;
|
||||||
|
case '<':
|
||||||
|
return TOK_LTHAN;
|
||||||
|
case '>':
|
||||||
|
return TOK_GTHAN;
|
||||||
|
case ',':
|
||||||
|
return TOK_COMMA;
|
||||||
|
case '^':
|
||||||
|
return TOK_XOR;
|
||||||
|
case '&':
|
||||||
|
return TOK_AND;
|
||||||
|
case '|':
|
||||||
|
return TOK_OR;
|
||||||
|
default:
|
||||||
|
return TOK_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class HotkeySuppressions
|
class HotkeySuppressions
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -156,7 +195,32 @@ Token Lexer::NextToken()
|
|||||||
if (it == expr.end())
|
if (it == expr.end())
|
||||||
return Token(TOK_EOF);
|
return Token(TOK_EOF);
|
||||||
|
|
||||||
char c = *it++;
|
const char c = *it++;
|
||||||
|
|
||||||
|
// Handle /* */ style comments.
|
||||||
|
if (c == '/' && it != expr.end() && *it == '*')
|
||||||
|
{
|
||||||
|
++it;
|
||||||
|
const auto end_of_comment = expr.find("*/", it - expr.begin());
|
||||||
|
if (end_of_comment == std::string::npos)
|
||||||
|
return Token(TOK_INVALID);
|
||||||
|
it = expr.begin() + end_of_comment + 2;
|
||||||
|
return Token(TOK_COMMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto tok_type = GetBinaryOperatorTokenTypeFromChar(c);
|
||||||
|
if (tok_type != TOK_INVALID)
|
||||||
|
{
|
||||||
|
// Check for compound assignment op, e.g. + immediately followed by =.
|
||||||
|
if (IsCompoundAssignmentUsableBinaryOperator(tok_type) && it != expr.end() && *it == '=')
|
||||||
|
{
|
||||||
|
++it;
|
||||||
|
return Token(TOK_ASSIGN, std::string{c});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Token(tok_type);
|
||||||
|
}
|
||||||
|
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
case ' ':
|
case ' ':
|
||||||
@ -174,44 +238,8 @@ Token Lexer::NextToken()
|
|||||||
return Token(TOK_QUESTION);
|
return Token(TOK_QUESTION);
|
||||||
case ':':
|
case ':':
|
||||||
return Token(TOK_COLON);
|
return Token(TOK_COLON);
|
||||||
case '&':
|
|
||||||
return Token(TOK_AND);
|
|
||||||
case '|':
|
|
||||||
return Token(TOK_OR);
|
|
||||||
case '!':
|
case '!':
|
||||||
return Token(TOK_NOT);
|
return Token(TOK_NOT);
|
||||||
case '+':
|
|
||||||
return Token(TOK_ADD);
|
|
||||||
case '-':
|
|
||||||
return Token(TOK_SUB);
|
|
||||||
case '*':
|
|
||||||
return Token(TOK_MUL);
|
|
||||||
case '/':
|
|
||||||
{
|
|
||||||
// Handle /* */ style comments.
|
|
||||||
if (it != expr.end() && *it == '*')
|
|
||||||
{
|
|
||||||
++it;
|
|
||||||
const auto end_of_comment = expr.find("*/", it - expr.begin());
|
|
||||||
if (end_of_comment == std::string::npos)
|
|
||||||
return Token(TOK_INVALID);
|
|
||||||
it = expr.begin() + end_of_comment + 2;
|
|
||||||
return Token(TOK_COMMENT);
|
|
||||||
}
|
|
||||||
return Token(TOK_DIV);
|
|
||||||
}
|
|
||||||
case '%':
|
|
||||||
return Token(TOK_MOD);
|
|
||||||
case '=':
|
|
||||||
return Token(TOK_ASSIGN);
|
|
||||||
case '<':
|
|
||||||
return Token(TOK_LTHAN);
|
|
||||||
case '>':
|
|
||||||
return Token(TOK_GTHAN);
|
|
||||||
case ',':
|
|
||||||
return Token(TOK_COMMA);
|
|
||||||
case '^':
|
|
||||||
return Token(TOK_XOR);
|
|
||||||
case '\'':
|
case '\'':
|
||||||
return GetDelimitedLiteral();
|
return GetDelimitedLiteral();
|
||||||
case '$':
|
case '$':
|
||||||
@ -363,6 +391,11 @@ public:
|
|||||||
const ControlState lhs_value = lhs->GetValue();
|
const ControlState lhs_value = lhs->GetValue();
|
||||||
const ControlState rhs_value = rhs->GetValue();
|
const ControlState rhs_value = rhs->GetValue();
|
||||||
|
|
||||||
|
return CalculateValue(op, lhs_value, rhs_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ControlState CalculateValue(TokenType op, ControlState lhs_value, ControlState rhs_value)
|
||||||
|
{
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case TOK_AND:
|
case TOK_AND:
|
||||||
@ -436,6 +469,23 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CompoundAssignmentExpression : public BinaryExpression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using BinaryExpression::BinaryExpression;
|
||||||
|
|
||||||
|
ControlState GetValue() override { return GetLValue()->GetValue(); }
|
||||||
|
|
||||||
|
Expression* GetLValue() override
|
||||||
|
{
|
||||||
|
Expression* const lvalue = lhs->GetLValue();
|
||||||
|
const ControlState lhs_value = lvalue->GetValue();
|
||||||
|
const ControlState rhs_value = rhs->GetValue();
|
||||||
|
lvalue->SetValue(CalculateValue(op, lhs_value, rhs_value));
|
||||||
|
return lvalue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class LiteralExpression : public Expression
|
class LiteralExpression : public Expression
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -934,7 +984,17 @@ private:
|
|||||||
if (rhs.status == ParseStatus::SyntaxError)
|
if (rhs.status == ParseStatus::SyntaxError)
|
||||||
return rhs;
|
return rhs;
|
||||||
|
|
||||||
expr = std::make_unique<BinaryExpression>(op.type, std::move(expr), std::move(rhs.expr));
|
// Compound assignment token has operator in the data string.
|
||||||
|
if (op.type == TOK_ASSIGN && !op.data.empty())
|
||||||
|
{
|
||||||
|
const TokenType op_type = GetBinaryOperatorTokenTypeFromChar(op.data[0]);
|
||||||
|
expr = std::make_unique<CompoundAssignmentExpression>(op_type, std::move(expr),
|
||||||
|
std::move(rhs.expr));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
expr = std::make_unique<BinaryExpression>(op.type, std::move(expr), std::move(rhs.expr));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (op.type == TOK_QUESTION && OperatorPrecedence(TOK_QUESTION) <= precedence)
|
else if (op.type == TOK_QUESTION && OperatorPrecedence(TOK_QUESTION) <= precedence)
|
||||||
{
|
{
|
||||||
|
@ -30,18 +30,20 @@ enum TokenType
|
|||||||
TOK_COLON,
|
TOK_COLON,
|
||||||
// Binary Ops:
|
// Binary Ops:
|
||||||
TOK_BINARY_OPS_BEGIN,
|
TOK_BINARY_OPS_BEGIN,
|
||||||
|
TOK_COMPOUND_ASSIGN_OPS_BEGIN = TOK_BINARY_OPS_BEGIN,
|
||||||
TOK_AND = TOK_BINARY_OPS_BEGIN,
|
TOK_AND = TOK_BINARY_OPS_BEGIN,
|
||||||
TOK_OR,
|
TOK_OR,
|
||||||
|
TOK_XOR,
|
||||||
TOK_ADD,
|
TOK_ADD,
|
||||||
TOK_SUB,
|
TOK_SUB,
|
||||||
TOK_MUL,
|
TOK_MUL,
|
||||||
TOK_DIV,
|
TOK_DIV,
|
||||||
TOK_MOD,
|
TOK_MOD,
|
||||||
TOK_ASSIGN,
|
TOK_COMPOUND_ASSIGN_OPS_END,
|
||||||
|
TOK_ASSIGN = TOK_COMPOUND_ASSIGN_OPS_END,
|
||||||
TOK_LTHAN,
|
TOK_LTHAN,
|
||||||
TOK_GTHAN,
|
TOK_GTHAN,
|
||||||
TOK_COMMA,
|
TOK_COMMA,
|
||||||
TOK_XOR,
|
|
||||||
TOK_BINARY_OPS_END,
|
TOK_BINARY_OPS_END,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user