001: /*=============================================================================
002: * Copyright Texas Instruments 2004. All Rights Reserved.
003: *
004: * This program is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2 of the License, or (at your option) any later version.
008: *
009: * This program is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */
018:
019: package oscript.compiler;
020:
021: import oscript.exceptions.*;
022: import org.apache.bcel.generic.BranchInstruction;
023: import java.util.*;
024:
025: /**
026: * A stack of <code>LoopStackNode</code> is used to track loop bodies, and
027: * related things, such as cleanup instructions that need to be inserted prior
028: * to a jump or return out of a loop.
029: */
030: class LoopStackNode {
031: private static final LinkedList EMPTY_LIST = new LinkedList();
032:
033: private LoopStackNode prev;
034: private LinkedList cleanupList;
035: private LinkedList breakInstructionList;
036: private LinkedList continueInstructionList;
037:
038: /**
039: * Class Constructor.
040: */
041: LoopStackNode(LoopStackNode prev) {
042: this .prev = prev;
043: }
044:
045: /**
046: * Pop the current loop-stack node off the stack, returning the next in
047: * the stack.
048: */
049: LoopStackNode pop() {
050: if ((cleanupList != null) && (cleanupList.size() > 0))
051: throw new ProgrammingErrorException(
052: "unremoved cleanup instruction generator!");
053: return prev;
054: }
055:
056: /**
057: * Add a branch instruction used to implement a "break". The branch target
058: * of this instruction will be set appropriately before this loop stack node
059: * is popped off the stack. <!-- currently done by "while" loop visitor -->
060: */
061: void addBreakBranchInstruction(BranchInstruction bi) {
062: if (breakInstructionList == null)
063: breakInstructionList = new LinkedList();
064: breakInstructionList.add(bi);
065: }
066:
067: /**
068: * Add a branch instruction used to implement a "continue". The branch target
069: * of this instruction will be set appropriately before this loop stack node
070: * is popped off the stack. <!-- currently done by "while" loop visitor -->
071: */
072: void addContinueBranchInstruction(BranchInstruction bi) {
073: if (continueInstructionList == null)
074: continueInstructionList = new LinkedList();
075: continueInstructionList.add(bi);
076: }
077:
078: /**
079: *
080: */
081: Collection getContinueInstructions() {
082: if (continueInstructionList == null)
083: return EMPTY_LIST;
084: return continueInstructionList;
085: }
086:
087: /**
088: *
089: */
090: Collection getBreakInstructions() {
091: if (breakInstructionList == null)
092: return EMPTY_LIST;
093: return breakInstructionList;
094: }
095:
096: /**
097: * Add a clean-up instruction generator that will be called in the case of
098: * a jump/return out of this loop body. The instruction generator should
099: * be removed after visiting the children of the syntax-tree node visit
100: * that added the generator. The instruction generator should not itself
101: * add/remove instruction generators, and it should not cause a net change
102: * to the stack height. Note that the instruction generator may be called
103: * multiple times if there are multiple points of jump/return out the loop
104: * body.
105: */
106: void addCleanupInstructionGenerator(CleanupInstructionGenerator g) {
107: if (cleanupList == null)
108: cleanupList = new LinkedList();
109: cleanupList.addFirst(g); // XXX I think we want to run most recently added generator first?
110: }
111:
112: /**
113: * Remove a clean-up instruction generator.
114: */
115: void removeCleanupInstructionGenerator(CleanupInstructionGenerator g) {
116: cleanupList.remove(g);
117: }
118:
119: /**
120: * Called in the case of a jump/return out of this loop body.
121: *
122: * @param il the instruction list to insert instructions into
123: * @param all <code>true</code> if "return" type exception that exits all
124: * loop frames, or <code>false</code> if "break" or "continue" type jump
125: * out of just this loop frame.
126: */
127: void insertCleanupInstructions(CompilerInstructionList il,
128: boolean all) {
129: if (cleanupList != null)
130: for (Iterator itr = cleanupList.iterator(); itr.hasNext();)
131: ((CleanupInstructionGenerator) (itr.next()))
132: .generate(il);
133: if (all && (prev != null))
134: prev.insertCleanupInstructions(il, all);
135: }
136:
137: /**
138: * A cleanup-instruction-generator is a generic interface that other parts
139: * of the compiler can use if they need to generate cleanpup instructions
140: * before a jump out of a loop body. This gives other parts of the compiler
141: * that need to generate instructions to perform cleanup (such as running
142: * "finally"s or releasing monitors) a chance to do that.
143: */
144: public interface CleanupInstructionGenerator {
145: /**
146: * Called when there is a jump out of the loop body (as opposed to normal
147: * completion of loop).
148: *
149: * @param il the instruction list to insert instructions into
150: */
151: public void generate(CompilerInstructionList il);
152: }
153: }
154:
155: /*
156: * Local Variables:
157: * tab-width: 2
158: * indent-tabs-mode: nil
159: * mode: java
160: * c-indentation-style: java
161: * c-basic-offset: 2
162: * eval: (c-set-offset 'substatement-open '0)
163: * eval: (c-set-offset 'case-label '+)
164: * eval: (c-set-offset 'inclass '+)
165: * eval: (c-set-offset 'inline-open '0)
166: * End:
167: */
|