001: /*
002: * Created on 11.07.2004
003: */
004: package net.sourceforge.pmd.dfa;
005:
006: import java.util.ArrayList;
007: import java.util.List;
008:
009: /**
010: * @author raik
011: * <p/>
012: * Computes the first sequence in a list.
013: * <p/>
014: * e.g.
015: * IF_START 0
016: * WHILE_EXPR 1
017: * WHILE_END 2
018: * IF_END 3
019: * <p/>
020: * The first sequence is WHILE_EXPR und WHILE_END. It returns always the
021: * first inner nested scope.
022: */
023: public class SequenceChecker {
024:
025: /*
026: * Element of logical structure of brace nodes.
027: * */
028: private static class Status {
029: public static final int ROOT = -1;
030:
031: private List<Status> nextSteps = new ArrayList<Status>();
032: private int type;
033: private boolean lastStep;
034:
035: public Status(int type) {
036: this (type, false);
037: }
038:
039: public Status(int type, boolean lastStep) {
040: this .type = type;
041: this .lastStep = lastStep;
042: }
043:
044: public void addStep(Status type) {
045: nextSteps.add(type);
046: }
047:
048: public Status step(int type) {
049: for (int i = 0; i < this .nextSteps.size(); i++) {
050: if (type == nextSteps.get(i).type) {
051: return nextSteps.get(i);
052: }
053: }
054: return null;
055: }
056:
057: public boolean isLastStep() {
058: return this .lastStep;
059: }
060:
061: public boolean hasMoreSteps() {
062: return this .nextSteps.size() > 1;
063: }
064: }
065:
066: private static Status root;
067:
068: static {
069: root = new Status(Status.ROOT);
070: Status ifNode = new Status(NodeType.IF_EXPR);
071: Status ifSt = new Status(NodeType.IF_LAST_STATEMENT);
072: Status ifStWithoutElse = new Status(
073: NodeType.IF_LAST_STATEMENT_WITHOUT_ELSE, true);
074: Status elseSt = new Status(NodeType.ELSE_LAST_STATEMENT, true);
075: Status whileNode = new Status(NodeType.WHILE_EXPR);
076: Status whileSt = new Status(NodeType.WHILE_LAST_STATEMENT, true);
077: Status switchNode = new Status(NodeType.SWITCH_START);
078: Status caseSt = new Status(NodeType.CASE_LAST_STATEMENT);
079: Status switchDefault = new Status(
080: NodeType.SWITCH_LAST_DEFAULT_STATEMENT);
081: Status switchEnd = new Status(NodeType.SWITCH_END, true);
082:
083: Status forInit = new Status(NodeType.FOR_INIT);
084: Status forExpr = new Status(NodeType.FOR_EXPR);
085: Status forUpdate = new Status(NodeType.FOR_UPDATE);
086: Status forSt = new Status(NodeType.FOR_BEFORE_FIRST_STATEMENT);
087: Status forEnd = new Status(NodeType.FOR_END, true);
088:
089: Status doSt = new Status(NodeType.DO_BEFORE_FIRST_STATEMENT);
090: Status doExpr = new Status(NodeType.DO_EXPR, true);
091:
092: Status labelNode = new Status(NodeType.LABEL_STATEMENT);
093: Status labelEnd = new Status(NodeType.LABEL_LAST_STATEMENT,
094: true);
095:
096: root.addStep(ifNode);
097: root.addStep(whileNode);
098: root.addStep(switchNode);
099: root.addStep(forInit);
100: root.addStep(forExpr);
101: root.addStep(forUpdate);
102: root.addStep(forSt);
103: root.addStep(doSt);
104: root.addStep(labelNode);
105:
106: ifNode.addStep(ifSt);
107: ifNode.addStep(ifStWithoutElse);
108: ifSt.addStep(elseSt);
109: ifStWithoutElse.addStep(root);
110: elseSt.addStep(root);
111:
112: labelNode.addStep(labelEnd);
113: labelEnd.addStep(root);
114:
115: whileNode.addStep(whileSt);
116: whileSt.addStep(root);
117:
118: switchNode.addStep(caseSt);
119: switchNode.addStep(switchDefault);
120: switchNode.addStep(switchEnd);
121: caseSt.addStep(caseSt);
122: caseSt.addStep(switchDefault);
123: caseSt.addStep(switchEnd);
124: switchDefault.addStep(switchEnd);
125: switchDefault.addStep(caseSt);
126: switchEnd.addStep(root);
127:
128: forInit.addStep(forExpr);
129: forInit.addStep(forUpdate);
130: forInit.addStep(forSt);
131: forExpr.addStep(forUpdate);
132: forExpr.addStep(forSt);
133: forUpdate.addStep(forSt);
134: forSt.addStep(forEnd);
135: forEnd.addStep(root);
136:
137: doSt.addStep(doExpr);
138: doExpr.addStep(root);
139: }
140:
141: private Status aktStatus;
142: private List bracesList;
143:
144: private int firstIndex = -1;
145: private int lastIndex = -1;
146:
147: /*
148: * Defines the logical structure.
149: * */
150: public SequenceChecker(List bracesList) {
151: this .aktStatus = root;
152: this .bracesList = bracesList;
153: }
154:
155: /**
156: * Finds the first most inner sequence e.g IFStart & IFEnd. If no sequence
157: * is found or the list is empty the method returns false.
158: */
159: public boolean run() {
160: this .aktStatus = root;
161: this .firstIndex = 0;
162: this .lastIndex = 0;
163: boolean lookAhead = false;
164:
165: for (int i = 0; i < this .bracesList.size(); i++) {
166: StackObject so = (StackObject) bracesList.get(i);
167: aktStatus = this .aktStatus.step(so.getType());
168:
169: if (aktStatus == null) {
170: if (lookAhead) {
171: this .lastIndex = i - 1;
172: return false;
173: }
174: this .aktStatus = root;
175: this .firstIndex = i;
176: i--;
177: continue;
178: } else {
179: if (aktStatus.isLastStep() && !aktStatus.hasMoreSteps()) {
180: this .lastIndex = i;
181: return false;
182: } else if (aktStatus.isLastStep()
183: && aktStatus.hasMoreSteps()) {
184: lookAhead = true;
185: this .lastIndex = i;
186: }
187: }
188: }
189: return this .firstIndex == this .lastIndex;
190: }
191:
192: public int getFirstIndex() {
193: return this .firstIndex;
194: }
195:
196: public int getLastIndex() {
197: return this.lastIndex;
198: }
199:
200: }
|