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 @ 43983

History | View | Annotate | Download (6.37 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.Stack;
10
import org.gvsig.expressionevaluator.ExpressionSyntaxException;
11
import org.gvsig.tools.lang.Cloneable;
12

    
13
public abstract class AbstractLexicalAnalyzer implements LexicalAnalyzer {
14

    
15
    protected class DefaultToken implements Token {
16

    
17
        private int type;
18
        private String literal;
19
        private Object value;
20

    
21
        public DefaultToken() {
22
        }
23

    
24
        @Override
25
        public Token clone() throws CloneNotSupportedException {
26
            // We will assume that the properties of the class are immutable, so 
27
            // it would suffice to call the super class.
28
            DefaultToken other = (DefaultToken) super.clone();
29
            return other;
30
        }
31

    
32
        @Override
33
        public void set(int type, String literal) {
34
            this.set(type, literal, literal);
35
        }
36

    
37
        @Override
38
        public void set(int type, String literal, Object value) {
39
            this.literal = literal;
40
            this.type = type;
41
            this.value = value;
42
        }
43

    
44
        @Override
45
        public int getType() {
46
            return type;
47
        }
48

    
49
        @Override
50
        public Object getValue() {
51
            return value;
52
        }
53

    
54
        @Override
55
        public String getLiteral() {
56
            return literal;
57
        }
58

    
59
        public void setLiteral(String literal) {
60
            this.literal = literal;
61
        }
62

    
63
    }
64

    
65
    protected class Buffer implements Cloneable {
66

    
67
        StringBuilder builder;
68

    
69
        public Buffer() {
70
            this.builder = new StringBuilder();
71
        }
72

    
73
        @Override
74
        public Buffer clone() throws CloneNotSupportedException {
75
            Buffer other = (Buffer) super.clone();
76
            other.builder = new StringBuilder(builder);
77
            return other;
78
        }
79

    
80
        public void clear() {
81
            builder.delete(0, builder.length());
82
        }
83

    
84
        public void add(char ch) {
85
            builder.append(ch);
86
        }
87

    
88
        public int length() {
89
            return this.builder.length();
90
        }
91

    
92
        @Override
93
        public String toString() {
94
            return this.builder.toString();
95
        }
96
    }
97

    
98
    protected static final char EOF = 0;
99

    
100
    private NumberFormat nf;
101
    private ParsePosition nfPos;
102
    private Stack<Integer> states;
103
    private String source;
104
    private int position;
105

    
106
    protected Buffer buffer;
107
    protected Token token;
108
    protected Map<String, Integer> tokens;
109

    
110
    public AbstractLexicalAnalyzer(String source) {
111
        this.position = 0;
112
        this.source = source;
113
        this.states = new Stack<>();
114
        this.buffer = new Buffer();
115
        this.token = this.createToken();
116

    
117
        this.nf = NumberFormat.getInstance(Locale.UK);
118
        this.nfPos = new ParsePosition(0);
119

    
120
        this.tokens = new HashMap<>();
121
    }
122

    
123
    public AbstractLexicalAnalyzer() {
124
        this(null);
125
    }
126

    
127
    protected Token createToken() {
128
        return new DefaultToken();
129
    }
130
    
131
    @Override
132
    public LexicalAnalyzer clone() throws CloneNotSupportedException {
133
        AbstractLexicalAnalyzer other = (AbstractLexicalAnalyzer) super.clone();
134
        other.nf = NumberFormat.getInstance(Locale.UK);
135
        other.nfPos = new ParsePosition(0);
136
        other.buffer = buffer.clone();
137
        other.token = token.clone();
138
        other.states = new Stack<>();
139
        other.states.addAll(states);
140
        other.tokens = new HashMap<>(tokens);
141
        return other;
142
    }
143

    
144
    @Override
145
    public void setSource(String source) {
146
        this.source = source;
147
        this.position = 0;
148
    }
149

    
150
    @Override
151
    public String getSource() {
152
        return this.source;
153
    }
154

    
155
    @Override
156
    public Token next() {
157
        return getToken();
158
    }
159

    
160
    @Override
161
    public Token look() {
162
        push_state();
163
        try {
164
            return getToken();
165
        } finally {
166
            pop_state();
167
        }
168
    }
169

    
170
    abstract protected Token getToken();
171

    
172
    protected void push_state() {
173
        this.states.push(position);
174
    }
175

    
176
    protected void pop_state() {
177
        position = this.states.pop();
178
    }
179

    
180
    @Override
181
    public int getPosition() {
182
        return position;
183
    }
184

    
185
    public boolean isEOF() {
186
        return this.position >= this.source.length();
187
    }
188

    
189
    protected void skipblanks() {
190
        if (isEOF()) {
191
            return;
192
        }
193
        char ch = getch();
194
        while (ch != EOF && Character.isSpaceChar(ch)) {
195
            ch = getch();
196
        }
197
        ungetch();
198
    }
199

    
200
    protected char lookch() {
201
        if (this.position >= this.source.length()) {
202
            return EOF;
203
        }
204
        return this.source.charAt(this.position);
205
    }
206

    
207
    protected char getch() {
208
        if (this.position >= this.source.length()) {
209
            return EOF;
210
        }
211
        return this.source.charAt(this.position++);
212
    }
213

    
214
    protected void ungetch() {
215
        this.position--;
216
        if (this.position < 0) {
217
            this.position = 0;
218
        }
219
    }
220

    
221
    protected void parseString() {
222
        buffer.clear();
223
        char ch = getch();
224
        while (true) {
225
            if (ch == EOF) {
226
                throw new ExpressionSyntaxException("Found end of source and expected end of string", this);
227
            }
228
            if (ch == '\'') {
229
                ch = getch();
230
                if (ch == EOF) {
231
                    break;
232
                }
233
                if (ch != '\'') {
234
                    ungetch();
235
                    break;
236
                }
237
            }
238
            buffer.add(ch);
239
            ch = getch();
240
        }
241
        token.set(Token.STRING_LITERAL, buffer.toString());
242
    }
243

    
244
    protected void parseNumber() {
245
        this.nfPos.setIndex(this.position);
246
        Number n = nf.parse(source, this.nfPos);
247
        if (this.nfPos.getIndex() == this.position) {
248
            throw new RuntimeException("Expected a number at position " + this.nfPos.getIndex() + ".");
249
        }
250
        String literal = source.substring(this.position, this.nfPos.getIndex());
251
        this.position = this.nfPos.getIndex();
252
        if (n instanceof Long || n instanceof Integer) {
253
            token.set(Token.INTEGER_LITERAL, literal, n);
254
        } else {
255
            token.set(Token.FLOATING_POINT_LITERAL, literal, n);
256
        }
257
    }
258
}