|
@@ -8,8 +8,8 @@ namespace NTERA.Interpreter
|
|
|
public partial class Interpreter
|
|
|
{
|
|
|
protected Lexer Lexer { get; set; }
|
|
|
- private Token prevToken;
|
|
|
- private Token CurrentToken => tokens.Current;
|
|
|
+ private Token previousToken;
|
|
|
+ private Token CurrentToken => Tokens.Current;
|
|
|
|
|
|
public VariableDictionary Variables { get; } = new VariableDictionary();
|
|
|
protected Dictionary<string, Marker> Loops { get; } = new Dictionary<string, Marker>();
|
|
@@ -18,8 +18,6 @@ namespace NTERA.Interpreter
|
|
|
|
|
|
private readonly IConsole console;
|
|
|
|
|
|
- private int ifcounter;
|
|
|
-
|
|
|
private Marker lineMarker;
|
|
|
|
|
|
private bool exit;
|
|
@@ -28,7 +26,6 @@ namespace NTERA.Interpreter
|
|
|
{
|
|
|
this.console = console;
|
|
|
Lexer = new Lexer(input);
|
|
|
- ifcounter = 0;
|
|
|
|
|
|
GenerateKeywordDictionary();
|
|
|
GenerateFunctionDictionary();
|
|
@@ -53,13 +50,13 @@ namespace NTERA.Interpreter
|
|
|
Error("Expect " + tok + " got " + CurrentToken);
|
|
|
}
|
|
|
|
|
|
- private IEnumerator<Token> tokens;
|
|
|
+ private IEnumerator<Token> Tokens;
|
|
|
|
|
|
public void Exec()
|
|
|
{
|
|
|
exit = false;
|
|
|
|
|
|
- tokens = Lexer.GetTokens().GetEnumerator();
|
|
|
+ Tokens = Lexer.GetTokens().GetEnumerator();
|
|
|
|
|
|
GetNextToken();
|
|
|
|
|
@@ -69,11 +66,11 @@ namespace NTERA.Interpreter
|
|
|
|
|
|
protected Token GetNextToken()
|
|
|
{
|
|
|
- prevToken = CurrentToken;
|
|
|
+ previousToken = CurrentToken;
|
|
|
|
|
|
- tokens.MoveNext();
|
|
|
+ Tokens.MoveNext();
|
|
|
|
|
|
- if (CurrentToken == Token.EOF && prevToken == Token.EOF)
|
|
|
+ if (CurrentToken == Token.EOF && previousToken == Token.EOF)
|
|
|
Error("Unexpected end of file");
|
|
|
|
|
|
return CurrentToken;
|
|
@@ -149,8 +146,8 @@ namespace NTERA.Interpreter
|
|
|
|
|
|
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))
|
|
|
+
|
|
|
+ if (double.TryParse(input, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out var d))
|
|
|
Variables[Lexer.Identifer] = new Value(d);
|
|
|
else
|
|
|
Variables[Lexer.Identifer] = new Value(input);
|
|
@@ -174,115 +171,25 @@ namespace NTERA.Interpreter
|
|
|
|
|
|
private Value RealExpression()
|
|
|
{
|
|
|
- return RealExpression(Lexer, tokens);
|
|
|
+ return Expression(Lexer, Tokens);
|
|
|
}
|
|
|
|
|
|
private Value RealExpression(string input)
|
|
|
{
|
|
|
- return RealExpression(new Lexer(input));
|
|
|
- }
|
|
|
-
|
|
|
- private Value RealExpression(Lexer lexer, IEnumerator<Token> enumerator = null)
|
|
|
- {
|
|
|
- Stack<Value> stack = new Stack<Value>();
|
|
|
- Stack<Token> operators = new Stack<Token>();
|
|
|
-
|
|
|
- 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<Value> args = new List<Value>();
|
|
|
- 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();
|
|
|
+ return Expression(new Lexer(input));
|
|
|
}
|
|
|
|
|
|
private Value StringExpression()
|
|
|
{
|
|
|
Lexer.Type = LexerType.String;
|
|
|
GetNextToken();
|
|
|
- var result = StringExpression(Lexer, tokens);
|
|
|
+ var result = Expression(Lexer, Tokens, LexerType.String);
|
|
|
Lexer.Type = LexerType.Real;
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
- private Value StringExpression(Lexer lexer, IEnumerator<Token> enumerator = null)
|
|
|
+ private Value Expression(Lexer lexer, IEnumerator<Token> enumerator = null, LexerType type = LexerType.Real)
|
|
|
{
|
|
|
Stack<Value> stack = new Stack<Value>();
|
|
|
Stack<Token> operators = new Stack<Token>();
|
|
@@ -306,7 +213,7 @@ namespace NTERA.Interpreter
|
|
|
{
|
|
|
if (enumerator.Current == Token.Value)
|
|
|
{
|
|
|
- stack.Push(lexer.Value.String);
|
|
|
+ stack.Push(lexer.Value);
|
|
|
}
|
|
|
else if (enumerator.Current == Token.Identifer)
|
|
|
{
|
|
@@ -319,11 +226,13 @@ namespace NTERA.Interpreter
|
|
|
string name = lexer.Identifer;
|
|
|
List<Value> args = new List<Value>();
|
|
|
enumerator.MoveNext();
|
|
|
- AssertToken(Token.LParen, false);
|
|
|
|
|
|
- while (!TryAssertToken(Token.RParen))
|
|
|
+ if (enumerator.Current != Token.LParen)
|
|
|
+ Error($"Was expecting [LParen] got [{enumerator.Current}]");
|
|
|
+
|
|
|
+ while (enumerator.MoveNext() && enumerator.Current != Token.RParen)
|
|
|
{
|
|
|
- args.Add(StringExpression(lexer, enumerator));
|
|
|
+ args.Add(Expression(lexer, enumerator, type));
|
|
|
if (enumerator.Current != Token.Comma)
|
|
|
break;
|
|
|
}
|
|
@@ -332,19 +241,28 @@ namespace NTERA.Interpreter
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- if (stack.Count > 0)
|
|
|
- operators.Push(Token.Plus);
|
|
|
-
|
|
|
- stack.Push(lexer.Identifer);
|
|
|
+ if (type == LexerType.String)
|
|
|
+ stack.Push(lexer.Identifer);
|
|
|
+ else
|
|
|
+ Error("Undeclared variable " + lexer.Identifer);
|
|
|
}
|
|
|
}
|
|
|
else if (enumerator.Current == Token.LParen)
|
|
|
{
|
|
|
enumerator.MoveNext();
|
|
|
- stack.Push(StringExpression(lexer, enumerator));
|
|
|
- AssertToken(Token.RParen, false);
|
|
|
+ stack.Push(Expression(lexer, enumerator, type));
|
|
|
+
|
|
|
+ if (enumerator.Current != Token.RParen)
|
|
|
+ Error($"Was expecting [LParen] got [{enumerator.Current}]");
|
|
|
+ }
|
|
|
+ else if (type == LexerType.Real && enumerator.Current.IsArithmetic()
|
|
|
+ && enumerator.Current.IsUnary() && (i == 0 || previousToken == Token.LParen))
|
|
|
+ {
|
|
|
+ stack.Push(0);
|
|
|
+ operators.Push(enumerator.Current);
|
|
|
}
|
|
|
- else if (enumerator.Current.IsStringOp())
|
|
|
+ else if (type == LexerType.String && enumerator.Current.IsStringOp()
|
|
|
+ || type == LexerType.Real && enumerator.Current.IsArithmetic())
|
|
|
{
|
|
|
while (operators.Count > 0 && OrderOfOps[enumerator.Current] <= OrderOfOps[operators.Peek()])
|
|
|
Operation(operators.Pop());
|
|
@@ -364,7 +282,9 @@ namespace NTERA.Interpreter
|
|
|
while (operators.Count > 0)
|
|
|
Operation(operators.Pop());
|
|
|
|
|
|
- return stack.Aggregate((a, b) => b.String + a.String);
|
|
|
+ return type == LexerType.String
|
|
|
+ ? stack.Aggregate((a, b) => b.String + a.String)
|
|
|
+ : stack.Pop();
|
|
|
}
|
|
|
}
|
|
|
}
|