private void ParsePenCommand(ParseTreeNode node) { var commandNode = node.ChildNodes[0]; switch (commandNode.Term.Name) { case "PEN_UP": this.OnPenUp(EventArgs.Empty); break; case "PEN_DOWN": this.OnPenDown(EventArgs.Empty); break; case "SET_PEN_COLOR": switch (commandNode.ChildNodes[1].Term.Name) { case "TUPLE": var rgb = new List <float>(); ParseTupleValues(commandNode.ChildNodes[1], rgb); if (rgb.Count != 3) { throw new ParsingException("Incorrect command invocation.", new[] { ParsingError.FromParseTreeNode(node, $"The number of arguments must be 3, instead of {rgb.Count}.") }); } if (rgb.Any(v => v < 0 || v > 255)) { throw new ParsingException("Command parameters are out of range.", new[] { ParsingError.FromParseTreeNode(node, "The parameter value should be greater than or equal to 0 and less than or equal to 255.") }); } this.OnSetPenColor(new PenColorEventArgs(Convert.ToInt32(rgb[0]), Convert.ToInt32(rgb[1]), Convert.ToInt32(rgb[2]))); break; case "EXPRESSION": var evaluation = this.EvaluateArithmeticExpression(commandNode.ChildNodes[1]); var colorIndex = Convert.ToInt32(evaluation.Value) % 16; var colorValue = colorTable[colorIndex]; this.OnSetPenColor(new PenColorEventArgs(colorValue.Item1, colorValue.Item2, colorValue.Item3)); break; } break; } }
private Evaluation EvaluateArithmeticExpression(ParseTreeNode expression) { switch (expression.Term.Name) { case "EXPRESSION": if (expression.ChildNodes.Count == 1) { return(EvaluateArithmeticExpression(expression.ChildNodes[0])); } else if (expression.ChildNodes.Count == 3 && expression.ChildNodes[0].Token.Text == "(" && expression.ChildNodes[2].Token.Text == ")") { return(EvaluateArithmeticExpression(expression.ChildNodes[1])); } else { throw new RuntimeException($"Invalid expression at: {expression.Span.Location}"); } case "VARIABLE_REF": var variableName = expression.ChildNodes[1].Token.Text; if (!CurrentProcedureScope.Exists(variableName)) { throw new ParsingException("Variable has not been defined.", new[] { ParsingError.FromParseTreeNode(expression, $"The requested parameter '{variableName}' is not defined.") }); } return(new ConstantEvaluation(Convert.ToSingle(CurrentProcedureScope[variableName]))); case "BINARY_EXPRESSION": var leftNode = expression.ChildNodes[0]; var operatorNode = expression.ChildNodes[1]; var rightNode = expression.ChildNodes[2]; var leftEvaluation = EvaluateArithmeticExpression(leftNode); var rightEvaluation = EvaluateArithmeticExpression(rightNode); var binaryOperation = BinaryOperation.Add; switch (operatorNode.Term.Name) { case "+": binaryOperation = BinaryOperation.Add; break; case "-": binaryOperation = BinaryOperation.Sub; break; case "*": binaryOperation = BinaryOperation.Mul; break; case "/": binaryOperation = BinaryOperation.Div; break; } return(new BinaryEvaluation(leftEvaluation, rightEvaluation, binaryOperation)); case "REP_COUNT": if (CurrentRepeatScope != null) { return(new ConstantEvaluation(CurrentRepeatScope.RepCount)); } throw new ParsingException("Variable repCount doesn't have a valid value.", new[] { ParsingError.FromParseTreeNode(expression, "Reference to repCount variable is not in a valid REPEAT scope.") }); case "FUNCTION_CALL": var val = ExecuteProcedureCall(expression); return(new ConstantEvaluation(Convert.ToSingle(val))); default: return(new ConstantEvaluation(Convert.ToSingle(expression.Token.Text))); } }