001: package fri.patterns.interpreter.parsergenerator.lexer;
002:
003: import java.util.*;
004: import java.io.IOException;
005:
006: /**
007: Input for text lines. Line number, line position, current line and
008: previous line are available.
009:
010: @author (c) 2002, Fritz Ritzberger
011: */
012:
013: class InputText extends Input {
014: private int[] line; // current line buffer
015: private int[] prevLine; // previous line buffer
016: private int prevLength;
017: private boolean wasCr = false; // flag if '\r' occured
018: private int column; // line position
019: private List lineLengths = new ArrayList(); // list of Integer containing line lengths including newline sequence
020: private int[] scanPoint;
021:
022: InputText(Object input) throws IOException {
023: super (input);
024: }
025:
026: protected int convertInput(int i) {
027: if (i == '\r') {
028: wasCr = true;
029: newLine();
030: } else {
031: if (i == '\n') {
032: if (wasCr == false) // on UNIX
033: newLine();
034: else
035: // on WINDOWS, ignore \n after \r, but adjust previous line length
036: lineLengths.set(lineLengths.size() - 1,
037: new Integer(((Integer) lineLengths
038: .get(lineLengths.size() - 1))
039: .intValue() + 1));
040: } else {
041: storeRead(i);
042: }
043: wasCr = false;
044: }
045:
046: scanPoint = null; // force new scan point calculation
047: return i;
048: }
049:
050: private void newLine() {
051: lineLengths.add(new Integer(column + 1)); // line length plus one for the newline, will be adjusted when \r\n
052:
053: prevLength = column;
054: column = 0; // reset current line offset
055:
056: if (line == null)
057: line = new int[64];
058:
059: if (prevLine == null || prevLine.length < line.length)
060: prevLine = new int[Math.max(line.length, 64)];
061:
062: System.arraycopy(line, 0, prevLine, 0, prevLength);
063: }
064:
065: private void storeRead(int i) {
066: if (line == null) { // allocate buffer
067: line = new int[64];
068: } else if (column == line.length) { // reallocate line buffer
069: int[] old = line;
070: line = new int[old.length * 2];
071: System.arraycopy(old, 0, line, 0, old.length);
072: }
073:
074: line[column] = i;
075: column++;
076: }
077:
078: /** Returns the current read line number (1-n). This is always bigger equal than scan line. */
079: public int getReadLine() {
080: return lineLengths.size() + 1;
081: }
082:
083: /** Returns the current read position (0-n). This is different from scan position. */
084: public int getReadColumn() {
085: return column;
086: }
087:
088: /** Returns the current scan line number (1-n). This is always smaller equal than read line. */
089: public int getScanLine() {
090: return calculateScanPoint()[0];
091: }
092:
093: /** Returns the current scan position (0-n). This is different from read position. */
094: public int getScanColumn() {
095: return calculateScanPoint()[1];
096: }
097:
098: private int[] calculateScanPoint() { // returns line/column
099: if (scanPoint != null) // use buffered scan pointer when possible, as line/column requests always are coupled
100: return scanPoint;
101:
102: int diff = getReadColumn() - getUnreadLength();
103: if (diff >= 0)
104: return scanPoint = new int[] { getReadLine(), diff };
105:
106: for (int i = lineLengths.size() - 1; i >= 0; i--) { // loop back all lines
107: int len = ((Integer) lineLengths.get(i)).intValue();
108: diff += len;
109: if (diff >= 0)
110: return scanPoint = new int[] { i + 1, diff };
111: }
112: throw new IllegalStateException(
113: "Something went wrong when calculating scan point: "
114: + diff);
115: }
116:
117: /** Overridden to resolve scan pointer. Delegates to super. */
118: public int read() throws IOException {
119: scanPoint = null;
120: return super .read();
121: }
122:
123: /** Overridden to resolve scan pointer. Delegates to super. */
124: public void setMark(int mark) {
125: scanPoint = null;
126: super .setMark(mark);
127: }
128:
129: /** Returns a String representing current line up to read position. */
130: public String getLine() {
131: return createLineString(line, column);
132: }
133:
134: /** Returns a String representing previous line. */
135: public String getPreviousLine() {
136: return createLineString(prevLine, prevLength);
137: }
138:
139: /** Returns all unscanned input in buffer. */
140: public String getUnreadText() {
141: int[] buf = getUnreadBuffer();
142: return createLineString(buf, buf.length);
143: }
144:
145: private String createLineString(int[] line, int end) {
146: StringBuffer sb = new StringBuffer();
147: for (int i = 0; i < end; i++)
148: sb.append((char) line[i]);
149: return sb.toString();
150: }
151:
152: }
|