svn-gvsig-desktop / trunk / extSymbology / src / org / gvsig / symbology / fmap / labeling / parse / LabelExpressionParser.jj @ 18755
History | View | Annotate | Download (13.1 KB)
1 |
/** |
---|---|
2 |
* JavaCC file |
3 |
*/ |
4 |
|
5 |
options { |
6 |
JDK_VERSION = "1.5"; |
7 |
STATIC = false; |
8 |
} |
9 |
PARSER_BEGIN(LabelExpressionParser) |
10 |
package org.gvsig.symbology.fmap.labeling.parse; |
11 |
|
12 |
import org.apache.log4j.Logger; |
13 |
import com.hardcode.gdbms.engine.instruction.EvaluationException; |
14 |
import com.hardcode.gdbms.engine.values.*; |
15 |
import java.io.*; |
16 |
import java.util.*; |
17 |
import org.gvsig.symbology.fmap.labeling.lang.Symbol; |
18 |
import org.gvsig.symbology.fmap.labeling.lang.Function; |
19 |
|
20 |
|
21 |
public class LabelExpressionParser { |
22 |
private static Hashtable<String, Function> function_table = new Hashtable<String, Function>(); |
23 |
|
24 |
private Hashtable<String, Symbol> symbol_table = new Hashtable<String, Symbol>(); |
25 |
private Stack stack = new Stack(); |
26 |
|
27 |
public static void addFunction(Class functionClass) { |
28 |
try { |
29 |
Function f = (Function) functionClass.newInstance(); |
30 |
function_table.put(f.getName(), f); |
31 |
} catch (Exception e) { |
32 |
Logger.getLogger(LabelExpressionParser.class).error("couldn't install function '"+functionClass.getName(), e); |
33 |
}; |
34 |
} |
35 |
|
36 |
public Object pop() { |
37 |
return stack.pop(); |
38 |
} |
39 |
|
40 |
public static void main(String args[]) throws ParseException { |
41 |
|
42 |
LabelExpressionParser parser = new LabelExpressionParser(System.in); |
43 |
|
44 |
parser.putSymbol(new Symbol( |
45 |
"TIPNOMCALL", |
46 |
Symbol.DATA_TYPE_STRING, |
47 |
ValueFactory.createValue("Yaba daba doo...") |
48 |
) |
49 |
); |
50 |
parser.putSymbol(new Symbol( |
51 |
"LONGITUD", |
52 |
Symbol.DATA_TYPE_FLOATING, |
53 |
ValueFactory.createValue(4.0) |
54 |
) |
55 |
); |
56 |
while (true) { |
57 |
try { |
58 |
String[] texts = parser.LabelExpression(); |
59 |
for (int i = 0; i < texts.length; i++) { |
60 |
System.out.println("Text at field "+i+": "+texts[i]); |
61 |
} |
62 |
} catch (ParseException e) { |
63 |
System.err.println(e.getMessage()); |
64 |
System.exit(-1); |
65 |
} |
66 |
} |
67 |
} |
68 |
|
69 |
public void putSymbol(Symbol sym) { |
70 |
symbol_table.put(sym.getName(), sym); |
71 |
} |
72 |
} |
73 |
|
74 |
class LabelField { |
75 |
String text; |
76 |
int pos; |
77 |
|
78 |
public LabelField(String text, int pos) { |
79 |
this.text = text; |
80 |
this.pos = pos; |
81 |
} |
82 |
} |
83 |
|
84 |
class LabelFieldComparator implements Comparator<LabelField> { |
85 |
public int compare(LabelField o1, LabelField o2) { |
86 |
if (o1 != null && o2 == null) return -1; |
87 |
if (o1 == null && o2 != null) return 1; |
88 |
if (o1 == null && o2 == null) return 0; |
89 |
if (o1.pos <= o2.pos) return -1; |
90 |
else return 1; |
91 |
} |
92 |
} |
93 |
PARSER_END(LabelExpressionParser) |
94 |
|
95 |
SKIP : |
96 |
{ |
97 |
" " |
98 |
| "\r" |
99 |
| "\t" |
100 |
| "\n" |
101 |
} |
102 |
|
103 |
|
104 |
TOKEN : /* OPERATORS */ |
105 |
{ |
106 |
< PLUS: "+" > |
107 |
| < MINUS: "-" > |
108 |
| < MULTIPLY: "*" > |
109 |
| < DIVIDE: "/" > |
110 |
| < GT: ">" > |
111 |
| < LT: "<" > |
112 |
| < NOT: "!" > |
113 |
| < EQ: "==" > |
114 |
| < LE: "<=" > |
115 |
| < GE: ">=" > |
116 |
| < NE: "!=" > |
117 |
| < OR: "||" > |
118 |
| < AND: "&&" > |
119 |
} |
120 |
TOKEN : /* MISC */ |
121 |
{ |
122 |
< #DOT: "." > |
123 |
| < OPEN_SQ_BRACKETS : "[" > |
124 |
| < CLOSE_SQ_BRACKETS : "]" > |
125 |
| < OPEN_PARENTHESIS : "(" > |
126 |
| < CLOSE_PARENTHESIS : ")" > |
127 |
| < DOUBLE_QUOTE : "\"" > |
128 |
| < COMMA : "," > |
129 |
| < EOEXPR : ";" > |
130 |
} |
131 |
TOKEN : /* CONSTANTS AND IDENTIFIERS */ |
132 |
{ |
133 |
< BOOLEAN: "true" | "false" > |
134 |
| < IDENTIFIER: ( <LETTER> ) ( <LETTER>|<DIGIT> )* > |
135 |
| < #LETTER: ( ["_","$","%"] | ( ["a"-"z"] ) | ( ["A"-"Z"] ) ) > |
136 |
} |
137 |
TOKEN : /* NUMBER */ |
138 |
{ |
139 |
< #DIGIT: ["0"-"9"] > |
140 |
| < INTEGER: ( <DIGIT> )+ > |
141 |
| < FLOATING_POINT: (<DIGIT>)+ "." (<DIGIT>)* (<EXPONENT>)? (["f","F","d","D"])? |
142 |
| <DOT> (<DIGIT>)+ (<EXPONENT>)? (["f","F","d","D"])? |
143 |
| (<DIGIT>)+ <EXPONENT> (["f","F","d","D"])? |
144 |
| (<DIGIT>)+ (<EXPONENT>)? ["f","F","d","D"] > |
145 |
| < #EXPONENT: ["e","E"] (["+","-"])? (<DIGIT>)+ > |
146 |
} |
147 |
TOKEN: /* STRING */ |
148 |
{ |
149 |
< STRING: ( <DOUBLE_QUOTE> ( <CHAR_STRING> )* <DOUBLE_QUOTE> )> |
150 |
| < CHAR_STRING : ~[ "\"", ";","\n","\r"] > |
151 |
} |
152 |
|
153 |
|
154 |
TOKEN : /* LABELING TOKENS */ |
155 |
{ |
156 |
< FIELD_IDENTIFIER: <OPEN_SQ_BRACKETS> <CHAR_STRING> <CLOSE_SQ_BRACKETS> > |
157 |
} |
158 |
|
159 |
/* |
160 |
* The grammar. |
161 |
*/ |
162 |
|
163 |
/* LABEL EXPRESSION */ |
164 |
String[] LabelExpression() : |
165 |
{ |
166 |
ArrayList<String> labelFields = new ArrayList<String>(); |
167 |
String f; |
168 |
} |
169 |
{ |
170 |
f = FieldExpression() { labelFields.add(f); } |
171 |
( |
172 |
<COMMA> |
173 |
f = FieldExpression() { labelFields.add(f); } |
174 |
)* <EOEXPR> |
175 |
{ |
176 |
return labelFields.toArray(new String[0]); |
177 |
} |
178 |
| <EOEXPR> { return new String[0]; } |
179 |
} |
180 |
|
181 |
/* FIELD EXPRESSIONS */ |
182 |
String FieldExpression() : |
183 |
{ |
184 |
Token t; |
185 |
String value; |
186 |
} |
187 |
{ |
188 |
Expression() { value = stack.pop().toString(); } |
189 |
( Expression() { value += stack.pop().toString(); } ) * |
190 |
{ return value; } |
191 |
} |
192 |
|
193 |
void Expression(): {} |
194 |
{ |
195 |
AndExpression() ( <OR> AndExpression() { |
196 |
try { |
197 |
boolean a = (Boolean) stack.pop(); |
198 |
boolean b = (Boolean) stack.pop(); |
199 |
stack.push(ValueFactory.createValue(a || b)); |
200 |
} catch (ClassCastException ex) { |
201 |
throw new SemanticException(SemanticException.TYPE_MISMATCH); |
202 |
} |
203 |
} |
204 |
)* |
205 |
} |
206 |
|
207 |
void AndExpression() : {} |
208 |
{ |
209 |
EqComparisonExpression() ( <AND> EqComparisonExpression() { |
210 |
try { |
211 |
boolean a = (Boolean) stack.pop(); |
212 |
boolean b = (Boolean) stack.pop(); |
213 |
stack.push(new Boolean(b && a)); |
214 |
} catch (ClassCastException ex) { |
215 |
throw new SemanticException(SemanticException.TYPE_MISMATCH, |
216 |
"Trying to perform logical AND with non-boolean data types"); |
217 |
} |
218 |
})* |
219 |
} |
220 |
|
221 |
void EqComparisonExpression(): |
222 |
{ |
223 |
Token t; |
224 |
} |
225 |
{ |
226 |
ComparisonExpression() ( ( t = <EQ> | t = <NE> ) ComparisonExpression() { |
227 |
try { |
228 |
Object A = stack.pop(); Object B = stack.pop(); boolean aInt = A.getClass().equals(Integer.class); boolean bInt = B.getClass().equals(Integer.class); if (aInt && bInt) { int a = (Integer) A; int b = (Integer) B; if (t.kind == EQ) stack.push(new Boolean(b==a)); else stack.push(new Boolean(b!=a)); } else { double a = (!aInt) ? (Double) A : new Double(A.toString()); double b = (!bInt) ? (Double) B : new Double(B.toString()); |
229 |
if (t.kind == EQ) |
230 |
stack.push(new Boolean(b==a)); |
231 |
else |
232 |
stack.push(new Boolean(b!=a)); |
233 |
} |
234 |
} catch (ClassCastException ex) { |
235 |
throw new SemanticException(SemanticException.TYPE_MISMATCH, |
236 |
"Trying to perform comparison '"+t.image+"' with non-numeric data types"); |
237 |
} |
238 |
})* |
239 |
} |
240 |
|
241 |
void ComparisonExpression() : |
242 |
{ |
243 |
Token t; |
244 |
} |
245 |
{ |
246 |
AdditiveExpression() ((t = <LT> | t = <GT> | t = <LE> | t = <GE> ) AdditiveExpression() { |
247 |
try { |
248 |
Object A = stack.pop(); Object B = stack.pop(); boolean aInt = A.getClass().equals(Integer.class); boolean bInt = B.getClass().equals(Integer.class); if (aInt && bInt) { int a = (Integer) A; int b = (Integer) B; if (t.kind == LT) stack.push(new Boolean(b < a)); else if (t.kind == GT) stack.push(new Boolean(b > a)); else if (t.kind == LE) stack.push(new Boolean(b <= a)); else if (t.kind == GE) stack.push(new Boolean(b >= a)); } else { double a = (!aInt) ? (Double) A : new Double(A.toString()); double b = (!bInt) ? (Double) B : new Double(B.toString()); |
249 |
if (t.kind == LT) |
250 |
stack.push(new Boolean(b < a)); |
251 |
else if (t.kind == GT) |
252 |
stack.push(new Boolean(b > a)); |
253 |
else if (t.kind == LE) |
254 |
stack.push(new Boolean(b <= a)); |
255 |
else if (t.kind == GE) |
256 |
stack.push(new Boolean(b >= a)); |
257 |
} |
258 |
|
259 |
} catch (ClassCastException ex) { |
260 |
throw new SemanticException(SemanticException.TYPE_MISMATCH, |
261 |
"Trying to perform relational '"+t.image+"' with non-numeric data types"); |
262 |
} |
263 |
})* |
264 |
} |
265 |
|
266 |
void AdditiveExpression(): |
267 |
{ |
268 |
Token t; |
269 |
} |
270 |
{ |
271 |
MultiplicativeExpression() ( ( t = <PLUS> | t = <MINUS> ) MultiplicativeExpression() { |
272 |
try { |
273 |
Object A = stack.pop(); Object B = stack.pop(); boolean aInt = A.getClass().equals(Integer.class); boolean bInt = B.getClass().equals(Integer.class); if (aInt && bInt) { int a = (Integer) A; int b = (Integer) B; if (t.kind == PLUS) stack.push(new Integer(b + a)); else stack.push(new Integer(b - a)); } else { double a = (!aInt) ? (Double) A : new Double(A.toString()); double b = (!bInt) ? (Double) B : new Double(B.toString()); |
274 |
if (t.kind == PLUS) |
275 |
stack.push(new Double(b + a)); |
276 |
else |
277 |
stack.push(new Double(b - a)); |
278 |
} |
279 |
} catch (ClassCastException ex) { |
280 |
throw new SemanticException(SemanticException.TYPE_MISMATCH, |
281 |
"Trying to perform ADD '"+t.image+"' with non-numeric data types"); |
282 |
} |
283 |
})* |
284 |
} |
285 |
|
286 |
void MultiplicativeExpression(): |
287 |
{ |
288 |
Token t; |
289 |
} |
290 |
{ |
291 |
ArithmeticUnaryExpression() ( ( t = <MULTIPLY> | t = <DIVIDE> ) ArithmeticUnaryExpression() { |
292 |
try { |
293 |
Object A = stack.pop(); Object B = stack.pop(); boolean aInt = A.getClass().equals(Integer.class); boolean bInt = B.getClass().equals(Integer.class); if (aInt && bInt) { int a = (Integer) A; int b = (Integer) B; if (t.kind == PLUS) stack.push(new Integer(b * a)); else stack.push(new Integer(b / a)); } else { double a = (!aInt) ? (Double) A : new Double(A.toString()); double b = (!bInt) ? (Double) B : new Double(B.toString()); |
294 |
if (t.kind == MULTIPLY) |
295 |
stack.push(new Double(b * a)); |
296 |
else |
297 |
stack.push(new Double(b / a)); |
298 |
} |
299 |
} catch (ClassCastException ex) { |
300 |
throw new SemanticException(SemanticException.TYPE_MISMATCH, |
301 |
"Trying to perform MULT '"+t.image+"' with non-numeric data types"); |
302 |
} |
303 |
})* |
304 |
} |
305 |
|
306 |
void ArithmeticUnaryExpression(): |
307 |
{ |
308 |
Token t; |
309 |
} |
310 |
{ |
311 |
( t = <PLUS> | t = <MINUS> ) ArithmeticUnaryExpression() { |
312 |
try { |
313 |
Object A = stack.pop(); |
314 |
if (A.getClass().equals(Integer.class)) { |
315 |
int a = (Integer) A; |
316 |
if (t.kind == PLUS) |
317 |
stack.push(new Integer(a)); |
318 |
else |
319 |
stack.push(new Integer(-a)); |
320 |
} else { |
321 |
|
322 |
double a = (Double) A; |
323 |
if (t.kind == PLUS) |
324 |
stack.push(new Double(a)); |
325 |
else |
326 |
stack.push(new Double(-a)); |
327 |
} |
328 |
} catch (ClassCastException ex) { |
329 |
throw new SemanticException(SemanticException.TYPE_MISMATCH, |
330 |
"Trying to perform UNARY '"+t.image+"' with non-numeric data types"); |
331 |
} |
332 |
} |
333 |
| BooleanUnaryExpression() |
334 |
} |
335 |
|
336 |
void BooleanUnaryExpression(): |
337 |
{ |
338 |
Token t; |
339 |
} |
340 |
{ |
341 |
t = <NOT> ArithmeticUnaryExpression() { |
342 |
try { |
343 |
boolean a = (Boolean) stack.pop(); |
344 |
stack.push(new Boolean(!a)); |
345 |
} catch (ClassCastException ex) { |
346 |
throw new SemanticException(SemanticException.TYPE_MISMATCH, |
347 |
"Trying to perform UNARY '"+t.image+"' with non-numeric data types"); |
348 |
} |
349 |
} |
350 |
| PrimitiveExpression() |
351 |
} |
352 |
|
353 |
void PrimitiveExpression(): |
354 |
{ |
355 |
Token t; |
356 |
} |
357 |
{ |
358 |
Literal() |
359 |
| LOOKAHEAD(2) |
360 |
Function() |
361 |
| <OPEN_SQ_BRACKETS> t = <IDENTIFIER> <CLOSE_SQ_BRACKETS> |
362 |
{ String name = t.image.trim(); } |
363 |
{ Symbol sym = symbol_table.get(name); } |
364 |
{ if (sym == null) |
365 |
throw new SemanticException(SemanticException.UNDEFINED_SYMBOL, |
366 |
"Symbol "+name+" undefined"); } |
367 |
{ switch (sym.getDataType()) { |
368 |
case Symbol.DATA_TYPE_INT: |
369 |
stack.push(new Integer(((Value) sym.getValue()).toString())); |
370 |
break; |
371 |
case Symbol.DATA_TYPE_FLOATING: |
372 |
stack.push(new Double(((Value) sym.getValue()).toString())); |
373 |
break; |
374 |
case Symbol.DATA_TYPE_STRING: |
375 |
stack.push(((StringValue) sym.getValue()).toString()); |
376 |
break; |
377 |
case Symbol.DATA_TYPE_NULL: |
378 |
stack.push(null); |
379 |
break; |
380 |
case Symbol.DATA_TYPE_BOOLEAN: |
381 |
stack.push(new Boolean(((Value) sym.getValue()).toString())); |
382 |
break; |
383 |
case Symbol.DATA_TYPE_DATE: |
384 |
stack.push(((DateValue) sym.getValue()).getValue()); |
385 |
break; |
386 |
default: |
387 |
throw new SemanticException(SemanticException.TYPE_MISMATCH, |
388 |
"Unknown type for "+name); |
389 |
} |
390 |
} |
391 |
| <OPEN_PARENTHESIS> Expression() <CLOSE_PARENTHESIS> |
392 |
} |
393 |
|
394 |
void Function(): |
395 |
{ |
396 |
Token t; |
397 |
int argCount; |
398 |
String name; |
399 |
} |
400 |
{ |
401 |
t = <IDENTIFIER> {name = t.image;} argCount = Arguments() |
402 |
{ Function f = function_table.get(name); |
403 |
if (f == null) |
404 |
throw new SemanticException(SemanticException.UNDEFINED_SYMBOL, |
405 |
"Symbol "+name+" undefined"); |
406 |
// if (sym.getSymbolType() == Symbol.SYMBOL_TYPE_FUNCTION) { |
407 |
// Function f = (Function) sym.getValue(); |
408 |
if (f.getArgumentCount() != argCount) { |
409 |
throw new SemanticException(SemanticException.TYPE_MISMATCH, |
410 |
"Function '"+name+"' requires "+f.getArgumentCount()+", "+argCount+" were provided."); |
411 |
} |
412 |
ArrayList<Object> argList = new ArrayList<Object>(); |
413 |
for (int i = 0; i <= argCount-1; i++) { |
414 |
argList.add(0, stack.pop()); |
415 |
} |
416 |
try { |
417 |
stack.push(f.evaluate(argList.toArray(new Object[0]))); |
418 |
} catch (EvaluationException evEx) { |
419 |
throw new Error("Aquesta excepció no deuria de llançar-se així, deuria de ser una extensió de parse exception (o bé repensar-se el funcinament!!!"); |
420 |
} |
421 |
|
422 |
// } else { // throw new SemanticException(SemanticException.TYPE_MISMATCH, // "Tye symbol '"+name+"' is not a function"); // } |
423 |
} |
424 |
} |
425 |
|
426 |
void Literal() : |
427 |
{ |
428 |
Token t; |
429 |
} |
430 |
|
431 |
{ |
432 |
t = <INTEGER> { stack.push(new Integer(t.image)); } |
433 |
| t = <FLOATING_POINT> { stack.push(new Double(t.image)); } |
434 |
| t = <BOOLEAN> { stack.push(new Boolean(t.image)); } |
435 |
| t = <STRING> { stack.push(t.image.substring(1, t.image.length()-1)); } |
436 |
} |
437 |
|
438 |
int Arguments(): |
439 |
{ |
440 |
int argCount = 0; |
441 |
} |
442 |
{ |
443 |
<OPEN_PARENTHESIS> ( Expression() { argCount++; } |
444 |
( <COMMA> Expression() { argCount++; } |
445 |
)* |
446 |
) <CLOSE_PARENTHESIS> |
447 |
{ return argCount; } |
448 |
} |
449 |
|