|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
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); |
|
} |
|
} |
|
} |