History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/tools/jstat/Parser.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/tools/jstat/Parser.java+585−0
@@ -0,0 +1,585 @@
1+/*
2+ * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.tools.jstat;
27+
28+import java.io.*;
29+import java.util.*;
30+
31+/**
32+ * A class implementing a simple predictive parser for output format
33+ * specification language for the jstat command.
34+ *
35+ * @author Brian Doherty
36+ * @since 1.5
37+ */
38+public class Parser {
39+
40+ private static boolean pdebug = Boolean.getBoolean("jstat.parser.debug");
41+ private static boolean ldebug = Boolean.getBoolean("jstat.lex.debug");
42+
43+ private static final char OPENBLOCK = '{';
44+ private static final char CLOSEBLOCK = '}';
45+ private static final char DOUBLEQUOTE = '"';
46+ private static final char PERCENT_CHAR = '%';
47+ private static final char OPENPAREN = '(';
48+ private static final char CLOSEPAREN = ')';
49+
50+ private static final char OPERATOR_PLUS = '+';
51+ private static final char OPERATOR_MINUS = '-';
52+ private static final char OPERATOR_MULTIPLY = '*';
53+ private static final char OPERATOR_DIVIDE = '/';
54+
55+ private static final String OPTION = "option";
56+ private static final String COLUMN = "column";
57+ private static final String DATA = "data";
58+ private static final String HEADER = "header";
59+ private static final String WIDTH = "width";
60+ private static final String FORMAT = "format";
61+ private static final String ALIGN = "align";
62+ private static final String SCALE = "scale";
63+
64+ private static final String START = OPTION;
65+
66+ private static final Set scaleKeyWords = Scale.keySet();
67+ private static final Set alignKeyWords = Alignment.keySet();
68+ private static String[] otherKeyWords = {
69+ OPTION, COLUMN, DATA, HEADER, WIDTH, FORMAT, ALIGN, SCALE
70+ };
71+
72+ private static char[] infixOps = {
73+ OPERATOR_PLUS, OPERATOR_MINUS, OPERATOR_MULTIPLY, OPERATOR_DIVIDE
74+ };
75+
76+ private static char[] delimiters = {
77+ OPENBLOCK, CLOSEBLOCK, PERCENT_CHAR, OPENPAREN, CLOSEPAREN
78+ };
79+
80+
81+ private static Set<String> reservedWords;
82+
83+ private StreamTokenizer st;
84+ private String filename;
85+ private Token lookahead;
86+ private Token previous;
87+ private int columnCount;
88+ private OptionFormat optionFormat;
89+
90+ public Parser(String filename) throws FileNotFoundException {
91+ this.filename = filename;
92+ Reader r = new BufferedReader(new FileReader(filename));
93+ }
94+
95+ public Parser(Reader r) {
96+ st = new StreamTokenizer(r);
97+
98+ // allow both c++ style comments
99+ st.ordinaryChar('/');
100+ st.wordChars('_','_');
101+ st.slashSlashComments(true);
102+ st.slashStarComments(true);
103+
104+ reservedWords = new HashSet<String>();
105+ for (int i = 0; i < otherKeyWords.length; i++) {
106+ reservedWords.add(otherKeyWords[i]);
107+ }
108+
109+ for (int i = 0; i < delimiters.length; i++ ) {
110+ st.ordinaryChar(delimiters[i]);
111+ }
112+
113+ for (int i = 0; i < infixOps.length; i++ ) {
114+ st.ordinaryChar(infixOps[i]);
115+ }
116+ }
117+
118+ /**
119+ * push back the lookahead token and restore the lookahead token
120+ * to the previous token.
121+ */
122+ private void pushBack() {
123+ lookahead = previous;
124+ st.pushBack();
125+ }
126+
127+ /**
128+ * retrieve the next token, placing the token value in the lookahead
129+ * member variable, storing its previous value in the previous member
130+ * variable.
131+ */
132+ private void nextToken() throws ParserException, IOException {
133+ int t = st.nextToken();
134+ previous = lookahead;
135+ lookahead = new Token(st.ttype, st.sval, st.nval);
136+ log(ldebug, "lookahead = " + lookahead);
137+ }
138+
139+ /**
140+ * match one of the token values in the given set of key words
141+ * token is assumed to be of type TT_WORD, and the set is assumed
142+ * to contain String objects.
143+ */
144+ private Token matchOne(Set keyWords) throws ParserException, IOException {
145+ if ((lookahead.ttype == StreamTokenizer.TT_WORD)
146+ && keyWords.contains(lookahead.sval)) {
147+ Token t = lookahead;
148+ nextToken();
149+ return t;
150+ }
151+ throw new SyntaxException(st.lineno(), keyWords, lookahead);
152+ }
153+
154+ /**
155+ * match a token with TT_TYPE=type, and the token value is a given sequence
156+ * of characters.
157+ */
158+ private void match(int ttype, String token)
159+ throws ParserException, IOException {
160+ if (lookahead.ttype == ttype && lookahead.sval.compareTo(token) == 0) {
161+ nextToken();
162+ } else {
163+ throw new SyntaxException(st.lineno(), new Token(ttype, token),
164+ lookahead);
165+ }
166+ }
167+
168+ /**
169+ * match a token with TT_TYPE=type
170+ */
171+ private void match(int ttype) throws ParserException, IOException {
172+ if (lookahead.ttype == ttype) {
173+ nextToken();
174+ } else {
175+ throw new SyntaxException(st.lineno(), new Token(ttype), lookahead);
176+ }
177+ }
178+
179+ /**
180+ * match a token with TT_TYPE=char, where the token value is the given char.
181+ */
182+ private void match(char ttype) throws ParserException, IOException {
183+ if (lookahead.ttype == (int)ttype) {
184+ nextToken();
185+ }
186+ else {
187+ throw new SyntaxException(st.lineno(), new Token((int)ttype),
188+ lookahead);
189+ }
190+ }
191+
192+ /**
193+ * match a token with TT_TYPE='"', where the token value is a sequence
194+ * of characters between matching quote characters.
195+ */
196+ private void matchQuotedString() throws ParserException, IOException {
197+ match(DOUBLEQUOTE);
198+ }
199+
200+ /**
201+ * match a TT_NUMBER token that matches a parsed number value
202+ */
203+ private void matchNumber() throws ParserException, IOException {
204+ match(StreamTokenizer.TT_NUMBER);
205+ }
206+
207+ /**
208+ * match a TT_WORD token that matches an arbitrary, not quoted token.
209+ */
210+ private void matchID() throws ParserException, IOException {
211+ match(StreamTokenizer.TT_WORD);
212+ }
213+
214+ /**
215+ * match a TT_WORD token that matches the given string
216+ */
217+ private void match(String token) throws ParserException, IOException {
218+ match(StreamTokenizer.TT_WORD, token);
219+ }
220+
221+ /**
222+ * determine if the given word is a reserved key word
223+ */
224+ private boolean isReservedWord(String word) {
225+ return reservedWords.contains(word);
226+ }
227+
228+ /**
229+ * determine if the give work is a reserved key word
230+ */
231+ private boolean isInfixOperator(char op) {
232+ for (int i = 0; i < infixOps.length; i++) {
233+ if (op == infixOps[i]) {
234+ return true;
235+ }
236+ }
237+ return false;
238+ }
239+
240+ /**
241+ * scalestmt -> 'scale' scalespec
242+ * scalespec -> <see above scaleTerminals array>
243+ */
244+ private void scaleStmt(ColumnFormat cf)
245+ throws ParserException, IOException {
246+ match(SCALE);
247+ Token t = matchOne(scaleKeyWords);
248+ cf.setScale(Scale.toScale(t.sval));
249+ String scaleString = t.sval;
250+ log(pdebug, "Parsed: scale -> " + scaleString);
251+ }
252+
253+ /**
254+ * alignstmt -> 'align' alignspec
255+ * alignspec -> <see above alignTerminals array>
256+ */
257+ private void alignStmt(ColumnFormat cf)
258+ throws ParserException, IOException {
259+ match(ALIGN);
260+ Token t = matchOne(alignKeyWords);
261+ cf.setAlignment(Alignment.toAlignment(t.sval));
262+ String alignString = t.sval;
263+ log(pdebug, "Parsed: align -> " + alignString);
264+ }
265+
266+ /**
267+ * headerstmt -> 'header' quotedstring
268+ */
269+ private void headerStmt(ColumnFormat cf)
270+ throws ParserException, IOException {
271+ match(HEADER);
272+ String headerString = lookahead.sval;
273+ matchQuotedString();
274+ cf.setHeader(headerString);
275+ log(pdebug, "Parsed: header -> " + headerString);
276+ }
277+
278+ /**
279+ * widthstmt -> 'width' integer
280+ */
281+ private void widthStmt(ColumnFormat cf)
282+ throws ParserException, IOException {
283+ match(WIDTH);
284+ double width = lookahead.nval;
285+ matchNumber();
286+ cf.setWidth((int)width);
287+ log(pdebug, "Parsed: width -> " + width );
288+ }
289+
290+ /**
291+ * formatstmt -> 'format' quotedstring
292+ */
293+ private void formatStmt(ColumnFormat cf)
294+ throws ParserException, IOException {
295+ match(FORMAT);
296+ String formatString = lookahead.sval;
297+ matchQuotedString();
298+ cf.setFormat(formatString);
299+ log(pdebug, "Parsed: format -> " + formatString);
300+ }
301+
302+ /**
303+ * Primary -> Literal | Identifier | '(' Expression ')'
304+ */
305+ private Expression primary() throws ParserException, IOException {
306+ Expression e = null;
307+
308+ switch (lookahead.ttype) {
309+ case OPENPAREN:
310+ match(OPENPAREN);
311+ e = expression();
312+ match(CLOSEPAREN);
313+ break;
314+ case StreamTokenizer.TT_WORD:
315+ String s = lookahead.sval;
316+ if (isReservedWord(s)) {
317+ throw new SyntaxException(st.lineno(), "IDENTIFIER",
318+ "Reserved Word: " + lookahead.sval);
319+ }
320+ matchID();
321+ e = new Identifier(s);
322+ log(pdebug, "Parsed: ID -> " + s);
323+ break;
324+ case StreamTokenizer.TT_NUMBER:
325+ double literal = lookahead.nval;
326+ matchNumber();
327+ e = new Literal(new Double(literal));
328+ log(pdebug, "Parsed: number -> " + literal);
329+ break;
330+ default:
331+ throw new SyntaxException(st.lineno(), "IDENTIFIER", lookahead);
332+ }
333+ log(pdebug, "Parsed: primary -> " + e);
334+ return e;
335+ }
336+
337+ /**
338+ * Unary -> ('+'|'-') Unary | Primary
339+ */
340+ private Expression unary() throws ParserException, IOException {
341+ Expression e = null;
342+ Operator op = null;
343+
344+ while (true) {
345+ switch (lookahead.ttype) {
346+ case OPERATOR_PLUS:
347+ match(OPERATOR_PLUS);
348+ op = Operator.PLUS;
349+ break;
350+ case OPERATOR_MINUS:
351+ match(OPERATOR_MINUS);
352+ op = Operator.MINUS;
353+ break;
354+ default:
355+ e = primary();
356+ log(pdebug, "Parsed: unary -> " + e);
357+ return e;
358+ }
359+ Expression e1 = new Expression();
360+ e1.setOperator(op);
361+ e1.setRight(e);
362+ log(pdebug, "Parsed: unary -> " + e1);
363+ e1.setLeft(new Literal(new Double(0)));
364+ e = e1;
365+ }
366+ }
367+
368+ /**
369+ * MultExpression -> Unary (('*' | '/') Unary)*
370+ */
371+ private Expression multExpression() throws ParserException, IOException {
372+ Expression e = unary();
373+ Operator op = null;
374+
375+ while (true) {
376+ switch (lookahead.ttype) {
377+ case OPERATOR_MULTIPLY:
378+ match(OPERATOR_MULTIPLY);
379+ op = Operator.MULTIPLY;
380+ break;
381+ case OPERATOR_DIVIDE:
382+ match(OPERATOR_DIVIDE);
383+ op = Operator.DIVIDE;
384+ break;
385+ default:
386+ log(pdebug, "Parsed: multExpression -> " + e);
387+ return e;
388+ }
389+ Expression e1 = new Expression();
390+ e1.setOperator(op);
391+ e1.setLeft(e);
392+ e1.setRight(unary());
393+ e = e1;
394+ log(pdebug, "Parsed: multExpression -> " + e);
395+ }
396+ }
397+
398+ /**
399+ * AddExpression -> MultExpression (('+' | '-') MultExpression)*
400+ */
401+ private Expression addExpression() throws ParserException, IOException {
402+ Expression e = multExpression();
403+ Operator op = null;
404+
405+ while (true) {
406+ switch (lookahead.ttype) {
407+ case OPERATOR_PLUS:
408+ match(OPERATOR_PLUS);
409+ op = Operator.PLUS;
410+ break;
411+ case OPERATOR_MINUS:
412+ match(OPERATOR_MINUS);
413+ op = Operator.MINUS;
414+ break;
415+ default:
416+ log(pdebug, "Parsed: addExpression -> " + e);
417+ return e;
418+ }
419+ Expression e1 = new Expression();
420+ e1.setOperator(op);
421+ e1.setLeft(e);
422+ e1.setRight(multExpression());
423+ e = e1;
424+ log(pdebug, "Parsed: addExpression -> " + e);
425+ }
426+ }
427+
428+ /**
429+ * Expression -> AddExpression
430+ */
431+ private Expression expression() throws ParserException, IOException {
432+ Expression e = addExpression();
433+ log(pdebug, "Parsed: expression -> " + e);
434+ return e;
435+ }
436+
437+ /**
438+ * datastmt -> 'data' expression
439+ */
440+ private void dataStmt(ColumnFormat cf) throws ParserException, IOException {
441+ match(DATA);
442+ Expression e = expression();
443+ cf.setExpression(e);
444+ log(pdebug, "Parsed: data -> " + e);
445+ }
446+
447+ /**
448+ * statementlist -> optionalstmt statementlist
449+ * optionalstmt -> 'data' expression
450+ * 'header' quotedstring
451+ * 'width' integer
452+ * 'format' formatstring
453+ * 'align' alignspec
454+ * 'scale' scalespec
455+ */
456+ private void statementList(ColumnFormat cf)
457+ throws ParserException, IOException {
458+ while (true) {
459+ if (lookahead.ttype != StreamTokenizer.TT_WORD) {
460+ return;
461+ }
462+
463+ if (lookahead.sval.compareTo(DATA) == 0) {
464+ dataStmt(cf);
465+ } else if (lookahead.sval.compareTo(HEADER) == 0) {
466+ headerStmt(cf);
467+ } else if (lookahead.sval.compareTo(WIDTH) == 0) {
468+ widthStmt(cf);
469+ } else if (lookahead.sval.compareTo(FORMAT) == 0) {
470+ formatStmt(cf);
471+ } else if (lookahead.sval.compareTo(ALIGN) == 0) {
472+ alignStmt(cf);
473+ } else if (lookahead.sval.compareTo(SCALE) == 0) {
474+ scaleStmt(cf);
475+ } else {
476+ return;
477+ }
478+ }
479+ }
480+
481+ /**
482+ * optionlist -> columspec optionlist
483+ * null
484+ * columspec -> 'column' '{' statementlist '}'
485+ */
486+ private void optionList(OptionFormat of)
487+ throws ParserException, IOException {
488+ while (true) {
489+ if (lookahead.ttype != StreamTokenizer.TT_WORD) {
490+ return;
491+ }
492+
493+ match(COLUMN);
494+ match(OPENBLOCK);
495+ ColumnFormat cf = new ColumnFormat(columnCount++);
496+ statementList(cf);
497+ match(CLOSEBLOCK);
498+ cf.validate();
499+ of.addSubFormat(cf);
500+ }
501+ }
502+
503+ /**
504+ * optionstmt -> 'option' ID '{' optionlist '}'
505+ */
506+ private OptionFormat optionStmt() throws ParserException, IOException {
507+ match(OPTION);
508+ String optionName=lookahead.sval;
509+ matchID();
510+ match(OPENBLOCK);
511+ OptionFormat of = new OptionFormat(optionName);
512+ optionList(of);
513+ match(CLOSEBLOCK);
514+ return of;
515+ }
516+
517+ /**
518+ * parse the specification for the given option identifier
519+ */
520+ public OptionFormat parse(String option)
521+ throws ParserException, IOException {
522+ nextToken();
523+
524+ /*
525+ * this search stops on the first occurance of an option
526+ * statement with a name matching the given option. Any
527+ * duplicate options are ignored.
528+ */
529+ while (lookahead.ttype != StreamTokenizer.TT_EOF) {
530+ // look for the start symbol
531+ if ((lookahead.ttype != StreamTokenizer.TT_WORD)
532+ || (lookahead.sval.compareTo(START) != 0)) {
533+ // skip tokens until a start symbol is found
534+ nextToken();
535+ continue;
536+ }
537+
538+ // check if the option name is the one we are interested in
539+ match(START);
540+
541+ if ((lookahead.ttype == StreamTokenizer.TT_WORD)
542+ && (lookahead.sval.compareTo(option) == 0)) {
543+ // this is the one we are looking for, parse it
544+ pushBack();
545+ return optionStmt();
546+ } else {
547+ // not what we are looking for, start skipping tokens
548+ nextToken();
549+ }
550+ }
551+ return null;
552+ }
553+
554+ public Set<OptionFormat> parseOptions() throws ParserException, IOException {
555+ Set<OptionFormat> options = new HashSet<OptionFormat>();
556+
557+ nextToken();
558+
559+ while (lookahead.ttype != StreamTokenizer.TT_EOF) {
560+ // look for the start symbol
561+ if ((lookahead.ttype != StreamTokenizer.TT_WORD)
562+ || (lookahead.sval.compareTo(START) != 0)) {
563+ // skip tokens until a start symbol is found
564+ nextToken();
565+ continue;
566+ }
567+
568+ // note: if a duplicate option statement exists, then
569+ // first one encountered is the chosen definition.
570+ OptionFormat of = optionStmt();
571+ options.add(of);
572+ }
573+ return options;
574+ }
575+
576+ OptionFormat getOptionFormat() {
577+ return optionFormat;
578+ }
579+
580+ private void log(boolean logging, String s) {
581+ if (logging) {
582+ System.out.println(s);
583+ }
584+ }
585+}