KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > medor > expression > parser > string > ExpressionParser


1 /**
2  * MEDOR: Middleware Enabling Distributed Object Requests
3  *
4  * Copyright (C) 2001-2004 France Telecom R&D
5  * Contact: alexandre.lefebvre@rd.francetelecom.com
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  *
21  * Initial developers: M. Alia, S. Chassande-Barrioz, A. Lefebvre
22  */

23 package org.objectweb.medor.expression.parser.string;
24
25 import org.objectweb.jorm.type.api.PType;
26 import org.objectweb.medor.expression.api.Comparator;
27 import org.objectweb.medor.expression.api.Expression;
28 import org.objectweb.medor.expression.api.ExpressionException;
29 import org.objectweb.medor.expression.api.MalformedExpressionException;
30 import org.objectweb.medor.expression.api.Operator;
31 import org.objectweb.medor.expression.lib.And;
32 import org.objectweb.medor.expression.lib.BasicOperand;
33 import org.objectweb.medor.expression.lib.BasicParameterOperand;
34 import org.objectweb.medor.expression.lib.ConditionalAnd;
35 import org.objectweb.medor.expression.lib.ConditionalOr;
36 import org.objectweb.medor.expression.lib.DivideBy;
37 import org.objectweb.medor.expression.lib.Equal;
38 import org.objectweb.medor.expression.lib.Greater;
39 import org.objectweb.medor.expression.lib.GreaterEqual;
40 import org.objectweb.medor.expression.lib.Lower;
41 import org.objectweb.medor.expression.lib.LowerEqual;
42 import org.objectweb.medor.expression.lib.Minus;
43 import org.objectweb.medor.expression.lib.Mod;
44 import org.objectweb.medor.expression.lib.Mult;
45 import org.objectweb.medor.expression.lib.NotEqual;
46 import org.objectweb.medor.expression.lib.Or;
47 import org.objectweb.medor.expression.lib.Plus;
48 import org.objectweb.medor.expression.parser.api.ParameterTypeProvider;
49 import org.objectweb.medor.expression.parser.lib.ReplaceStringPlusByConcat;
50
51 import java.util.ArrayList JavaDoc;
52 import java.util.StringTokenizer JavaDoc;
53
54 /**
55  * This class is a string parser of expressions.
56  *
57  * @author P. Dechamboux, A.Lefebvre, S.Chassande-Barrioz
58  */

