KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > quercus > lib > gettext > expr > PluralExprParser


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Nam Nguyen
28  */

29
30 package com.caucho.quercus.lib.gettext.expr;
31
32 /**
33  * Parses a gettext plural expression.
34  */

35 class PluralExprParser
36 {
37   final static int INTEGER = 256;
38
39   final static int EQ = 270;
40   final static int NEQ = 271;
41   final static int LE = 272;
42   final static int GE = 273;
43
44   final static int AND = 280;
45   final static int OR = 281;
46
47   final static int VARIABLE_N = 290;
48   final static int UNKNOWN = 291;
49   final static int UNSET = 292;
50
51   private CharSequence JavaDoc _expr;
52   private int _exprLength;
53   private int _parseIndex;
54
55   private Expr _npluralsExpr;
56   private Expr _pluralExpr;
57
58   private int _peekToken;
59   private int _integer;
60
61   private boolean _isError;
62   private boolean _isInitialized;
63
64   protected PluralExprParser(CharSequence JavaDoc expr)
65   {
66     _expr = expr;
67     _exprLength = expr.length();
68
69     _isInitialized = false;
70   }
71
72   public Expr getNpluralsExpr()
73   {
74     if (! _isInitialized)
75       init();
76
77     if (_isError)
78       return null;
79
80     return _npluralsExpr;
81   }
82
83   public Expr getPluralExpr()
84   {
85     if (! _isInitialized)
86       init();
87
88     if (_isError)
89       return null;
90
91     return _pluralExpr;
92   }
93
94   private void init()
95   {
96     _parseIndex = 0;
97     _peekToken = UNSET;
98     _isError = false;
99
100     parseAssignExpr();
101     parseAssignExpr();
102
103     _isInitialized = true;
104   }
105
106   private void parseAssignExpr()
107   {
108     int ch = consumeWhiteSpace();
109
110     boolean isNplurals;
111
112     if (ch == 'n' &&
113         read() == 'p' &&
114         read() == 'l' &&
115         read() == 'u' &&
116         read() == 'r' &&
117         read() == 'a' &&
118         read() == 'l' &&
119         read() == 's') {
120       isNplurals = true;
121     }
122     else if (ch == 'p' &&
123              read() == 'l' &&
124              read() == 'u' &&
125              read() == 'r' &&
126              read() == 'a' &&
127              read() == 'l') {
128       isNplurals = false;
129     }
130     else
131       return;
132
133     ch = consumeWhiteSpace();
134
135     if (ch != '=')
136       return;
137
138     if (isNplurals)
139       _npluralsExpr = parseIfExpr();
140     else
141       _pluralExpr = parseIfExpr();
142
143     // Read semicolon
144
parseToken();
145   }
146
147   private Expr parseLiteralExpr()
148   {
149     int token = parseToken();
150
151     if (token == INTEGER)
152       return new LiteralExpr(_integer);
153     else if (token == VARIABLE_N)
154       return NExpr.N_EXPR;
155     else
156       return error("Expected INTEGER");
157   }
158
159   private Expr parseParenExpr()
160   {
161     int token = parseToken();
162
163     if (token != '(') {
164       _peekToken = token;
165       return parseLiteralExpr();
166     }
167
168     Expr expr = parseIfExpr();
169     if (parseToken() != ')')
170       return error("Expected ')'");
171
172     return expr;
173   }
174
175   private Expr parseMulExpr()
176   {
177     Expr expr = parseParenExpr();
178
179     while (true) {
180       int token = parseToken();
181       switch (token) {
182         case '%':
183           expr = new ModExpr(expr, parseParenExpr());
184           break;
185         case '*':
186           expr = new MulExpr(expr, parseParenExpr());
187           break;
188         case '/':
189           expr = new DivExpr(expr, parseParenExpr());
190           break;
191         default:
192           _peekToken = token;
193           return expr;
194       }
195     }
196   }
197
198   private Expr parseAddExpr()
199   {
200     Expr expr = parseMulExpr();
201
202     while (true) {
203       int token = parseToken();
204
205       switch (token) {
206         case '+':
207           expr = new AddExpr(expr, parseMulExpr());
208           break;
209         case '-':
210           expr = new SubExpr(expr, parseMulExpr());
211           break;
212         default:
213           _peekToken = token;
214           return expr;
215       }
216     }
217   }
218
219   private Expr parseCmpExpr()
220   {
221     Expr expr = parseAddExpr();
222
223     while (true) {
224       int token = parseToken();
225       switch (token) {
226         case '>':
227           expr = new GTExpr(expr, parseAddExpr());
228           break;
229         case '<':
230           expr = new LTExpr(expr, parseAddExpr());
231           break;
232         case GE:
233           expr = new GEExpr(expr, parseAddExpr());
234           break;
235         case LE:
236           expr = new LEExpr(expr, parseAddExpr());
237           break;
238         case EQ:
239           expr = new EQExpr(expr, parseAddExpr());
240           break;
241         case NEQ:
242           expr = new NEQExpr(expr, parseAddExpr());
243           break;
244         default:
245           _peekToken = token;
246           return expr;
247       }
248     }
249   }
250
251   private Expr parseAndExpr()
252   {
253     Expr expr = parseCmpExpr();
254
255     while (true) {
256       int token = parseToken();
257       if (token != AND) {
258         _peekToken = token;
259         return expr;
260       }
261
262       expr = new AndExpr(expr, parseCmpExpr());
263     }
264   }
265
266   private Expr parseOrExpr()
267   {
268     Expr expr = parseAndExpr();
269
270     while (true) {
271       int token = parseToken();
272       if (token != OR) {
273         _peekToken = token;
274         return expr;
275       }
276
277       expr = new OrExpr(expr, parseAndExpr());
278     }
279   }
280
281   private Expr parseIfExpr()
282   {
283     Expr expr = parseOrExpr();
284
285     int token = parseToken();
286     if (token != '?') {
287       _peekToken = token;
288       return expr;
289     }
290
291     Expr trueExpr = parseIfExpr();
292
293     token = parseToken();
294     if (token != ':')
295       return error("Expected ':'");
296
297     Expr falseExpr = parseIfExpr();
298
299     return new IfExpr(expr, trueExpr, falseExpr);
300   }
301
302   private int parseToken()
303   {
304
305     if (_peekToken != UNSET) {
306       int toReturn = _peekToken;
307       _peekToken = UNSET;
308       return toReturn;
309     }
310
311     int ch = consumeWhiteSpace();
312
313     switch (ch) {
314       case '(':
315       case ')':
316       case '?':
317       case ':':
318       case ';':
319       case '+':
320       case '-':
321       case '%':
322       case '*':
323       case '/':
324         return ch;
325       case '>':
326         if (read() == '=')
327           return GE;
328         unread();
329         return '>';
330       case '<':
331         if (read() == '=')
332           return LE;
333         unread();
334         return '<';
335       case '=':
336         if (read() == '=')
337           return EQ;
338         return UNKNOWN;
339       case '!':
340         if (read() == '=')
341           return NEQ;
342         return UNKNOWN;
343       case '&':
344         if (read() == '&')
345           return AND;
346         return UNKNOWN;
347       case '|':
348         if (read() == '|')
349           return OR;
350         return UNKNOWN;
351     }
352
353     return parseIntegerToken(ch);
354   }
355
356   private int parseIntegerToken(int ch)
357   {
358     if ('0' <= ch && ch <= '9') {
359       _integer = ch - '0';
360       for (ch = read(); '0' <= ch && ch <= '9'; ch = read()) {
361         _integer = _integer * 10 + ch - '0';
362       }
363
364       unread();
365       return INTEGER;
366     }
367
368     else if (ch == 'n') {
369       if (Character.isLetter(read()))
370         return UNKNOWN;
371
372       unread();
373       return VARIABLE_N;
374     }
375
376     return UNKNOWN;
377   }
378
379   /**
380    * Consumes whitespaces and returns the last non-whitespace character.
381    */

382   private int consumeWhiteSpace()
383   {
384     while (true) {
385       int ch = read();
386       switch (ch) {
387         case ' ':
388         case '\n':
389         case '\t':
390         case '\r':
391           continue;
392         default:
393           return ch;
394       }
395     }
396   }
397
398   private int read()
399   {
400     if (_parseIndex < _exprLength)
401       return _expr.charAt(_parseIndex++);
402     else
403       return -1;
404   }
405
406   private void unread()
407   {
408     if (_parseIndex > 0 && _parseIndex < _exprLength)
409       _parseIndex--;
410   }
411
412   private Expr error(String JavaDoc message)
413   {
414     _isError = true;
415     return NExpr.N_EXPR;
416   }
417 }
418
Popular Tags