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);
        }
Ejemplo n.º 2
0
        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);
                }
            }
        }