public List <ExpressionToken> ConvertToReversePolishNotation(ScriptVariableTable variableTable, List <InputToken> tokenstream) { // TODO Probably returns an expression object // That contains a list<semantictokens> but also a list of the variable lookups referenced in the list. var rv = new List <ExpressionToken>(); var opcodes = m_SemanticAnalyser.ApplySemantics(variableTable, tokenstream); var stack = new Stack <ExpressionToken>(tokenstream.Count); // Shunting Yard Algorithm // http://en.wikipedia.org/wiki/Shunting-yard_algorithm foreach (var opcode in opcodes) { if (opcode.IsNumber() || opcode.IsVariableNumberType()) { rv.Add(opcode); } else { if (opcode.IsFunction()) { stack.Push(opcode); } else { if (opcode.IsFunctionArgumentSeperator()) { while (stack.Count > 0) { var o = stack.Peek(); if (o.TokenType == SemanticTokenType.OpenBracket) { break; } rv.Add(o); } } else { if (opcode.IsOperator()) { while (stack.Count > 0) { var peek = stack.Peek(); if ((opcode.Precedence < peek.Precedence) || opcode.OperatorAssociativity == OperatorAssociativity.Left && opcode.Precedence == peek.Precedence) { rv.Add(stack.Pop()); } else { break; } } stack.Push(opcode); } else { // Left Bracket if (opcode.TokenType == SemanticTokenType.OpenBracket) { stack.Push(opcode); } if (opcode.TokenType == SemanticTokenType.CloseBracket) { var token = stack.Pop(); while (stack.Count > 0 && token.TokenType != SemanticTokenType.OpenBracket) { rv.Add(token); token = stack.Pop(); } if (token.TokenType != SemanticTokenType.OpenBracket) { throw new ExpressionParserException("Mismatched brackets"); } } } } } } } // When there are no more tokens to read while (stack.Count > 0) { var op = stack.Pop(); if (op.IsBracket()) { throw new ExpressionParserException("Mismatched brackets"); } rv.Add(op); } return(rv); }
public IEnumerable <ExpressionToken> ApplySemantics(ScriptVariableTable variableTable, IEnumerable <InputToken> tokenStream) { var tokens = tokenStream.ToList(); PreprocessSemantics(ref tokens); var rv = new List <ExpressionToken>(tokens.Count()); foreach (var token in tokens) { if (token.OperationType == TranspileTest.OperationType.Operator) { var t = OperatorToOpcode(token); rv.Add(t); } else { switch (token.TokenType) { // TODO Add variable lookups for this we might want some kind of index? // To be stored with the expression? case SemanticTokenType.FunctionCall: { var t = new ExpressionToken { TokenType = token.TokenType, OperationType = OperationType.FunctionCall, Precedence = 9 }; var function = m_HostCallTable.GetFunctionByName(token.TokenValue); t.Data.Int = function.Id; rv.Add(t); break; } case SemanticTokenType.FunctionArgumentSeperator: { rv.Add(new ExpressionToken { TokenType = token.TokenType, OperationType = OperationType.Operand }); break; } case SemanticTokenType.Symbol: { var symbol = HostSymbolTable.GetSymbolByName(token.TokenValue); var expressionData = new ExpressionData() { Int = symbol.SymbolId }; rv.Add(new ExpressionToken { TokenType = token.TokenType, OperationType = OperationType.Operator, Data = expressionData, Precedence = 9 }); break; } default: { var t = new ExpressionToken { TokenType = token.TokenType, OperationType = OperationType.Operand }; if (!t.IsBracket()) { if (t.TokenType == SemanticTokenType.VariableName) { t.Data.Guid = variableTable.GetGuid(token.TokenValue); } else { t.Data.Float = float.Parse(token.TokenValue); } } rv.Add(t); break; } } } } return(rv); }