?? scanner.java
字號:
package lolo;import java.io.Serializable;import java.io.IOException;import java.util.Map;import java.util.HashMap;import java.util.Iterator;import lolo.Scan.State;/** A <tt>Scanner</tt> collects <tt>Scan</tt> objects to maintain a lexical scanner. * The characters are read from an <tt>Input</tt> object. * <p>A <tt>Scanner</tt> can be serialized to be reused. * * @author <a href="http://www.inf.uos.de/bernd" target="_blank">Bernd Kühl</a> (<a href="mailto:bernd@informatik.uni-osnabrueck.de">bernd@informatik.uni-osnabrueck.de</a>) * @see lolo.Mux * @see lolo.Scan * @see lolo.Input * @see lolo.Scanner#scan(Input) */public class Scanner implements Serializable { /** Array of all <tt>Scan</tt> objects. * * @see lolo.Scan */ protected Scan[] scans = new Scan[1]; /** Indexes in <tt>scans</tt>. */ protected int next, max = scans.length; /** Constructs an empty <tt>Scanner</tt>. */ public Scanner() {} /** Constructs a <tt>Scanner</tt> managing one <tt>Scan</tt> instance. * * @see lolo.Scan */ public Scanner(Scan scan) { add(scan); } /** Constructs a <tt>Scanner</tt> managing many <tt>Scan</tt> instances. * * @see lolo.Scan */ public Scanner(Scan [] scans) { if (scans == null) throw new IllegalArgumentException("scans is null"); for (int i = 0; i < scans.length; i++) add(scans[i]); } /** Marks if this <tt>Scanner</tt> is packed. * * @see lolo.Scanner#pack() */ protected boolean packed; /** Adds a <tt>Scan</tt> instance to this <tt>Scanner</tt>. * * @param scan the added recognizer. * @throws IllegalArgumentException if the argument is <tt>null</tt>. * @see lolo.Scan */ public boolean add(Scan scan) throws IllegalArgumentException { if (scan == null) throw new IllegalArgumentException("scan is null"); if (contains(scan)) return false; if (max == next) { Scan [] help = new Scan[max*=2]; System.arraycopy(scans, 0, help, 0, max/2); scans = help; } scans[next++] = scan; packed = false; return true; } /** Adds all elements of a <tt>Scan</tt> array to this <tt>Scanner</tt>. * * @param scans the added recognizers. * @throws IllegalArgumentException if the argument or the elements of the argument are <tt>null</tt>. * @see lolo.Scan */ public boolean add(Scan [] scans) throws IllegalArgumentException { if (scans == null) throw new IllegalArgumentException("scan is null"); boolean b = false; for (int i = 0; i < scans.length; i++) b |= add(scans[i]); return b; } /** Removes a <tt>Scan</tt> instance to this <tt>Scanner</tt>. * * @see lolo.Scan */ public boolean remove(Scan scan) { for (int i = 0; i < next; i++) if (scans[i].equals(scan)) { if(i <= next-1) System.arraycopy(scans, i+1, scans, i, next-(i+1)); next--; packed = false; return true; } return false; } /** Returns if this <tt>Scanner</tt> contains the <tt>Scan</tt> instance. The check is done by using * <tt>equals()</tt>. * * @return if this <tt>Scanner</tt> contains the <tt>Scan</tt> instance. * @see lolo.Scan */ public boolean contains(Scan scan) { for (int i = 0; i < next; i++) if (scans[i].equals(scan)) return true; return false; } /** Returns if this <tt>Scanner</tt> is packed. * * @return if this <tt>Scanner</tt> is packed. */ public boolean packed() { return packed; } /** Array holding for every character-index a <tt>Scan</tt> or <tt>Mux</tt> object. * * @see lolo.Mux * @see lolo.Scan */ public transient Scan[] table; /** Packs the <tt>table</tt> with <tt>Scan</tt> or <tt>Mux</tt> objects. * * @see lolo.Mux * @see lolo.Scan */ public void pack() { if (packed) return; if (debug) System.err.println("start packing..."); table = new Scan[unicode ? Character.MAX_VALUE+1 : 128]; for (int ch = 0; ch <= (unicode ? Character.MAX_VALUE : 127); ch++) { for (int i = 0; i < next; i++) { Scan scan = scans[i]; scan.reset(); State state = scan.nextChar((char) ch); if (state.more || state.found) enter(ch, scan); } if (debug && ch > 0 && (ch % 5000 == 00)) System.err.println("packing up to "+ch+" done..."); } if (debug) System.err.println("replacing Mux objects..."); // replace equal Mux by one Mux and reset all recognizers Map muxs = new HashMap(); int countMux = 0; for (int ch = 0; ch <= (unicode ? Character.MAX_VALUE : 127); ch++) { Scan scan = table[ch]; if (scan instanceof Mux) { Mux mux = (Mux) scan; if (muxs.containsKey(mux)) { table[ch] = (Mux) muxs.get(mux); } else { muxs.put(mux, mux); // better use a Set collection.... countMux++; } } } if (debug) System.err.println(countMux+" Mux objects..."); // reset all scans and all mux objects Iterator iterator = muxs.keySet().iterator(); while (iterator.hasNext()) ((Scan) iterator.next()).reset(); for (int i = 0; i < next; i++) scans[i].reset(); packed = true; if (debug) System.err.println("packing done..."); } /** Enters <tt>scan</tt> at index <tt>index</tt> into the table. * This may creates a <tt>Mux</tt> object. * * @see lolo.Mux * @see lolo.Scan * @param index index into the table for <tt>scan</tt>. * @param scan the new <tt>Scan</tt> object for table index <tt>index</tt>. */ protected void enter(int index, Scan scan) { if (table[index] != null) if (table[index] instanceof Mux) ((Mux) table[index]).add(scan); else table[index] = new Mux(table[index], scan); else table[index] = scan; } /** debug mode? */ public boolean debug = false; /** Finds and returns the next winning <tt>Scan</tt> object or <tt>null</tt> at EOF. * * @return the winning <tt>Scan</tt> object or <tt>null</tt> at EOF. * @param the character input source. * @throws IllegalCharacterException if no symbol was found. * @throws IOException if an I/O error occured. */ public Scan scan(Input input) throws IllegalCharacterException, IOException { if (!packed) pack(); while (true) { input.setStartSymbol(); int first = input.next(); int symbolLength = -1, length = 1; if(!unicode && 127 < first) throw new IllegalCharacterException((char) first, input.toString()); int ch = first; if (ch < 0) return null; Scan scan = table[ch]; if (scan == null) throw new IllegalCharacterException((char) first, input.toString()); scan.reset(); boolean found = false; input.mark(); while (true) { if(!unicode && 127 < ch) throw new IllegalCharacterException((char) ch, input.toString()); State state = scan.nextChar((char) ch); if (state.found) { input.mark(); found = true; symbolLength = length; } if (!state.more) break; ch = input.next(); length++; if (ch < 0) break; } if (!found) throw new IllegalCharacterException((char) first, input.toString()); input.pushBackToMarked(); input.unmark(); Scan winner = scan instanceof Mux ? ((Mux) scan).winner() : scan; winner.action(input.buffer, input.startOfSymbol, symbolLength); if (!winner.getIgnore()) return winner ; } } /** Unicode (or ASCII) mode? */ protected boolean unicode; /** Set Unicode (or ASCII) mode mode. * * @param the new mode. */ public void setUnicode(boolean unicode) { packed = this.unicode == unicode; this.unicode = unicode; } /** Returns if the current mode is Unicode. * * @return if the current mode is Unicode. */ public boolean getUnicode() { return unicode; } /** Deserializes the object. */ private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); int length = stream.readInt(); table = new Scan[length]; int pairs = stream.readInt(); int n = 0; while (pairs > 0) { Scan s = (Scan) stream.readObject(); String string = (String) stream.readObject(); pairs--; for (int i = 0 ; i < string.length(); i++) { table[(int) string.charAt(i)] = s; n++; } } } /** Serializes the object. */ private void writeObject(java.io.ObjectOutputStream stream) throws IOException { stream.defaultWriteObject(); Map map = new HashMap(); for (int i = 0; i < this.table.length; i++) { Scan s = (Scan) this.table[i]; if (s != null) if (map.containsKey(s)) ((StringBuffer) map.get(s)).append((char) i); else map.put(s, new StringBuffer().append((char) i)); } stream.writeInt(table.length); stream.writeInt(map.size()); Iterator keys = map.keySet().iterator(); while (keys.hasNext()) { Scan s = (Scan) keys.next(); String string = ((StringBuffer) map.get(s)).toString(); stream.writeObject(s); stream.writeObject(string); } } /** An <tt>IllegalCharacterException</tt> is thrown, when no <tt>Scan</tt> instance matches * the current character. * * @author <a href="http://www.inf.uos.de/bernd" target="_blank">Bernd Kühl</a> (<a href="mailto:bernd@informatik.uni-osnabrueck.de">bernd@informatik.uni-osnabrueck.de</a>) */ public static class IllegalCharacterException extends Exception { /** The illegal character. */ protected char ch; /** Constructs an <tt>IllegalCharacterException</tt>. * * @param ch the illegal character. * @param message the message. */ public IllegalCharacterException(char ch, String message) { super(message); this.ch = ch; } /** Return the illegal character. * * @return the illegal character. */ public char getChar() { return ch; } /** Returns <tt>"IllegalCharacterException["+ch+","+getMessage()+"]"</tt> * * @return <tt>"IllegalCharacterException["+ch+","+getMessage()+"]"</tt> */ public String toString() { return "IllegalCharacterException["+ch+","+getMessage()+"]"; } }}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -