source: josm/trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/parser/MapCSSParser.jj@ 3848

Last change on this file since 3848 was 3848, checked in by bastiK, 14 years ago

Experimental mapcss support. All *.java files in the gui/mappaint/mapcss/parser folder are generated from the javacc source file MapCSSParser.jj in the same folder. The generated code sums up to 2700 lines, there is no further build dependency.

File size: 8.8 KB
Line 
1// License: GPL. For details, see LICENSE file.
2options {
3 STATIC = false;
4}
5
6PARSER_BEGIN(MapCSSParser)
7package org.openstreetmap.josm.gui.mappaint.mapcss.parser;
8
9import java.awt.Color;
10import java.util.ArrayList;
11import java.util.List;
12
13import org.openstreetmap.josm.gui.mappaint.mapcss.Condition;
14import org.openstreetmap.josm.gui.mappaint.mapcss.Expression;
15import org.openstreetmap.josm.gui.mappaint.mapcss.Instruction;
16import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSRule;
17import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
18import org.openstreetmap.josm.gui.mappaint.mapcss.Selector;
19import org.openstreetmap.josm.gui.mappaint.mapcss.Expression.FunctionExpression;
20import org.openstreetmap.josm.gui.mappaint.mapcss.Expression.LiteralExpression;
21import org.openstreetmap.josm.tools.Pair;
22
23public class MapCSSParser {
24}
25PARSER_END(MapCSSParser)
26
27/*************
28 * Token definitions
29 */
30
31<DEFAULT>
32TOKEN:
33{
34 < IDENT: ["a"-"z","A"-"Z","_"] ( ["a"-"z","A"-"Z","_","-","0"-"9"] )* >
35| < UINT: ["1"-"9"] ( ["0"-"9"] )* >
36| < UFLOAT: ( ["0"-"9"] )+ ( "." ( ["0"-"9"] )+ )? >
37| < STRING: "\"" ( [" ","!","#"-"&","("-"[","]"-"~","\u0080"-"\uFFFF"] | "\\\"" | "\\\\" )* "\"" >
38| < #H: ["0"-"9","a"-"f","A"-"F"] >
39| < HEXCOLOR: "#" ( <H><H><H><H><H><H> | <H><H><H> ) >
40| < S: ( " " | "\t" | "\n" | "\r" | "\f" )+ >
41| < STAR: "*" >
42| < SLASH: "/" >
43| < LBRACE: "{" >
44| < RBRACE: "}" >
45| < LSQUARE: "[" >
46| < RSQUARE: "]" >
47| < LPAR: "(" >
48| < RPAR: ")" >
49| < EQUAL: "=" >
50| < EXCLAMATION: "!" >
51| < EXCLAMATION_EQUAL: "!=" >
52| < COLON: ":" >
53| < DCOLON: "::" >
54| < SEMICOLON: ";" >
55| < COMMA: "," >
56| < PIPE_Z: "|z" >
57| < PLUS: "+" >
58| < MINUS: "-" >
59| < COMMENT_START: "/*" > : COMMENT
60| < UNEXPECTED_CHAR : ~[] > // avoid TokenMgrErrors because they are hard to recover from
61}
62
63<COMMENT>
64TOKEN:
65{
66 < COMMENT_END: "*/" > : DEFAULT
67}
68
69<COMMENT>
70SKIP:
71{
72 < ~[] >
73}
74
75/*************
76 * Parser definitions
77 *
78 * rule
79 * _______________________|______________________________
80 * | |
81 * selector declaration
82 * _________|___________________ _________|____________
83 * | | | |
84 *
85 * way|z11-12[highway=residential] { color: red; width: 3 }
86 *
87 * |_____||___________________| |_________|
88 * | | |
89 * zoom condition instruction
90 *
91 * more general:
92 *
93 * way|z13-[a=b][c=d]::subpart, way|z-3[u=v]:closed::subpart2 { p1 : val; p2 : val; }
94 *
95 * 'val' can be a literal, or an expression like "prop(width, default) + 0.8".
96 *
97 */
98
99int uint() :
100{
101 Token i;
102}
103{
104 i=<UINT> { return Integer.parseInt(i.image); }
105}
106
107float ufloat() :
108{
109 Token f;
110}
111{
112 ( f=<UFLOAT> | f=<UINT> )
113 { return Float.parseFloat(f.image); }
114}
115
116String string() :
117{
118 Token t;
119}
120{
121 t=<STRING>
122 {
123 return t.image.substring(1, t.image.length() - 1).replace("\\\"", "\"").replace("\\\\", "\\");
124 }
125}
126
127String string_or_ident() :
128{
129 Token t;
130 String s;
131}
132{
133 t=<IDENT> { return t.image; } | s=string() { return s; }
134}
135
136/**
137 * white-space
138 */
139void s() :
140{
141}
142{
143 ( <S> )?
144}
145
146/**
147 * mix of white-space and comments
148 */
149void w() :
150{
151}
152{
153 ( <S> | ( <COMMENT_START> <COMMENT_END> ) )*
154}
155
156/**
157 * comma delimited list of floats (at least 2, all >= 0)
158 */
159float[] float_array() :
160{
161 float f;
162 List<Float> fs = new ArrayList<Float>();
163}
164{
165 f=ufloat() { fs.add(f); }
166 (
167 <COMMA> s()
168 f=ufloat() { fs.add(f); }
169 )+
170 {
171 float[] a = new float[fs.size()];
172 for (int i=0; i<fs.size(); ++i) {
173 a[i] = fs.get(i);
174 }
175 return a;
176 }
177}
178
179/**
180 * root
181 */
182void sheet(MapCSSStyleSource sheet):
183{
184 MapCSSRule r;
185 Token com = null;
186}
187{
188 w()
189 ( r=rule() { sheet.rules.add(r); } w() )*
190 <EOF>
191}
192
193MapCSSRule rule():
194{
195 List<Selector> selectors = new ArrayList<Selector>();
196 Selector sel;
197 List<Instruction> decl;
198}
199{
200 sel=selector() { selectors.add(sel); } w()
201 (
202 <COMMA> w()
203 sel=selector() { selectors.add(sel); } w()
204 )*
205 decl=declaration()
206 { return new MapCSSRule(selectors, decl); }
207}
208
209Selector selector() :
210{
211 Token base;
212 Condition c;
213 Pair<Integer, Integer> r = null;
214 List<Condition> conditions = new ArrayList<Condition>();
215 String sub = null;
216}
217{
218 ( base=<IDENT> | base=<STAR> )
219 ( r=zoom() )?
220 ( ( c=condition() | c=pseudoclass() ) { conditions.add(c); } )*
221 ( sub=subpart() )?
222 { return new Selector(base.image, r, conditions, sub); }
223}
224
225Pair<Integer, Integer> zoom() :
226{
227 Integer min = 0;
228 Integer max = Integer.MAX_VALUE;
229}
230{
231 <PIPE_Z>
232 (
233 ( <MINUS> max=uint() ) |
234 ( min=uint() ( <MINUS> ( max=uint() )? )? )
235 )
236 { return new Pair<Integer, Integer>(min, max); }
237}
238
239Condition condition() :
240{
241 boolean not = false;
242 String key;
243 String val;
244}
245{
246 <LSQUARE>
247 ( <EXCLAMATION> { not = true; } )?
248 key=string_or_ident()
249 (
250 ( <EXCLAMATION_EQUAL> { not = true; } | <EQUAL> )
251 val=string_or_ident()
252 <RSQUARE>
253 { return new Condition.KeyValueCondition(key, val, not ? Condition.Op.NEQ : Condition.Op.EQ); }
254 )?
255 <RSQUARE>
256 { return new Condition.KeyCondition(key, not); }
257}
258
259Condition pseudoclass() :
260{
261 Token t;
262 boolean not = false;
263}
264{
265 <COLON>
266 ( <EXCLAMATION> { not = true; } )? t=<IDENT>
267 { return new Condition.PseudoClassCondition(t.image, not); }
268}
269
270String subpart() :
271{
272 Token t;
273}
274{
275 <DCOLON>
276 ( t=<IDENT> | t=<STAR> )
277 { return t.image; }
278}
279
280List<Instruction> declaration() :
281{
282 List<Instruction> ins = new ArrayList<Instruction>();
283 Instruction i;
284}
285{
286 <LBRACE> w()
287 ( <RBRACE> { return ins; } )?
288 try {
289 i=instruction() { if (i != null) ins.add(i); }
290 (
291 <SEMICOLON> w()
292 ( <RBRACE> { return ins; } )?
293 i=instruction() { if (i != null) ins.add(i); }
294 )*
295 <RBRACE> { return ins; }
296 } catch (ParseException ex) {
297 error_skipto(RBRACE);
298 return ins;
299 }
300}
301
302Instruction instruction() :
303{
304 Token key;
305 Object val;
306}
307{
308 key=<IDENT> w()
309 <COLON> w()
310 (
311 LOOKAHEAD(2) // both number and float array start with a number
312 ( val=float_array() w() )
313 |
314 val=expression()
315 )
316 {
317 if (val instanceof LiteralExpression)
318 return new Instruction.AssignmentInstruction(key.image, ((LiteralExpression) val).evaluate(null));
319 else
320 return new Instruction.AssignmentInstruction(key.image, val);
321 }
322}
323
324Expression expression():
325{
326 List<Expression> args = new ArrayList<Expression>();
327 Expression e;
328 String op = null;
329}
330{
331 e=primary() { args.add(e); } w()
332 (
333 ( <PLUS> { op = "+"; } w() e=primary() { args.add(e); } w() )+
334 |
335 ( <STAR> { op = "*"; } w() e=primary() { args.add(e); } w() )+
336 |
337 ( <MINUS> { op = "-"; } w() e=primary() { args.add(e); } w() )
338 |
339 ( <SLASH> { op = "/"; } w() e=primary() { args.add(e); } w() )
340 )?
341 {
342 if (args.size() == 1)
343 return args.get(0);
344 return new FunctionExpression(op, args);
345 }
346}
347
348Expression primary() :
349{
350 Expression nested;
351 FunctionExpression fn;
352 Object lit;
353}
354{
355 LOOKAHEAD(2) // both function and identifier start with an identifier
356 fn=function() { return fn; }
357 |
358 lit=literal() { return new LiteralExpression(lit); }
359 |
360 ( <LPAR> w() nested=expression() <RPAR> ) { return nested; }
361}
362
363FunctionExpression function() :
364{
365 Token tmp;
366 Expression arg;
367 String name;
368 List<Expression> args = new ArrayList<Expression>();
369}
370{
371 tmp=<IDENT> { name = tmp.image; } w()
372 <LPAR> w()
373 arg=expression() { args.add(arg); }
374 ( <COMMA> w() arg=expression() { args.add(arg); } )*
375 <RPAR>
376 { return new FunctionExpression(name, args); }
377}
378
379Object literal() :
380{
381 Object val;
382 Token t;
383 float f;
384}
385{
386 val=string_or_ident() { return val; }
387 |
388 ( <PLUS> f=ufloat() ) { return new Instruction.RelativeFloat(f); }
389 |
390 ( <MINUS> f=ufloat() ) { return -f; }
391 |
392 f=ufloat() { return f; }
393 |
394 t=<HEXCOLOR>
395 {
396 String clr = t.image.substring(1);
397 if (clr.length() == 3) {
398 clr = new String(new char[] {clr.charAt(0),clr.charAt(0),clr.charAt(1),clr.charAt(1),clr.charAt(2),clr.charAt(2)});
399 }
400 if (clr.length() != 6)
401 throw new AssertionError();
402 return new Color(Integer.parseInt(clr, 16));
403 }
404}
405
406JAVACODE
407void error_skipto(int kind) {
408 ParseException e = generateParseException();
409 System.err.println(e);
410 Token t;
411 do {
412 t = getNextToken();
413 } while (t.kind != kind);
414}
415
Note: See TracBrowser for help on using the repository browser.