| 
									
										
										
										
											2014-02-10 13:54:46 -05:00
										 |  |  | // Copyright 2013 Dolphin Emulator Project
 | 
					
						
							| 
									
										
										
										
											2015-05-18 01:08:10 +02:00
										 |  |  | // Licensed under GPLv2+
 | 
					
						
							| 
									
										
										
										
											2014-02-10 13:54:46 -05:00
										 |  |  | // Refer to the license.txt file included.
 | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include <algorithm>
 | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | #include <cassert>
 | 
					
						
							|  |  |  | #include <iostream>
 | 
					
						
							|  |  |  | #include <map>
 | 
					
						
							| 
									
										
										
										
											2016-06-26 05:34:09 +02:00
										 |  |  | #include <memory>
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include <string>
 | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | #include <vector>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-11 17:48:38 -07:00
										 |  |  | #include "InputCommon/ControlReference/ExpressionParser.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | using namespace ciface::Core; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace ciface | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | namespace ExpressionParser | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | enum TokenType | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   TOK_DISCARD, | 
					
						
							|  |  |  |   TOK_INVALID, | 
					
						
							|  |  |  |   TOK_EOF, | 
					
						
							|  |  |  |   TOK_LPAREN, | 
					
						
							|  |  |  |   TOK_RPAREN, | 
					
						
							|  |  |  |   TOK_AND, | 
					
						
							|  |  |  |   TOK_OR, | 
					
						
							|  |  |  |   TOK_NOT, | 
					
						
							|  |  |  |   TOK_ADD, | 
					
						
							|  |  |  |   TOK_CONTROL, | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | inline std::string OpName(TokenType op) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   switch (op) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case TOK_AND: | 
					
						
							|  |  |  |     return "And"; | 
					
						
							|  |  |  |   case TOK_OR: | 
					
						
							|  |  |  |     return "Or"; | 
					
						
							|  |  |  |   case TOK_NOT: | 
					
						
							|  |  |  |     return "Not"; | 
					
						
							|  |  |  |   case TOK_ADD: | 
					
						
							|  |  |  |     return "Add"; | 
					
						
							|  |  |  |   default: | 
					
						
							|  |  |  |     assert(false); | 
					
						
							|  |  |  |     return ""; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Token | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   TokenType type; | 
					
						
							|  |  |  |   ControlQualifier qualifier; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Token(TokenType type_) : type(type_) {} | 
					
						
							|  |  |  |   Token(TokenType type_, ControlQualifier qualifier_) : type(type_), qualifier(qualifier_) {} | 
					
						
							|  |  |  |   operator std::string() | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     switch (type) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case TOK_DISCARD: | 
					
						
							|  |  |  |       return "Discard"; | 
					
						
							|  |  |  |     case TOK_EOF: | 
					
						
							|  |  |  |       return "EOF"; | 
					
						
							|  |  |  |     case TOK_LPAREN: | 
					
						
							|  |  |  |       return "("; | 
					
						
							|  |  |  |     case TOK_RPAREN: | 
					
						
							|  |  |  |       return ")"; | 
					
						
							|  |  |  |     case TOK_AND: | 
					
						
							|  |  |  |       return "&"; | 
					
						
							|  |  |  |     case TOK_OR: | 
					
						
							|  |  |  |       return "|"; | 
					
						
							|  |  |  |     case TOK_NOT: | 
					
						
							|  |  |  |       return "!"; | 
					
						
							|  |  |  |     case TOK_ADD: | 
					
						
							|  |  |  |       return "+"; | 
					
						
							|  |  |  |     case TOK_CONTROL: | 
					
						
							|  |  |  |       return "Device(" + (std::string)qualifier + ")"; | 
					
						
							|  |  |  |     case TOK_INVALID: | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return "Invalid"; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | class Lexer | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | public: | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   std::string expr; | 
					
						
							|  |  |  |   std::string::iterator it; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Lexer(const std::string& expr_) : expr(expr_) { it = expr.begin(); } | 
					
						
							|  |  |  |   bool FetchBacktickString(std::string& value, char otherDelim = 0) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     value = ""; | 
					
						
							|  |  |  |     while (it != expr.end()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       char c = *it; | 
					
						
							|  |  |  |       ++it; | 
					
						
							|  |  |  |       if (c == '`') | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |       if (c > 0 && c == otherDelim) | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |       value += c; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Token GetFullyQualifiedControl() | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     ControlQualifier qualifier; | 
					
						
							|  |  |  |     std::string value; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (FetchBacktickString(value, ':')) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       // Found colon, this is the device name
 | 
					
						
							|  |  |  |       qualifier.has_device = true; | 
					
						
							|  |  |  |       qualifier.device_qualifier.FromString(value); | 
					
						
							|  |  |  |       FetchBacktickString(value); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     qualifier.control_name = value; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return Token(TOK_CONTROL, qualifier); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Token GetBarewordsControl(char c) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     std::string name; | 
					
						
							|  |  |  |     name += c; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while (it != expr.end()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       c = *it; | 
					
						
							|  |  |  |       if (!isalpha(c)) | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       name += c; | 
					
						
							|  |  |  |       ++it; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ControlQualifier qualifier; | 
					
						
							|  |  |  |     qualifier.control_name = name; | 
					
						
							|  |  |  |     return Token(TOK_CONTROL, qualifier); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Token NextToken() | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     if (it == expr.end()) | 
					
						
							|  |  |  |       return Token(TOK_EOF); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     char c = *it++; | 
					
						
							|  |  |  |     switch (c) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case ' ': | 
					
						
							|  |  |  |     case '\t': | 
					
						
							|  |  |  |     case '\n': | 
					
						
							|  |  |  |     case '\r': | 
					
						
							|  |  |  |       return Token(TOK_DISCARD); | 
					
						
							|  |  |  |     case '(': | 
					
						
							|  |  |  |       return Token(TOK_LPAREN); | 
					
						
							|  |  |  |     case ')': | 
					
						
							|  |  |  |       return Token(TOK_RPAREN); | 
					
						
							|  |  |  |     case '&': | 
					
						
							|  |  |  |       return Token(TOK_AND); | 
					
						
							|  |  |  |     case '|': | 
					
						
							|  |  |  |       return Token(TOK_OR); | 
					
						
							|  |  |  |     case '!': | 
					
						
							|  |  |  |       return Token(TOK_NOT); | 
					
						
							|  |  |  |     case '+': | 
					
						
							|  |  |  |       return Token(TOK_ADD); | 
					
						
							|  |  |  |     case '`': | 
					
						
							|  |  |  |       return GetFullyQualifiedControl(); | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       if (isalpha(c)) | 
					
						
							|  |  |  |         return GetBarewordsControl(c); | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         return Token(TOK_INVALID); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ExpressionParseStatus Tokenize(std::vector<Token>& tokens) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     while (true) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       Token tok = NextToken(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (tok.type == TOK_DISCARD) | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (tok.type == TOK_INVALID) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         tokens.clear(); | 
					
						
							|  |  |  |         return EXPRESSION_PARSE_SYNTAX_ERROR; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       tokens.push_back(tok); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (tok.type == TOK_EOF) | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return EXPRESSION_PARSE_SUCCESS; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ExpressionNode | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   virtual ~ExpressionNode() {} | 
					
						
							|  |  |  |   virtual ControlState GetValue() { return 0; } | 
					
						
							|  |  |  |   virtual void SetValue(ControlState state) {} | 
					
						
							|  |  |  |   virtual int CountNumControls() { return 0; } | 
					
						
							|  |  |  |   virtual operator std::string() { return ""; } | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-26 00:41:59 +01:00
										 |  |  | class DummyExpression : public ExpressionNode | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   std::string name; | 
					
						
							| 
									
										
										
										
											2015-02-26 00:41:59 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   DummyExpression(const std::string& name_) : name(name_) {} | 
					
						
							|  |  |  |   ControlState GetValue() override { return 0.0; } | 
					
						
							|  |  |  |   void SetValue(ControlState value) override {} | 
					
						
							|  |  |  |   int CountNumControls() override { return 0; } | 
					
						
							|  |  |  |   operator std::string() override { return "`" + name + "`"; } | 
					
						
							| 
									
										
										
										
											2015-02-26 00:41:59 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | class ControlExpression : public ExpressionNode | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   ControlQualifier qualifier; | 
					
						
							|  |  |  |   Device::Control* control; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-14 17:45:59 +02:00
										 |  |  |   ControlExpression(ControlQualifier qualifier_, std::shared_ptr<Device> device, | 
					
						
							|  |  |  |                     Device::Control* control_) | 
					
						
							|  |  |  |       : qualifier(qualifier_), control(control_), m_device(device) | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   { | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-11 17:48:38 -07:00
										 |  |  |   ControlState GetValue() override { return control->ToInput()->GetState(); } | 
					
						
							|  |  |  |   void SetValue(ControlState value) override { control->ToOutput()->SetState(value); } | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   int CountNumControls() override { return 1; } | 
					
						
							|  |  |  |   operator std::string() override { return "`" + (std::string)qualifier + "`"; } | 
					
						
							| 
									
										
										
										
											2016-07-14 17:45:59 +02:00
										 |  |  | private: | 
					
						
							|  |  |  |   std::shared_ptr<Device> m_device; | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class BinaryExpression : public ExpressionNode | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   TokenType op; | 
					
						
							|  |  |  |   ExpressionNode* lhs; | 
					
						
							|  |  |  |   ExpressionNode* rhs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   BinaryExpression(TokenType op_, ExpressionNode* lhs_, ExpressionNode* rhs_) | 
					
						
							|  |  |  |       : op(op_), lhs(lhs_), rhs(rhs_) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   virtual ~BinaryExpression() | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     delete lhs; | 
					
						
							|  |  |  |     delete rhs; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ControlState GetValue() override | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     ControlState lhsValue = lhs->GetValue(); | 
					
						
							|  |  |  |     ControlState rhsValue = rhs->GetValue(); | 
					
						
							|  |  |  |     switch (op) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case TOK_AND: | 
					
						
							|  |  |  |       return std::min(lhsValue, rhsValue); | 
					
						
							|  |  |  |     case TOK_OR: | 
					
						
							|  |  |  |       return std::max(lhsValue, rhsValue); | 
					
						
							|  |  |  |     case TOK_ADD: | 
					
						
							|  |  |  |       return std::min(lhsValue + rhsValue, 1.0); | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       assert(false); | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void SetValue(ControlState value) override | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // Don't do anything special with the op we have.
 | 
					
						
							|  |  |  |     // Treat "A & B" the same as "A | B".
 | 
					
						
							|  |  |  |     lhs->SetValue(value); | 
					
						
							|  |  |  |     rhs->SetValue(value); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int CountNumControls() override { return lhs->CountNumControls() + rhs->CountNumControls(); } | 
					
						
							|  |  |  |   operator std::string() override | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     return OpName(op) + "(" + (std::string)(*lhs) + ", " + (std::string)(*rhs) + ")"; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class UnaryExpression : public ExpressionNode | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   TokenType op; | 
					
						
							|  |  |  |   ExpressionNode* inner; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   UnaryExpression(TokenType op_, ExpressionNode* inner_) : op(op_), inner(inner_) {} | 
					
						
							|  |  |  |   virtual ~UnaryExpression() { delete inner; } | 
					
						
							|  |  |  |   ControlState GetValue() override | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     ControlState value = inner->GetValue(); | 
					
						
							|  |  |  |     switch (op) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case TOK_NOT: | 
					
						
							|  |  |  |       return 1.0 - value; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       assert(false); | 
					
						
							|  |  |  |       return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void SetValue(ControlState value) override | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     switch (op) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case TOK_NOT: | 
					
						
							|  |  |  |       inner->SetValue(1.0 - value); | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       assert(false); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int CountNumControls() override { return inner->CountNumControls(); } | 
					
						
							|  |  |  |   operator std::string() override { return OpName(op) + "(" + (std::string)(*inner) + ")"; } | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-25 21:46:39 +02:00
										 |  |  | std::shared_ptr<Device> ControlFinder::FindDevice(ControlQualifier qualifier) | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (qualifier.has_device) | 
					
						
							|  |  |  |     return container.FindDevice(qualifier.device_qualifier); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     return container.FindDevice(default_device); | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | Device::Control* ControlFinder::FindControl(ControlQualifier qualifier) | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-25 21:46:39 +02:00
										 |  |  |   const std::shared_ptr<Device> device = FindDevice(qualifier); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (!device) | 
					
						
							|  |  |  |     return nullptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (is_input) | 
					
						
							|  |  |  |     return device->FindInput(qualifier.control_name); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     return device->FindOutput(qualifier.control_name); | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Parser | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Parser(std::vector<Token> tokens_, ControlFinder& finder_) : tokens(tokens_), finder(finder_) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     m_it = tokens.begin(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ExpressionParseStatus Parse(Expression** expr_out) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     ExpressionNode* node; | 
					
						
							|  |  |  |     ExpressionParseStatus status = Toplevel(&node); | 
					
						
							|  |  |  |     if (status != EXPRESSION_PARSE_SUCCESS) | 
					
						
							|  |  |  |       return status; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     *expr_out = new Expression(node); | 
					
						
							|  |  |  |     return EXPRESSION_PARSE_SUCCESS; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   std::vector<Token> tokens; | 
					
						
							|  |  |  |   std::vector<Token>::iterator m_it; | 
					
						
							|  |  |  |   ControlFinder& finder; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Token Chew() { return *m_it++; } | 
					
						
							|  |  |  |   Token Peek() { return *m_it; } | 
					
						
							|  |  |  |   bool Expects(TokenType type) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     Token tok = Chew(); | 
					
						
							|  |  |  |     return tok.type == type; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ExpressionParseStatus Atom(ExpressionNode** expr_out) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     Token tok = Chew(); | 
					
						
							|  |  |  |     switch (tok.type) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case TOK_CONTROL: | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-07-14 17:45:59 +02:00
										 |  |  |       std::shared_ptr<Device> device = finder.FindDevice(tok.qualifier); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |       Device::Control* control = finder.FindControl(tok.qualifier); | 
					
						
							|  |  |  |       if (control == nullptr) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         *expr_out = new DummyExpression(tok.qualifier); | 
					
						
							| 
									
										
										
										
											2016-07-13 16:51:19 +02:00
										 |  |  |         return EXPRESSION_PARSE_NO_DEVICE; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-14 17:45:59 +02:00
										 |  |  |       *expr_out = new ControlExpression(tok.qualifier, device, control); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |       return EXPRESSION_PARSE_SUCCESS; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     case TOK_LPAREN: | 
					
						
							|  |  |  |       return Paren(expr_out); | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       return EXPRESSION_PARSE_SYNTAX_ERROR; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool IsUnaryExpression(TokenType type) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     switch (type) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case TOK_NOT: | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ExpressionParseStatus Unary(ExpressionNode** expr_out) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     if (IsUnaryExpression(Peek().type)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       Token tok = Chew(); | 
					
						
							|  |  |  |       ExpressionNode* atom_expr; | 
					
						
							| 
									
										
										
										
											2016-07-13 16:51:19 +02:00
										 |  |  |       ExpressionParseStatus status = Atom(&atom_expr); | 
					
						
							|  |  |  |       if (status == EXPRESSION_PARSE_SYNTAX_ERROR) | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |         return status; | 
					
						
							|  |  |  |       *expr_out = new UnaryExpression(tok.type, atom_expr); | 
					
						
							|  |  |  |       return EXPRESSION_PARSE_SUCCESS; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return Atom(expr_out); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   bool IsBinaryToken(TokenType type) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     switch (type) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case TOK_AND: | 
					
						
							|  |  |  |     case TOK_OR: | 
					
						
							|  |  |  |     case TOK_ADD: | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ExpressionParseStatus Binary(ExpressionNode** expr_out) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-07-13 16:51:19 +02:00
										 |  |  |     ExpressionParseStatus status = Unary(expr_out); | 
					
						
							|  |  |  |     if (status == EXPRESSION_PARSE_SYNTAX_ERROR) | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |       return status; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while (IsBinaryToken(Peek().type)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       Token tok = Chew(); | 
					
						
							|  |  |  |       ExpressionNode* unary_expr; | 
					
						
							| 
									
										
										
										
											2016-07-13 16:51:19 +02:00
										 |  |  |       status = Unary(&unary_expr); | 
					
						
							|  |  |  |       if (status == EXPRESSION_PARSE_SYNTAX_ERROR) | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |       { | 
					
						
							|  |  |  |         delete *expr_out; | 
					
						
							|  |  |  |         return status; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       *expr_out = new BinaryExpression(tok.type, *expr_out, unary_expr); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return EXPRESSION_PARSE_SUCCESS; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ExpressionParseStatus Paren(ExpressionNode** expr_out) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     ExpressionParseStatus status; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // lparen already chewed
 | 
					
						
							|  |  |  |     if ((status = Toplevel(expr_out)) != EXPRESSION_PARSE_SUCCESS) | 
					
						
							|  |  |  |       return status; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!Expects(TOK_RPAREN)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       delete *expr_out; | 
					
						
							|  |  |  |       return EXPRESSION_PARSE_SYNTAX_ERROR; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return EXPRESSION_PARSE_SUCCESS; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ExpressionParseStatus Toplevel(ExpressionNode** expr_out) { return Binary(expr_out); } | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ControlState Expression::GetValue() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return node->GetValue(); | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Expression::SetValue(ControlState value) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   node->SetValue(value); | 
					
						
							| 
									
										
										
										
											2013-06-26 20:19:23 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | Expression::Expression(ExpressionNode* node_) | 
					
						
							| 
									
										
										
										
											2013-06-26 20:19:23 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   node = node_; | 
					
						
							|  |  |  |   num_controls = node->CountNumControls(); | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Expression::~Expression() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   delete node; | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | static ExpressionParseStatus ParseExpressionInner(const std::string& str, ControlFinder& finder, | 
					
						
							|  |  |  |                                                   Expression** expr_out) | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   ExpressionParseStatus status; | 
					
						
							|  |  |  |   Expression* expr; | 
					
						
							|  |  |  |   *expr_out = nullptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (str == "") | 
					
						
							|  |  |  |     return EXPRESSION_PARSE_SUCCESS; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Lexer l(str); | 
					
						
							|  |  |  |   std::vector<Token> tokens; | 
					
						
							|  |  |  |   status = l.Tokenize(tokens); | 
					
						
							|  |  |  |   if (status != EXPRESSION_PARSE_SUCCESS) | 
					
						
							|  |  |  |     return status; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Parser p(tokens, finder); | 
					
						
							|  |  |  |   status = p.Parse(&expr); | 
					
						
							|  |  |  |   if (status != EXPRESSION_PARSE_SUCCESS) | 
					
						
							|  |  |  |     return status; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   *expr_out = expr; | 
					
						
							|  |  |  |   return EXPRESSION_PARSE_SUCCESS; | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | ExpressionParseStatus ParseExpression(const std::string& str, ControlFinder& finder, | 
					
						
							|  |  |  |                                       Expression** expr_out) | 
					
						
							| 
									
										
										
										
											2013-06-26 20:19:23 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // Add compatibility with old simple expressions, which are simple
 | 
					
						
							|  |  |  |   // barewords control names.
 | 
					
						
							| 
									
										
										
										
											2013-06-26 20:19:23 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   ControlQualifier qualifier; | 
					
						
							|  |  |  |   qualifier.control_name = str; | 
					
						
							|  |  |  |   qualifier.has_device = false; | 
					
						
							| 
									
										
										
										
											2013-06-26 20:19:23 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-14 17:45:59 +02:00
										 |  |  |   std::shared_ptr<Device> device = finder.FindDevice(qualifier); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Device::Control* control = finder.FindControl(qualifier); | 
					
						
							|  |  |  |   if (control) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2016-07-14 17:45:59 +02:00
										 |  |  |     *expr_out = new Expression(new ControlExpression(qualifier, device, control)); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     return EXPRESSION_PARSE_SUCCESS; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-06-26 20:19:23 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return ParseExpressionInner(str, finder, expr_out); | 
					
						
							| 
									
										
										
										
											2013-06-26 20:19:23 -04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-06-13 23:09:55 -04:00
										 |  |  | } | 
					
						
							|  |  |  | } |