/*******************************************************************************
* openDLX - A DLX/MIPS processor simulator.
* Copyright (C) 2013 The openDLX project, University of Augsburg, Germany
* Project URL: <https://sourceforge.net/projects/opendlx>
* Development branch: <https://github.com/smetzlaff/openDLX>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program, see <LICENSE>. If not, see
* <http://www.gnu.org/licenses/>.
******************************************************************************/
package openDLX.asm.tokenizer;
import java.io.BufferedReader;
import java.io.IOException;
/**
* reads characters from underlying stream and buffers them deletes leading
* whitespace and comments
*/
public class BufferedCharReader {
private static char NO_CHAR = '_';
Position position_;
private BufferedReader reader_;
private char[] buffer_;
public BufferedCharReader(BufferedReader reader) throws IOException {
if (reader == null)
throw new IllegalArgumentException();
this.reader_ = reader;
this.position_ = new Position();
buffer_ = new char[0];
}
/**
* reads next line to buffer and deletes comments
*
* @return false if EOF reached true otherwise
* @throws IOException
*/
public boolean readLine() throws IOException {
String str = reader_.readLine();
if (str == null)
return false;
char[] tmp = str.toCharArray();
// calculate bounding
boolean inLiteral = false;
int offset;
int end = tmp.length;
int i = 0;
offset = i;
// comments
while (i < tmp.length) {
if (tmp[i] == '"') {
inLiteral = !inLiteral;
} else if (!inLiteral && tmp[i] == ';') {
end = i;
break;
}
i++;
}
buffer_ = new char[end - offset];
i = 0;
while (offset < end) {
buffer_[i] = tmp[offset];
offset++;
i++;
}
position_.nextLine();
return true;
}
/**
* decrements current pointer
*
* @return character preceding current or -1 if no preceding available
*/
public int previous() {
if (position_.column >= 0) {
position_.column--;
return current();
}
return -1;
}
/**
* does not decrement pointer
*
* @return character preceding current or -1 if no preceding available
*/
public int peekPrevious() {
if (position_.column - 1 > 0) {
return buffer_[position_.column - 1];
}
return -1;
}
/**
*
* @return current character or -1 if not available
*/
public int current() {
if (position_.column < 0 || position_.column >= buffer_.length)
return -1;
return buffer_[position_.column];
}
/**
* increments current pointer
*
* @return character following current or -1 if no following available
*/
public int next() {
if (position_.column < buffer_.length) {
position_.column++;
return current();
}
return -1;
}
/**
* does not increment pointer
*
* @return character following current or -1 if no following available
*/
public int peekNext() {
if (position_.column + 1 < buffer_.length) {
return buffer_[position_.column + 1];
}
return -1;
}
/**
*
* @return true if line is empty false otherwise
*/
public boolean isEmptyLine() {
if (buffer_.length == 0)
return true;
else
return false;
}
/**
*
* @return new Position object copied from current position
*/
public Position position() {
return new Position(position_);
}
/**
*
* @return true is c is -1 otherwise false
*/
public boolean isEol() {
return isEol(current());
}
/**
*
* @param c
* @return true is c is -1 otherwise false
*/
public static boolean isEol(int c) {
return c == -1;
}
/**
* @return current buffer state and position as string
*/
public String toString() {
StringBuffer str = new StringBuffer();
str.append('|');
for (int i = 0; i < buffer_.length; i++) {
str.append(escapeChars(buffer_[i]));
}
str.append('|');
str.append(position_.toString());
return str.toString();
}
private String escapeChars(int c) {
if (c < 0)
return Character.toString(NO_CHAR) + NO_CHAR;
else {
switch (c) {
case '\n':
return "\\n";
case '\t':
return "\\t";
case '\r':
return "\\r";
case '\b':
return "\\b";
case '\f':
return "\\f";
default:
if (c < 0x20)
return Character.toString((char) c);
else
return Character.toString((char) c) + ' ';
}
}
}
}