| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- //--------------------------------------------------------------------------------------------------------------------------------
- // Cartoon FX
- // (c) 2012-2020 Jean Moreno
- //--------------------------------------------------------------------------------------------------------------------------------
- using System.Collections.Generic;
- using System.IO;
- // Parse conditional expressions from CFXR_MaterialInspector to show/hide some parts of the UI easily
- namespace CartoonFX
- {
- public static class ExpressionParser
- {
- public delegate bool EvaluateFunction(string content);
- //--------------------------------------------------------------------------------------------------------------------------------
- // Main Function to use
- static public bool EvaluateExpression(string expression, EvaluateFunction evalFunction)
- {
- //Remove white spaces and double && ||
- string cleanExpr = "";
- for(int i = 0; i < expression.Length; i++)
- {
- switch(expression[i])
- {
- case ' ': break;
- case '&': cleanExpr += expression[i]; i++; break;
- case '|': cleanExpr += expression[i]; i++; break;
- default: cleanExpr += expression[i]; break;
- }
- }
- List<Token> tokens = new List<Token>();
- StringReader reader = new StringReader(cleanExpr);
- Token t = null;
- do
- {
- t = new Token(reader);
- tokens.Add(t);
- } while(t.type != Token.TokenType.EXPR_END);
- List<Token> polishNotation = Token.TransformToPolishNotation(tokens);
- var enumerator = polishNotation.GetEnumerator();
- enumerator.MoveNext();
- Expression root = MakeExpression(ref enumerator, evalFunction);
- return root.Evaluate();
- }
- //--------------------------------------------------------------------------------------------------------------------------------
- // Expression Token
- public class Token
- {
- static Dictionary<char, KeyValuePair<TokenType, string>> typesDict = new Dictionary<char, KeyValuePair<TokenType, string>>()
- {
- {'(', new KeyValuePair<TokenType, string>(TokenType.OPEN_PAREN, "(")},
- {')', new KeyValuePair<TokenType, string>(TokenType.CLOSE_PAREN, ")")},
- {'!', new KeyValuePair<TokenType, string>(TokenType.UNARY_OP, "NOT")},
- {'&', new KeyValuePair<TokenType, string>(TokenType.BINARY_OP, "AND")},
- {'|', new KeyValuePair<TokenType, string>(TokenType.BINARY_OP, "OR")}
- };
- public enum TokenType
- {
- OPEN_PAREN,
- CLOSE_PAREN,
- UNARY_OP,
- BINARY_OP,
- LITERAL,
- EXPR_END
- }
- public TokenType type;
- public string value;
- public Token(StringReader s)
- {
- int c = s.Read();
- if(c == -1)
- {
- type = TokenType.EXPR_END;
- value = "";
- return;
- }
- char ch = (char)c;
- //Special case: solve bug where !COND_FALSE_1 && COND_FALSE_2 would return True
- bool embeddedNot = (ch == '!' && s.Peek() != '(');
- if(typesDict.ContainsKey(ch) && !embeddedNot)
- {
- type = typesDict[ch].Key;
- value = typesDict[ch].Value;
- }
- else
- {
- string str = "";
- str += ch;
- while(s.Peek() != -1 && !typesDict.ContainsKey((char)s.Peek()))
- {
- str += (char)s.Read();
- }
- type = TokenType.LITERAL;
- value = str;
- }
- }
- static public List<Token> TransformToPolishNotation(List<Token> infixTokenList)
- {
- Queue<Token> outputQueue = new Queue<Token>();
- Stack<Token> stack = new Stack<Token>();
- int index = 0;
- while(infixTokenList.Count > index)
- {
- Token t = infixTokenList[index];
- switch(t.type)
- {
- case Token.TokenType.LITERAL:
- outputQueue.Enqueue(t);
- break;
- case Token.TokenType.BINARY_OP:
- case Token.TokenType.UNARY_OP:
- case Token.TokenType.OPEN_PAREN:
- stack.Push(t);
- break;
- case Token.TokenType.CLOSE_PAREN:
- while(stack.Peek().type != Token.TokenType.OPEN_PAREN)
- {
- outputQueue.Enqueue(stack.Pop());
- }
- stack.Pop();
- if(stack.Count > 0 && stack.Peek().type == Token.TokenType.UNARY_OP)
- {
- outputQueue.Enqueue(stack.Pop());
- }
- break;
- default:
- break;
- }
- index++;
- }
- while(stack.Count > 0)
- {
- outputQueue.Enqueue(stack.Pop());
- }
- var list = new List<Token>(outputQueue);
- list.Reverse();
- return list;
- }
- }
- //--------------------------------------------------------------------------------------------------------------------------------
- // Boolean Expression Classes
- public abstract class Expression
- {
- public abstract bool Evaluate();
- }
- public class ExpressionLeaf : Expression
- {
- private string content;
- private EvaluateFunction evalFunction;
- public ExpressionLeaf(EvaluateFunction _evalFunction, string _content)
- {
- this.evalFunction = _evalFunction;
- this.content = _content;
- }
- override public bool Evaluate()
- {
- //embedded not, see special case in Token declaration
- if(content.StartsWith("!"))
- {
- return !this.evalFunction(content.Substring(1));
- }
- return this.evalFunction(content);
- }
- }
- public class ExpressionAnd : Expression
- {
- private Expression left;
- private Expression right;
- public ExpressionAnd(Expression _left, Expression _right)
- {
- this.left = _left;
- this.right = _right;
- }
- override public bool Evaluate()
- {
- return left.Evaluate() && right.Evaluate();
- }
- }
- public class ExpressionOr : Expression
- {
- private Expression left;
- private Expression right;
- public ExpressionOr(Expression _left, Expression _right)
- {
- this.left = _left;
- this.right = _right;
- }
- override public bool Evaluate()
- {
- return left.Evaluate() || right.Evaluate();
- }
- }
- public class ExpressionNot : Expression
- {
- private Expression expr;
- public ExpressionNot(Expression _expr)
- {
- this.expr = _expr;
- }
- override public bool Evaluate()
- {
- return !expr.Evaluate();
- }
- }
- static public Expression MakeExpression(ref List<Token>.Enumerator polishNotationTokensEnumerator, EvaluateFunction _evalFunction)
- {
- if(polishNotationTokensEnumerator.Current.type == Token.TokenType.LITERAL)
- {
- Expression lit = new ExpressionLeaf(_evalFunction, polishNotationTokensEnumerator.Current.value);
- polishNotationTokensEnumerator.MoveNext();
- return lit;
- }
- else
- {
- if(polishNotationTokensEnumerator.Current.value == "NOT")
- {
- polishNotationTokensEnumerator.MoveNext();
- Expression operand = MakeExpression(ref polishNotationTokensEnumerator, _evalFunction);
- return new ExpressionNot(operand);
- }
- else if(polishNotationTokensEnumerator.Current.value == "AND")
- {
- polishNotationTokensEnumerator.MoveNext();
- Expression left = MakeExpression(ref polishNotationTokensEnumerator, _evalFunction);
- Expression right = MakeExpression(ref polishNotationTokensEnumerator, _evalFunction);
- return new ExpressionAnd(left, right);
- }
- else if(polishNotationTokensEnumerator.Current.value == "OR")
- {
- polishNotationTokensEnumerator.MoveNext();
- Expression left = MakeExpression(ref polishNotationTokensEnumerator, _evalFunction);
- Expression right = MakeExpression(ref polishNotationTokensEnumerator, _evalFunction);
- return new ExpressionOr(left, right);
- }
- }
- return null;
- }
- }
- }
|