Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/jdk.jcmd/share/classes/sun/tools/jstat/Parser.java
41159 views
1
/*
2
* Copyright (c) 2004, 2018, 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
private static final String REQUIRED = "required";
64
65
private static final String START = OPTION;
66
67
private static final Set<String> scaleKeyWords = Scale.keySet();
68
private static final Set<String> alignKeyWords = Alignment.keySet();
69
private static final Set<String> boolKeyWords = Set.of("true", "false");
70
private static String[] otherKeyWords = {
71
OPTION, COLUMN, DATA, HEADER, WIDTH, FORMAT, ALIGN, SCALE, REQUIRED
72
};
73
74
private static char[] infixOps = {
75
OPERATOR_PLUS, OPERATOR_MINUS, OPERATOR_MULTIPLY, OPERATOR_DIVIDE
76
};
77
78
private static char[] delimiters = {
79
OPENBLOCK, CLOSEBLOCK, PERCENT_CHAR, OPENPAREN, CLOSEPAREN
80
};
81
82
83
private static Set<String> reservedWords;
84
85
private StreamTokenizer st;
86
private String filename;
87
private Token lookahead;
88
private Token previous;
89
private int columnCount;
90
private OptionFormat optionFormat;
91
92
public Parser(String filename) throws FileNotFoundException {
93
this.filename = filename;
94
Reader r = new BufferedReader(new FileReader(filename));
95
}
96
97
public Parser(Reader r) {
98
st = new StreamTokenizer(r);
99
100
// allow both c++ style comments
101
st.ordinaryChar('/');
102
st.wordChars('_','_');
103
st.slashSlashComments(true);
104
st.slashStarComments(true);
105
106
reservedWords = new HashSet<String>();
107
for (int i = 0; i < otherKeyWords.length; i++) {
108
reservedWords.add(otherKeyWords[i]);
109
}
110
111
for (int i = 0; i < delimiters.length; i++ ) {
112
st.ordinaryChar(delimiters[i]);
113
}
114
115
for (int i = 0; i < infixOps.length; i++ ) {
116
st.ordinaryChar(infixOps[i]);
117
}
118
}
119
120
/**
121
* push back the lookahead token and restore the lookahead token
122
* to the previous token.
123
*/
124
private void pushBack() {
125
lookahead = previous;
126
st.pushBack();
127
}
128
129
/**
130
* retrieve the next token, placing the token value in the lookahead
131
* member variable, storing its previous value in the previous member
132
* variable.
133
*/
134
private void nextToken() throws ParserException, IOException {
135
int t = st.nextToken();
136
previous = lookahead;
137
lookahead = new Token(st.ttype, st.sval, st.nval);
138
log(ldebug, "lookahead = " + lookahead);
139
}
140
141
/**
142
* match one of the token values in the given set of key words
143
* token is assumed to be of type TT_WORD, and the set is assumed
144
* to contain String objects.
145
*/
146
private Token matchOne(Set<String> keyWords) throws ParserException, IOException {
147
if ((lookahead.ttype == StreamTokenizer.TT_WORD)
148
&& keyWords.contains(lookahead.sval)) {
149
Token t = lookahead;
150
nextToken();
151
return t;
152
}
153
throw new SyntaxException(st.lineno(), keyWords, lookahead);
154
}
155
156
/**
157
* match a token with TT_TYPE=type, and the token value is a given sequence
158
* of characters.
159
*/
160
private void match(int ttype, String token)
161
throws ParserException, IOException {
162
if (lookahead.ttype == ttype && lookahead.sval.compareTo(token) == 0) {
163
nextToken();
164
} else {
165
throw new SyntaxException(st.lineno(), new Token(ttype, token),
166
lookahead);
167
}
168
}
169
170
/**
171
* match a token with TT_TYPE=type
172
*/
173
private void match(int ttype) throws ParserException, IOException {
174
if (lookahead.ttype == ttype) {
175
nextToken();
176
} else {
177
throw new SyntaxException(st.lineno(), new Token(ttype), lookahead);
178
}
179
}
180
181
/**
182
* match a token with TT_TYPE=char, where the token value is the given char.
183
*/
184
private void match(char ttype) throws ParserException, IOException {
185
if (lookahead.ttype == (int)ttype) {
186
nextToken();
187
}
188
else {
189
throw new SyntaxException(st.lineno(), new Token((int)ttype),
190
lookahead);
191
}
192
}
193
194
/**
195
* match a token with TT_TYPE='"', where the token value is a sequence
196
* of characters between matching quote characters.
197
*/
198
private void matchQuotedString() throws ParserException, IOException {
199
match(DOUBLEQUOTE);
200
}
201
202
/**
203
* match a TT_NUMBER token that matches a parsed number value
204
*/
205
private void matchNumber() throws ParserException, IOException {
206
match(StreamTokenizer.TT_NUMBER);
207
}
208
209
/**
210
* match a TT_WORD token that matches an arbitrary, not quoted token.
211
*/
212
private void matchID() throws ParserException, IOException {
213
match(StreamTokenizer.TT_WORD);
214
}
215
216
/**
217
* match a TT_WORD token that matches the given string
218
*/
219
private void match(String token) throws ParserException, IOException {
220
match(StreamTokenizer.TT_WORD, token);
221
}
222
223
/**
224
* determine if the given word is a reserved key word
225
*/
226
private boolean isReservedWord(String word) {
227
return reservedWords.contains(word);
228
}
229
230
/**
231
* determine if the give work is a reserved key word
232
*/
233
private boolean isInfixOperator(char op) {
234
for (int i = 0; i < infixOps.length; i++) {
235
if (op == infixOps[i]) {
236
return true;
237
}
238
}
239
return false;
240
}
241
242
/**
243
* scalestmt -> 'scale' scalespec
244
* scalespec -> <see above scaleTerminals array>
245
*/
246
private void scaleStmt(ColumnFormat cf)
247
throws ParserException, IOException {
248
match(SCALE);
249
Token t = matchOne(scaleKeyWords);
250
cf.setScale(Scale.toScale(t.sval));
251
String scaleString = t.sval;
252
log(pdebug, "Parsed: scale -> " + scaleString);
253
}
254
255
/**
256
* alignstmt -> 'align' alignspec
257
* alignspec -> <see above alignTerminals array>
258
*/
259
private void alignStmt(ColumnFormat cf)
260
throws ParserException, IOException {
261
match(ALIGN);
262
Token t = matchOne(alignKeyWords);
263
cf.setAlignment(Alignment.toAlignment(t.sval));
264
String alignString = t.sval;
265
log(pdebug, "Parsed: align -> " + alignString);
266
}
267
268
/**
269
* headerstmt -> 'header' quotedstring
270
*/
271
private void headerStmt(ColumnFormat cf)
272
throws ParserException, IOException {
273
match(HEADER);
274
String headerString = lookahead.sval;
275
matchQuotedString();
276
cf.setHeader(headerString);
277
log(pdebug, "Parsed: header -> " + headerString);
278
}
279
280
/**
281
* widthstmt -> 'width' integer
282
*/
283
private void widthStmt(ColumnFormat cf)
284
throws ParserException, IOException {
285
match(WIDTH);
286
double width = lookahead.nval;
287
matchNumber();
288
cf.setWidth((int)width);
289
log(pdebug, "Parsed: width -> " + width );
290
}
291
292
/**
293
* formatstmt -> 'format' quotedstring
294
*/
295
private void formatStmt(ColumnFormat cf)
296
throws ParserException, IOException {
297
match(FORMAT);
298
String formatString = lookahead.sval;
299
matchQuotedString();
300
cf.setFormat(formatString);
301
log(pdebug, "Parsed: format -> " + formatString);
302
}
303
304
/**
305
* Primary -> Literal | Identifier | '(' Expression ')'
306
*/
307
private Expression primary() throws ParserException, IOException {
308
Expression e = null;
309
310
switch (lookahead.ttype) {
311
case OPENPAREN:
312
match(OPENPAREN);
313
e = expression();
314
match(CLOSEPAREN);
315
break;
316
case StreamTokenizer.TT_WORD:
317
String s = lookahead.sval;
318
if (isReservedWord(s)) {
319
throw new SyntaxException(st.lineno(), "IDENTIFIER",
320
"Reserved Word: " + lookahead.sval);
321
}
322
matchID();
323
e = new Identifier(s);
324
log(pdebug, "Parsed: ID -> " + s);
325
break;
326
case StreamTokenizer.TT_NUMBER:
327
double literal = lookahead.nval;
328
matchNumber();
329
e = new Literal(Double.valueOf(literal));
330
log(pdebug, "Parsed: number -> " + literal);
331
break;
332
default:
333
throw new SyntaxException(st.lineno(), "IDENTIFIER", lookahead);
334
}
335
log(pdebug, "Parsed: primary -> " + e);
336
return e;
337
}
338
339
/**
340
* Unary -> ('+'|'-') Unary | Primary
341
*/
342
private Expression unary() throws ParserException, IOException {
343
Expression e = null;
344
Operator op = null;
345
346
while (true) {
347
switch (lookahead.ttype) {
348
case OPERATOR_PLUS:
349
match(OPERATOR_PLUS);
350
op = Operator.PLUS;
351
break;
352
case OPERATOR_MINUS:
353
match(OPERATOR_MINUS);
354
op = Operator.MINUS;
355
break;
356
default:
357
e = primary();
358
log(pdebug, "Parsed: unary -> " + e);
359
return e;
360
}
361
Expression e1 = new Expression();
362
e1.setOperator(op);
363
e1.setRight(e);
364
log(pdebug, "Parsed: unary -> " + e1);
365
e1.setLeft(new Literal(Double.valueOf(0)));
366
e = e1;
367
}
368
}
369
370
/**
371
* MultExpression -> Unary (('*' | '/') Unary)*
372
*/
373
private Expression multExpression() throws ParserException, IOException {
374
Expression e = unary();
375
Operator op = null;
376
377
while (true) {
378
switch (lookahead.ttype) {
379
case OPERATOR_MULTIPLY:
380
match(OPERATOR_MULTIPLY);
381
op = Operator.MULTIPLY;
382
break;
383
case OPERATOR_DIVIDE:
384
match(OPERATOR_DIVIDE);
385
op = Operator.DIVIDE;
386
break;
387
default:
388
log(pdebug, "Parsed: multExpression -> " + e);
389
return e;
390
}
391
Expression e1 = new Expression();
392
e1.setOperator(op);
393
e1.setLeft(e);
394
e1.setRight(unary());
395
e = e1;
396
log(pdebug, "Parsed: multExpression -> " + e);
397
}
398
}
399
400
/**
401
* AddExpression -> MultExpression (('+' | '-') MultExpression)*
402
*/
403
private Expression addExpression() throws ParserException, IOException {
404
Expression e = multExpression();
405
Operator op = null;
406
407
while (true) {
408
switch (lookahead.ttype) {
409
case OPERATOR_PLUS:
410
match(OPERATOR_PLUS);
411
op = Operator.PLUS;
412
break;
413
case OPERATOR_MINUS:
414
match(OPERATOR_MINUS);
415
op = Operator.MINUS;
416
break;
417
default:
418
log(pdebug, "Parsed: addExpression -> " + e);
419
return e;
420
}
421
Expression e1 = new Expression();
422
e1.setOperator(op);
423
e1.setLeft(e);
424
e1.setRight(multExpression());
425
e = e1;
426
log(pdebug, "Parsed: addExpression -> " + e);
427
}
428
}
429
430
/**
431
* Expression -> AddExpression
432
*/
433
private Expression expression() throws ParserException, IOException {
434
Expression e = addExpression();
435
log(pdebug, "Parsed: expression -> " + e);
436
return e;
437
}
438
439
/**
440
* datastmt -> 'data' expression
441
*/
442
private void dataStmt(ColumnFormat cf) throws ParserException, IOException {
443
match(DATA);
444
Expression e = expression();
445
cf.setExpression(e);
446
log(pdebug, "Parsed: data -> " + e);
447
}
448
449
/**
450
* requiredstmt -> 'required' expression
451
*/
452
private void requiredStmt(ColumnFormat cf) throws ParserException, IOException {
453
match(REQUIRED);
454
Token t = matchOne(boolKeyWords);
455
cf.setRequired(Boolean.parseBoolean(t.sval));
456
log(pdebug, "Parsed: required -> " + cf.isRequired());
457
}
458
459
/**
460
* statementlist -> optionalstmt statementlist
461
* optionalstmt -> 'data' expression
462
* 'header' quotedstring
463
* 'width' integer
464
* 'format' formatstring
465
* 'align' alignspec
466
* 'scale' scalespec
467
* 'required' boolean
468
*/
469
private void statementList(ColumnFormat cf)
470
throws ParserException, IOException {
471
while (true) {
472
if (lookahead.ttype != StreamTokenizer.TT_WORD) {
473
return;
474
}
475
476
if (lookahead.sval.compareTo(DATA) == 0) {
477
dataStmt(cf);
478
} else if (lookahead.sval.compareTo(HEADER) == 0) {
479
headerStmt(cf);
480
} else if (lookahead.sval.compareTo(WIDTH) == 0) {
481
widthStmt(cf);
482
} else if (lookahead.sval.compareTo(FORMAT) == 0) {
483
formatStmt(cf);
484
} else if (lookahead.sval.compareTo(ALIGN) == 0) {
485
alignStmt(cf);
486
} else if (lookahead.sval.compareTo(SCALE) == 0) {
487
scaleStmt(cf);
488
} else if (lookahead.sval.compareTo(REQUIRED) == 0) {
489
requiredStmt(cf);
490
} else {
491
return;
492
}
493
}
494
}
495
496
/**
497
* optionlist -> columspec optionlist
498
* null
499
* columspec -> 'column' '{' statementlist '}'
500
*/
501
private void optionList(OptionFormat of)
502
throws ParserException, IOException {
503
while (true) {
504
if (lookahead.ttype != StreamTokenizer.TT_WORD) {
505
return;
506
}
507
508
match(COLUMN);
509
match(OPENBLOCK);
510
ColumnFormat cf = new ColumnFormat(columnCount++);
511
statementList(cf);
512
match(CLOSEBLOCK);
513
cf.validate();
514
of.addSubFormat(cf);
515
}
516
}
517
518
/**
519
* optionstmt -> 'option' ID '{' optionlist '}'
520
*/
521
private OptionFormat optionStmt() throws ParserException, IOException {
522
match(OPTION);
523
String optionName=lookahead.sval;
524
matchID();
525
match(OPENBLOCK);
526
OptionFormat of = new OptionFormat(optionName);
527
optionList(of);
528
match(CLOSEBLOCK);
529
return of;
530
}
531
532
/**
533
* parse the specification for the given option identifier
534
*/
535
public OptionFormat parse(String option)
536
throws ParserException, IOException {
537
nextToken();
538
539
/*
540
* this search stops on the first occurance of an option
541
* statement with a name matching the given option. Any
542
* duplicate options are ignored.
543
*/
544
while (lookahead.ttype != StreamTokenizer.TT_EOF) {
545
// look for the start symbol
546
if ((lookahead.ttype != StreamTokenizer.TT_WORD)
547
|| (lookahead.sval.compareTo(START) != 0)) {
548
// skip tokens until a start symbol is found
549
nextToken();
550
continue;
551
}
552
553
// check if the option name is the one we are interested in
554
match(START);
555
556
if ((lookahead.ttype == StreamTokenizer.TT_WORD)
557
&& (lookahead.sval.compareTo(option) == 0)) {
558
// this is the one we are looking for, parse it
559
pushBack();
560
return optionStmt();
561
} else {
562
// not what we are looking for, start skipping tokens
563
nextToken();
564
}
565
}
566
return null;
567
}
568
569
public Set<OptionFormat> parseOptions() throws ParserException, IOException {
570
Set<OptionFormat> options = new HashSet<OptionFormat>();
571
572
nextToken();
573
574
while (lookahead.ttype != StreamTokenizer.TT_EOF) {
575
// look for the start symbol
576
if ((lookahead.ttype != StreamTokenizer.TT_WORD)
577
|| (lookahead.sval.compareTo(START) != 0)) {
578
// skip tokens until a start symbol is found
579
nextToken();
580
continue;
581
}
582
583
// note: if a duplicate option statement exists, then
584
// first one encountered is the chosen definition.
585
OptionFormat of = optionStmt();
586
options.add(of);
587
}
588
return options;
589
}
590
591
OptionFormat getOptionFormat() {
592
return optionFormat;
593
}
594
595
private void log(boolean logging, String s) {
596
if (logging) {
597
System.out.println(s);
598
}
599
}
600
}
601
602