blob: dae1fb1d17f0b68a2edc44539ee6a54a0c3c08e0 [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;
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;
45
46// ================================================================================
47// Auxiliary functions. Can parse the tokens used in the grammar as partial/auxiliary
48// ================================================================================
49
50 [LEXER_AUXFUNCTIONS]
51
52// ================================================================================
53// Main method. Return a TOKEN_CONSTANT
54// ================================================================================
55
56 public int next() throws [LEXER_NAME]Exception, IOException{
57 char currentChar = buffer[bufpos];
58 while (currentChar == ' ' || currentChar=='\t' || currentChar == '\n' || currentChar=='\r')
59 currentChar = readNextChar();
60 tokenBegin = bufpos;
61 if (currentChar==EOF_CHAR) return TOKEN_EOF;
62
63 [LEXER_LOGIC]
64 }
65
66// ================================================================================
67// Public interface
68// ================================================================================
69
70 public [LEXER_NAME](java.io.Reader stream) throws IOException{
71 reInit(stream);
72 }
73
74 public void reInit(java.io.Reader stream) throws IOException{
75 done();
76 inputStream = stream;
77 bufsize = 4096;
78 line = 1;
79 column = 0;
80 bufpos = -1;
81 endOf_UNUSED_Buffer = bufsize;
82 endOf_USED_Buffer = 0;
83 prevCharIsCR = false;
84 prevCharIsLF = false;
85 buffer = new char[bufsize];
86 tokenBegin = -1;
87 maxUnusedBufferSize = 4096/2;
88 readNextChar();
89 }
90
91 public String getLastTokenImage() {
92 if (bufpos >= tokenBegin)
93 return new String(buffer, tokenBegin, bufpos - tokenBegin);
94 else
95 return new String(buffer, tokenBegin, bufsize - tokenBegin) +
96 new String(buffer, 0, bufpos);
97 }
98
99 public static String tokenKindToString(int token) {
100 return tokenImage[token];
101 }
102
103 public void done(){
104 buffer = null;
105 }
106
107// ================================================================================
108// Parse error management
109// ================================================================================
110
111 protected int parseError(String reason) throws [LEXER_NAME]Exception {
112 StringBuilder message = new StringBuilder();
113 message.append(reason).append("\n");
114 message.append("Line: ").append(line).append("\n");
115 message.append("Row: ").append(column).append("\n");
116 throw new [LEXER_NAME]Exception(message.toString());
117 }
118
119 protected int parseError(int ... tokens) throws [LEXER_NAME]Exception {
120 StringBuilder message = new StringBuilder();
121 message.append("Error while parsing. ");
122 message.append(" Line: ").append(line);
123 message.append(" Row: ").append(column);
124 message.append(" Expecting:");
125 for (int tokenId : tokens){
126 message.append(" ").append([LEXER_NAME].tokenKindToString(tokenId));
127 }
128 throw new [LEXER_NAME]Exception(message.toString());
129 }
130
131 protected void updateLineColumn(char c){
132 column++;
133
134 if (prevCharIsLF)
135 {
136 prevCharIsLF = false;
137 line += (column = 1);
138 }
139 else if (prevCharIsCR)
140 {
141 prevCharIsCR = false;
142 if (c == '\n')
143 {
144 prevCharIsLF = true;
145 }
146 else
147 {
148 line += (column = 1);
149 }
150 }
151
152 if (c=='\r') {
153 prevCharIsCR = true;
154 } else if(c == '\n') {
155 prevCharIsLF = true;
156 }
157 }
158
159// ================================================================================
160// Read data, buffer management. It uses a circular (and expandable) buffer
161// ================================================================================
162
163 protected char readNextChar() throws IOException {
164 if (++bufpos >= endOf_USED_Buffer)
165 fillBuff();
166 char c = buffer[bufpos];
167 updateLineColumn(c);
168 return c;
169 }
170
171 protected boolean fillBuff() throws IOException {
172 if (endOf_UNUSED_Buffer == endOf_USED_Buffer) // If no more unused buffer space
173 {
174 if (endOf_UNUSED_Buffer == bufsize) // -- If the previous unused space was
175 { // -- at the end of the buffer
176 if (tokenBegin > maxUnusedBufferSize) // -- -- If the first N bytes before
177 { // the current token are enough
178 bufpos = endOf_USED_Buffer = 0; // -- -- -- setup buffer to use that fragment
179 endOf_UNUSED_Buffer = tokenBegin;
180 }
181 else if (tokenBegin < 0) // -- -- If no token yet
182 bufpos = endOf_USED_Buffer = 0; // -- -- -- reuse the whole buffer
183 else
184 ExpandBuff(false); // -- -- Otherwise expand buffer after its end
185 }
186 else if (endOf_UNUSED_Buffer > tokenBegin) // If the endOf_UNUSED_Buffer is after the token
187 endOf_UNUSED_Buffer = bufsize; // -- set endOf_UNUSED_Buffer to the end of the buffer
188 else if ((tokenBegin - endOf_UNUSED_Buffer) < maxUnusedBufferSize)
189 { // If between endOf_UNUSED_Buffer and the token
190 ExpandBuff(true); // there is NOT enough space expand the buffer
191 } // reorganizing it
192 else
193 endOf_UNUSED_Buffer = tokenBegin; // Otherwise there is enough space at the start
194 } // so we set the buffer to use that fragment
195 int i;
196 if ((i = inputStream.read(buffer, endOf_USED_Buffer, endOf_UNUSED_Buffer - endOf_USED_Buffer)) == -1)
197 {
198 inputStream.close();
199 buffer[endOf_USED_Buffer]=(char)EOF_CHAR;
200 endOf_USED_Buffer++;
201 return false;
202 }
203 else
204 endOf_USED_Buffer += i;
205 return true;
206 }
207
208
209 protected void ExpandBuff(boolean wrapAround)
210 {
211 char[] newbuffer = new char[bufsize + maxUnusedBufferSize];
212
213 try {
214 if (wrapAround) {
215 System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
216 System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos);
217 buffer = newbuffer;
218 endOf_USED_Buffer = (bufpos += (bufsize - tokenBegin));
219 }
220 else {
221 System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
222 buffer = newbuffer;
223 endOf_USED_Buffer = (bufpos -= tokenBegin);
224 }
225 } catch (Throwable t) {
226 throw new Error(t.getMessage());
227 }
228
229 bufsize += maxUnusedBufferSize;
230 endOf_UNUSED_Buffer = bufsize;
231 tokenBegin = 0;
232 }
233}