blob: a1138644c93a65273b01e4cc0e084a655095ce2e [file] [log] [blame]
Till Westmannea8ab392013-06-05 15:17:08 -07001/*
Ian Maxon928bbd12015-09-14 17:12:48 -07002 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
Ian Maxon032a1782015-06-30 17:10:51 -07009 *
Ian Maxon928bbd12015-09-14 17:12:48 -070010 * http://www.apache.org/licenses/LICENSE-2.0
Ian Maxon032a1782015-06-30 17:10:51 -070011 *
Ian Maxon928bbd12015-09-14 17:12:48 -070012 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
Till Westmannea8ab392013-06-05 15:17:08 -070018 */
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +000019package [PACKAGE];
20
21import java.io.IOException;
22import [PACKAGE].[LEXER_NAME]Exception;
23
24public class [LEXER_NAME] {
25
26 public static final int
27 TOKEN_EOF = 0, TOKEN_AUX_NOT_FOUND = 1 [TOKENS_CONSTANTS];
28
29 // Human representation of tokens. Useful for debug.
30 // Is possible to convert a TOKEN_CONSTANT in its image through
31 // [LEXER_NAME].tokenKindToString(TOKEN_CONSTANT);
32 private static final String[] tokenImage = {
33 "<EOF>", "<AUX_NOT_FOUND>" [TOKENS_IMAGES]
34 };
35
36 private static final char EOF_CHAR = 4;
37 protected java.io.Reader inputStream;
38 protected int column;
39 protected int line;
40 protected boolean prevCharIsCR;
41 protected boolean prevCharIsLF;
Till Westmann8cdbd392014-04-04 18:31:08 -070042 protected boolean containsEscapes;
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +000043 protected char[] buffer;
44 protected int bufsize;
45 protected int bufpos;
46 protected int tokenBegin;
47 protected int endOf_USED_Buffer;
48 protected int endOf_UNUSED_Buffer;
49 protected int maxUnusedBufferSize;
50
51// ================================================================================
52// Auxiliary functions. Can parse the tokens used in the grammar as partial/auxiliary
53// ================================================================================
54
55 [LEXER_AUXFUNCTIONS]
56
57// ================================================================================
58// Main method. Return a TOKEN_CONSTANT
59// ================================================================================
60
Till Westmann8cdbd392014-04-04 18:31:08 -070061 public int next() throws [LEXER_NAME]Exception, IOException {
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +000062 char currentChar = buffer[bufpos];
63 while (currentChar == ' ' || currentChar=='\t' || currentChar == '\n' || currentChar=='\r')
64 currentChar = readNextChar();
65 tokenBegin = bufpos;
Till Westmann8cdbd392014-04-04 18:31:08 -070066 containsEscapes = false;
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +000067 if (currentChar==EOF_CHAR) return TOKEN_EOF;
68
69 [LEXER_LOGIC]
70 }
71
72// ================================================================================
73// Public interface
74// ================================================================================
Abdullah Alamoudi284590e2016-01-03 15:42:18 +030075
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +000076 public [LEXER_NAME](java.io.Reader stream) throws IOException{
77 reInit(stream);
78 }
79
Abdullah Alamoudi284590e2016-01-03 15:42:18 +030080 public [LEXER_NAME]() throws IOException{
81 reInit();
82 }
83
84 public void setBuffer(char[] buffer){
85 this.buffer = buffer;
86 tokenBegin = bufpos = 0;
87 containsEscapes = false;
88 line++;
89 tokenBegin = -1;
90 }
91
92 public void reInit(){
93 bufsize = Integer.MAX_VALUE;
94 endOf_UNUSED_Buffer = bufsize;
95 endOf_USED_Buffer = bufsize;
96 line = 0;
97 prevCharIsCR = false;
98 prevCharIsLF = false;
99 tokenBegin = -1;
100 maxUnusedBufferSize = bufsize;
101 }
102
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +0000103 public void reInit(java.io.Reader stream) throws IOException{
104 done();
105 inputStream = stream;
106 bufsize = 4096;
107 line = 1;
108 column = 0;
109 bufpos = -1;
110 endOf_UNUSED_Buffer = bufsize;
111 endOf_USED_Buffer = 0;
112 prevCharIsCR = false;
113 prevCharIsLF = false;
114 buffer = new char[bufsize];
115 tokenBegin = -1;
116 maxUnusedBufferSize = 4096/2;
117 readNextChar();
118 }
119
120 public String getLastTokenImage() {
121 if (bufpos >= tokenBegin)
122 return new String(buffer, tokenBegin, bufpos - tokenBegin);
123 else
124 return new String(buffer, tokenBegin, bufsize - tokenBegin) +
125 new String(buffer, 0, bufpos);
126 }
127
Till Westmannab40b092014-03-28 15:44:01 -0700128 public int getColumn() {
129 return column;
130 }
131
132 public int getLine() {
133 return line;
134 }
135
Till Westmann8cdbd392014-04-04 18:31:08 -0700136 public boolean containsEscapes() {
137 return containsEscapes;
138 }
139
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +0000140 public static String tokenKindToString(int token) {
141 return tokenImage[token];
142 }
143
144 public void done(){
145 buffer = null;
146 }
147
148// ================================================================================
149// Parse error management
150// ================================================================================
151
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +0000152 protected int parseError(int ... tokens) throws [LEXER_NAME]Exception {
153 StringBuilder message = new StringBuilder();
Till Westmannab40b092014-03-28 15:44:01 -0700154 message.append("Parse error at (").append(line).append(", ").append(column).append(")");
155 if (tokens.length > 0) {
156 message.append(" expecting:");
157 for (int tokenId : tokens){
158 message.append(" ").append([LEXER_NAME].tokenKindToString(tokenId));
159 }
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +0000160 }
161 throw new [LEXER_NAME]Exception(message.toString());
162 }
163
164 protected void updateLineColumn(char c){
165 column++;
166
167 if (prevCharIsLF)
168 {
169 prevCharIsLF = false;
170 line += (column = 1);
171 }
172 else if (prevCharIsCR)
173 {
174 prevCharIsCR = false;
175 if (c == '\n')
176 {
177 prevCharIsLF = true;
178 }
179 else
180 {
181 line += (column = 1);
182 }
183 }
184
185 if (c=='\r') {
186 prevCharIsCR = true;
187 } else if(c == '\n') {
188 prevCharIsLF = true;
189 }
190 }
191
192// ================================================================================
193// Read data, buffer management. It uses a circular (and expandable) buffer
194// ================================================================================
195
196 protected char readNextChar() throws IOException {
197 if (++bufpos >= endOf_USED_Buffer)
198 fillBuff();
199 char c = buffer[bufpos];
200 updateLineColumn(c);
201 return c;
202 }
203
204 protected boolean fillBuff() throws IOException {
205 if (endOf_UNUSED_Buffer == endOf_USED_Buffer) // If no more unused buffer space
206 {
207 if (endOf_UNUSED_Buffer == bufsize) // -- If the previous unused space was
208 { // -- at the end of the buffer
209 if (tokenBegin > maxUnusedBufferSize) // -- -- If the first N bytes before
210 { // the current token are enough
211 bufpos = endOf_USED_Buffer = 0; // -- -- -- setup buffer to use that fragment
212 endOf_UNUSED_Buffer = tokenBegin;
213 }
214 else if (tokenBegin < 0) // -- -- If no token yet
215 bufpos = endOf_USED_Buffer = 0; // -- -- -- reuse the whole buffer
216 else
217 ExpandBuff(false); // -- -- Otherwise expand buffer after its end
218 }
219 else if (endOf_UNUSED_Buffer > tokenBegin) // If the endOf_UNUSED_Buffer is after the token
220 endOf_UNUSED_Buffer = bufsize; // -- set endOf_UNUSED_Buffer to the end of the buffer
221 else if ((tokenBegin - endOf_UNUSED_Buffer) < maxUnusedBufferSize)
222 { // If between endOf_UNUSED_Buffer and the token
223 ExpandBuff(true); // there is NOT enough space expand the buffer
224 } // reorganizing it
225 else
226 endOf_UNUSED_Buffer = tokenBegin; // Otherwise there is enough space at the start
227 } // so we set the buffer to use that fragment
228 int i;
229 if ((i = inputStream.read(buffer, endOf_USED_Buffer, endOf_UNUSED_Buffer - endOf_USED_Buffer)) == -1)
230 {
231 inputStream.close();
232 buffer[endOf_USED_Buffer]=(char)EOF_CHAR;
233 endOf_USED_Buffer++;
234 return false;
235 }
236 else
237 endOf_USED_Buffer += i;
238 return true;
239 }
240
241
242 protected void ExpandBuff(boolean wrapAround)
243 {
244 char[] newbuffer = new char[bufsize + maxUnusedBufferSize];
245
246 try {
247 if (wrapAround) {
248 System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
249 System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos);
250 buffer = newbuffer;
251 endOf_USED_Buffer = (bufpos += (bufsize - tokenBegin));
252 }
253 else {
254 System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
255 buffer = newbuffer;
256 endOf_USED_Buffer = (bufpos -= tokenBegin);
257 }
258 } catch (Throwable t) {
259 throw new Error(t.getMessage());
260 }
261
262 bufsize += maxUnusedBufferSize;
263 endOf_UNUSED_Buffer = bufsize;
264 tokenBegin = 0;
Abdullah Alamoudi284590e2016-01-03 15:42:18 +0300265 }
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +0000266}