public void Visit(ForNode node) { if (node.Children.Count != 4) { throw new InternalCompilerError("Invalid child count for ForNode"); } if (!(node.Children[0] is IdentifierNode)) { throw new InternalCompilerError("Invalid node type for loop variable"); } var loopVariable = (IdentifierNode)node.Children[0]; loopVariable.Accept(this); if (loopVariable.NodeType() != VariableType.INTEGER && loopVariable.NodeType() != VariableType.ERROR_TYPE) { reporter.ReportError( Error.SEMANTIC_ERROR, "Loop control variable must have type '" + VariableType.INTEGER.Name() + "'" + " but has type '" + loopVariable.NodeType().Name() + "'", loopVariable.Line, loopVariable.Column); NoteVariableWasDeclaredHere(loopVariable.Name); } var acceptableTypes = new List<VariableType> { VariableType.INTEGER }; var startExpression = node.Children[1]; HandleExpression(startExpression, acceptableTypes); var endExpression = node.Children[2]; HandleExpression(endExpression, acceptableTypes); var loopBody = node.Children[3]; loopBody.Accept(this); CheckLoopControlVariableUsageInStartEndExpression(node, loopVariable, startExpression, endExpression); CheckVariableAssignmentUsedInStartEndExpression(loopVariable, startExpression, endExpression, loopBody); CheckLoopControlVariableAssignmentInBody(node, loopVariable, loopBody); }
public void Visit(ForNode node) { // Extremely naive strategy: // Create new variable for end condition, and never reuse it elsewhere var loop_counter = symbolTable[((IdentifierNode)node.Children[0]).Name].id; var endVariable = variableId++; // Initialize loop counter node.Children[1].Accept(this); Emit(Bytecode.STORE_VARIABLE); Emit(loop_counter); // initialize end varible node.Children[2].Accept(this); Emit(Bytecode.STORE_VARIABLE); Emit(endVariable); var jumpTarget = bytecode.Count; node.Children[3].Accept(this); // increase loop counter Emit(Bytecode.PUSH_INT_VAR); Emit(loop_counter); Emit(Bytecode.PUSH_INT); Emit(1L); Emit(Bytecode.ADD); Emit(Bytecode.STORE_VARIABLE); Emit(loop_counter); // do start\end comparison Emit(Bytecode.PUSH_INT_VAR); Emit(loop_counter); Emit(Bytecode.PUSH_INT_VAR); Emit(endVariable); Emit(Bytecode.IS_LESS_OR_EQUAL_INT); // and jump, based on results Emit(Bytecode.JUMP_IF_TRUE); Emit(jumpTarget); }
private void CheckLoopControlVariableUsageInStartEndExpression(ForNode node, IdentifierNode loopVariable, Node startExpression, Node endExpression) { var stack = new Stack<Node>(); stack.Push(endExpression); stack.Push(startExpression); while (stack.Count != 0) { var current = stack.Pop(); if (current is IdentifierNode && ((IdentifierNode)current).Name == loopVariable.Name) { reporter.ReportError( Error.WARNING, "Possibly incorrect or confusing usage of loop control variable '" + loopVariable.Name + "' in loop expression", current.Line, current.Column); reporter.ReportError( Error.NOTE, "Loop is here", node.Line, node.Column); reporter.ReportError( Error.NOTE_GENERIC, "Loop start and end expressions are evaluated only once before entering the loop", 0, 0); break; } foreach (var child in current.Children) { stack.Push(child); } } }
private void CheckLoopControlVariableAssignmentInBody(ForNode node, IdentifierNode loopVariable, Node loopBody) { var stack = new Stack<Node>(); stack.Push(loopBody); while (stack.Count != 0) { var current = stack.Pop(); if (current is VariableAssignmentNode && ((VariableAssignmentNode)current).Name == loopVariable.Name) { reporter.ReportError( Error.SEMANTIC_ERROR, "Cannot reassign control variable '" + loopVariable.Name + "'", current.Line, current.Column); reporter.ReportError( Error.NOTE, "Loop is here", node.Line, node.Column); break; } foreach (var child in current.Children) { stack.Push(child); } } }