|
@@ -6,12 +6,12 @@ namespace NTERA.Interpreter
|
|
|
{
|
|
|
public partial class Interpreter
|
|
|
{
|
|
|
- private Lexer lex;
|
|
|
+ protected Lexer Lexer { get; set; }
|
|
|
private Token prevToken;
|
|
|
private Token lastToken;
|
|
|
|
|
|
- public Dictionary<string, Value> Variables { get; } = new Dictionary<string, Value>();
|
|
|
- private Dictionary<string, Marker> loops;
|
|
|
+ public VariableDictionary Variables { get; } = new VariableDictionary();
|
|
|
+ protected Dictionary<string, Marker> Loops { get; } = new Dictionary<string, Marker>();
|
|
|
|
|
|
public delegate Value BasicFunction(List<Value> args);
|
|
|
|
|
@@ -26,9 +26,7 @@ namespace NTERA.Interpreter
|
|
|
public Interpreter(IConsole console, string input)
|
|
|
{
|
|
|
this.console = console;
|
|
|
- lex = new Lexer(input);
|
|
|
- Variables = new Dictionary<string, Value>();
|
|
|
- loops = new Dictionary<string, Marker>();
|
|
|
+ Lexer = new Lexer(input);
|
|
|
ifcounter = 0;
|
|
|
|
|
|
GenerateKeywordDictionary();
|
|
@@ -40,7 +38,7 @@ namespace NTERA.Interpreter
|
|
|
throw new Exception(text + " at line: " + lineMarker.Line);
|
|
|
}
|
|
|
|
|
|
- protected bool TryAssertNextToken(Token tok, bool pullNext = true)
|
|
|
+ protected bool TryAssertToken(Token tok, bool pullNext = true)
|
|
|
{
|
|
|
if (pullNext)
|
|
|
GetNextToken();
|
|
@@ -50,7 +48,7 @@ namespace NTERA.Interpreter
|
|
|
|
|
|
protected void AssertToken(Token tok, bool pullNext = true)
|
|
|
{
|
|
|
- if (!TryAssertNextToken(tok, pullNext))
|
|
|
+ if (!TryAssertToken(tok, pullNext))
|
|
|
Error("Expect " + tok + " got " + lastToken);
|
|
|
}
|
|
|
|
|
@@ -60,7 +58,7 @@ namespace NTERA.Interpreter
|
|
|
{
|
|
|
exit = false;
|
|
|
|
|
|
- tokens = lex.GetTokens().GetEnumerator();
|
|
|
+ tokens = Lexer.GetTokens().GetEnumerator();
|
|
|
|
|
|
GetNextToken();
|
|
|
|
|
@@ -83,7 +81,8 @@ namespace NTERA.Interpreter
|
|
|
|
|
|
private void Line()
|
|
|
{
|
|
|
- while (lastToken == Token.NewLine) GetNextToken();
|
|
|
+ while (lastToken == Token.NewLine)
|
|
|
+ GetNextToken();
|
|
|
|
|
|
if (lastToken == Token.EOF)
|
|
|
{
|
|
@@ -91,7 +90,7 @@ namespace NTERA.Interpreter
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- lineMarker = lex.TokenMarker;
|
|
|
+ lineMarker = Lexer.TokenMarker;
|
|
|
Statement();
|
|
|
|
|
|
if (lastToken != Token.NewLine && lastToken != Token.EOF)
|
|
@@ -100,44 +99,53 @@ namespace NTERA.Interpreter
|
|
|
|
|
|
private void Statement()
|
|
|
{
|
|
|
- Token keyword = lastToken;
|
|
|
- GetNextToken();
|
|
|
-
|
|
|
- if (KeywordMethods.ContainsKey(keyword))
|
|
|
- KeywordMethods[keyword]();
|
|
|
- else
|
|
|
+ while (true)
|
|
|
{
|
|
|
- switch (keyword)
|
|
|
+ Token keyword = lastToken;
|
|
|
+ GetNextToken();
|
|
|
+
|
|
|
+ if (KeywordMethods.ContainsKey(keyword))
|
|
|
+ KeywordMethods[keyword]();
|
|
|
+ else
|
|
|
{
|
|
|
- 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;
|
|
|
+ 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
|
|
|
+ Error("Expected assignment got " + lastToken);
|
|
|
+ break;
|
|
|
+ case Token.EOF:
|
|
|
+ exit = true;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ Error("Expect keyword got " + keyword);
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- if (lastToken == Token.Colon)
|
|
|
- {
|
|
|
- GetNextToken();
|
|
|
- Statement();
|
|
|
+ if (lastToken == Token.Colon)
|
|
|
+ {
|
|
|
+ GetNextToken();
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
public Dictionary<string, BasicFunction> FunctionDictionary { get; protected set; }
|
|
|
|
|
|
public Dictionary<Token, Action> KeywordMethods { get; set; }
|
|
@@ -149,17 +157,17 @@ namespace NTERA.Interpreter
|
|
|
{
|
|
|
AssertToken(Token.Identifer);
|
|
|
|
|
|
- if (!Variables.ContainsKey(lex.Identifer)) Variables.Add(lex.Identifer, new Value());
|
|
|
+ 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[lex.Identifer] = new Value(d);
|
|
|
+ Variables[Lexer.Identifer] = new Value(d);
|
|
|
else
|
|
|
- Variables[lex.Identifer] = new Value(input);
|
|
|
+ Variables[Lexer.Identifer] = new Value(input);
|
|
|
|
|
|
- if (!TryAssertNextToken(Token.Comma))
|
|
|
+ if (!TryAssertToken(Token.Comma))
|
|
|
break;
|
|
|
|
|
|
GetNextToken();
|
|
@@ -176,34 +184,42 @@ namespace NTERA.Interpreter
|
|
|
{ Token.Caret, 4 }
|
|
|
};
|
|
|
|
|
|
- private Value Expr()
|
|
|
+ private Value RealExpression()
|
|
|
{
|
|
|
Stack<Value> stack = new Stack<Value>();
|
|
|
Stack<Token> operators = new Stack<Token>();
|
|
|
|
|
|
+ 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 (lastToken == Token.Value)
|
|
|
{
|
|
|
- stack.Push(lex.Value);
|
|
|
+ stack.Push(Lexer.Value);
|
|
|
}
|
|
|
else if (lastToken == Token.Identifer)
|
|
|
{
|
|
|
- if (Variables.ContainsKey(lex.Identifer))
|
|
|
+ if (Variables.ContainsKey(Lexer.Identifer))
|
|
|
{
|
|
|
- stack.Push(Variables[lex.Identifer]);
|
|
|
+ stack.Push(Variables[Lexer.Identifer]);
|
|
|
}
|
|
|
- else if (FunctionDictionary.ContainsKey(lex.Identifer))
|
|
|
+ else if (FunctionDictionary.ContainsKey(Lexer.Identifer))
|
|
|
{
|
|
|
- string name = lex.Identifer;
|
|
|
+ string name = Lexer.Identifer;
|
|
|
List<Value> args = new List<Value>();
|
|
|
GetNextToken();
|
|
|
AssertToken(Token.LParen, false);
|
|
|
|
|
|
- while (!TryAssertNextToken(Token.RParen))
|
|
|
+ while (!TryAssertToken(Token.RParen))
|
|
|
{
|
|
|
- args.Add(Expr());
|
|
|
+ args.Add(RealExpression());
|
|
|
if (lastToken != Token.Comma)
|
|
|
break;
|
|
|
}
|
|
@@ -212,13 +228,13 @@ namespace NTERA.Interpreter
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- Error("Undeclared variable " + lex.Identifer);
|
|
|
+ Error("Undeclared variable " + Lexer.Identifer);
|
|
|
}
|
|
|
}
|
|
|
else if (lastToken == Token.LParen)
|
|
|
{
|
|
|
GetNextToken();
|
|
|
- stack.Push(Expr());
|
|
|
+ stack.Push(RealExpression());
|
|
|
AssertToken(Token.RParen, false);
|
|
|
}
|
|
|
else if (lastToken.IsArithmetic())
|
|
@@ -231,7 +247,7 @@ namespace NTERA.Interpreter
|
|
|
else
|
|
|
{
|
|
|
while (operators.Count > 0 && OrderOfOps[lastToken] <= OrderOfOps[operators.Peek()])
|
|
|
- Operation(stack, operators.Pop());
|
|
|
+ Operation(operators.Pop());
|
|
|
operators.Push(lastToken);
|
|
|
}
|
|
|
}
|
|
@@ -247,17 +263,17 @@ namespace NTERA.Interpreter
|
|
|
}
|
|
|
|
|
|
while (operators.Count > 0)
|
|
|
- Operation(stack, operators.Pop());
|
|
|
+ Operation(operators.Pop());
|
|
|
|
|
|
return stack.Pop();
|
|
|
}
|
|
|
|
|
|
- private void Operation(Stack<Value> stack, Token token)
|
|
|
+ private Value StringExpression()
|
|
|
{
|
|
|
- Value b = stack.Pop();
|
|
|
- Value a = stack.Pop();
|
|
|
- Value result = a.Operate(b, token);
|
|
|
- stack.Push(result);
|
|
|
+ foreach (var t in Lexer.ReturnAsLine(Token.Unknown)) { }
|
|
|
+
|
|
|
+ lastToken = Token.NewLine;
|
|
|
+ return Lexer.Value;
|
|
|
}
|
|
|
}
|
|
|
}
|