private void AppendControlFlow(ASTNode astNode) { astNode.Accept(this); }
/// <summary> /// Preprocess a string of text /// </summary> /// <param name="source">source</param> /// <returns>preprocessed source</returns> public string Process(string source) { //search for #* macro *# List <MacroDefinition> macros = new List <MacroDefinition>(); using (StringReader sr = new StringReader(source)) { bool isInMacro = false; int pos = 0; int start = 0; int end = 0; while (sr.Peek() != -1) { char c = (char)sr.Read(); pos++; if (c == '#' && sr.Peek() == '*') { start = pos; if (isInMacro) { //throw error } sr.Read(); pos++; isInMacro = true; } else if (c == '*' && sr.Peek() == '#') { if (!isInMacro) { //throw error } sr.Read(); pos++; end = pos; isInMacro = false; macros.Add(new MacroDefinition(start, end, source.Substring(start + 1, end - (start + 1) - 2).Trim())); } } } //solve all macro and put it back string processedSource = source; Dictionary <string, int> variables = new Dictionary <string, int>(); Interpreter interpreter = new Interpreter(variables); foreach (MacroDefinition macro in macros) { Lexer lexer = new Lexer(macro.Macro); Parser parser = new Parser(lexer); try { ASTNode result = parser.Parse(); result.Accept(interpreter); int output = interpreter.Output; if (result is Assignment) { Assignment asgm = result as Assignment; processedSource = processedSource.Replace(macro.Start - 1, macro.End - macro.Start + 1, ""); } else { processedSource = processedSource.Replace(macro.Start - 1, macro.End - macro.Start + 1, output.ToString()); } } catch (Exception e) { ErrorMessage = e.Message; IsSuccess = false; } } return(processedSource); }
public NodeMapper(ASTNode root) { this.root = root; idToNodeMap = new Dictionary <int, ASTNode>(); root.Accept(this); }
private StackValue Evaluate(ASTNode Expression) { #region operation int IntegerOperation(StackValue operand1, StackValue operand2, TokenType op) { int i1 = (int)operand1.Value; int i2 = (int)operand2.Value; switch (op) { case TokenType.PLUS: return(i1 + i2); case TokenType.MINUS: return(i1 - i2); case TokenType.MULTIPLY: return(i1 * i2); case TokenType.DIVIDE: return(i1 / i2); case TokenType.MODULO: return(i1 % i2); } return(0); } float FloatOperation(StackValue operand1, StackValue operand2, TokenType op) { float f1 = operand1.Value is float?(float)operand1.Value : (int)operand1.Value; float f2 = operand2.Value is float?(float)operand2.Value : (int)operand2.Value; switch (op) { case TokenType.PLUS: return(f1 + f2); case TokenType.MINUS: return(f1 - f2); case TokenType.MULTIPLY: return(f1 * f2); case TokenType.DIVIDE: return(f1 / f2); case TokenType.EXPONENT: return((float)Math.Pow(f1, f2)); } return(0); } string StringOperation(StackValue operand1, StackValue operand2, TokenType op) { string s1 = operand1.Value.ToString(); string s2 = operand2.Value.ToString(); if (op == TokenType.PLUS) { return(s1 + s2); } return(""); } bool BoolOperation(StackValue operand1, StackValue operand2, TokenType op) { bool b1 = (bool)operand1.Value; bool b2 = op == TokenType.NOT ? true : (bool)operand2.Value; switch (op) { case TokenType.AND: return(b1 && b2); case TokenType.OR: return(b1 || b2); case TokenType.XOR: return(b1 ^ b2); case TokenType.NOT: return(!b1); } return(false); } bool IntComparison(StackValue operand1, StackValue operand2, TokenType op) { int i1 = (int)operand1.Value; int i2 = (int)operand2.Value; switch (op) { case TokenType.EQUAL: return(i1 == i2); case TokenType.NOTEQUAL: return(i1 != i2); case TokenType.LARGER: return(i1 > i2); case TokenType.LARGEREQUAL: return(i1 >= i2); case TokenType.LESSER: return(i1 < i2); case TokenType.LESSEREQUAL: return(i1 <= i2); } return(false); } bool FloatComparison(StackValue operand1, StackValue operand2, TokenType op) { float f1 = (float)operand1.Value; float f2 = (float)operand2.Value; switch (op) { case TokenType.EQUAL: return(f1 == f2); case TokenType.NOTEQUAL: return(f1 != f2); case TokenType.LARGER: return(f1 > f2); case TokenType.LARGEREQUAL: return(f1 >= f2); case TokenType.LESSER: return(f1 < f2); case TokenType.LESSEREQUAL: return(f1 <= f2); } return(false); } bool CharComparison(StackValue operand1, StackValue operand2, TokenType op) { char c1 = (char)operand1.Value; char c2 = (char)operand2.Value; switch (op) { case TokenType.EQUAL: return(c1 == c2); case TokenType.NOTEQUAL: return(c1 != c2); case TokenType.LARGER: return(c1 > c2); case TokenType.LARGEREQUAL: return(c1 >= c2); case TokenType.LESSER: return(c1 < c2); case TokenType.LESSEREQUAL: return(c1 <= c2); } return(false); } bool StringComparison(StackValue operand1, StackValue operand2, TokenType op) { string s1 = (string)operand1.Value; string s2 = (string)operand2.Value; var comparison = s1.CompareTo(s2); switch (op) { case TokenType.EQUAL: return(s1.Equals(s2)); case TokenType.NOTEQUAL: return(!s1.Equals(s2)); case TokenType.LARGER: return(comparison > 0); case TokenType.LARGEREQUAL: return(comparison >= 0); case TokenType.LESSER: return(comparison < 0); case TokenType.LESSEREQUAL: return(comparison <= 0); } return(false); } bool BoolComparison(StackValue operand1, StackValue operand2, TokenType op) { bool b1 = (bool)operand1.Value; bool b2 = (bool)operand2.Value; switch (op) { case TokenType.EQUAL: return(b1 == b2); case TokenType.NOTEQUAL: return(b1 != b2); } return(false); } bool Comparison(StackValue operand1, StackValue operand2, TokenType op) { bool result = true; switch (operand1.Type) { case ValType.Integer: int i1 = (int)operand1.Value; if (operand2.Type == ValType.Float) { //do int comparison int i2 = (int)(float)operand2.Value; switch (op) { case TokenType.EQUAL: result = i1 == i2; break; case TokenType.NOTEQUAL: result = i1 != i2; break; case TokenType.LARGER: result = i1 > i2; break; case TokenType.LARGEREQUAL: result = i1 >= i2; break; case TokenType.LESSER: result = i1 < i2; break; case TokenType.LESSEREQUAL: result = i1 <= i2; break; } } else if (operand2.Type == ValType.Char) { //do int comparison int i2 = (int)(char)operand2.Value; switch (op) { case TokenType.EQUAL: result = i1 == i2; break; case TokenType.NOTEQUAL: result = i1 != i2; break; case TokenType.LARGER: result = i1 > i2; break; case TokenType.LARGEREQUAL: result = i1 >= i2; break; case TokenType.LESSER: result = i1 < i2; break; case TokenType.LESSEREQUAL: result = i1 <= i2; break; } } else { BinaryRuntimeError(operand1, operand2, op); } break; case ValType.Float: float f1 = (float)operand1.Value; if (operand2.Type == ValType.Integer) { //do flt math float f2 = (float)(int)operand2.Value; switch (op) { case TokenType.EQUAL: result = f1 == f2; break; case TokenType.NOTEQUAL: result = f1 != f2; break; case TokenType.LARGER: result = f1 > f2; break; case TokenType.LARGEREQUAL: result = f1 >= f2; break; case TokenType.LESSER: result = f1 < f2; break; case TokenType.LESSEREQUAL: result = f1 <= f2; break; } } else { BinaryRuntimeError(operand1, operand2, op); } break; case ValType.Char: int c1 = (int)(char)operand1.Value; if (operand2.Type == ValType.Integer) { //do int comparison int c2 = (int)(char)operand2.Value; switch (op) { case TokenType.EQUAL: result = c1 == c2; break; case TokenType.NOTEQUAL: result = c1 != c2; break; case TokenType.LARGER: result = c1 > c2; break; case TokenType.LARGEREQUAL: result = c1 >= c2; break; case TokenType.LESSER: result = c1 < c2; break; case TokenType.LESSEREQUAL: result = c1 <= c2; break; } } else { BinaryRuntimeError(operand1, operand2, op); } break; case ValType.Bool: //cause there is no boolean comparison operator with mixed type BinaryRuntimeError(operand1, operand2, op); break; case ValType.String: //cause there is no string comparison operator with mixed type BinaryRuntimeError(operand1, operand2, op); break; case ValType.Null: BinaryRuntimeError(operand1, operand2, op); break; } return(result); } bool TypeTesting(StackValue operand1, StackValue operand2, TokenType op) { ValType type = operand2.CastTo <ValType>(); switch (op) { case TokenType.EQUAL: case TokenType.NOTEQUAL: if (operand1.Type != ValType.Type) { return(false); } else { var type2 = operand1.CastTo <ValType>(); return(op == TokenType.EQUAL ? type == type2 : !(type == type2)); } case TokenType.IS: // <value> is <Type> return(operand1.Type == type); } return(false); } #endregion #region evaluate expression void EvaluateBinaryOperation(StackValue operand1, StackValue operand2, TokenType op) { var v1 = ResolveStackValue(operand1); var v2 = ResolveStackValue(operand2); if (v1.Type == v2.Type) { switch (v1.Type) { case ValType.Integer: switch (op) { case TokenType.PLUS: case TokenType.MINUS: case TokenType.MULTIPLY: case TokenType.DIVIDE: case TokenType.MODULO: Push(IntegerOperation(v1, v2, op)); break; case TokenType.EXPONENT: Push(FloatOperation(v1, v2, TokenType.EXPONENT)); break; case TokenType.EQUAL: case TokenType.NOTEQUAL: case TokenType.LARGER: case TokenType.LARGEREQUAL: case TokenType.LESSER: case TokenType.LESSEREQUAL: Push(IntComparison(v1, v2, op)); break; default: BinaryRuntimeError(v1, v2, op); break; } break; case ValType.Float: switch (op) { case TokenType.PLUS: case TokenType.MINUS: case TokenType.MULTIPLY: case TokenType.DIVIDE: case TokenType.EXPONENT: Push(FloatOperation(v1, v2, op)); break; case TokenType.EQUAL: case TokenType.NOTEQUAL: case TokenType.LARGER: case TokenType.LARGEREQUAL: case TokenType.LESSER: case TokenType.LESSEREQUAL: Push(FloatComparison(v1, v2, op)); break; default: BinaryRuntimeError(v1, v2, op); break; } break; case ValType.Bool: switch (op) { case TokenType.AND: case TokenType.OR: case TokenType.XOR: Push(BoolOperation(v1, v2, op)); break; case TokenType.EQUAL: case TokenType.NOTEQUAL: Push(BoolComparison(v1, v2, op)); break; default: BinaryRuntimeError(v1, v2, op); break; } break; case ValType.Char: //concat char switch (op) { case TokenType.PLUS: Push(StringOperation(v1, v2, TokenType.PLUS)); break; case TokenType.EQUAL: case TokenType.NOTEQUAL: case TokenType.LARGER: case TokenType.LARGEREQUAL: case TokenType.LESSER: case TokenType.LESSEREQUAL: Push(CharComparison(v1, v2, op)); break; default: BinaryRuntimeError(v1, v2, op); break; } break; case ValType.String: //concat string switch (op) { case TokenType.PLUS: Push(StringOperation(v1, v2, TokenType.PLUS)); break; case TokenType.EQUAL: case TokenType.NOTEQUAL: case TokenType.LARGER: case TokenType.LARGEREQUAL: case TokenType.LESSER: case TokenType.LESSEREQUAL: Push(StringComparison(v1, v2, op)); break; default: BinaryRuntimeError(v1, v2, op); break; } break; case ValType.Null: BinaryRuntimeError(v1, v2, op); break; case ValType.Type: switch (op) { case TokenType.EQUAL: case TokenType.NOTEQUAL: Push(TypeTesting(v1, v2, op)); break; default: BinaryRuntimeError(v1, v2, op); break; } break; default: switch (op) { case TokenType.IS: Push(TypeTesting(v1, v2, op)); break; default: BinaryRuntimeError(v1, v2, op); break; } break; } } else { switch (v1.Type) { case ValType.Integer: if (v2.Type == ValType.Float) { //do flt math switch (op) { case TokenType.PLUS: case TokenType.MINUS: case TokenType.MULTIPLY: case TokenType.DIVIDE: case TokenType.EXPONENT: Push(FloatOperation(v1, v2, op)); break; case TokenType.EQUAL: case TokenType.NOTEQUAL: case TokenType.LARGER: case TokenType.LARGEREQUAL: case TokenType.LESSER: case TokenType.LESSEREQUAL: Push(Comparison(v1, v2, op)); break; } } else if (v2.Type == ValType.Char) { //do int math switch (op) { case TokenType.PLUS: case TokenType.MINUS: case TokenType.MULTIPLY: case TokenType.DIVIDE: Push(IntegerOperation(v1, v2, op)); break; case TokenType.EXPONENT: Push(FloatOperation(v1, v2, TokenType.EXPONENT)); break; case TokenType.EQUAL: case TokenType.NOTEQUAL: case TokenType.LARGER: case TokenType.LARGEREQUAL: case TokenType.LESSER: case TokenType.LESSEREQUAL: Push(Comparison(v1, v2, op)); break; } } else if (op == TokenType.IS) { Push(TypeTesting(v1, v2, op)); } else { BinaryRuntimeError(v1, v2, op); } break; case ValType.Float: if (v2.Type == ValType.Integer) { //do flt math switch (op) { case TokenType.PLUS: case TokenType.MINUS: case TokenType.MULTIPLY: case TokenType.DIVIDE: case TokenType.EXPONENT: Push(FloatOperation(v1, v2, op)); break; case TokenType.EQUAL: case TokenType.NOTEQUAL: case TokenType.LARGER: case TokenType.LARGEREQUAL: case TokenType.LESSER: case TokenType.LESSEREQUAL: Push(Comparison(v1, v2, op)); break; } } else if (op == TokenType.IS) { Push(TypeTesting(v1, v2, op)); } else { BinaryRuntimeError(v1, v2, op); } break; case ValType.Char: switch (op) { case TokenType.EQUAL: case TokenType.NOTEQUAL: case TokenType.LARGER: case TokenType.LARGEREQUAL: case TokenType.LESSER: case TokenType.LESSEREQUAL: Push(Comparison(v1, v2, op)); break; case TokenType.IS: Push(TypeTesting(v1, v2, op)); break; default: BinaryRuntimeError(v1, v2, op); break; } break; case ValType.Bool: if (op == TokenType.IS) { Push(TypeTesting(v1, v2, op)); } else { BinaryRuntimeError(v1, v2, op); } break; case ValType.String: //concat string if (op == TokenType.PLUS) { Push(StringOperation(v1, v2, TokenType.PLUS)); } else if (op == TokenType.IS) { Push(TypeTesting(v1, v2, op)); } else if (op == TokenType.IS) { Push(TypeTesting(v1, v2, op)); } else { BinaryRuntimeError(v1, v2, op); } break; default: switch (op) { case TokenType.IS: Push(TypeTesting(v1, v2, op)); break; default: BinaryRuntimeError(v1, v2, op); break; } break; } } } void EvaluateUnaryOperation(StackValue operand, TokenType op) { var v = ResolveStackValue(operand); switch (op) { case TokenType.MINUS: if (v.Type == ValType.Integer) { int i = v.CastTo <int>(); Push(-i); } else if (v.Type == ValType.Float) { float f = v.CastTo <float>(); Push(-f); } else { UnaryRuntimeError(operand, op); } break; case TokenType.NOT: if (v.Type == ValType.Bool) { bool b = v.CastTo <bool>(); Push(!b); } break; case TokenType.TYPEOF: Push(v.Type); break; } } #endregion #region visit the astnode Expression.Accept(this); #endregion #region process operand if (EvaluationStack.Count == 0) { return(StackValue.Null); } ReverseStack(); while (EvaluationStack.Count > 1) { StackValue operand1 = EvaluationStack.Pop(); StackValue operand2 = EvaluationStack.Pop(); TokenType op; if (operand2.Type == ValType.Operator) { //unary opearation op = (TokenType)operand2.Value; EvaluateUnaryOperation(operand1, op); } else { var tots = EvaluationStack.Pop(); op = (TokenType)tots.Value; if (op == TokenType.ASSIGN) { //do assignment //todo check type var varname = (string)operand2.Value; if (!CurrentScope.Contain(varname)) { RuntimeError($"{varname} is not defined"); } CurrentScope.Assign(varname, ResolveStackValue(operand1).Value); Push(ResolveStackValue(operand2)); } else if (op == TokenType.VAR) { //declare a variable in the environment var varname = operand2.CastTo <string>(); if (CurrentScope.Contain(varname)) { RuntimeError($"{varname} already defined"); } CurrentScope.Define(varname, ResolveStackValue(operand1).Value); Push(ResolveStackValue(operand2)); } else { EvaluateBinaryOperation(operand1, operand2, op); } } } return(ResolveStackValue(EvaluationStack.Pop())); #endregion }