blob: 92d1c8edc1a35928d14c45f3e1cb24d82e97ed35 [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
Abdullah Alamoudi679a7be2013-08-12 00:19:11 +030022 public static final int
23 TOKEN_EOF = 0, TOKEN_AUX_NOT_FOUND = 1 [TOKENS_CONSTANTS];
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +000024
Abdullah Alamoudi679a7be2013-08-12 00:19:11 +030025 // 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 };
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +000031
Abdullah Alamoudi679a7be2013-08-12 00:19:11 +030032 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;
38 protected char[] buffer;
39 protected int bufsize;
40 protected int bufpos;
41 protected int tokenBegin;
42 protected int endOf_USED_Buffer;
43 protected int endOf_UNUSED_Buffer;
44 protected int maxUnusedBufferSize;
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +000045
Abdullah Alamoudi679a7be2013-08-12 00:19:11 +030046 // ================================================================================
47 // Auxiliary functions. Can parse the tokens used in the grammar as partial/auxiliary
48 // ================================================================================
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +000049
Abdullah Alamoudi679a7be2013-08-12 00:19:11 +030050 [LEXER_AUXFUNCTIONS]
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +000051
Abdullah Alamoudi679a7be2013-08-12 00:19:11 +030052 // ================================================================================
53 // Main method. Return a TOKEN_CONSTANT
54 // ================================================================================
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +000055
Abdullah Alamoudi679a7be2013-08-12 00:19:11 +030056 public int next() throws [LEXER_NAME]Exception, IOException{
Abdullah Alamoudi863d5d22013-08-31 04:41:21 +030057 if(bufpos < 0)
58 readNextChar();
Abdullah Alamoudi679a7be2013-08-12 00:19:11 +030059 char currentChar = buffer[bufpos];
60 while (currentChar == ' ' || currentChar=='\t' || currentChar == '\n' || currentChar=='\r')
61 currentChar = readNextChar();
62 tokenBegin = bufpos;
63 if (currentChar==EOF_CHAR) return TOKEN_EOF;
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +000064
Abdullah Alamoudi679a7be2013-08-12 00:19:11 +030065 [LEXER_LOGIC]
66 }
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +000067
Abdullah Alamoudi679a7be2013-08-12 00:19:11 +030068 //used when done with stream, must be called exiplicitly now.
69 public void close()throws IOException
70 {
71 inputStream.close();
72 }
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +000073
Abdullah Alamoudi679a7be2013-08-12 00:19:11 +030074 //used before processing a new patch in the inputStream
75 public void reset(){
Abdullah Alamoudi863d5d22013-08-31 04:41:21 +030076 line = 1;
77 column = 0;
78 bufpos = -1;
79 endOf_UNUSED_Buffer = bufsize;
80 endOf_USED_Buffer = 0;
81 prevCharIsCR = false;
82 prevCharIsLF = false;
83 tokenBegin = -1;
Abdullah Alamoudi679a7be2013-08-12 00:19:11 +030084 }
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +000085
Abdullah Alamoudi679a7be2013-08-12 00:19:11 +030086 // ================================================================================
87 // Public interface
88 // ================================================================================
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +000089
Abdullah Alamoudi679a7be2013-08-12 00:19:11 +030090 public [LEXER_NAME](java.io.Reader stream) throws IOException{
91 reInit(stream);
92 }
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +000093
Abdullah Alamoudi679a7be2013-08-12 00:19:11 +030094 public void reInit(java.io.Reader stream) throws IOException{
95 done();
96 inputStream = stream;
97 bufsize = 4096;
98 line = 1;
99 column = 0;
100 bufpos = -1;
101 endOf_UNUSED_Buffer = bufsize;
102 endOf_USED_Buffer = 0;
103 prevCharIsCR = false;
104 prevCharIsLF = false;
105 buffer = new char[bufsize];
106 tokenBegin = -1;
107 maxUnusedBufferSize = 4096/2;
Abdullah Alamoudi679a7be2013-08-12 00:19:11 +0300108 }
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +0000109
Abdullah Alamoudi679a7be2013-08-12 00:19:11 +0300110 public String getLastTokenImage() {
111 if (bufpos >= tokenBegin)
112 return new String(buffer, tokenBegin, bufpos - tokenBegin);
113 else
114 return new String(buffer, tokenBegin, bufsize - tokenBegin) +
115 new String(buffer, 0, bufpos);
116 }
117
118 public static String tokenKindToString(int token) {
119 return tokenImage[token];
120 }
121
122 public void done(){
123 buffer = null;
124 }
125
126 // ================================================================================
127 // Parse error management
128 // ================================================================================
129
130 protected int parseError(String reason) throws [LEXER_NAME]Exception {
131 StringBuilder message = new StringBuilder();
132 message.append(reason).append("\n");
133 message.append("Line: ").append(line).append("\n");
134 message.append("Row: ").append(column).append("\n");
135 throw new [LEXER_NAME]Exception(message.toString());
136 }
137
138 protected int parseError(int ... tokens) throws [LEXER_NAME]Exception {
139 StringBuilder message = new StringBuilder();
140 message.append("Error while parsing. ");
141 message.append(" Line: ").append(line);
142 message.append(" Row: ").append(column);
143 message.append(" Expecting:");
144 for (int tokenId : tokens){
145 message.append(" ").append([LEXER_NAME].tokenKindToString(tokenId));
146 }
147 throw new [LEXER_NAME]Exception(message.toString());
148 }
149
150 protected void updateLineColumn(char c){
151 column++;
152
153 if (prevCharIsLF)
154 {
155 prevCharIsLF = false;
156 line += (column = 1);
157 }
158 else if (prevCharIsCR)
159 {
160 prevCharIsCR = false;
161 if (c == '\n')
162 {
163 prevCharIsLF = true;
164 }
165 else
166 {
167 line += (column = 1);
168 }
169 }
170
171 if (c=='\r') {
172 prevCharIsCR = true;
173 } else if(c == '\n') {
174 prevCharIsLF = true;
175 }
176 }
177
178 // ================================================================================
179 // Read data, buffer management. It uses a circular (and expandable) buffer
180 // ================================================================================
181
182 protected char readNextChar() throws IOException {
183 if (++bufpos >= endOf_USED_Buffer)
184 fillBuff();
185 char c = buffer[bufpos];
186 updateLineColumn(c);
187 return c;
188 }
189
190 protected boolean fillBuff() throws IOException {
191 if (endOf_UNUSED_Buffer == endOf_USED_Buffer) // If no more unused buffer space
192 {
193 if (endOf_UNUSED_Buffer == bufsize) // -- If the previous unused space was
194 { // -- at the end of the buffer
195 if (tokenBegin > maxUnusedBufferSize) // -- -- If the first N bytes before
196 { // the current token are enough
197 bufpos = endOf_USED_Buffer = 0; // -- -- -- setup buffer to use that fragment
198 endOf_UNUSED_Buffer = tokenBegin;
199 }
200 else if (tokenBegin < 0) // -- -- If no token yet
201 bufpos = endOf_USED_Buffer = 0; // -- -- -- reuse the whole buffer
202 else
203 ExpandBuff(false); // -- -- Otherwise expand buffer after its end
204 }
205 else if (endOf_UNUSED_Buffer > tokenBegin) // If the endOf_UNUSED_Buffer is after the token
206 endOf_UNUSED_Buffer = bufsize; // -- set endOf_UNUSED_Buffer to the end of the buffer
207 else if ((tokenBegin - endOf_UNUSED_Buffer) < maxUnusedBufferSize)
208 { // If between endOf_UNUSED_Buffer and the token
209 ExpandBuff(true); // there is NOT enough space expand the buffer
210 } // reorganizing it
211 else
212 endOf_UNUSED_Buffer = tokenBegin; // Otherwise there is enough space at the start
213 } // so we set the buffer to use that fragment
214 int i;
215 if ((i = inputStream.read(buffer, endOf_USED_Buffer, endOf_UNUSED_Buffer - endOf_USED_Buffer)) == -1)
216 {
217 //moved outside
218 //inputStream.close();
219 buffer[endOf_USED_Buffer]=(char)EOF_CHAR;
220 endOf_USED_Buffer++;
221 return false;
222 }
223 else
224 endOf_USED_Buffer += i;
225 return true;
226 }
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +0000227
228
Abdullah Alamoudi679a7be2013-08-12 00:19:11 +0300229 protected void ExpandBuff(boolean wrapAround)
230 {
231 char[] newbuffer = new char[bufsize + maxUnusedBufferSize];
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +0000232
Abdullah Alamoudi679a7be2013-08-12 00:19:11 +0300233 try {
234 if (wrapAround) {
235 System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
236 System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos);
237 buffer = newbuffer;
238 endOf_USED_Buffer = (bufpos += (bufsize - tokenBegin));
239 }
240 else {
241 System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
242 buffer = newbuffer;
243 endOf_USED_Buffer = (bufpos -= tokenBegin);
244 }
245 } catch (Throwable t) {
246 throw new Error(t.getMessage());
247 }
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +0000248
Abdullah Alamoudi679a7be2013-08-12 00:19:11 +0300249 bufsize += maxUnusedBufferSize;
250 endOf_UNUSED_Buffer = bufsize;
251 tokenBegin = 0;
252 }
diegogiorgini@gmail.com2de6d342013-02-16 02:41:45 +0000253}