|
@@ -46,7 +46,7 @@ public class ConditionTree {
|
46
|
46
|
/** Doesn't do anything (an empty tree). */
|
47
|
47
|
NOOP
|
48
|
48
|
}
|
49
|
|
-
|
|
49
|
+
|
50
|
50
|
/** The left subtree of this tree. */
|
51
|
51
|
private ConditionTree leftArg = null;
|
52
|
52
|
|
|
@@ -57,11 +57,11 @@ public class ConditionTree {
|
57
|
57
|
private int argument = -1;
|
58
|
58
|
|
59
|
59
|
/** The operation that this tree performs. */
|
60
|
|
- private OPERATION op;
|
61
|
|
-
|
|
60
|
+ private final OPERATION op;
|
|
61
|
+
|
62
|
62
|
/**
|
63
|
63
|
* Creates a new ConditionTree for a binary operation.
|
64
|
|
- *
|
|
64
|
+ *
|
65
|
65
|
* @param op The binary operation to perform
|
66
|
66
|
* @param leftArg The left argument/subtree
|
67
|
67
|
* @param rightArg The right argument/subtree
|
|
@@ -72,46 +72,46 @@ public class ConditionTree {
|
72
|
72
|
assert(op != OPERATION.NOT);
|
73
|
73
|
assert(leftArg != null);
|
74
|
74
|
assert(rightArg != null);
|
75
|
|
-
|
|
75
|
+
|
76
|
76
|
this.op = op;
|
77
|
77
|
this.leftArg = leftArg;
|
78
|
78
|
this.rightArg = rightArg;
|
79
|
79
|
}
|
80
|
|
-
|
|
80
|
+
|
81
|
81
|
/**
|
82
|
82
|
* Creates a new ConditionTree for a unary operation.
|
83
|
|
- *
|
|
83
|
+ *
|
84
|
84
|
* @param op
|
85
|
85
|
* @param argument
|
86
|
86
|
*/
|
87
|
87
|
private ConditionTree(final OPERATION op, final ConditionTree argument) {
|
88
|
88
|
assert(op == OPERATION.NOT);
|
89
|
|
-
|
|
89
|
+
|
90
|
90
|
this.op = op;
|
91
|
91
|
this.leftArg = argument;
|
92
|
|
- }
|
93
|
|
-
|
|
92
|
+ }
|
|
93
|
+
|
94
|
94
|
/**
|
95
|
95
|
* Creates a new ConditionTree for a VAR operation with the specified
|
96
|
96
|
* argument number.
|
97
|
|
- *
|
|
97
|
+ *
|
98
|
98
|
* @param argument The number of the argument that's to be tested.
|
99
|
99
|
*/
|
100
|
100
|
private ConditionTree(final int argument) {
|
101
|
101
|
this.op = OPERATION.VAR;
|
102
|
102
|
this.argument = argument;
|
103
|
103
|
}
|
104
|
|
-
|
|
104
|
+
|
105
|
105
|
/**
|
106
|
106
|
* Creates a new ConditionTree for a NOOP operation.
|
107
|
107
|
*/
|
108
|
108
|
private ConditionTree() {
|
109
|
109
|
this.op = OPERATION.NOOP;
|
110
|
110
|
}
|
111
|
|
-
|
|
111
|
+
|
112
|
112
|
/**
|
113
|
113
|
* Retrieves the highest argument number that is used in this condition tree.
|
114
|
|
- *
|
|
114
|
+ *
|
115
|
115
|
* @return The highest argument number used in this tree
|
116
|
116
|
*/
|
117
|
117
|
public int getMaximumArgument() {
|
|
@@ -129,7 +129,7 @@ public class ConditionTree {
|
129
|
129
|
/**
|
130
|
130
|
* Evaluates this tree with the specified conditions. Returns the result
|
131
|
131
|
* of the evaluation.
|
132
|
|
- *
|
|
132
|
+ *
|
133
|
133
|
* @param conditions The binary values of each of the conditions used in
|
134
|
134
|
* this three
|
135
|
135
|
* @return The result of the evaluation of this tree
|
|
@@ -148,13 +148,13 @@ public class ConditionTree {
|
148
|
148
|
return true;
|
149
|
149
|
}
|
150
|
150
|
}
|
151
|
|
-
|
|
151
|
+
|
152
|
152
|
/**
|
153
|
153
|
* Retrieves a String representation of this ConditionTree. The string
|
154
|
154
|
* representation is a normalised formula describing this tree and all of
|
155
|
155
|
* its children. The output of this method will generate an identical tree
|
156
|
156
|
* if passed to parseString.
|
157
|
|
- *
|
|
157
|
+ *
|
158
|
158
|
* @return A string representation of this tree
|
159
|
159
|
*/
|
160
|
160
|
@Override
|
|
@@ -173,42 +173,42 @@ public class ConditionTree {
|
173
|
173
|
default:
|
174
|
174
|
return "<unknown>";
|
175
|
175
|
}
|
176
|
|
- }
|
177
|
|
-
|
|
176
|
+ }
|
|
177
|
+
|
178
|
178
|
/**
|
179
|
179
|
* Parses the specified string into a condition tree.
|
180
|
|
- *
|
|
180
|
+ *
|
181
|
181
|
* @param string The string to be parsed
|
182
|
182
|
* @return The corresponding condition tree, or null if there was an error
|
183
|
183
|
* while parsing the data
|
184
|
184
|
*/
|
185
|
185
|
public static ConditionTree parseString(final String string) {
|
186
|
186
|
final Deque<Object> stack = new ArrayDeque<Object>();
|
187
|
|
-
|
|
187
|
+
|
188
|
188
|
for (int i = 0; i < string.length(); i++) {
|
189
|
189
|
final char m = string.charAt(i);
|
190
|
|
-
|
|
190
|
+
|
191
|
191
|
if (isInt(m)) {
|
192
|
|
- String temp = "" + m;
|
193
|
|
-
|
|
192
|
+ String temp = String.valueOf(m);
|
|
193
|
+
|
194
|
194
|
while (i + 1 < string.length() && isInt(string.charAt(i + 1))) {
|
195
|
195
|
temp = temp + string.charAt(i + 1);
|
196
|
196
|
i++;
|
197
|
197
|
}
|
198
|
|
-
|
|
198
|
+
|
199
|
199
|
stack.add(new ConditionTree(Integer.parseInt(temp)));
|
200
|
200
|
} else if (m != ' ' && m != '\t' && m != '\n' && m != '\r') {
|
201
|
201
|
stack.add(m);
|
202
|
202
|
}
|
203
|
203
|
}
|
204
|
|
-
|
|
204
|
+
|
205
|
205
|
return parseStack(stack);
|
206
|
206
|
}
|
207
|
|
-
|
|
207
|
+
|
208
|
208
|
/**
|
209
|
209
|
* Parses the specified stack of elements, and returns a corresponding
|
210
|
210
|
* ConditionTree.
|
211
|
|
- *
|
|
211
|
+ *
|
212
|
212
|
* @param stack The stack to be read.
|
213
|
213
|
* @return The corresponding condition tree, or null if there was an error
|
214
|
214
|
* while parsing the data.
|
|
@@ -216,10 +216,10 @@ public class ConditionTree {
|
216
|
216
|
@SuppressWarnings("fallthrough")
|
217
|
217
|
private static ConditionTree parseStack(final Deque<Object> stack) {
|
218
|
218
|
final Deque<Object> myStack = new ArrayDeque<Object>();
|
219
|
|
-
|
|
219
|
+
|
220
|
220
|
while (!stack.isEmpty()) {
|
221
|
221
|
final Object object = stack.poll();
|
222
|
|
-
|
|
222
|
+
|
223
|
223
|
if (object instanceof Character && ((Character) object) == ')') {
|
224
|
224
|
final ConditionTree bracket = readBracket(myStack);
|
225
|
225
|
|
|
@@ -232,34 +232,36 @@ public class ConditionTree {
|
232
|
232
|
myStack.add(object);
|
233
|
233
|
}
|
234
|
234
|
}
|
235
|
|
-
|
|
235
|
+
|
236
|
236
|
while (!myStack.isEmpty()) {
|
237
|
237
|
switch (myStack.size()) {
|
238
|
238
|
case 1:
|
239
|
239
|
final Object first = myStack.pollFirst();
|
240
|
240
|
if (first instanceof ConditionTree) {
|
241
|
241
|
return (ConditionTree) first;
|
242
|
|
- }
|
|
242
|
+ }
|
243
|
243
|
case 0:
|
244
|
244
|
return null;
|
245
|
245
|
}
|
246
|
|
-
|
|
246
|
+
|
247
|
247
|
final ConditionTree first = readTerm(myStack);
|
248
|
|
-
|
|
248
|
+
|
249
|
249
|
if (first == null) {
|
250
|
250
|
return null;
|
251
|
251
|
} else if (myStack.isEmpty()) {
|
252
|
252
|
return first;
|
253
|
253
|
}
|
254
|
|
-
|
|
254
|
+
|
255
|
255
|
final Object second = myStack.pollFirst();
|
256
|
|
-
|
257
|
|
- if (!myStack.isEmpty()) {
|
|
256
|
+
|
|
257
|
+ if (myStack.isEmpty()) {
|
|
258
|
+ return null;
|
|
259
|
+ } else {
|
258
|
260
|
final ConditionTree third = readTerm(myStack);
|
259
|
|
-
|
|
261
|
+
|
260
|
262
|
if (first != null && third != null && second instanceof Character) {
|
261
|
263
|
OPERATION op;
|
262
|
|
-
|
|
264
|
+
|
263
|
265
|
if ((Character) second == '&') {
|
264
|
266
|
op = OPERATION.AND;
|
265
|
267
|
} else if ((Character) second == '|') {
|
|
@@ -267,48 +269,46 @@ public class ConditionTree {
|
267
|
269
|
} else {
|
268
|
270
|
return null;
|
269
|
271
|
}
|
270
|
|
-
|
|
272
|
+
|
271
|
273
|
myStack.addFirst(new ConditionTree(op, first, third));
|
272
|
274
|
} else {
|
273
|
275
|
return null;
|
274
|
276
|
}
|
275
|
|
- } else {
|
276
|
|
- return null;
|
277
|
277
|
}
|
278
|
278
|
}
|
279
|
|
-
|
|
279
|
+
|
280
|
280
|
return new ConditionTree();
|
281
|
281
|
}
|
282
|
|
-
|
|
282
|
+
|
283
|
283
|
/**
|
284
|
284
|
* Reads and returns a single term from the specified stack.
|
285
|
|
- *
|
|
285
|
+ *
|
286
|
286
|
* @param stack The stack to be read
|
287
|
287
|
* @return The ConditionTree representing the last element on the stack,
|
288
|
288
|
* or null if it was not possible to create one.
|
289
|
289
|
*/
|
290
|
290
|
private static ConditionTree readTerm(final Deque<Object> stack) {
|
291
|
291
|
final Object first = stack.pollFirst();
|
292
|
|
-
|
|
292
|
+
|
293
|
293
|
if (first instanceof Character && (Character) first == '!') {
|
294
|
294
|
if (stack.isEmpty()) {
|
295
|
295
|
return null;
|
296
|
296
|
}
|
297
|
|
-
|
|
297
|
+
|
298
|
298
|
return new ConditionTree(OPERATION.NOT, readTerm(stack));
|
299
|
299
|
} else {
|
300
|
300
|
if (!(first instanceof ConditionTree)) {
|
301
|
301
|
return null;
|
302
|
302
|
}
|
303
|
|
-
|
|
303
|
+
|
304
|
304
|
return (ConditionTree) first;
|
305
|
305
|
}
|
306
|
306
|
}
|
307
|
|
-
|
|
307
|
+
|
308
|
308
|
/**
|
309
|
309
|
* Pops elements off of the end of the specified stack until an opening
|
310
|
310
|
* bracket is reached, and then returns the parsed content of the bracket.
|
311
|
|
- *
|
|
311
|
+ *
|
312
|
312
|
* @param stack The stack to be read for the bracket
|
313
|
313
|
* @return The parsed contents of the bracket, or null if the brackets were
|
314
|
314
|
* mismatched.
|
|
@@ -316,74 +316,74 @@ public class ConditionTree {
|
316
|
316
|
private static ConditionTree readBracket(final Deque<Object> stack) {
|
317
|
317
|
final Deque<Object> tempStack = new ArrayDeque<Object>();
|
318
|
318
|
boolean found = false;
|
319
|
|
-
|
|
319
|
+
|
320
|
320
|
while (!found && !stack.isEmpty()) {
|
321
|
321
|
final Object object = stack.pollLast();
|
322
|
|
-
|
|
322
|
+
|
323
|
323
|
if (object instanceof Character && ((Character) object) == '(') {
|
324
|
324
|
found = true;
|
325
|
325
|
} else {
|
326
|
326
|
tempStack.addFirst(object);
|
327
|
327
|
}
|
328
|
328
|
}
|
329
|
|
-
|
330
|
|
- if (!found) {
|
331
|
|
- return null;
|
332
|
|
- } else {
|
|
329
|
+
|
|
330
|
+ if (found) {
|
333
|
331
|
return parseStack(tempStack);
|
|
332
|
+ } else {
|
|
333
|
+ return null;
|
334
|
334
|
}
|
335
|
335
|
}
|
336
|
|
-
|
|
336
|
+
|
337
|
337
|
/**
|
338
|
338
|
* Determines if the specified character represents a single digit.
|
339
|
|
- *
|
|
339
|
+ *
|
340
|
340
|
* @param target The character to be tested
|
341
|
341
|
* @return True if the character is a digit, false otherwise
|
342
|
342
|
*/
|
343
|
343
|
private static boolean isInt(final char target) {
|
344
|
344
|
return target >= '0' && target <= '9';
|
345
|
345
|
}
|
346
|
|
-
|
|
346
|
+
|
347
|
347
|
/**
|
348
|
348
|
* Creates a condition tree by disjoining the specified number of arguments
|
349
|
349
|
* together.
|
350
|
|
- *
|
|
350
|
+ *
|
351
|
351
|
* @param numArgs The number of arguments to be disjoined
|
352
|
352
|
* @return The corresponding condition tree
|
353
|
353
|
*/
|
354
|
354
|
public static ConditionTree createDisjunction(final int numArgs) {
|
355
|
355
|
final StringBuilder builder = new StringBuilder();
|
356
|
|
-
|
|
356
|
+
|
357
|
357
|
for (int i = 0; i < numArgs; i++) {
|
358
|
358
|
if (builder.length() != 0) {
|
359
|
359
|
builder.append('|');
|
360
|
360
|
}
|
361
|
|
-
|
|
361
|
+
|
362
|
362
|
builder.append(i);
|
363
|
363
|
}
|
364
|
|
-
|
365
|
|
- return parseString(builder.toString());
|
|
364
|
+
|
|
365
|
+ return parseString(builder.toString());
|
366
|
366
|
}
|
367
|
367
|
|
368
|
368
|
/**
|
369
|
369
|
* Creates a condition tree by conjoining the specified number of arguments
|
370
|
370
|
* together.
|
371
|
|
- *
|
|
371
|
+ *
|
372
|
372
|
* @param numArgs The number of arguments to be conjoined
|
373
|
373
|
* @return The corresponding condition tree
|
374
|
|
- */
|
|
374
|
+ */
|
375
|
375
|
public static ConditionTree createConjunction(final int numArgs) {
|
376
|
376
|
final StringBuilder builder = new StringBuilder();
|
377
|
|
-
|
|
377
|
+
|
378
|
378
|
for (int i = 0; i < numArgs; i++) {
|
379
|
379
|
if (builder.length() != 0) {
|
380
|
380
|
builder.append('&');
|
381
|
381
|
}
|
382
|
|
-
|
|
382
|
+
|
383
|
383
|
builder.append(i);
|
384
|
384
|
}
|
385
|
|
-
|
|
385
|
+
|
386
|
386
|
return parseString(builder.toString());
|
387
|
387
|
}
|
388
|
|
-
|
|
388
|
+
|
389
|
389
|
}
|