diff options
Diffstat (limited to 'Source/Core/InputCommon/ControlReference/ExpressionParser.h')
| -rw-r--r-- | Source/Core/InputCommon/ControlReference/ExpressionParser.h | 154 |
1 files changed, 140 insertions, 14 deletions
diff --git a/Source/Core/InputCommon/ControlReference/ExpressionParser.h b/Source/Core/InputCommon/ControlReference/ExpressionParser.h index 56c0340f49..cab6096c0e 100644 --- a/Source/Core/InputCommon/ControlReference/ExpressionParser.h +++ b/Source/Core/InputCommon/ControlReference/ExpressionParser.h @@ -4,13 +4,102 @@ #pragma once +#include <map> #include <memory> +#include <optional> #include <string> -#include <utility> + #include "InputCommon/ControllerInterface/Device.h" namespace ciface::ExpressionParser { +enum TokenType +{ + TOK_WHITESPACE, + TOK_INVALID, + TOK_EOF, + TOK_LPAREN, + TOK_RPAREN, + TOK_NOT, + TOK_CONTROL, + TOK_LITERAL, + TOK_VARIABLE, + TOK_BAREWORD, + TOK_COMMENT, + // Binary Ops: + TOK_BINARY_OPS_BEGIN, + TOK_AND = TOK_BINARY_OPS_BEGIN, + TOK_OR, + TOK_ADD, + TOK_SUB, + TOK_MUL, + TOK_DIV, + TOK_MOD, + TOK_ASSIGN, + TOK_LTHAN, + TOK_GTHAN, + TOK_COMMA, + TOK_BINARY_OPS_END, +}; + +class Token +{ +public: + TokenType type; + std::string data; + + // Position in the input string: + std::size_t string_position = 0; + std::size_t string_length = 0; + + explicit Token(TokenType type_); + Token(TokenType type_, std::string data_); + + bool IsBinaryOperator() const; +}; + +enum class ParseStatus +{ + Successful, + SyntaxError, + EmptyExpression, +}; + +class Lexer +{ +public: + std::string expr; + std::string::iterator it; + + explicit Lexer(std::string expr_); + + ParseStatus Tokenize(std::vector<Token>& tokens); + +private: + template <typename F> + std::string FetchCharsWhile(F&& func) + { + std::string value; + while (it != expr.end() && func(*it)) + { + value += *it; + ++it; + } + return value; + } + + std::string FetchDelimString(char delim); + std::string FetchWordChars(); + Token GetDelimitedLiteral(); + Token GetVariable(); + Token GetFullyQualifiedControl(); + Token GetBareword(char c); + Token GetRealLiteral(char c); + + Token PeekToken(); + Token NextToken(); +}; + class ControlQualifier { public: @@ -19,6 +108,7 @@ public: std::string control_name; ControlQualifier() : has_device(false) {} + operator std::string() const { if (has_device) @@ -26,23 +116,45 @@ public: else return control_name; } + + void FromString(const std::string& str) + { + const auto col_pos = str.find_last_of(':'); + + has_device = (str.npos != col_pos); + if (has_device) + { + device_qualifier.FromString(str.substr(0, col_pos)); + control_name = str.substr(col_pos + 1); + } + else + { + device_qualifier.FromString(""); + control_name = str; + } + } }; -class ControlFinder +class ControlEnvironment { public: - ControlFinder(const Core::DeviceContainer& container_, const Core::DeviceQualifier& default_, - const bool is_input_) - : container(container_), default_device(default_), is_input(is_input_) + using VariableContainer = std::map<std::string, ControlState>; + + ControlEnvironment(const Core::DeviceContainer& container_, const Core::DeviceQualifier& default_, + VariableContainer& vars) + : m_variables(vars), container(container_), default_device(default_) { } + std::shared_ptr<Core::Device> FindDevice(ControlQualifier qualifier) const; - Core::Device::Control* FindControl(ControlQualifier qualifier) const; + Core::Device::Input* FindInput(ControlQualifier qualifier) const; + Core::Device::Output* FindOutput(ControlQualifier qualifier) const; + ControlState* GetVariablePtr(const std::string& name); private: + VariableContainer& m_variables; const Core::DeviceContainer& container; const Core::DeviceQualifier& default_device; - bool is_input; }; class Expression @@ -52,16 +164,30 @@ public: virtual ControlState GetValue() const = 0; virtual void SetValue(ControlState state) = 0; virtual int CountNumControls() const = 0; - virtual void UpdateReferences(ControlFinder& finder) = 0; - virtual operator std::string() const = 0; + virtual void UpdateReferences(ControlEnvironment& finder) = 0; }; -enum class ParseStatus +class ParseResult { - Successful, - SyntaxError, - EmptyExpression, +public: + static ParseResult MakeEmptyResult(); + static ParseResult MakeSuccessfulResult(std::unique_ptr<Expression>&& expr); + static ParseResult MakeErrorResult(Token token, std::string description); + + ParseStatus status; + std::unique_ptr<Expression> expr; + + // Used for parse errors: + // TODO: This should probably be moved elsewhere: + std::optional<Token> token; + std::optional<std::string> description; + +private: + ParseResult() = default; }; -std::pair<ParseStatus, std::unique_ptr<Expression>> ParseExpression(const std::string& expr); +ParseResult ParseExpression(const std::string& expr); +ParseResult ParseTokens(const std::vector<Token>& tokens); +void RemoveInertTokens(std::vector<Token>* tokens); + } // namespace ciface::ExpressionParser |
