$ template make_lexer() $ // generate the lexer/LexerException.java $ output $basedir + '/lexer/LexerException.java' /* This file was generated by SableCC (http://www.sablecc.org/). */ package @package.lexer; public class LexerException extends Exception { public LexerException(String message) { super(message); } } $ end output $ // generate the lexer/Lexer.java $ output $basedir + '/lexer/Lexer.java' /* This file was generated by SableCC (http://www.sablecc.org/). */ package @package.lexer; import java.io.*; import java.util.*; import @package.node.*; public class Lexer { protected Token token; protected State state = State.${lexer_data/state/@name}; private PushbackReader in; private int line; private int pos; private boolean cr; private boolean eof; private final StringBuffer text = new StringBuffer(); protected void filter() throws LexerException, IOException { } public Lexer(PushbackReader in) { this.in = in; if(gotoTable == null) { try { BufferedReader r = new BufferedReader (new InputStreamReader ( Lexer.class.getResourceAsStream("lexer.dat"))); // read gotoTable int length = Integer.parseInt(r.readLine()); gotoTable = new int[length][][][]; for(int i = 0; i < gotoTable.length; i++) { length = Integer.parseInt(r.readLine()); gotoTable[i] = new int[length][][]; for(int j = 0; j < gotoTable[i].length; j++) { length = Integer.parseInt(r.readLine()); gotoTable[i][j] = new int[length][3]; for(int k = 0; k < gotoTable[i][j].length; k++) { for(int l = 0; l < 3; l++) { gotoTable[i][j][k][l] = Integer.parseInt(r.readLine()); } } } } // read accept length = Integer.parseInt(r.readLine()); accept = new int[length][]; for(int i = 0; i < accept.length; i++) { length = Integer.parseInt(r.readLine()); accept[i] = new int[length]; for(int j = 0; j < accept[i].length; j++) { accept[i][j] = Integer.parseInt(r.readLine()); } } r.close(); } catch(Exception e) { throw new RuntimeException("The file \"lexer.dat\" is either missing or corrupted."); } } } public Token peek() throws LexerException, IOException { while(token == null) { token = getToken(); filter(); } return token; } public Token next() throws LexerException, IOException { while(token == null) { token = getToken(); filter(); } Token result = token; token = null; return result; } protected Token getToken() throws IOException, LexerException { int dfa_state = 0; int start_pos = pos; int start_line = line; int accept_state = -1; int accept_token = -1; int accept_length = -1; int accept_pos = -1; int accept_line = -1; int[][][] gotoTable = this.gotoTable[state.id()]; int[] accept = this.accept[state.id()]; text.setLength(0); while(true) { int c = getChar(); if(c != -1) { switch(c) { case 10: if(cr) { cr = false; } else { line++; pos = 0; } break; case 13: line++; pos = 0; cr = true; break; default: pos++; cr = false; break; }; text.append((char) c); do { int oldState = (dfa_state < -1) ? (-2 -dfa_state) : dfa_state; dfa_state = -1; int[][] tmp1 = gotoTable[oldState]; int low = 0; int high = tmp1.length - 1; while(low <= high) { int middle = (low + high) / 2; int[] tmp2 = tmp1[middle]; if(c < tmp2[0]) { high = middle - 1; } else if(c > tmp2[1]) { low = middle + 1; } else { dfa_state = tmp2[2]; break; } } }while(dfa_state < -1); } else { dfa_state = -1; } if(dfa_state >= 0) { if(accept[dfa_state] != -1) { accept_state = dfa_state; accept_token = accept[dfa_state]; accept_length = text.length(); accept_pos = pos; accept_line = line; } } else { if(accept_state != -1) { switch(accept_token) { $ foreach {//token} case ${position()-1}: { $ if {not(@value)} Token token = new${position()-1}( getText(accept_length), start_line + 1, start_pos + 1); $ else Token token = new${position()-1}( start_line + 1, start_pos + 1); $ end pushBack(accept_length); pos = accept_pos; line = accept_line; $ if {count(transition[@from!=@to])!=0} switch (state.id()) { $ foreach transition in {transition[@from!=@to]} case ${/parser/lexer_data/state[@name=$transition/@from]/@id}: state = State.@to; break; $ end } $ end if return token; } $ end foreach } } else { if(text.length() > 0) { throw new LexerException( "[" + (start_line + 1) + "," + (start_pos + 1) + "]" + " Unknown token: " + text); } else { EOF token = new EOF( start_line + 1, start_pos + 1); return token; } } } } } $ foreach {//token} $ if @value Token new${position()-1}(int line, int pos) { return new @ename(line, pos); } $ else Token new${position()-1}(String text, int line, int pos) { return new @ename(text, line, pos); } $ end if $ end foreach private int getChar() throws IOException { if(eof) { return -1; } int result = in.read(); if(result == -1) { eof = true; } return result; } private void pushBack(int acceptLength) throws IOException { int length = text.length(); for(int i = length - 1; i >= acceptLength; i--) { eof = false; in.unread(text.charAt(i)); } } protected void unread(Token token) throws IOException { String text = token.getText(); int length = text.length(); for(int i = length - 1; i >= 0; i--) { eof = false; in.unread(text.charAt(i)); } pos = token.getPos() - 1; line = token.getLine() - 1; } private String getText(int acceptLength) { StringBuffer s = new StringBuffer(acceptLength); for(int i = 0; i < acceptLength; i++) { s.append(text.charAt(i)); } return s.toString(); } private static int[][][][] gotoTable; /* = { $ foreach {lexer_data/goto_table/state} { $ foreach {row} { $ foreach {goto} {@low, @high, @state}, $ end foreach }, $ end foreach }, $ end foreach }; */ private static int[][] accept; /* = { $ foreach {lexer_data/accept_table/state} { [-foreach {i}-]${.}, [-end foreach-] }, $ end foreach }; */ public static class State { $ foreach {lexer_data/state} public final static State @name = new State(@id); $ end private int id; private State(int id) { this.id = id; } public int id() { return id; } } } $ end output $ output $basedir + '/lexer/lexer.dat' $ // number of gotos ${count(lexer_data/goto_table/state)} $ foreach {lexer_data/goto_table/state} $ // number of rows ${count(row)} $ foreach {row} $ // number of gotos ${count(goto)} $ foreach {goto} @low @high @state $ end foreach $ end foreach $ end foreach $ // number of accepts ${count(lexer_data/accept_table/state)} $ foreach {lexer_data/accept_table/state} $ // number of items ${count(i)} $ foreach {i} ${.} $ end $ end foreach $ end output $ end template