using System; using System.Collections.Generic; using NTERA.Core; namespace NTERA.Interpreter { public partial class Interpreter { private Lexer lex; private Token prevToken; private Token lastToken; public readonly Dictionary Variables; private Dictionary loops; 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; lex = new Lexer(input); Variables = new Dictionary(); loops = new Dictionary(); ifcounter = 0; GenerateKeywordDictionary(); GenerateFunctionDictionary(); } private void Error(string text) { throw new Exception(text + " at line: " + lineMarker.Line); } protected bool TryAssertNextToken(Token tok, bool pullNext = true) { if (pullNext) GetNextToken(); return lastToken == tok; } protected void AssertToken(Token tok, bool pullNext = true) { if (!TryAssertNextToken(tok, pullNext)) Error("Expect " + tok + " got " + lastToken); } private IEnumerator tokens; public void Exec() { exit = false; tokens = lex.GetTokens().GetEnumerator(); GetNextToken(); while (!exit) Line(); } protected Token GetNextToken() { prevToken = lastToken; tokens.MoveNext(); lastToken = tokens.Current; if (lastToken == Token.EOF && prevToken == Token.EOF) Error("Unexpected end of file"); return lastToken; } private void Line() { while (lastToken == Token.NewLine) GetNextToken(); if (lastToken == Token.EOF) { exit = true; return; } lineMarker = lex.TokenMarker; Statement(); if (lastToken != Token.NewLine && lastToken != Token.EOF) Error("Expect new line got " + lastToken); } private void Statement() { Token keyword = lastToken; GetNextToken(); if (KeywordMethods.ContainsKey(keyword)) KeywordMethods[keyword](); else { switch (keyword) { case Token.Input: Input(); break; case Token.Function: case Token.Global: case Token.Dim: case Token.Const: while (GetNextToken() != Token.NewLine) { } break; case Token.Identifer: if (lastToken == Token.Equal) Let(); else goto default; break; case Token.EOF: exit = true; break; default: Error("Expect keyword got " + keyword); break; } } if (lastToken == Token.Colon) { GetNextToken(); Statement(); } } public Dictionary FunctionDictionary { get; protected set; } public Dictionary KeywordMethods { get; set; } private void Input() { while (true) { AssertToken(Token.Identifer); if (!Variables.ContainsKey(lex.Identifer)) Variables.Add(lex.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[lex.Identifer] = new Value(d); else Variables[lex.Identifer] = new Value(input); if (!TryAssertNextToken(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 Expr() { Stack stack = new Stack(); Stack operators = new Stack(); int i = 0; while (true) { if (lastToken == Token.Value) { stack.Push(lex.Value); } else if (lastToken == Token.Identifer) { if (Variables.ContainsKey(lex.Identifer)) { stack.Push(Variables[lex.Identifer]); } else if (FunctionDictionary.ContainsKey(lex.Identifer)) { string name = lex.Identifer; List args = new List(); GetNextToken(); AssertToken(Token.LParen, false); while (!TryAssertNextToken(Token.RParen)) { args.Add(Expr()); if (lastToken != Token.Comma) break; } stack.Push(FunctionDictionary[name](args)); } else { Error("Undeclared variable " + lex.Identifer); } } else if (lastToken == Token.LParen) { GetNextToken(); stack.Push(Expr()); AssertToken(Token.RParen, false); } else if (lastToken.IsArithmetic()) { if (lastToken.IsUnary() && (i == 0 || prevToken == Token.LParen)) { stack.Push(0); operators.Push(lastToken); } else { while (operators.Count > 0 && OrderOfOps[lastToken] <= OrderOfOps[operators.Peek()]) Operation(stack, operators.Pop()); operators.Push(lastToken); } } else { if (i == 0) Error("Empty expression"); break; } i++; GetNextToken(); } while (operators.Count > 0) Operation(stack, operators.Pop()); return stack.Pop(); } private void Operation(Stack stack, Token token) { Value b = stack.Pop(); Value a = stack.Pop(); Value result = a.Operate(b, token); stack.Push(result); } } }