Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/tools/jstat/Parser.java
38918 views
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
}
586
587