作用:用于代码编辑器中的括号匹配测试
package com.tokenizer.cc; import java.io.IOException; import java.io.PushbackReader; import java.io.Reader; /** * Tokenizer class. * @author SunnyBoy * @version Time:2017年8月3日 下午3:57:00 */ public class Tokenizer { private PushbackReader in;// The input Stream private char ch;//Current character private int currentLine;//Current line private int errors;//Number of errors seen public static final int SLASH_SLAH = 0; public static final int SLASH_STAR = 1; public Tokenizer( Reader inStream) { errors = 0; ch = '\0'; currentLine = 1; in = new PushbackReader(inStream); } public int getLineNumber() { return currentLine; } public int getErrorCount() { return errors; } /** * Get the next opening or closing symbol. * Return false if end of file. * Skip past comments and character and string constants */ public char getNextOpenClose() { while(nextChar()) { if(ch == '/') processSlash(); else if(ch == '\''||ch =='"') skipQuote(ch); else if(ch =='(' || ch == '[' || ch == '{' || ch ==')' || ch == ']' || ch == '}') return ch; } return '\0'; } /** * @return next identifier.skipping comments * string constants.and character constants. * Place identifier in currentIdNode.word and return false * only if end of stream is reached. */ public String getNextID() { while(nextChar()) { if(ch =='/') processSlash(); else if(ch =='\\') nextChar(); else if(ch =='\'' || ch =='"') skipQuote(ch); else if (!Character.isDigit(ch)&&isIdChar(ch)) return getRemainingString(); } return null; } /** * nextChar sets ch based on the next character in the input stream. * putBackChar puts thecharacter back onto the stream. * It should be used only once after a call to nextChar. * Both routines adjust currentLine if necessary. * @return */ private boolean nextChar() { try { int readVal = in.read(); if(readVal == -1) return false; ch = (char) readVal; if(ch == '\n') currentLine++; return true; } catch(IOException e) { return false; } } private void putBackChar() { if(ch == '\n') currentLine--; try { in.unread((int)ch); }catch(IOException e) { } } /** * Precondition: We are about to process a comment; * have already seen comment-start token * Postcondition: Stream will be set immediately after * commment-ending token * @param start */ private void skipComment(int start) { if(start == SLASH_SLAH) { while(nextChar()&&(ch!='\n')); return; } boolean state = false; while(nextChar()) { if(state&&ch=='/') return; state = (ch =='*'); } errors++; System.out.println("Unterminated comment!"); } /** * Precondition: We are about to process a quote; * have already seen beginning quote. * Postcondition: Stream will be set immediately after * matching quote * @param quoteType */ private void skipQuote(char quoteType) { while(nextChar()) { if(ch == quoteType) return; if(ch == '\n') { errors++; System.out.println("Missing closed quote at line "+ currentLine); return; } else if(ch == '\\') nextChar(); } } /** * After the opening slash is seen deal with next character. * If it is a comment starter. process it; otherwise putback * the next character if it is not a newline. */ private void processSlash() { if (nextChar()) { if (ch == '*') { // Javadoc comment if (nextChar() && ch != '*') putBackChar(); skipComment(SLASH_STAR); } else if (ch == '/') skipComment(SLASH_SLAH); else if (ch == '\n') putBackChar(); } } /** * Return true if ch can be part of a Java identifier * @param ch * @return */ private static final boolean isIdChar(char ch) { return Character.isJavaIdentifierPart(ch); } /** * Return an identifier read from input stream * First character is already read into ch * @return */ private String getRemainingString() { String result = ""+ch; for(;nextChar();result+=ch) if(!isIdChar(ch)) { putBackChar(); break; } return result; } }