using System; using System.Collections.Generic; using System.Linq; using NTERA.Core; namespace NTERA.Interpreter { public partial class Interpreter { protected Lexer Lexer { get; set; } private Token prevToken; private Token CurrentToken => tokens.Current; public VariableDictionary Variables { get; } = new VariableDictionary(); protected Dictionary Loops { get; } = new Dictionary(); public delegate Value BasicFunction(List args); private readonly IConsole console; private int ifcounter; private Marker lineMarker; private bool exit; public Interpreter(IConsole console, string input) { this.console = console; Lexer = new Lexer(input); ifcounter = 0; GenerateKeywordDictionary(); GenerateFunctionDictionary(); } private void Error(string text) { throw new Exception(text + " at line: " + lineMarker.Line); } protected bool TryAssertToken(Token tok, bool pullNext = true) { if (pullNext) GetNextToken(); return CurrentToken == tok; } protected void AssertToken(Token tok, bool pullNext = true) { if (!TryAssertToken(tok, pullNext)) Error("Expect " + tok + " got " + CurrentToken); } private IEnumerator tokens; public void Exec() { exit = false; tokens = Lexer.GetTokens().GetEnumerator(); GetNextToken(); while (!exit) Line(); } protected Token GetNextToken() { prevToken = CurrentToken; tokens.MoveNext(); if (CurrentToken == Token.EOF && prevToken == Token.EOF) Error("Unexpected end of file"); return CurrentToken; } private void Line() { while (CurrentToken == Token.NewLine) GetNextToken(); if (CurrentToken == Token.EOF) { exit = true; return; } lineMarker = Lexer.TokenMarker; Statement(); if (CurrentToken != Token.NewLine && CurrentToken != Token.EOF) Error("Expect new line got " + CurrentToken); } private void Statement() { Token keyword = CurrentToken; GetNextToken(); if (KeywordMethods.ContainsKey(keyword)) KeywordMethods[keyword](); else { switch (keyword) { case Token.Input: Input(); break; case Token.Function: case Token.Dim: case Token.Const: while (GetNextToken() != Token.NewLine) { } break; case Token.Identifer: if (CurrentToken != Token.Equal && CurrentToken != Token.Colon) Error("Expected assignment got " + CurrentToken); Let(); break; case Token.EOF: exit = true; break; default: Error("Expect keyword got " + keyword); break; } } } public Dictionary FunctionDictionary { get; protected set; } public Dictionary KeywordMethods { get; set; } private void Input() { while (true) { AssertToken(Token.Identifer); if (!Variables.ContainsKey(Lexer.Identifer)) Variables.Add(Lexer.Identifer, new Value()); console.WaitInput(new Core.Interop.InputRequest() { InputType = Core.Interop.InputType.StrValue }); string input = console.LastInput; double d; if (double.TryParse(input, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out d)) Variables[Lexer.Identifer] = new Value(d); else Variables[Lexer.Identifer] = new Value(input); if (!TryAssertToken(Token.Comma)) break; GetNextToken(); } } private static readonly Dictionary OrderOfOps = new Dictionary { { Token.Or, 0 }, { Token.And, 0 }, { Token.Equal, 1 }, { Token.NotEqual, 1 }, { Token.Less, 1 }, { Token.More, 1 }, { Token.LessEqual, 1 }, { Token.MoreEqual, 1 }, { Token.Plus, 2 }, { Token.Minus, 2 }, { Token.Asterisk, 3 }, {Token.Slash, 3 }, { Token.Caret, 4 } }; private Value RealExpression() { return RealExpression(Lexer, tokens); } private Value RealExpression(string input) { return RealExpression(new Lexer(input)); } private Value RealExpression(Lexer lexer, IEnumerator enumerator = null) { Stack stack = new Stack(); Stack operators = new Stack(); if (enumerator == null) { enumerator = lexer.GetTokens().GetEnumerator(); enumerator.MoveNext(); } void Operation(Token token) { Value b = stack.Pop(); Value a = stack.Pop(); Value result = a.Operate(b, token); stack.Push(result); } int i = 0; while (true) { if (enumerator.Current == Token.Value) { stack.Push(lexer.Value); } else if (enumerator.Current == Token.Identifer) { if (Variables.ContainsKey(lexer.Identifer)) { stack.Push(Variables[lexer.Identifer]); } else if (FunctionDictionary.ContainsKey(lexer.Identifer)) { string name = lexer.Identifer; List args = new List(); enumerator.MoveNext(); //AssertToken(Token.LParen, false); while (enumerator.MoveNext() && enumerator.Current != Token.RParen) { args.Add(RealExpression(lexer, enumerator)); if (enumerator.Current != Token.Comma) break; } stack.Push(FunctionDictionary[name](args)); } else { Error("Undeclared variable " + lexer.Identifer); } } else if (enumerator.Current == Token.LParen) { enumerator.MoveNext(); stack.Push(RealExpression(lexer, enumerator)); //AssertToken(Token.RParen, false); } else if (enumerator.Current.IsArithmetic()) { if (enumerator.Current.IsUnary() && (i == 0 || prevToken == Token.LParen)) { stack.Push(0); operators.Push(enumerator.Current); } else { while (operators.Count > 0 && OrderOfOps[enumerator.Current] <= OrderOfOps[operators.Peek()]) Operation(operators.Pop()); operators.Push(enumerator.Current); } } else { if (i == 0) Error("Empty expression"); break; } i++; enumerator.MoveNext(); } while (operators.Count > 0) Operation(operators.Pop()); return stack.Pop(); } private Value StringExpression() { Lexer.Type = LexerType.String; GetNextToken(); var result = StringExpression(Lexer, tokens); Lexer.Type = LexerType.Real; return result; } private Value StringExpression(Lexer lexer, IEnumerator enumerator = null) { Stack stack = new Stack(); Stack operators = new Stack(); if (enumerator == null) { enumerator = lexer.GetTokens().GetEnumerator(); enumerator.MoveNext(); } void Operation(Token token) { Value b = stack.Pop(); Value a = stack.Pop(); Value result = a.Operate(b, token); stack.Push(result); } int i = 0; while (true) { if (enumerator.Current == Token.Value) { stack.Push(lexer.Value.String); } else if (enumerator.Current == Token.Identifer) { if (Variables.ContainsKey(lexer.Identifer)) { stack.Push(Variables[lexer.Identifer]); } else if (FunctionDictionary.ContainsKey(lexer.Identifer)) { string name = lexer.Identifer; List args = new List(); enumerator.MoveNext(); AssertToken(Token.LParen, false); while (!TryAssertToken(Token.RParen)) { args.Add(StringExpression(lexer, enumerator)); if (enumerator.Current != Token.Comma) break; } stack.Push(FunctionDictionary[name](args)); } else { if (stack.Count > 0) operators.Push(Token.Plus); stack.Push(lexer.Identifer); } } else if (enumerator.Current == Token.LParen) { enumerator.MoveNext(); stack.Push(StringExpression(lexer, enumerator)); AssertToken(Token.RParen, false); } else if (enumerator.Current.IsStringOp()) { while (operators.Count > 0 && OrderOfOps[enumerator.Current] <= OrderOfOps[operators.Peek()]) Operation(operators.Pop()); operators.Push(enumerator.Current); } else { if (i == 0) Error("Empty expression"); break; } i++; enumerator.MoveNext(); } while (operators.Count > 0) Operation(operators.Pop()); return stack.Aggregate((a, b) => b.String + a.String); } } }