585 lines · 18.1 KB · Java
RawDownload
/* * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.tools.jstat; import java.io.*;import java.util.*; /** * A class implementing a simple predictive parser for output format * specification language for the jstat command. * * @author Brian Doherty * @since 1.5 */public class Parser {     private static boolean pdebug = Boolean.getBoolean("jstat.parser.debug");    private static boolean ldebug = Boolean.getBoolean("jstat.lex.debug");     private static final char OPENBLOCK = '{';    private static final char CLOSEBLOCK = '}';    private static final char DOUBLEQUOTE = '"';    private static final char PERCENT_CHAR = '%';    private static final char OPENPAREN = '(';    private static final char CLOSEPAREN = ')';     private static final char OPERATOR_PLUS = '+';    private static final char OPERATOR_MINUS = '-';    private static final char OPERATOR_MULTIPLY = '*';    private static final char OPERATOR_DIVIDE = '/';     private static final String OPTION = "option";    private static final String COLUMN = "column";    private static final String DATA = "data";    private static final String HEADER = "header";    private static final String WIDTH = "width";    private static final String FORMAT = "format";    private static final String ALIGN = "align";    private static final String SCALE = "scale";     private static final String START = OPTION;     private static final Set scaleKeyWords = Scale.keySet();    private static final Set alignKeyWords = Alignment.keySet();    private static String[] otherKeyWords = {        OPTION, COLUMN, DATA, HEADER, WIDTH, FORMAT, ALIGN, SCALE    };     private static char[] infixOps = {        OPERATOR_PLUS, OPERATOR_MINUS, OPERATOR_MULTIPLY, OPERATOR_DIVIDE    };     private static char[] delimiters = {        OPENBLOCK, CLOSEBLOCK, PERCENT_CHAR, OPENPAREN, CLOSEPAREN    };      private static Set<String> reservedWords;     private StreamTokenizer st;    private String filename;    private Token lookahead;    private Token previous;    private int columnCount;    private OptionFormat optionFormat;     public Parser(String filename) throws FileNotFoundException {        this.filename = filename;        Reader r = new BufferedReader(new FileReader(filename));    }     public Parser(Reader r) {        st = new StreamTokenizer(r);         // allow both c++ style comments        st.ordinaryChar('/');        st.wordChars('_','_');        st.slashSlashComments(true);        st.slashStarComments(true);         reservedWords = new HashSet<String>();        for (int i = 0; i < otherKeyWords.length; i++) {            reservedWords.add(otherKeyWords[i]);        }         for (int i = 0; i < delimiters.length; i++ ) {            st.ordinaryChar(delimiters[i]);        }         for (int i = 0; i < infixOps.length; i++ ) {            st.ordinaryChar(infixOps[i]);        }    }     /**     * push back the lookahead token and restore the lookahead token     * to the previous token.     */    private void pushBack() {        lookahead = previous;        st.pushBack();    }     /**     * retrieve the next token, placing the token value in the lookahead     * member variable, storing its previous value in the previous member     * variable.     */    private void nextToken() throws ParserException, IOException {        int t = st.nextToken();        previous = lookahead;        lookahead = new Token(st.ttype, st.sval, st.nval);        log(ldebug, "lookahead = " + lookahead);    }     /**     * match one of the token values in the given set of key words     * token is assumed to be of type TT_WORD, and the set is assumed     * to contain String objects.     */    private Token matchOne(Set keyWords) throws ParserException, IOException {        if ((lookahead.ttype == StreamTokenizer.TT_WORD)                && keyWords.contains(lookahead.sval)) {            Token t = lookahead;            nextToken();            return t;        }        throw new SyntaxException(st.lineno(), keyWords, lookahead);    }     /**     * match a token with TT_TYPE=type, and the token value is a given sequence     * of characters.     */    private void match(int ttype, String token)                 throws ParserException, IOException {        if (lookahead.ttype == ttype && lookahead.sval.compareTo(token) == 0) {            nextToken();        } else {           throw new SyntaxException(st.lineno(), new Token(ttype, token),                                     lookahead);        }    }     /**     * match a token with TT_TYPE=type     */    private void match(int ttype) throws ParserException, IOException {        if (lookahead.ttype == ttype) {            nextToken();        } else {           throw new SyntaxException(st.lineno(), new Token(ttype), lookahead);        }    }     /**     * match a token with TT_TYPE=char, where the token value is the given char.     */    private void match(char ttype) throws ParserException, IOException {      if (lookahead.ttype == (int)ttype) {          nextToken();      }      else {          throw new SyntaxException(st.lineno(), new Token((int)ttype),                                    lookahead);      }    }     /**     * match a token with TT_TYPE='"', where the token value is a sequence     * of characters between matching quote characters.     */    private void matchQuotedString() throws ParserException, IOException {        match(DOUBLEQUOTE);    }     /**     * match a TT_NUMBER token that matches a parsed number value     */    private void matchNumber() throws ParserException, IOException {        match(StreamTokenizer.TT_NUMBER);    }     /**     * match a TT_WORD token that matches an arbitrary, not quoted token.     */    private void matchID() throws ParserException, IOException {        match(StreamTokenizer.TT_WORD);    }     /**     * match a TT_WORD token that matches the given string     */    private void match(String token) throws ParserException, IOException {        match(StreamTokenizer.TT_WORD, token);    }     /**     * determine if the given word is a reserved key word     */    private boolean isReservedWord(String word) {        return reservedWords.contains(word);    }     /**     * determine if the give work is a reserved key word     */    private boolean isInfixOperator(char op) {        for (int i = 0; i < infixOps.length; i++) {            if (op == infixOps[i]) {                return true;            }        }        return false;    }     /**     * scalestmt -> 'scale' scalespec     * scalespec -> <see above scaleTerminals array>     */    private void scaleStmt(ColumnFormat cf)                 throws ParserException, IOException {        match(SCALE);        Token t = matchOne(scaleKeyWords);        cf.setScale(Scale.toScale(t.sval));        String scaleString = t.sval;        log(pdebug, "Parsed: scale -> " + scaleString);    }     /**     * alignstmt -> 'align' alignspec     * alignspec -> <see above alignTerminals array>     */    private void alignStmt(ColumnFormat cf)                 throws ParserException, IOException {        match(ALIGN);        Token t = matchOne(alignKeyWords);        cf.setAlignment(Alignment.toAlignment(t.sval));        String alignString = t.sval;        log(pdebug, "Parsed: align -> " + alignString);    }     /**     * headerstmt -> 'header' quotedstring     */    private void headerStmt(ColumnFormat cf)                 throws ParserException, IOException {        match(HEADER);        String headerString = lookahead.sval;        matchQuotedString();        cf.setHeader(headerString);        log(pdebug, "Parsed: header -> " + headerString);    }     /**     * widthstmt -> 'width' integer     */    private void widthStmt(ColumnFormat cf)                 throws ParserException, IOException {        match(WIDTH);        double width = lookahead.nval;        matchNumber();        cf.setWidth((int)width);        log(pdebug, "Parsed: width -> " + width );    }     /**     * formatstmt -> 'format' quotedstring     */    private void formatStmt(ColumnFormat cf)                 throws ParserException, IOException {        match(FORMAT);        String formatString = lookahead.sval;        matchQuotedString();        cf.setFormat(formatString);        log(pdebug, "Parsed: format -> " + formatString);    }     /**     *  Primary -> Literal | Identifier | '(' Expression ')'     */    private Expression primary() throws ParserException, IOException {        Expression e = null;         switch (lookahead.ttype) {        case OPENPAREN:            match(OPENPAREN);            e = expression();            match(CLOSEPAREN);            break;        case StreamTokenizer.TT_WORD:            String s = lookahead.sval;            if (isReservedWord(s)) {                throw new SyntaxException(st.lineno(), "IDENTIFIER",                                          "Reserved Word: " + lookahead.sval);            }            matchID();            e = new Identifier(s);            log(pdebug, "Parsed: ID -> " + s);            break;        case StreamTokenizer.TT_NUMBER:            double literal = lookahead.nval;            matchNumber();            e = new Literal(new Double(literal));            log(pdebug, "Parsed: number -> " + literal);            break;        default:            throw new SyntaxException(st.lineno(), "IDENTIFIER", lookahead);        }        log(pdebug, "Parsed: primary -> " + e);        return e;    }     /**     * Unary -> ('+'|'-') Unary | Primary     */    private Expression unary() throws ParserException, IOException {        Expression e = null;        Operator op = null;         while (true) {            switch (lookahead.ttype) {            case OPERATOR_PLUS:                match(OPERATOR_PLUS);                op = Operator.PLUS;                break;            case OPERATOR_MINUS:                match(OPERATOR_MINUS);                op = Operator.MINUS;                break;            default:                e = primary();                log(pdebug, "Parsed: unary -> " + e);                return e;            }            Expression e1 = new Expression();            e1.setOperator(op);            e1.setRight(e);            log(pdebug, "Parsed: unary -> " + e1);            e1.setLeft(new Literal(new Double(0)));            e = e1;        }    }     /**     *  MultExpression -> Unary (('*' | '/') Unary)*     */    private Expression multExpression() throws ParserException, IOException {        Expression e = unary();        Operator op = null;         while (true) {            switch (lookahead.ttype) {            case OPERATOR_MULTIPLY:                match(OPERATOR_MULTIPLY);                op = Operator.MULTIPLY;                break;            case OPERATOR_DIVIDE:                match(OPERATOR_DIVIDE);                op = Operator.DIVIDE;                break;            default:                log(pdebug, "Parsed: multExpression -> " + e);                return e;            }            Expression e1 = new Expression();            e1.setOperator(op);            e1.setLeft(e);            e1.setRight(unary());            e = e1;            log(pdebug, "Parsed: multExpression -> " + e);        }    }     /**     *  AddExpression -> MultExpression (('+' | '-') MultExpression)*     */    private Expression addExpression() throws ParserException, IOException {        Expression e = multExpression();        Operator op = null;         while (true) {            switch (lookahead.ttype) {            case OPERATOR_PLUS:                match(OPERATOR_PLUS);                op = Operator.PLUS;                break;            case OPERATOR_MINUS:                match(OPERATOR_MINUS);                op = Operator.MINUS;                break;            default:                log(pdebug, "Parsed: addExpression -> " + e);                return e;            }            Expression e1 = new Expression();            e1.setOperator(op);            e1.setLeft(e);            e1.setRight(multExpression());            e = e1;            log(pdebug, "Parsed: addExpression -> " + e);        }    }     /**     *  Expression -> AddExpression     */    private Expression expression() throws ParserException, IOException {        Expression e = addExpression();        log(pdebug, "Parsed: expression -> " + e);        return e;    }     /**     * datastmt -> 'data' expression     */    private void dataStmt(ColumnFormat cf) throws ParserException, IOException {        match(DATA);        Expression e = expression();        cf.setExpression(e);        log(pdebug, "Parsed: data -> " + e);    }     /**     * statementlist -> optionalstmt statementlist     * optionalstmt -> 'data' expression     *                 'header' quotedstring     *                 'width' integer     *                 'format' formatstring     *                 'align' alignspec     *                 'scale' scalespec     */    private void statementList(ColumnFormat cf)                 throws ParserException, IOException {        while (true) {            if (lookahead.ttype != StreamTokenizer.TT_WORD) {                return;            }             if (lookahead.sval.compareTo(DATA) == 0) {                dataStmt(cf);            } else if (lookahead.sval.compareTo(HEADER) == 0) {                headerStmt(cf);            } else if (lookahead.sval.compareTo(WIDTH) == 0) {                widthStmt(cf);            } else if (lookahead.sval.compareTo(FORMAT) == 0) {                formatStmt(cf);            } else if (lookahead.sval.compareTo(ALIGN) == 0) {                alignStmt(cf);            } else if (lookahead.sval.compareTo(SCALE) == 0) {                scaleStmt(cf);            } else {                return;            }        }    }     /**     * optionlist -> columspec optionlist     *               null     * columspec -> 'column' '{' statementlist '}'     */    private void optionList(OptionFormat of)                 throws ParserException, IOException {        while (true) {            if (lookahead.ttype != StreamTokenizer.TT_WORD) {                return;            }             match(COLUMN);            match(OPENBLOCK);            ColumnFormat cf = new ColumnFormat(columnCount++);            statementList(cf);              match(CLOSEBLOCK);            cf.validate();            of.addSubFormat(cf);        }

Lines 1–500 of 585.