Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.library / org.gvsig.expressionevaluator / org.gvsig.expressionevaluator.lib / org.gvsig.expressionevaluator.lib.api / src / main / java / org / gvsig / expressionevaluator / spi / AbstractLexicalAnalyzer.java @ 46091

History | View | Annotate | Download (16.7 KB)

1
package org.gvsig.expressionevaluator.spi;
2

    
3
import org.gvsig.expressionevaluator.LexicalAnalyzer;
4
import java.text.NumberFormat;
5
import java.text.ParsePosition;
6
import java.util.HashMap;
7
import java.util.Locale;
8
import java.util.Map;
9
import java.util.Objects;
10
import java.util.Stack;
11
import org.apache.commons.lang3.StringUtils;
12
import org.gvsig.expressionevaluator.ExpressionRuntimeException;
13
import org.gvsig.expressionevaluator.ExpressionSyntaxException;
14
import org.gvsig.expressionevaluator.I18N;
15
import org.gvsig.tools.lang.Cloneable;
16

    
17
public abstract class AbstractLexicalAnalyzer implements LexicalAnalyzer {
18

    
19
    public static class RowCol {
20
        private final int row;
21
        private final int col;
22
        
23
        public RowCol(int row, int col) {
24
            this.row = row;
25
            this.col = col;
26
        }
27
    }
28

    
29
    protected class DefaultToken implements Token {
30

    
31
        private int type;
32
        private String literal;
33
        private Object value;
34

    
35
        public DefaultToken() {
36
        }
37

    
38
        @Override
39
        public Token clone() throws CloneNotSupportedException {
40
            // We will assume that the properties of the class are immutable, so 
41
            // it would suffice to call the super class.
42
            DefaultToken other = (DefaultToken) super.clone();
43
            return other;
44
        }
45

    
46
        @Override
47
        public void set(int type, String literal) {
48
            this.set(type, literal, literal);
49
        }
50

    
51
        @Override
52
        public void set(int type, String literal, Object value) {
53
            this.literal = literal;
54
            this.type = type;
55
            this.value = value;
56
        }
57

    
58
        @Override
59
        public int getType() {
60
            return type;
61
        }
62

    
63
        @Override
64
        public Object getValue() {
65
            return value;
66
        }
67

    
68
        @Override
69
        public String getLiteral() {
70
            return literal;
71
        }
72

    
73
        @Override
74
        public void setLiteral(String literal) {
75
            this.literal = literal;
76
        }
77

    
78
        @Override
79
        public boolean is(String... values) {
80
            for (String theValue : values) {
81
                if( StringUtils.isBlank(literal) ) {
82
                    if( StringUtils.isBlank(theValue) ) {
83
                        return true;
84
                    }
85
                    continue;
86
                }
87
                if( StringUtils.isBlank(theValue) ) {
88
                    continue;
89
                }
90
                if( theValue.trim().equalsIgnoreCase(this.literal.trim()) ) {
91
                    return true;
92
                }
93
            }
94
            return false;
95
        }
96

    
97
        @Override
98
        public String toString() {
99
            return String.format("{%d,%s,%s}", this.type, Objects.toString(this.literal), Objects.toString(value));
100
        }
101
        
102
    }
103

    
104
    protected class Buffer implements Cloneable {
105

    
106
        StringBuilder builder;
107

    
108
        public Buffer() {
109
            this.builder = new StringBuilder();
110
        }
111

    
112
        @Override
113
        public Buffer clone() throws CloneNotSupportedException {
114
            Buffer other = (Buffer) super.clone();
115
            other.builder = new StringBuilder(builder);
116
            return other;
117
        }
118

    
119
        public void clear() {
120
            builder.delete(0, builder.length());
121
        }
122

    
123
        public void add(char ch) {
124
            builder.append(ch);
125
        }
126

    
127
        public int length() {
128
            return this.builder.length();
129
        }
130

    
131
        @Override
132
        public String toString() {
133
            return this.builder.toString();
134
        }
135
    }
136

    
137
    protected static final char EOF = 0;
138

    
139
    private NumberFormat nf;
140
    private ParsePosition nfPos;
141
    private Stack<Integer> states;
142
    private String source;
143
    private int position;
144
    private int maxposition;
145
    private int lineno;
146
    private int column;
147

    
148
    protected Buffer buffer;
149
    protected Token token;
150
    protected Map<String, Integer> tokens;
151
    protected boolean useBracketsForIdentifiers;
152
            
153
    public AbstractLexicalAnalyzer(String source) {
154
        this.useBracketsForIdentifiers = false;
155
        this.position = 0;
156
        this.maxposition = 0;
157
        this.source = source;
158
        this.states = new Stack<>();
159
        this.buffer = new Buffer();
160
        this.token = this.createToken();
161

    
162
        this.nf = NumberFormat.getInstance(Locale.UK);
163
        this.nf.setGroupingUsed(false);
164
        
165
        this.nfPos = new ParsePosition(0);
166

    
167
        this.tokens = new HashMap<>();
168
    }
169

    
170
    public AbstractLexicalAnalyzer() {
171
        this(null);
172
    }
173

    
174
    protected Token createToken() {
175
        return new DefaultToken();
176
    }
177
    
178
    @Override
179
    public LexicalAnalyzer clone() throws CloneNotSupportedException {
180
        AbstractLexicalAnalyzer other = (AbstractLexicalAnalyzer) super.clone();
181
        other.nf = NumberFormat.getInstance(Locale.UK);
182
        other.nfPos = new ParsePosition(0);
183
        other.buffer = buffer.clone();
184
        other.token = token.clone();
185
        other.states = new Stack<>();
186
        other.states.addAll(states);
187
        other.tokens = new HashMap<>(tokens);
188
        return other;
189
    }
190

    
191
    @Override
192
    public void setSource(String source) {
193
        this.source = source;
194
        this.position = 0;
195
        this.maxposition = 0;
196
    }
197

    
198
    @Override
199
    public String getSource() {
200
        return this.source;
201
    }
202

    
203
    @Override
204
    public Token next() {
205
        return getToken();
206
    }
207

    
208
    @Override
209
    public Token look() {
210
        save_state();
211
        try {
212
            return getToken();
213
        } finally {
214
            restore_state();
215
        }
216
    }
217

    
218
    abstract protected Token getToken();
219

    
220
    public void save_state() {
221
        this.states.push(position);
222
    }
223

    
224
    public void restore_state() {
225
        position = this.states.pop();
226
    }
227

    
228
    public void drop_state() {
229
        this.states.pop();
230
    }
231

    
232
    @Override
233
    public int getPosition() {
234
        return position;
235
    }
236

    
237
    @Override
238
    public int getMaxPosition() {
239
        return this.maxposition;
240
    }
241
    
242
    private RowCol calcualteRowAndColumn(int position) {
243
        final String s = this.source;
244
        int max = s.length();
245
        if( max > position ) {
246
            max = position;
247
        }
248
        int line = 1;
249
        int col = 0;
250
        for (int i = 0; i < max ; i++) {
251
            if( s.charAt(i)=='\n' ) {
252
                line++;
253
                col = 0;
254
            } 
255
            col++;
256
        }
257
        return new RowCol(line, col);
258
    }
259

    
260
    @Override
261
    public int getLine() {
262
        RowCol rowcol = this.calcualteRowAndColumn(this.position);
263
        this.lineno = rowcol.row;
264
        this.column = rowcol.col;
265
        return lineno;
266
    }
267

    
268
    @Override
269
    public int getMaxLine() {
270
        RowCol rowcol = this.calcualteRowAndColumn(this.maxposition);
271
        return rowcol.row;
272
    }
273

    
274
    @Override
275
    public int getColumn() {
276
        RowCol rowcol = this.calcualteRowAndColumn(this.position);
277
        this.lineno = rowcol.row;
278
        this.column = rowcol.col;
279
        return column;
280
    }
281

    
282
    @Override
283
    public int getMaxColumn() {
284
        RowCol rowcol = this.calcualteRowAndColumn(this.maxposition);
285
        return rowcol.col;
286
    }
287

    
288
    @Override
289
    public boolean isEOF() {
290
        return this.position >= this.source.length();
291
    }
292

    
293
    protected void skipblanks() {
294
        if (isEOF()) {
295
            return;
296
        }
297
        char ch = getch();
298
        while (ch != EOF && Character.isWhitespace(ch)) {
299
            ch = getch();
300
        }
301
        ungetch();
302
    }
303

    
304
    protected char lookch() {
305
        if (this.position >= this.source.length()) {
306
            return EOF;
307
        }
308
        return this.source.charAt(this.position);
309
    }
310

    
311
    protected char getch() {
312
        if (this.position >= this.source.length()) {
313
            return EOF;
314
        }
315
        this.column++;
316
        char ch = this.source.charAt(this.position++);
317
        if( this.position>this.maxposition ) {
318
            this.maxposition = this.position;
319
        }
320
        return ch;
321
    }
322

    
323
    protected void ungetch() {
324
        this.position--;
325
        if (this.position < 0) {
326
            this.position = 0;
327
        }
328
        this.column--;
329
        if (this.column < 0) {
330
            this.column = 0;
331
        }
332
    }
333

    
334
    protected void parseString() {
335
        buffer.clear();
336
        char ch = getch();
337
        while (true) {
338
            if (ch == EOF) {
339
                throw new ExpressionSyntaxException(I18N.End_of_string_was_expected_and_end_of_source_was_found(), this);
340
            }
341
            if (ch == '\'') {
342
                ch = getch();
343
                if (ch == EOF) {
344
                    break;
345
                }
346
                if (ch != '\'') {
347
                    ungetch();
348
                    break;
349
                }
350
            }
351
            buffer.add(ch);
352
            ch = getch();
353
        }
354
        token.set(Token.STRING_LITERAL, buffer.toString());
355
    }
356
    
357
//    protected void parseStringBlock() {
358
//        buffer.clear();
359
//        char ch = getch();
360
//        while (true) {
361
//            if (ch == EOF) {
362
//                throw new ExpressionSyntaxException(I18N.End_of_string_was_expected_and_end_of_source_was_found(), this);
363
//            }
364
//            if (ch == '$') {
365
//                ch = getch();
366
//                if (ch == EOF) {
367
//                    break;
368
//                }
369
//                if (ch != '$') {
370
//                    ungetch();
371
//                    break;
372
//                }
373
//            }
374
//            buffer.add(ch);
375
//            ch = getch();
376
//        }
377
//        token.set(Token.STRING_LITERAL, buffer.toString());
378
//    }
379
    
380
    protected void parseDMSNumber() {
381
        int d;
382
        int m;
383
        int s_i;
384
        double s_d;
385
        double s;
386
        char ch;
387
        Integer sign = null;
388
        
389
        skipblanks();
390
        ch = getch();
391
        if( ch!='@' ) {
392
            throw new ExpressionSyntaxException(I18N.Wrong_special_number_start(), this);
393
        }
394
        
395
        // Parseamos los grados
396
        skipblanks();
397
        ch = getch();
398
        if( ch=='+' ) {
399
            sign = 1;
400
            ch = getch();
401
        } else if ( ch=='-' ) {
402
            sign = -1;
403
            ch = getch();
404
        }
405
        
406
        buffer.clear();
407
        if( !Character.isDigit(ch) ) {
408
            throw new ExpressionSyntaxException(I18N.Expected_a_number_at_position_XpositionX(this.getPosition()), this);        
409
        }
410
        while (true) {
411
            if (ch == EOF) {
412
                throw new ExpressionSyntaxException(I18N.End_of_string_was_expected_and_end_of_source_was_found(), this);        
413
            }
414
            if( !Character.isDigit(ch) ) {
415
                break;
416
            }
417
            buffer.add(ch);
418
            ch = getch();
419
        }
420
        if( !StringUtils.contains(" ?:", ch) ) {
421
            throw new ExpressionSyntaxException(I18N.Expected_XexpectedX_and_found_XfoundX(" ", String.valueOf(ch)), this);
422
        }
423
        d = Integer.parseInt(buffer.toString());
424
        
425
        // Parseamos los minutos
426
        skipblanks();
427
        ch = getch();
428
        buffer.clear();
429
        if( !Character.isDigit(ch) ) {
430
            throw new ExpressionSyntaxException(I18N.Expected_a_number_at_position_XpositionX(this.getPosition()), this);        
431
        }
432
        while (true) {
433
            if (ch == EOF) {
434
                throw new ExpressionSyntaxException(I18N.End_of_string_was_expected_and_end_of_source_was_found(), this);        
435
            }
436
            if( !Character.isDigit(ch) ) {
437
                break;
438
            }
439
            buffer.add(ch);
440
            ch = getch();
441
        }
442
        if( !StringUtils.contains(" ':", ch) ) {
443
            throw new ExpressionSyntaxException(I18N.Expected_XexpectedX_and_found_XfoundX(" ", String.valueOf(ch)), this);
444
        }
445
        m = Integer.parseInt(buffer.toString());
446

    
447
        // Parseamos la parte entera de los segundos
448
        skipblanks();
449
        ch = getch();
450
        buffer.clear();
451
        if( !Character.isDigit(ch) ) {
452
            throw new ExpressionSyntaxException(I18N.Expected_a_number_at_position_XpositionX(this.getPosition()), this);        
453
        }
454
        while (true) {
455
            if (ch == EOF) {
456
                throw new ExpressionSyntaxException(I18N.End_of_string_was_expected_and_end_of_source_was_found(), this);        
457
            }
458
            if( !Character.isDigit(ch) ) {
459
                break;
460
            }
461
            buffer.add(ch);
462
            ch = getch();
463
        }
464
        s_i = Integer.parseInt(buffer.toString());
465

    
466
        if( ch == '.' ) {
467
            // Parseamos la parte decimal de los segundos
468
            skipblanks();
469
            ch = getch();
470
            buffer.clear();
471
            if( !Character.isDigit(ch) ) {
472
                throw new ExpressionSyntaxException(I18N.Expected_a_number_at_position_XpositionX(this.getPosition()), this);        
473
            }
474
            while (true) {
475
                if (ch == EOF) {
476
//                    throw new ExpressionSyntaxException(I18N.End_of_string_was_expected_and_end_of_source_was_found(), this);        
477
                    break;
478
                }
479
                if( !Character.isDigit(ch) ) {
480
                    break;
481
                }
482
                buffer.add(ch);
483
                ch = getch();
484
            }            
485
            String ss = buffer.toString();
486
            s_d = (double) Integer.parseInt(ss) / Math.pow(10, ss.length());
487
        } else {
488
            s_d = 0;
489
        }
490
        if( ch!=EOF && !StringUtils.contains(" \"", ch) ) {
491
            throw new ExpressionSyntaxException(I18N.Expected_XexpectedX_and_found_XfoundX(" ", String.valueOf(ch)), this);
492
        }
493
        
494
        s = s_i + s_d; 
495
        
496
        double dd = d + m / 60.0 + s / 3600.0;
497
        
498
        if( sign==null ) {
499
            skipblanks();
500
            ch = getch();
501
            switch(ch) {
502
                case 'N':
503
                case 'n':
504
                    if( dd>90 ) {
505
                        throw new ExpressionSyntaxException(I18N.Incorrect_value_for_latitude(dd), this);
506
                    }
507
                    sign = 1;
508
                    break;
509

    
510
                case 'S':
511
                case 's':
512
                    if( dd>90 ) {
513
                        throw new ExpressionSyntaxException(I18N.Incorrect_value_for_latitude(dd), this);
514
                    }
515
                    sign = -1;
516
                    break;
517
                case 'E':
518
                case 'e':
519
                    if( dd>180 ) {
520
                        throw new ExpressionSyntaxException(I18N.Incorrect_value_for_latitude(dd), this);
521
                    }
522
                    sign = 1;
523
                    break;
524

    
525
                case 'O':
526
                case 'o':
527
                case 'W':
528
                case 'w':
529
                    if( dd>180 ) {
530
                        throw new ExpressionSyntaxException(I18N.Incorrect_value_for_longitude(dd), this);
531
                    }
532
                    sign = -1;
533
                    break;
534

    
535
                default:
536
                    throw new ExpressionSyntaxException(I18N.Expected_XexpectedX_and_found_XfoundX("N/S/E/W", String.valueOf(ch)), this);
537
            }
538
        } 
539
        dd = dd * sign;
540
        token.set(
541
                Token.FLOATING_POINT_LITERAL,
542
                String.format("@%s%d? %d' %f\"", sign<0? "-":"+", d,m,s) ,
543
                dd
544
        );
545
    }
546
    
547
    protected void parseNumber() {
548
        this.nfPos.setIndex(this.position);
549
        Number n = nf.parse(source, this.nfPos);
550
        if (this.nfPos.getIndex() == this.position) {
551
            throw new ExpressionRuntimeException(I18N.Expected_a_number_at_position_XpositionX(this.nfPos.getIndex()));
552
        }
553
        String literal = source.substring(this.position, this.nfPos.getIndex());
554
        this.position = this.nfPos.getIndex();
555
        if( n instanceof Long ) {
556
            long l = ((Long)n);
557
            if( l>Integer.MIN_VALUE && l<Integer.MAX_VALUE ) {
558
                token.set(Token.INTEGER_LITERAL, literal, (int)l);
559
            } else {
560
                token.set(Token.INTEGER_LITERAL, literal, n);
561
            }
562
        } else if( n instanceof Integer) {
563
            token.set(Token.INTEGER_LITERAL, literal, n);
564
        } else {
565
            token.set(Token.FLOATING_POINT_LITERAL, literal, n);
566
        }
567
    }
568
    
569
    @Override
570
    public void setUseBracketsForIdentifiers(boolean useBracketsForIdentifiers) {
571
        this.useBracketsForIdentifiers = useBracketsForIdentifiers;
572
    }
573
    
574
    @Override
575
    public boolean getUseBracketsForIdentifiers() {
576
        return this.useBracketsForIdentifiers;
577
    }
578
    
579
    @Override
580
    public String getSourceContext() {
581
        String s = StringUtils.left(source, maxposition) + "[*]" + StringUtils.mid(source, maxposition, 200);
582
        if( s.length()>200 ) {
583
            s = "..."+StringUtils.mid(s, maxposition-100, 200)+"...";
584
        }
585
        return s;
586
    }      
587
    
588
}