001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.pde.internal.ui.wizards.templates;
011:
012: import java.util.Hashtable;
013: import java.util.Stack;
014:
015: import org.eclipse.pde.ui.templates.IVariableProvider;
016:
017: public class PreprocessorParser {
018: private static final int T_VAR = 1;
019: private static final int T_LBR = 2;
020: private static final int T_RBR = 3;
021: private static final int T_NOT = 4;
022: private static final int T_AND = 5;
023: private static final int T_OR = 6;
024: private static final int T_EQ = 7;
025: private static final int T_NEQ = 8;
026: private static final int T_STRING = 9;
027: private static final int T_TRUE = 22;
028: private static final int T_FALSE = 23;
029: private static final int T_ERROR = 99;
030: private static final int T_EOF = 10;
031:
032: //private static final int OP_LEAF = -1;
033: private static final int OP_AND = 1;
034: private static final int OP_OR = 2;
035: private static final int OP_EQ = 3;
036: private static final int OP_NEQ = 4;
037: private static final int OP_NOT = 5;
038: //private static final int OP_DEFER = 55;
039:
040: private IVariableProvider provider;
041: private String line;
042: private Stack exprStack;
043: private int loc;
044: private String tvalue;
045:
046: abstract class Node {
047: abstract Object getValue();
048: }
049:
050: class LeafNode extends Node {
051: Object value;
052:
053: LeafNode(Object value) {
054: this .value = value;
055: }
056:
057: public Object getValue() {
058: return value;
059: }
060:
061: public String toString() {
062: if (value != null)
063: return "leaf[" + value.toString() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
064: return "leaf[null]"; //$NON-NLS-1$
065: }
066: }
067:
068: class ExpressionNode extends Node {
069: int opcode;
070: Node left;
071: Node right;
072:
073: public ExpressionNode(Node left, Node right, int opcode) {
074: this .opcode = opcode;
075: this .left = left;
076: this .right = right;
077: }
078:
079: public Object getValue() {
080: boolean result = false;
081: Object leftValue = left != null ? left.getValue()
082: : Boolean.FALSE;
083: Object rightValue = right != null ? right.getValue()
084: : Boolean.FALSE;
085:
086: if (opcode == OP_NOT && rightValue instanceof Boolean) {
087: result = rightValue.equals(Boolean.TRUE) ? false : true;
088: } else {
089:
090: if (leftValue instanceof Boolean
091: && rightValue instanceof Boolean) {
092: boolean bleft = ((Boolean) leftValue)
093: .booleanValue();
094: boolean bright = ((Boolean) rightValue)
095: .booleanValue();
096:
097: switch (opcode) {
098: case OP_AND:
099: result = bleft && bright;
100: break;
101: case OP_OR:
102: result = bleft || bright;
103: break;
104: case OP_EQ:
105: result = bleft == bright;
106: break;
107: case OP_NEQ:
108: result = bleft != bright;
109: break;
110: }
111: }
112: if (leftValue instanceof String
113: && rightValue instanceof String) {
114: switch (opcode) {
115: case OP_EQ:
116: result = leftValue.equals(rightValue);
117: break;
118: case OP_NEQ:
119: result = leftValue.equals(rightValue);
120: break;
121: }
122: }
123: }
124: return result ? Boolean.TRUE : Boolean.FALSE;
125: }
126:
127: public String toString() {
128: String lstring = left != null ? left.toString() : "*"; //$NON-NLS-1$
129: String rstring = right != null ? right.toString() : "*"; //$NON-NLS-1$
130: return "(" + lstring + "<" + opcode + ">" + rstring + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
131: }
132: }
133:
134: class RootEntry {
135: Node root;
136: }
137:
138: public PreprocessorParser() {
139: this (null);
140: }
141:
142: public PreprocessorParser(IVariableProvider provider) {
143: this .provider = provider;
144: exprStack = new Stack();
145: }
146:
147: public void setVariableProvider(IVariableProvider provider) {
148: this .provider = provider;
149: }
150:
151: public static void main(String[] args) {
152: final Hashtable vars = new Hashtable();
153: vars.put("a", Boolean.FALSE); //$NON-NLS-1$
154: vars.put("b", "3"); //$NON-NLS-1$ //$NON-NLS-2$
155: vars.put("c", Boolean.TRUE); //$NON-NLS-1$
156: PreprocessorParser parser = new PreprocessorParser(
157: new IVariableProvider() {
158: public Object getValue(String variable) {
159: return vars.get(variable);
160: }
161: });
162: try {
163: boolean value = parser
164: .parseAndEvaluate("!a || (b==\"2\" && c)"); //$NON-NLS-1$
165: System.out.println("Result: " + value); //$NON-NLS-1$
166: } catch (Exception e) {
167: System.out.println(e);
168: }
169: }
170:
171: public boolean parseAndEvaluate(String line) throws Exception {
172: reset();
173: this .line = line;
174: //System.out.println("Line: " + line);
175: parse();
176: //printExpression();
177: return evaluate();
178: }
179:
180: private boolean evaluate() {
181: boolean result = false;
182: if (exprStack.isEmpty() == false) {
183: RootEntry entry = (RootEntry) exprStack.peek();
184: if (entry.root != null) {
185: Object value = entry.root.getValue();
186: if (value != null && value instanceof Boolean) {
187: if (((Boolean) value).equals(Boolean.TRUE))
188: result = true;
189: }
190: }
191: }
192: return result;
193: }
194:
195: private void reset() {
196: loc = 0;
197: tvalue = null;
198: exprStack.clear();
199: }
200:
201: private void parse() throws Exception {
202: for (;;) {
203: int token = getNextToken();
204: //System.out.println("Token: " + token + ", val=\"" + tvalue+"\"");
205: if (token == T_EOF)
206: break;
207:
208: if (token == T_VAR) {
209: Node node = new LeafNode(provider.getValue(tvalue
210: .toString()));
211: pushNode(node);
212: continue;
213: }
214: if (token == T_TRUE || token == T_FALSE) {
215: Object value = token == T_TRUE ? Boolean.TRUE
216: : Boolean.FALSE;
217: Node node = new LeafNode(value);
218: pushNode(node);
219: continue;
220: }
221: if (token == T_STRING) {
222: Node node = new LeafNode(tvalue);
223: pushNode(node);
224: continue;
225: }
226:
227: if (token == T_NOT) {
228: pushNode(OP_NOT);
229: continue;
230: }
231:
232: int opcode = 0;
233:
234: switch (token) {
235: case T_AND:
236: opcode = OP_AND;
237: break;
238: case T_OR:
239: opcode = OP_OR;
240: break;
241: case T_EQ:
242: opcode = OP_EQ;
243: break;
244: case T_NEQ:
245: opcode = OP_NEQ;
246: break;
247: }
248: if (opcode != 0) {
249: pushNode(opcode);
250: continue;
251: }
252: if (token == T_LBR) {
253: pushRoot();
254: continue;
255: }
256: if (token == T_RBR) {
257: if (exprStack.isEmpty())
258: throwUnexpectedToken("not )", token); //$NON-NLS-1$
259: popRoot();
260: continue;
261: }
262: }
263: }
264:
265: private RootEntry getCurrentRoot() {
266: if (exprStack.isEmpty()) {
267: RootEntry entry = new RootEntry();
268: exprStack.push(entry);
269: }
270: return (RootEntry) exprStack.peek();
271: }
272:
273: private void replaceRoot(ExpressionNode newRoot) {
274: RootEntry entry = getCurrentRoot();
275: if (entry.root != null)
276: newRoot.left = entry.root;
277: entry.root = newRoot;
278: }
279:
280: private void pushNode(Node node) {
281: RootEntry entry = getCurrentRoot();
282: if (entry.root == null)
283: entry.root = node;
284: else {
285: ExpressionNode enode = (ExpressionNode) entry.root;
286: if (enode.opcode == OP_NOT)
287: enode.right = node;
288: else {
289: if (enode.left == null)
290: enode.left = node;
291: else
292: enode.right = node;
293: }
294: }
295: }
296:
297: private void pushNode(int opcode) {
298: ExpressionNode node = new ExpressionNode(null, null, opcode);
299: replaceRoot(node);
300: }
301:
302: private void pushRoot() {
303: exprStack.push(new RootEntry());
304: }
305:
306: private void popRoot() {
307: RootEntry entry = getCurrentRoot();
308: exprStack.pop();
309: pushNode(entry.root);
310: }
311:
312: private void throwUnexpectedToken(String expected, int token)
313: throws Exception {
314: String message = "Expected " + expected + ", found " + token; //$NON-NLS-1$ //$NON-NLS-2$
315: throw new Exception(message);
316: }
317:
318: private int getNextToken() {
319: boolean string = false;
320: boolean variable = false;
321: int vloc = loc;
322: tvalue = null;
323: for (;;) {
324: if (loc == line.length()) {
325: // check if we have panding identifier
326: if (variable) {
327: tvalue = line.substring(vloc, loc);
328: variable = false;
329: if (tvalue.equalsIgnoreCase("false")) //$NON-NLS-1$
330: return T_FALSE;
331: if (tvalue.equalsIgnoreCase("true")) //$NON-NLS-1$
332: return T_TRUE;
333: return T_VAR;
334: }
335: if (string) {
336: // EOF in string
337: string = false;
338: return T_ERROR;
339: }
340: // regular end of line
341: tvalue = "EOF"; //$NON-NLS-1$
342: return T_EOF;
343: }
344: char c = line.charAt(loc++);
345:
346: if (c == '\"') {
347: if (string) {
348: tvalue = line.substring(vloc, loc - 1);
349: string = false;
350: return T_STRING;
351: }
352: vloc = loc;
353: string = true;
354: continue;
355: } else if (string)
356: continue;
357:
358: if (!variable && Character.isJavaIdentifierStart(c)) {
359: variable = true;
360: vloc = loc - 1;
361: continue;
362: }
363: if (variable) {
364: if (!Character.isJavaIdentifierPart(c)) {
365: loc--;
366: tvalue = line.substring(vloc, loc);
367: variable = false;
368: if (tvalue.equalsIgnoreCase("false")) //$NON-NLS-1$
369: return T_FALSE;
370: if (tvalue.equalsIgnoreCase("true")) //$NON-NLS-1$
371: return T_TRUE;
372: return T_VAR;
373: }
374: continue;
375: }
376:
377: if (testDoubleToken(c, "!=")) //$NON-NLS-1$
378: return T_NEQ;
379: if (testDoubleToken(c, "==")) //$NON-NLS-1$
380: return T_EQ;
381: if (testDoubleToken(c, "&&")) //$NON-NLS-1$
382: return T_AND;
383: if (testDoubleToken(c, "||")) //$NON-NLS-1$
384: return T_OR;
385: if (testSingleToken(c, '!'))
386: return T_NOT;
387: if (testSingleToken(c, '('))
388: return T_LBR;
389: if (testSingleToken(c, ')'))
390: return T_RBR;
391: if (c == ' ' || c == '\t' || c == '\n')
392: continue;
393: tvalue = "" + c; //$NON-NLS-1$
394: return T_ERROR;
395: }
396: }
397:
398: private boolean testSingleToken(char c, char expected) {
399: if (c == expected) {
400: tvalue = "" + expected; //$NON-NLS-1$
401: return true;
402: }
403: return false;
404: }
405:
406: private boolean testDoubleToken(char c1, String pattern) {
407: if (c1 != pattern.charAt(0))
408: return false;
409: char c2 = line.charAt(loc);
410: if (c2 == pattern.charAt(1)) {
411: loc++;
412: tvalue = pattern;
413: return true;
414: }
415: return false;
416: }
417: }
|