using System; using System.Collections.Generic; using NTERA.Interpreter.Functions; namespace NTERA.Interpreter { public partial class Interpreter { public bool HasPrint { get; set; } = true; public bool HasInput { get; set; } = true; private Lexer lex; private Token prevToken; private Token lastToken; private Dictionary vars; private Dictionary loops; public delegate Value BasicFunction(Interpreter interpreter, List args); private Dictionary funcs; private int ifcounter; private Marker lineMarker; private bool exit; public Interpreter(string input) { lex = new Lexer(input); vars = new Dictionary(); loops = new Dictionary(); funcs = new Dictionary(); ifcounter = 0; BuiltInFunctions.InstallAll(this); } public Value GetVar(string name) { if (!vars.ContainsKey(name)) throw new Exception("Variable with name " + name + " does not exist."); return vars[name]; } public void SetVar(string name, Value val) { if (!vars.ContainsKey(name)) vars.Add(name, val); else vars[name] = val; } public void AddFunction(string name, BasicFunction function) { if (!funcs.ContainsKey(name)) funcs.Add(name, function); else funcs[name] = function; } void Error(string text) { throw new Exception(text + " at line: " + lineMarker.Line); } void Match(Token tok) { if (lastToken != tok) Error("Expect " + tok + " got " + lastToken); } public void Exec() { exit = false; GetNextToken(); while (!exit) Line(); } Token GetNextToken() { prevToken = lastToken; lastToken = lex.GetToken(); if (lastToken == Token.EOF && prevToken == Token.EOF) Error("Unexpected end of file"); return lastToken; } void Line() { while (lastToken == Token.NewLine) GetNextToken(); if (lastToken == Token.EOF) { exit = true; return; } lineMarker = lex.TokenMarker; Statment(); if (lastToken != Token.NewLine && lastToken != Token.EOF) Error("Expect new line got " + lastToken); } void Statment() { Token keyword = lastToken; GetNextToken(); switch (keyword) { case Token.Print: Print(); break; case Token.Input: Input(); break; case Token.If: If(); break; case Token.Else: Else(); break; case Token.EndIf: break; case Token.For: For(); break; case Token.Next: Next(); break; case Token.Let: Let(); break; case Token.End: End(); 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(); Statment(); } } void Print() { if (!HasPrint) Error("Print command not allowed"); Console.WriteLine(Expr().ToString()); } void Input() { if (!HasInput) Error("Input command not allowed"); while (true) { Match(Token.Identifer); if (!vars.ContainsKey(lex.Identifer)) vars.Add(lex.Identifer, new Value()); string input = Console.ReadLine(); double d; if (double.TryParse(input, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out d)) vars[lex.Identifer] = new Value(d); else vars[lex.Identifer] = new Value(input); GetNextToken(); if (lastToken != Token.Comma) break; GetNextToken(); } } Value Expr() { Dictionary prec = 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 } }; 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 (vars.ContainsKey(lex.Identifer)) { stack.Push(vars[lex.Identifer]); } else if (funcs.ContainsKey(lex.Identifer)) { string name = lex.Identifer; List args = new List(); GetNextToken(); Match(Token.LParen); start: if (GetNextToken() != Token.RParen) { args.Add(Expr()); if (lastToken == Token.Comma) goto start; } stack.Push(funcs[name](null, args)); } else { Error("Undeclared variable " + lex.Identifer); } } else if (lastToken == Token.LParen) { GetNextToken(); stack.Push(Expr()); Match(Token.RParen); } else if (lastToken >= Token.Plus && lastToken <= Token.Not) { if ((lastToken == Token.Minus || lastToken == Token.Minus) && (i == 0 || prevToken == Token.LParen)) { stack.Push(new Value(0)); operators.Push(lastToken); } else { while (operators.Count > 0 && prec[lastToken] <= prec[operators.Peek()]) Operation(ref stack, operators.Pop()); operators.Push(lastToken); } } else { if (i == 0) Error("Empty expression"); break; } i++; GetNextToken(); } while (operators.Count > 0) Operation(ref stack, operators.Pop()); return stack.Pop(); } void Operation(ref Stack stack, Token token) { Value b = stack.Pop(); Value a = stack.Pop(); Value result = a.BinOp(b, token); stack.Push(result); } } }