blob: e34bde43693af3c45df4cd1a69f7187e0f5fc9b8 [file] [log] [blame]
Till Westmannea8ab392013-06-05 15:17:08 -07001/*
2 * Copyright 2009-2013 by The Regents of the University of California
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * you may obtain a copy of the License from
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +000015package [PACKAGE];
16
17import java.io.IOException;
18import [PACKAGE].[LEXER_NAME]Exception;
19
20public class [LEXER_NAME] {
21
22 public static final int
23 TOKEN_EOF = 0, TOKEN_AUX_NOT_FOUND = 1 [TOKENS_CONSTANTS];
24
25 // Human representation of tokens. Useful for debug.
26 // Is possible to convert a TOKEN_CONSTANT in its image through
27 // [LEXER_NAME].tokenKindToString(TOKEN_CONSTANT);
28 private static final String[] tokenImage = {
29 "<EOF>", "<AUX_NOT_FOUND>" [TOKENS_IMAGES]
30 };
31
32 private static final char EOF_CHAR = 4;
33 protected java.io.Reader inputStream;
34 protected int column;
35 protected int line;
36 protected boolean prevCharIsCR;
37 protected boolean prevCharIsLF;
Till Westmann8cdbd392014-04-04 18:31:08 -070038 protected boolean containsEscapes;
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +000039 protected char[] buffer;
40 protected int bufsize;
41 protected int bufpos;
42 protected int tokenBegin;
43 protected int endOf_USED_Buffer;
44 protected int endOf_UNUSED_Buffer;
45 protected int maxUnusedBufferSize;
46
47// ================================================================================
48// Auxiliary functions. Can parse the tokens used in the grammar as partial/auxiliary
49// ================================================================================
50
51 [LEXER_AUXFUNCTIONS]
52
53// ================================================================================
54// Main method. Return a TOKEN_CONSTANT
55// ================================================================================
56
Till Westmann8cdbd392014-04-04 18:31:08 -070057 public int next() throws [LEXER_NAME]Exception, IOException {
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +000058 char currentChar = buffer[bufpos];
59 while (currentChar == ' ' || currentChar=='\t' || currentChar == '\n' || currentChar=='\r')
60 currentChar = readNextChar();
61 tokenBegin = bufpos;
Till Westmann8cdbd392014-04-04 18:31:08 -070062 containsEscapes = false;
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +000063 if (currentChar==EOF_CHAR) return TOKEN_EOF;
64
65 [LEXER_LOGIC]
66 }
67
68// ================================================================================
69// Public interface
70// ================================================================================
71
72 public [LEXER_NAME](java.io.Reader stream) throws IOException{
73 reInit(stream);
74 }
75
76 public void reInit(java.io.Reader stream) throws IOException{
77 done();
78 inputStream = stream;
79 bufsize = 4096;
80 line = 1;
81 column = 0;
82 bufpos = -1;
83 endOf_UNUSED_Buffer = bufsize;
84 endOf_USED_Buffer = 0;
85 prevCharIsCR = false;
86 prevCharIsLF = false;
87 buffer = new char[bufsize];
88 tokenBegin = -1;
89 maxUnusedBufferSize = 4096/2;
90 readNextChar();
91 }
92
93 public String getLastTokenImage() {
94 if (bufpos >= tokenBegin)
95 return new String(buffer, tokenBegin, bufpos - tokenBegin);
96 else
97 return new String(buffer, tokenBegin, bufsize - tokenBegin) +
98 new String(buffer, 0, bufpos);
99 }
100
Till Westmannab40b092014-03-28 15:44:01 -0700101 public int getColumn() {
102 return column;
103 }
104
105 public int getLine() {
106 return line;
107 }
108
Till Westmann8cdbd392014-04-04 18:31:08 -0700109 public boolean containsEscapes() {
110 return containsEscapes;
111 }
112
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +0000113 public static String tokenKindToString(int token) {
114 return tokenImage[token];
115 }
116
117 public void done(){
118 buffer = null;
119 }
120
121// ================================================================================
122// Parse error management
123// ================================================================================
124
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +0000125 protected int parseError(int ... tokens) throws [LEXER_NAME]Exception {
126 StringBuilder message = new StringBuilder();
Till Westmannab40b092014-03-28 15:44:01 -0700127 message.append("Parse error at (").append(line).append(", ").append(column).append(")");
128 if (tokens.length > 0) {
129 message.append(" expecting:");
130 for (int tokenId : tokens){
131 message.append(" ").append([LEXER_NAME].tokenKindToString(tokenId));
132 }
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +0000133 }
134 throw new [LEXER_NAME]Exception(message.toString());
135 }
136
137 protected void updateLineColumn(char c){
138 column++;
139
140 if (prevCharIsLF)
141 {
142 prevCharIsLF = false;
143 line += (column = 1);
144 }
145 else if (prevCharIsCR)
146 {
147 prevCharIsCR = false;
148 if (c == '\n')
149 {
150 prevCharIsLF = true;
151 }
152 else
153 {
154 line += (column = 1);
155 }
156 }
157
158 if (c=='\r') {
159 prevCharIsCR = true;
160 } else if(c == '\n') {
161 prevCharIsLF = true;
162 }
163 }
164
165// ================================================================================
166// Read data, buffer management. It uses a circular (and expandable) buffer
167// ================================================================================
168
169 protected char readNextChar() throws IOException {
170 if (++bufpos >= endOf_USED_Buffer)
171 fillBuff();
172 char c = buffer[bufpos];
173 updateLineColumn(c);
174 return c;
175 }
176
177 protected boolean fillBuff() throws IOException {
178 if (endOf_UNUSED_Buffer == endOf_USED_Buffer) // If no more unused buffer space
179 {
180 if (endOf_UNUSED_Buffer == bufsize) // -- If the previous unused space was
181 { // -- at the end of the buffer
182 if (tokenBegin > maxUnusedBufferSize) // -- -- If the first N bytes before
183 { // the current token are enough
184 bufpos = endOf_USED_Buffer = 0; // -- -- -- setup buffer to use that fragment
185 endOf_UNUSED_Buffer = tokenBegin;
186 }
187 else if (tokenBegin < 0) // -- -- If no token yet
188 bufpos = endOf_USED_Buffer = 0; // -- -- -- reuse the whole buffer
189 else
190 ExpandBuff(false); // -- -- Otherwise expand buffer after its end
191 }
192 else if (endOf_UNUSED_Buffer > tokenBegin) // If the endOf_UNUSED_Buffer is after the token
193 endOf_UNUSED_Buffer = bufsize; // -- set endOf_UNUSED_Buffer to the end of the buffer
194 else if ((tokenBegin - endOf_UNUSED_Buffer) < maxUnusedBufferSize)
195 { // If between endOf_UNUSED_Buffer and the token
196 ExpandBuff(true); // there is NOT enough space expand the buffer
197 } // reorganizing it
198 else
199 endOf_UNUSED_Buffer = tokenBegin; // Otherwise there is enough space at the start
200 } // so we set the buffer to use that fragment
201 int i;
202 if ((i = inputStream.read(buffer, endOf_USED_Buffer, endOf_UNUSED_Buffer - endOf_USED_Buffer)) == -1)
203 {
204 inputStream.close();
205 buffer[endOf_USED_Buffer]=(char)EOF_CHAR;
206 endOf_USED_Buffer++;
207 return false;
208 }
209 else
210 endOf_USED_Buffer += i;
211 return true;
212 }
213
214
215 protected void ExpandBuff(boolean wrapAround)
216 {
217 char[] newbuffer = new char[bufsize + maxUnusedBufferSize];
218
219 try {
220 if (wrapAround) {
221 System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
222 System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos);
223 buffer = newbuffer;
224 endOf_USED_Buffer = (bufpos += (bufsize - tokenBegin));
225 }
226 else {
227 System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
228 buffer = newbuffer;
229 endOf_USED_Buffer = (bufpos -= tokenBegin);
230 }
231 } catch (Throwable t) {
232 throw new Error(t.getMessage());
233 }
234
235 bufsize += maxUnusedBufferSize;
236 endOf_UNUSED_Buffer = bufsize;
237 tokenBegin = 0;
238 }
239}