| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package sun.tools.jstat;  | 
 | 
 | 
 | 
import java.io.*;  | 
 | 
import java.util.*;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
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);  | 
 | 
 | 
 | 
          | 
 | 
        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]);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private void pushBack() { | 
 | 
        lookahead = previous;  | 
 | 
        st.pushBack();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    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);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    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);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    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);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private void match(int ttype) throws ParserException, IOException { | 
 | 
        if (lookahead.ttype == ttype) { | 
 | 
            nextToken();  | 
 | 
        } else { | 
 | 
           throw new SyntaxException(st.lineno(), new Token(ttype), lookahead);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    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);  | 
 | 
      }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private void matchQuotedString() throws ParserException, IOException { | 
 | 
        match(DOUBLEQUOTE);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private void matchNumber() throws ParserException, IOException { | 
 | 
        match(StreamTokenizer.TT_NUMBER);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private void matchID() throws ParserException, IOException { | 
 | 
        match(StreamTokenizer.TT_WORD);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private void match(String token) throws ParserException, IOException { | 
 | 
        match(StreamTokenizer.TT_WORD, token);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private boolean isReservedWord(String word) { | 
 | 
        return reservedWords.contains(word);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private boolean isInfixOperator(char op) { | 
 | 
        for (int i = 0; i < infixOps.length; i++) { | 
 | 
            if (op == infixOps[i]) { | 
 | 
                return true;  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return false;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    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);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    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);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private void headerStmt(ColumnFormat cf)  | 
 | 
                 throws ParserException, IOException { | 
 | 
        match(HEADER);  | 
 | 
        String headerString = lookahead.sval;  | 
 | 
        matchQuotedString();  | 
 | 
        cf.setHeader(headerString);  | 
 | 
        log(pdebug, "Parsed: header -> " + headerString);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private void widthStmt(ColumnFormat cf)  | 
 | 
                 throws ParserException, IOException { | 
 | 
        match(WIDTH);  | 
 | 
        double width = lookahead.nval;  | 
 | 
        matchNumber();  | 
 | 
        cf.setWidth((int)width);  | 
 | 
        log(pdebug, "Parsed: width -> " + width );  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private void formatStmt(ColumnFormat cf)  | 
 | 
                 throws ParserException, IOException { | 
 | 
        match(FORMAT);  | 
 | 
        String formatString = lookahead.sval;  | 
 | 
        matchQuotedString();  | 
 | 
        cf.setFormat(formatString);  | 
 | 
        log(pdebug, "Parsed: format -> " + formatString);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    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;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    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;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    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);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    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);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private Expression expression() throws ParserException, IOException { | 
 | 
        Expression e = addExpression();  | 
 | 
        log(pdebug, "Parsed: expression -> " + e);  | 
 | 
        return e;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private void dataStmt(ColumnFormat cf) throws ParserException, IOException { | 
 | 
        match(DATA);  | 
 | 
        Expression e = expression();  | 
 | 
        cf.setExpression(e);  | 
 | 
        log(pdebug, "Parsed: data -> " + e);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    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;  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    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);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private OptionFormat optionStmt() throws ParserException, IOException { | 
 | 
        match(OPTION);  | 
 | 
        String optionName=lookahead.sval;  | 
 | 
        matchID();  | 
 | 
        match(OPENBLOCK);  | 
 | 
        OptionFormat of = new OptionFormat(optionName);  | 
 | 
        optionList(of);  | 
 | 
        match(CLOSEBLOCK);  | 
 | 
        return of;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public OptionFormat parse(String option)  | 
 | 
                        throws ParserException, IOException { | 
 | 
        nextToken();  | 
 | 
 | 
 | 
          | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
         */  | 
 | 
        while (lookahead.ttype != StreamTokenizer.TT_EOF) { | 
 | 
              | 
 | 
            if ((lookahead.ttype != StreamTokenizer.TT_WORD)  | 
 | 
                    || (lookahead.sval.compareTo(START) != 0)) { | 
 | 
                  | 
 | 
                nextToken();  | 
 | 
                continue;  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            match(START);  | 
 | 
 | 
 | 
            if ((lookahead.ttype == StreamTokenizer.TT_WORD)  | 
 | 
                    && (lookahead.sval.compareTo(option) == 0)) { | 
 | 
                  | 
 | 
                pushBack();  | 
 | 
                return optionStmt();  | 
 | 
            } else { | 
 | 
                  | 
 | 
                nextToken();  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return null;  | 
 | 
    }  | 
 | 
 | 
 | 
    public Set<OptionFormat> parseOptions() throws ParserException, IOException { | 
 | 
        Set<OptionFormat> options = new HashSet<OptionFormat>();  | 
 | 
 | 
 | 
        nextToken();  | 
 | 
 | 
 | 
        while (lookahead.ttype != StreamTokenizer.TT_EOF) { | 
 | 
              | 
 | 
            if ((lookahead.ttype != StreamTokenizer.TT_WORD)  | 
 | 
                    || (lookahead.sval.compareTo(START) != 0)) { | 
 | 
                  | 
 | 
                nextToken();  | 
 | 
                continue;  | 
 | 
            }  | 
 | 
 | 
 | 
            // note: if a duplicate option statement exists, then  | 
 | 
              | 
 | 
            OptionFormat of = optionStmt();  | 
 | 
            options.add(of);  | 
 | 
        }  | 
 | 
        return options;  | 
 | 
    }  | 
 | 
 | 
 | 
    OptionFormat getOptionFormat() { | 
 | 
       return optionFormat;  | 
 | 
    }  | 
 | 
 | 
 | 
    private void log(boolean logging, String s) { | 
 | 
        if (logging) { | 
 | 
            System.out.println(s);  | 
 | 
        }  | 
 | 
    }  | 
 | 
}  |