59 public class ExpressionParser {
60     /**
61      * The list of string constants extracted from the parsed expression.
62      */

63     /**
64      * This token represents a string constant to be picked from the list of
65      * extracted ones.
66      */

67     private final static String JavaDoc STRCONSTTOK = "$";
68     private final static String JavaDoc DELIMITERS = "$()+-=!<>&|/%*";
69     private final static int TOKENPOS = 0;
70     private final static int STRCONSTPOS = 1;
71
72     /**
73      * Produces a MEDOR Expression from a string.
74      *
75      * @param exprstr is the string expression to parse
76      * @param ptp is the parameter type provider. It permits to find the type
77      * of parameter found in the expression. If the expression does not contain
78      * parameter, no ParameterTypeProvider is required.
79      * @return the corresponding MEDOR Expression
80      * @throws ExpressionException
81      */

82     public Expression parse(String JavaDoc exprstr, ParameterTypeProvider ptp)
83             throws ExpressionException {
84         ArrayList JavaDoc stringConst = new ArrayList JavaDoc();
85         //Extract String constants and replace them by a $
86
String JavaDoc exprwithoutstrconst = extractStringConst(exprstr, stringConst);
87         //Parse
88
Expression res = buildExpr(toStringArray(exprwithoutstrconst),
89                 new int[]{0, 0},
90                 stringConst,
91                 ptp);
92         //replace ("toto" + "_titi") by concat("toto","_titi")
93
res = new ReplaceStringPlusByConcat().rewrite(res);
94         //Compute types
95
res.compileExpression();
96         return res;
97     }
98
99     /**
100      * Extracts all string constants from a expression string and stores them
101      * into the stringConst ArrayList, in the order they appear in the input
102      * expression. It also builds a new expression string which is the method
103      * result. All string constants has been replaced by a '$' character.
104      * @param expr The input expression.
105      * @return The resulting expression string.
106      * @throws MalformedExpressionException Thrown when a malformed string constant is
107      * found in the input expression string (non closed string constant).
108      */

109     String JavaDoc extractStringConst(String JavaDoc expr, ArrayList JavaDoc stringConst)
110             throws MalformedExpressionException {
111         StringBuffer JavaDoc res = new StringBuffer JavaDoc();
112         int curpos = 0;
113         do {
114             int startsc = expr.indexOf('"', curpos);
115             if (startsc == -1) {
116                 break;
117             }
118             int endsc = expr.indexOf('"', startsc + 1);
119             if (endsc == -1) {
120                 throw new MalformedExpressionException("Constant string starting at position"
121                                              + startsc + " never ended.");
122             }
123             res.append(expr.substring(curpos, startsc).replaceAll(" ", ""));
124             res.append(STRCONSTTOK);
125             stringConst.add(expr.substring(startsc + 1, endsc));
126             curpos = endsc + 1;
127         } while (true);
128         res.append(expr.substring(curpos).replaceAll(" ", ""));
129         return res.toString();
130     }
131
132     /**
133      *
134      * @param str
135      * @return
136      */

137     private String JavaDoc[] toStringArray(String JavaDoc str) {
138         StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(str, DELIMITERS, true);
139         ArrayList JavaDoc tokens = new ArrayList JavaDoc();
140         String JavaDoc[] nextToken = new String JavaDoc[]{null};
141         do {
142             String JavaDoc token = getNextToken(tokenizer, nextToken);
143             if (token == null) {
144                 break;
145             }
146             tokens.add(token);
147         } while (true);
148         return (String JavaDoc[]) tokens.toArray(new String JavaDoc[tokens.size()]);
149     }
150
151     /**
152      *
153      * @param tokens The array of tokens to be parsed.
154      * @param indexes The indexes of the current token to be parsed (pos 0)
155      * and of the next string constant to retrieve (pos 1).
156      * @param stringConst The list of string constants.
157      * @return The expression built by the method.
158      * @throws MalformedExpressionException
159      */

160     private Expression buildExpr(String JavaDoc[] tokens,
161                                  int[] indexes,
162                                  ArrayList JavaDoc stringConst,
163                                  ParameterTypeProvider ptp)
164             throws MalformedExpressionException {
165         if (indexes[TOKENPOS] == tokens.length) {
166             return null;
167         }
168         Expression firstnode;
169         if (tokens[indexes[TOKENPOS]].equals("(")) {
170             firstnode = buildParenthesExpr(tokens, indexes, stringConst, ptp);
171         } else {
172             firstnode = buildAtomicOperandExpr(tokens, indexes, stringConst, ptp);
173         }
174         if ((indexes[TOKENPOS] == tokens.length) || (tokens[indexes[TOKENPOS]].equals(")"))) {
175             return firstnode;
176         }
177         Expression operator = buildNextExpr(tokens, indexes, stringConst, firstnode, ptp);
178         if (operator == null) {
179             throw new MalformedExpressionException("Wrong token found in token position "
180                                          + indexes[TOKENPOS] + ": " + tokens[indexes[TOKENPOS]]
181                                          + " (should be an operator)");
182         }
183         return operator;
184     }
185
186     /**
187      *
188      * @param tokens The array of tokens to be parsed.
189      * @param indexes The indexes of the current token to be parsed (pos 0)
190      * and of the next string constant to retrieve (pos 1).
191      * @param stringConst The list of string constants.
192      * @return The expression built by the method.
193      * @throws MalformedExpressionException
194      */

195     private Operator buildNextExpr(String JavaDoc[] tokens,
196                              int[] indexes,
197                              ArrayList JavaDoc stringConst,
198                              Expression left,
199                              ParameterTypeProvider ptp)
200             throws MalformedExpressionException {
201         if (indexes[TOKENPOS] == tokens.length) {
202             return null;
203         }
204         if (tokens[indexes[TOKENPOS]].equals(")")) {
205             return null;
206         }
207         Operator operator;
208         Expression secondnode;
209         operator = buildPri1OperatorExpr(tokens, indexes);
210         if (operator != null) {
211             if (tokens[indexes[TOKENPOS]].equals("(")) {
212                 secondnode = buildParenthesExpr(tokens, indexes, stringConst, ptp);
213             } else {
214                 secondnode = buildAtomicOperandExpr(tokens, indexes, stringConst, ptp);
215             }
216             Operator next = buildNextExpr(tokens, indexes, stringConst, operator, ptp);
217             operator.setExpression(0, left);
218             if (next != null) {
219                 if (priorTo(operator, next)) {
220                     operator.setExpression(1, secondnode);
221                     return next;
222                 }
223                 operator.setExpression(1, next);
224                 next.setExpression(0, secondnode);
225                 return operator;
226             }
227             operator.setExpression(1, secondnode);
228             return operator;
229         }
230         operator = buildPri2OperatorExpr(tokens, indexes);
231         if (operator != null) {
232             if (tokens[indexes[TOKENPOS]].equals("(")) {
233                 secondnode = buildParenthesExpr(tokens, indexes, stringConst, ptp);
234             } else {
235                 secondnode = buildAtomicOperandExpr(tokens, indexes, stringConst, ptp);
236             }
237             Operator next = buildNextExpr(tokens, indexes, stringConst, operator, ptp);
238             operator.setExpression(0, left);
239             if (next != null) {
240                 if (priorTo(operator, next)) {
241                     operator.setExpression(1, secondnode);
242                     return next;
243                 }
244                 operator.setExpression(1, next);
245                 next.setExpression(0, secondnode);
246                 return operator;
247             }
248             operator.setExpression(1, secondnode);
249             return operator;
250         }
251         operator = buildCompOperatorExpr(tokens, indexes);
252         if (operator != null) {
253             if (tokens[indexes[TOKENPOS]].equals("(")) {
254                 secondnode = buildParenthesExpr(tokens, indexes, stringConst, ptp);
255             } else {
256                 secondnode = buildExpr(tokens, indexes, stringConst, ptp);
257             }
258             Operator next = buildNextExpr(tokens, indexes, stringConst, operator, ptp);
259             operator.setExpression(0, left);
260             if (next != null) {
261                 if (priorTo(operator, next)) {
262                     operator.setExpression(1, secondnode);
263                     return next;
264                 }
265                 operator.setExpression(1, next);
266                 next.setExpression(0, secondnode);
267                 return operator;
268             }
269             operator.setExpression(1, secondnode);
270             return operator;
271         }
272         operator = buildLogicalOperatorExpr(tokens, indexes);
273         if (operator != null) {
274             if (tokens[indexes[TOKENPOS]].equals("(")) {
275                 secondnode = buildParenthesExpr(tokens, indexes, stringConst, ptp);
276             } else {
277                 secondnode = buildExpr(tokens, indexes, stringConst, ptp);
278             }
279             Operator next = buildNextExpr(tokens, indexes, stringConst, operator, ptp);
280             operator.setExpression(0, left);
281             if (next != null) {
282                 if (priorTo(operator, next)) {
283                     operator.setExpression(1, secondnode);
284                     return next;
285                 }
286                 operator.setExpression(1, next);
287                 next.setExpression(0, secondnode);
288                 return operator;
289             }
290             operator.setExpression(1, secondnode);
291             return operator;
292         }
293         throw new MalformedExpressionException("Wrong token found in token position "
294                                      + indexes[TOKENPOS] + ": " + tokens[indexes[TOKENPOS]]
295                                      + " (should be an operator)");
296     }
297
298     /**
299      *
300      * @param tokens The array of tokens to be parsed.
301      * @param indexes The indexes of the current token to be parsed (pos 0)
302      * and of the next string constant to retrieve (pos 1).
303      * @param stringConst The list of string constants.
304      * @return The expression built by the method.
305      * @throws MalformedExpressionException
306      */

307     private Expression buildParenthesExpr(String JavaDoc[] tokens,
308                                   int[] indexes,
309                                   ArrayList JavaDoc stringConst,
310                                   ParameterTypeProvider ptp)
311             throws MalformedExpressionException {
312         indexes[TOKENPOS]++;
313         Expression res = buildExpr(tokens, indexes, stringConst, ptp);
314         if (!tokens[indexes[TOKENPOS]].equals(")")) {
315             throw new MalformedExpressionException("Wrong token found in token position "
316                                          + indexes[TOKENPOS] + ": " + tokens[indexes[TOKENPOS]]);
317         }
318         indexes[TOKENPOS]++;
319         return res;
320     }
321
322     /**
323      * Looks for an atomic operand. It should be either a constant (string or
324      * numeric), or a variable.
325      * @param tokens The array of tokens to be parsed.
326      * @param indexes The indexes of the current token to be parsed (pos 0)
327      * and of the next string constant to retrieve (pos 1).
328      * @param stringConst The list of string constants.
329      * @return The expression built by the method.
330      * @throws MalformedExpressionException
331      */

332     private Expression buildAtomicOperandExpr(String JavaDoc[] tokens,
333                                       int[] indexes,
334                                       ArrayList JavaDoc stringConst,
335                                       ParameterTypeProvider ptp)
336             throws MalformedExpressionException {
337         Expression res = null;
338         String JavaDoc operand = tokens[indexes[TOKENPOS]];
339         if (operand.equals("$")) { //constant string
340
// String constant
341
res = new BasicOperand(
342                     (String JavaDoc) stringConst.get(indexes[STRCONSTPOS]));
343             indexes[STRCONSTPOS]++;
344         }
345         if (res == null) { // boolean
346
if (operand.equalsIgnoreCase("true")) {
347                 res = new BasicOperand(true);
348             } else if (operand.equalsIgnoreCase("false")) {
349                 res = new BasicOperand(false);
350             }
351         }
352         if (res == null) { // integer
353
try {
354                 long l = Long.parseLong(operand);
355                 if (l <= Byte.MAX_VALUE && l >= Byte.MIN_VALUE) {
356                     res = new BasicOperand((byte) l);
357                 } else if (l <= Short.MAX_VALUE && l >= Short.MIN_VALUE) {
358                     res = new BasicOperand((short) l);
359                 } else if (l <= Integer.MAX_VALUE && l >= Integer.MIN_VALUE) {
360                     res = new BasicOperand((int) l);
361                 } else {
362                     res = new BasicOperand(l);
363                 }
364             } catch (NumberFormatException JavaDoc e) {
365             }
366         }
367         if (res == null) { // floating
368
try {
369                 double d = Double.parseDouble(operand);
370                 if (d <= Float.MAX_VALUE && d >= Float.MIN_VALUE) {
371                     res = new BasicOperand((float) d);
372                 } else {
373                     res = new BasicOperand(d);
374                 }
375             } catch (NumberFormatException JavaDoc e) {
376             }
377         }
378         if (res == null && Character.isLetterOrDigit(operand.charAt(0))) {
379             // this is a variable expr to create
380
String JavaDoc paramName = tokens[indexes[TOKENPOS]];
381             if (ptp == null) {
382                 throw new MalformedExpressionException("ParameterTypeProvider required, but was null, for parameter " + paramName);
383             }
384             PType paramType = ptp.getParameterPType(paramName);
385             if (paramType == null) {
386                 throw new MalformedExpressionException("Unknown type for parameter " + paramName);
387             }
388             res = new BasicParameterOperand(paramType, paramName);
389         }
390         if (res != null) {
391             indexes[TOKENPOS]++;
392             return res;
393         }
394         throw new MalformedExpressionException("Wrong token found in token position "
395                 + indexes[TOKENPOS] + ": " + tokens[indexes[TOKENPOS]]
396                 + " (should be a constant or a variable)");
397     }
398
399     /**
400      *
401      * @param tokens The array of tokens to be parsed.
402      * @param indexes The indexes of the current token to be parsed (pos 0)
403      * and of the next string constant to retrieve (pos 1).
404      * @return The expression built by the method.
405      */

406     private Operator buildLogicalOperatorExpr(String JavaDoc[] tokens,
407                                         int[] indexes) {
408         Operator res;
409         if (tokens[indexes[TOKENPOS]].equals("&&")) {
410             res = new ConditionalAnd();
411         } else if (tokens[indexes[TOKENPOS]].equals("||")) {
412             res = new ConditionalOr();
413         } else {
414             return null;
415         }
416         indexes[TOKENPOS]++;
417         return res;
418     }
419
420     /**
421      *
422      * @param tokens The array of tokens to be parsed.
423      * @param indexes The indexes of the current token to be parsed (pos 0)
424      * and of the next string constant to retrieve (pos 1).
425      * @return The expression built by the method.
426      */

427     private Operator buildCompOperatorExpr(String JavaDoc[] tokens,
428                                      int[] indexes) {
429         Operator res;
430         if (tokens[indexes[TOKENPOS]].equals("==")) {
431             res = new Equal();
432         } else if (tokens[indexes[TOKENPOS]].equals("!=")) {
433             res = new NotEqual();
434         } else if (tokens[indexes[TOKENPOS]].equals("<")) {
435             res = new Lower();
436         } else if (tokens[indexes[TOKENPOS]].equals("<=")) {
437             res = new LowerEqual();
438         } else if (tokens[indexes[TOKENPOS]].equals(">")) {
439             res = new Greater();
440         } else if (tokens[indexes[TOKENPOS]].equals(">=")) {
441             res = new GreaterEqual();
442         } else {
443             return null;
444         }
445         indexes[TOKENPOS]++;
446         return res;
447     }
448
449     /**
450      *
451      * @param tokens The array of tokens to be parsed.
452      * @param indexes The indexes of the current token to be parsed (pos 0)
453      * and of the next string constant to retrieve (pos 1).
454      * @return The expression built by the method.
455      */

456     private Operator buildPri2OperatorExpr(String JavaDoc[] tokens,
457                                      int[] indexes) {
458         Operator res;
459         if (tokens[indexes[TOKENPOS]].equals("+")) {
460             res = new Plus();
461         } else if (tokens[indexes[TOKENPOS]].equals("-")) {
462             res = new Minus();
463         } else if (tokens[indexes[TOKENPOS]].equals("|")) {
464             res = new Or();
465         } else {
466             return null;
467         }
468         indexes[TOKENPOS]++;
469         return res;
470     }
471
472     /**
473      *
474      * @param tokens The array of tokens to be parsed.
475      * @param indexes The indexes of the current token to be parsed (pos 0)
476      * and of the next string constant to retrieve (pos 1).
477      * @return The expression built by the method.
478      */

479     private Operator buildPri1OperatorExpr(String JavaDoc[] tokens,
480                                      int[] indexes) {
481         Operator res;
482         if (tokens[indexes[TOKENPOS]].equals("*")) {
483             res = new Mult();
484         } else if (tokens[indexes[TOKENPOS]].equals("/")) {
485             res = new DivideBy();
486         } else if (tokens[indexes[TOKENPOS]].equals("%")) {
487             res = new Mod();
488         } else if (tokens[indexes[TOKENPOS]].equals("&")) {
489             res = new And();
490         } else {
491             return null;
492         }
493         indexes[TOKENPOS]++;
494         return res;
495     }
496
497     /**
498      *
499      * @param tokenizer
500      * @param nexttoken
501      * @return
502      */

503     private String JavaDoc getNextToken(StringTokenizer JavaDoc tokenizer, String JavaDoc[] nexttoken) {
504         String JavaDoc res;
505         if (nexttoken[0] != null) {
506             res = nexttoken[0];
507             nexttoken[0] = null;
508             return res;
509         }
510         if (!tokenizer.hasMoreTokens()) {
511             return null;
512         }
513         res = tokenizer.nextToken();
514         if (res.equals("=") || res.equals("<") || res.equals(">") || res.equals("!")) {
515             if (!tokenizer.hasMoreTokens()) {
516                 return res;
517             }
518             nexttoken[0] = tokenizer.nextToken();
519             if (nexttoken[0].equals("=")) {
520                 nexttoken[0] = null;
521                 return res + "=";
522             }
523             return res;
524         } else if (res.equals("&")) {
525             if (!tokenizer.hasMoreTokens()) {
526                 return res;
527             }
528             nexttoken[0] = tokenizer.nextToken();
529             if (nexttoken[0].equals("&")) {
530                 nexttoken[0] = null;
531                 return "&&";
532             }
533             return res;
534         } else if (res.equals("|")) {
535             if (!tokenizer.hasMoreTokens()) {
536                 return res;
537             }
538             nexttoken[0] = tokenizer.nextToken();
539             if (nexttoken[0].equals("|")) {
540                 nexttoken[0] = null;
541                 return "||";
542             }
543             return res;
544         } else {
545             return res;
546         }
547     }
548
549     /**
550      *
551      * @param token
552      * @return
553      */

554     private boolean isLog(Operator token) {
555         return (token instanceof ConditionalAnd)
556                 || (token instanceof ConditionalOr);
557     }
558
559     /**
560      *
561      * @param token
562      * @return
563      */

564     private boolean isComp(Operator token) {
565         return (token instanceof Comparator);
566     }
567
568     /**
569      *
570      * @param token
571      * @return
572      */

573     private boolean isPri2(Operator token) {
574         return (token instanceof Plus)
575         || (token instanceof Minus)
576         || (token instanceof Or);
577     }
578
579     /**
580      *
581      * @param tok1
582      * @param tok2
583      * @return
584      */

585     private boolean priorTo(Operator tok1, Operator tok2) {
586         if (isLog(tok1)) {
587             return false;
588         }
589         if (isComp(tok1)) {
590             return isLog(tok2);
591         }
592         if (isPri2(tok1)) {
593             return isLog(tok2) || isComp(tok2);
594         }
595         return isLog(tok2) || isComp(tok2) || isPri2(tok2);
596     }
597 }
598
Popular Tags