Merge branch 'master' of github.com:parrt/antlr4 into move-doc-to-repo

This commit is contained in:
Terence Parr 2015-11-19 12:39:11 -08:00
commit 586bcd2368
17 changed files with 311 additions and 32 deletions

View File

@ -0,0 +1,22 @@
# Creating an ANTLR Language Target
This document describes how to make ANTLR generate parsers in a new language, *X*.
## Overview
Creating a new target involves the following key elements:
1. For the tool, create class *X*Target as a subclass of class `Target` in package `org.antlr.v4.codegen.target`. This class describes language specific details about escape characters and strings and so on. There is very little to do here typically.
1. Create *X*.stg in directory tool/resources/org/antlr/v4/tool/templates/codegen/*X*/*X*.stg. This is a [StringTemplate](http://www.stringtemplate.org/) group file (`.stg`) that tells ANTLR how to express all of the parsing elements needed to generate code. You will see templates called `ParserFile`, `Parser`, `Lexer`, `CodeBlockForAlt`, `AltBlock`, etc... Each of these must be described how to build the indicated chunk of code. Your best bet is to find the closest existing target, copy that template file, and tweak to suit.
1. Create a runtime library to support the parsers generated by ANTLR. Under directory runtime/*X*, you are in complete control of the directory structure is dictated by common usage of that target language. For example, Java has: `runtime/Java/lib` and `runtime/Java/src` directories. Under `src`, you will find a directory structure for package `org.antlr.v4.runtime` and below.
1. Create a template file for runtime tests. All you have to do is provide a few simple templates that indicate how to print values and declare variables. Our runtime test mechanism in dir `runtime-testsuite` will automatically generate code in a new target and check the results. All it needs to know is how to generate a test rig (i.e., a `main` program), how to define various class fields, compare members and so on. You must create a *X* directory underneath `runtime-testsuite/resources/org/antlr/v4/test/runtime`. Again, your best bet is to copy the templates from the closest language to your target and tweak it to suit.
## Getting started
1. Fork the `antlr/antlr4` repository at github to your own user so that you have repository `username/antlr4`.
2. Clone `username/antlr4`, forked repository, to your local disk. Your `origin` will be the forked repository and `upstream` will be the original `antlr/antlr4` repository. Changes that you would like to contribute back to the project are done with [pull requests](https://help.github.com/articles/using-pull-requests/).
3. Try to build it before doing anything
```bash
$ mvn compile
```
That should proceed with success. See [Building ANTLR](building-antlr.md) for more details. (That link does not currently work as I have that documentation in a branch. see https://github.com/parrt/antlr4/blob/move-doc-to-repo/doc/building-antlr.md for now.)

View File

@ -11,6 +11,8 @@ TestTemplates ::= [
"LL2": [],
"LL3": [],
"LLStar": [],
"SingleTokenDeletionBeforeAlt": [],
"SingleTokenDeletionBeforePredict": [],
"SingleTokenDeletionBeforeLoop": [],
"MultiTokenDeletionBeforeLoop": [],
"SingleTokenDeletionDuringLoop": [],

View File

@ -0,0 +1,28 @@
TestType() ::= "Parser"
Options ::= [
"Debug": false
]
Grammar ::= [
"T": {<grammar("T")>}
]
Input() ::= "ac"
Rule() ::= "a"
Output() ::= <<
>>
Errors() ::= <<
line 1:0 extraneous input 'a' expecting {'b', 'c'}<\n>
>>
grammar(grammarName) ::= <<
grammar <grammarName>;
a : ('b' | 'c')
;
q : 'a'
;
>>

View File

@ -0,0 +1,28 @@
TestType() ::= "Parser"
Options ::= [
"Debug": false
]
Grammar ::= [
"T": {<grammar("T")>}
]
Input() ::= "caaab"
Rule() ::= "a"
Output() ::= <<
>>
Errors() ::= <<
line 1:0 extraneous input 'c' expecting 'a'<\n>
>>
grammar(grammarName) ::= <<
grammar <grammarName>;
a : 'a'+ 'b'
| 'a'+ 'c'
;
q : 'e' ;
>>

View File

@ -370,6 +370,24 @@ public class TestParserErrors extends BaseTest {
assertEquals("line 1:1 extraneous input 'a' expecting 'b'\n", this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testSingleTokenDeletionBeforeAlt() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(38);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("a : ('b' | 'c')\n");
grammarBuilder.append(";\n");
grammarBuilder.append("q : 'a'\n");
grammarBuilder.append(";");
String grammar = grammarBuilder.toString();
String input ="ac";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", input, false);
assertEquals("", found);
assertEquals("line 1:0 extraneous input 'a' expecting {'b', 'c'}\n", this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
@ -404,6 +422,24 @@ public class TestParserErrors extends BaseTest {
"line 1:1 extraneous input 'a' expecting {<EOF>, 'b', 'z'}\n" +
"line 1:3 token recognition error at: 'c'\n", this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testSingleTokenDeletionBeforePredict() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(48);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("a : 'a'+ 'b'\n");
grammarBuilder.append(" | 'a'+ 'c'\n");
grammarBuilder.append(";\n");
grammarBuilder.append("q : 'e' ;");
String grammar = grammarBuilder.toString();
String input ="caaab";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", input, false);
assertEquals("", found);
assertEquals("line 1:0 extraneous input 'c' expecting 'a'\n", this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test

View File

@ -456,6 +456,28 @@ public class TestParserErrors extends BaseTest {
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testSingleTokenDeletionBeforeAlt() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(38);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("a : ('b' | 'c')\n");
grammarBuilder.append(";\n");
grammarBuilder.append("q : 'a'\n");
grammarBuilder.append(";");
String grammar = grammarBuilder.toString();
String input ="ac";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", input, false);
assertEquals("", found);
assertEquals("line 1:0 extraneous input 'a' expecting {'b', 'c'}\n", this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testSingleTokenDeletionBeforeLoop() throws Exception {
@ -498,6 +520,28 @@ public class TestParserErrors extends BaseTest {
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testSingleTokenDeletionBeforePredict() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(48);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("a : 'a'+ 'b'\n");
grammarBuilder.append(" | 'a'+ 'c'\n");
grammarBuilder.append(";\n");
grammarBuilder.append("q : 'e' ;");
String grammar = grammarBuilder.toString();
String input ="caaab";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "a", input, false);
assertEquals("", found);
assertEquals("line 1:0 extraneous input 'c' expecting 'a'\n", this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testSingleTokenDeletionConsumption() throws Exception {

View File

@ -414,6 +414,26 @@ public class TestParserErrors extends BaseTest {
assertEquals("line 1:1 extraneous input 'a' expecting 'b'\n", this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testSingleTokenDeletionBeforeAlt() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(38);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("a : ('b' | 'c')\n");
grammarBuilder.append(";\n");
grammarBuilder.append("q : 'a'\n");
grammarBuilder.append(";");
String grammar = grammarBuilder.toString();
String input ="ac";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"TListener", "TVisitor",
"a", input, false);
assertEquals("", found);
assertEquals("line 1:0 extraneous input 'a' expecting {'b', 'c'}\n", this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
@ -452,6 +472,26 @@ public class TestParserErrors extends BaseTest {
"line 1:1 extraneous input 'a' expecting {<EOF>, 'b', 'z'}\n" +
"line 1:3 token recognition error at: 'c'\n", this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testSingleTokenDeletionBeforePredict() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(48);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("a : 'a'+ 'b'\n");
grammarBuilder.append(" | 'a'+ 'c'\n");
grammarBuilder.append(";\n");
grammarBuilder.append("q : 'e' ;");
String grammar = grammarBuilder.toString();
String input ="caaab";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"TListener", "TVisitor",
"a", input, false);
assertEquals("", found);
assertEquals("line 1:0 extraneous input 'c' expecting 'a'\n", this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test

View File

@ -476,6 +476,29 @@ public class TestParserErrors extends BasePython2Test {
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testSingleTokenDeletionBeforeAlt() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(38);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("a : ('b' | 'c')\n");
grammarBuilder.append(";\n");
grammarBuilder.append("q : 'a'\n");
grammarBuilder.append(";");
String grammar = grammarBuilder.toString();
String input ="ac";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "TListener", "TVisitor", "a", input, false);
assertEquals("", found);
assertEquals("line 1:0 extraneous input 'a' expecting {'b', 'c'}\n", this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testSingleTokenDeletionBeforeLoop() throws Exception {
@ -520,6 +543,29 @@ public class TestParserErrors extends BasePython2Test {
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testSingleTokenDeletionBeforePredict() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(48);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("a : 'a'+ 'b'\n");
grammarBuilder.append(" | 'a'+ 'c'\n");
grammarBuilder.append(";\n");
grammarBuilder.append("q : 'e' ;");
String grammar = grammarBuilder.toString();
String input ="caaab";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "TListener", "TVisitor", "a", input, false);
assertEquals("", found);
assertEquals("line 1:0 extraneous input 'c' expecting 'a'\n", this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testSingleTokenDeletionConsumption() throws Exception {

View File

@ -476,6 +476,29 @@ public class TestParserErrors extends BasePython3Test {
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testSingleTokenDeletionBeforeAlt() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(38);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("a : ('b' | 'c')\n");
grammarBuilder.append(";\n");
grammarBuilder.append("q : 'a'\n");
grammarBuilder.append(";");
String grammar = grammarBuilder.toString();
String input ="ac";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "TListener", "TVisitor", "a", input, false);
assertEquals("", found);
assertEquals("line 1:0 extraneous input 'a' expecting {'b', 'c'}\n", this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testSingleTokenDeletionBeforeLoop() throws Exception {
@ -520,6 +543,29 @@ public class TestParserErrors extends BasePython3Test {
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testSingleTokenDeletionBeforePredict() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(48);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("a : 'a'+ 'b'\n");
grammarBuilder.append(" | 'a'+ 'c'\n");
grammarBuilder.append(";\n");
grammarBuilder.append("q : 'e' ;");
String grammar = grammarBuilder.toString();
String input ="caaab";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "TListener", "TVisitor", "a", input, false);
assertEquals("", found);
assertEquals("line 1:0 extraneous input 'c' expecting 'a'\n", this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testSingleTokenDeletionConsumption() throws Exception {

View File

@ -3,7 +3,7 @@
"version": "4.5.1",
"description": "JavaScript runtime for ANTLR4",
"main": "src/antlr4/index.js",
"repository": "antlr/antlr4-javascript.git",
"repository": "antlr/antlr4.git",
"keywords": [
"lexer",
"parser",
@ -13,7 +13,7 @@
],
"license": "BSD",
"bugs": {
"url": "https://github.com/antlr/antlr4-javascript/issues"
"url": "https://github.com/antlr/antlr4/issues"
},
"homepage": "https://github.com/antlr/antlr4-javascript"
"homepage": "https://github.com/antlr/antlr4"
}

View File

@ -537,7 +537,6 @@ CodeBlockForAlt(currentAltCodeBlock, locals, preamble, ops) ::= <<
LL1AltBlock(choice, preamble, alts, error) ::= <<
State = <choice.stateNumber>;
<!ErrorHandler.sync(this);!>
<if(choice.label)><labelref(choice.label)> = TokenStream.Lt(1);<endif>
<preamble; separator="\n">
switch (TokenStream.La(1)) {
@ -551,7 +550,6 @@ default:
LL1OptionalBlock(choice, alts, error) ::= <<
State = <choice.stateNumber>;
<!ErrorHandler.sync(this);!>
switch (TokenStream.La(1)) {
<choice.altLook,alts:{look,alt| <cases(ttypes=look)>
<alt>
@ -563,7 +561,6 @@ default:
LL1OptionalBlockSingleAlt(choice, expr, alts, preamble, error, followExpr) ::= <<
State = <choice.stateNumber>;
<!ErrorHandler.sync(this);!>
<preamble; separator="\n">
if (<expr>) {
<alts; separator="\n">
@ -599,7 +596,7 @@ do {
AltBlock(choice, preamble, alts, error) ::= <<
State = <choice.stateNumber>;
<!ErrorHandler.sync(this);!>
ErrorHandler.Sync(this);
<if(choice.label)><labelref(choice.label)> = TokenStream.Lt(1);<endif>
<preamble; separator="\n">
switch ( Interpreter.AdaptivePredict(TokenStream,<choice.decision>,Context) ) {
@ -612,7 +609,7 @@ case <i>:
OptionalBlock(choice, alts, error) ::= <<
State = <choice.stateNumber>;
<!ErrorHandler.sync(this);!>
ErrorHandler.Sync(this);
switch ( Interpreter.AdaptivePredict(TokenStream,<choice.decision>,Context) ) {
<alts:{alt |
case <i><if(!choice.ast.greedy)>+1<endif>:

View File

@ -469,7 +469,6 @@ CodeBlockForAlt(currentAltCodeBlock, locals, preamble, ops) ::= <<
LL1AltBlock(choice, preamble, alts, error) ::= <<
setState(<choice.stateNumber>);
<!_errHandler.sync(this);!>
<if(choice.label)><labelref(choice.label)> = _input.LT(1);<endif>
<preamble; separator="\n">
switch (_input.LA(1)) {
@ -483,7 +482,6 @@ default:
LL1OptionalBlock(choice, alts, error) ::= <<
setState(<choice.stateNumber>);
<!_errHandler.sync(this);!>
switch (_input.LA(1)) {
<choice.altLook,alts:{look,alt| <cases(ttypes=look)>
<alt>
@ -495,7 +493,6 @@ default:
LL1OptionalBlockSingleAlt(choice, expr, alts, preamble, error, followExpr) ::= <<
setState(<choice.stateNumber>);
<!_errHandler.sync(this);!>
<preamble; separator="\n">
if (<expr>) {
<alts; separator="\n">
@ -531,7 +528,7 @@ do {
AltBlock(choice, preamble, alts, error) ::= <<
setState(<choice.stateNumber>);
<!_errHandler.sync(this);!>
_errHandler.sync(this);
<if(choice.label)><labelref(choice.label)> = _input.LT(1);<endif>
<preamble; separator="\n">
switch ( getInterpreter().adaptivePredict(_input,<choice.decision>,_ctx) ) {
@ -544,7 +541,7 @@ case <i>:
OptionalBlock(choice, alts, error) ::= <<
setState(<choice.stateNumber>);
<!_errHandler.sync(this);!>
_errHandler.sync(this);
switch ( getInterpreter().adaptivePredict(_input,<choice.decision>,_ctx) ) {
<alts:{alt |
case <i><if(!choice.ast.greedy)>+1<endif>:

View File

@ -340,7 +340,6 @@ CodeBlockForAlt(currentAltCodeBlock, locals, preamble, ops) ::= <<
LL1AltBlock(choice, preamble, alts, error) ::= <<
this.state = <choice.stateNumber>;
<!_errHandler.sync(this);!>
<if(choice.label)><labelref(choice.label)> = this._input.LT(1);<endif>
<preamble; separator="\n">
switch(this._input.LA(1)) {
@ -354,7 +353,6 @@ default:
LL1OptionalBlock(choice, alts, error) ::= <<
this.state = <choice.stateNumber>;
<!_errHandler.sync(this);!>
switch (this._input.LA(1)) {
<choice.altLook,alts:{look,alt| <cases(ttypes=look)>
<alt>
@ -366,7 +364,6 @@ default:
LL1OptionalBlockSingleAlt(choice, expr, alts, preamble, error, followExpr) ::= <<
this.state = <choice.stateNumber>;
<!_errHandler.sync(this);!>
<preamble; separator="\n">
if(<expr>) {
<alts; separator="\n">
@ -402,7 +399,7 @@ do {
AltBlock(choice, preamble, alts, error) ::= <<
this.state = <choice.stateNumber>;
<!_errHandler.sync(this);!>
this._errHandler.sync(this);
<if(choice.label)><labelref(choice.label)> = _input.LT(1)<endif>
<preamble; separator="\n">
var la_ = this._interp.adaptivePredict(this._input,<choice.decision>,this._ctx);
@ -417,7 +414,7 @@ case <i>:
OptionalBlock(choice, alts, error) ::= <<
this.state = <choice.stateNumber>;
<!_errHandler.sync(this);!>
this._errHandler.sync(this);
var la_ = this._interp.adaptivePredict(this._input,<choice.decision>,this._ctx);
<alts:{alt |
if(la_===<i><if(!choice.ast.greedy)>+1<endif>) {

View File

@ -314,7 +314,6 @@ CodeBlockForAlt(currentAltCodeBlock, locals, preamble, ops) ::= <<
LL1AltBlock(choice, preamble, alts, error) ::= <<
self.state = <choice.stateNumber>
<!_errHandler.sync(this);!>
<if(choice.label)><labelref(choice.label)> = _input.LT(1)<endif>
<preamble; separator="\n">
token = self._input.LA(1)
@ -328,7 +327,6 @@ else:
LL1OptionalBlock(choice, alts, error) ::= <<
self.state = <choice.stateNumber>
<!_errHandler.sync(this);!>
token = self._input.LA(1)
<choice.altLook,alts:{look,alt| <cases(ttypes=look)>
<alt>
@ -339,7 +337,6 @@ else:
LL1OptionalBlockSingleAlt(choice, expr, alts, preamble, error, followExpr) ::= <<
self.state = <choice.stateNumber>
<!_errHandler.sync(this);!>
<preamble; separator="\n">
if <expr>:
<alts; separator="\n">
@ -378,7 +375,7 @@ while True:
AltBlock(choice, preamble, alts, error) ::= <<
self.state = <choice.stateNumber>
<!_errHandler.sync(this);!>
self._errHandler.sync(this);
<if(choice.label)><labelref(choice.label)> = _input.LT(1)<endif>
<preamble; separator="\n">
la_ = self._interp.adaptivePredict(self._input,<choice.decision>,self._ctx)
@ -392,7 +389,7 @@ if la_ == <i>:
OptionalBlock(choice, alts, error) ::= <<
self.state = <choice.stateNumber>
<!_errHandler.sync(this);!>
self._errHandler.sync(this);
la_ = self._interp.adaptivePredict(self._input,<choice.decision>,self._ctx)
<alts:{alt |
if la_ == <i><if(!choice.ast.greedy)>+1<endif>:

View File

@ -322,7 +322,6 @@ CodeBlockForAlt(currentAltCodeBlock, locals, preamble, ops) ::= <<
LL1AltBlock(choice, preamble, alts, error) ::= <<
self.state = <choice.stateNumber>
<!_errHandler.sync(this);!>
<if(choice.label)><labelref(choice.label)> = _input.LT(1)<endif>
<preamble; separator="\n">
token = self._input.LA(1)
@ -336,7 +335,6 @@ else:
LL1OptionalBlock(choice, alts, error) ::= <<
self.state = <choice.stateNumber>
<!_errHandler.sync(this);!>
token = self._input.LA(1)
<choice.altLook,alts:{look,alt| <cases(ttypes=look)>
<alt>
@ -347,7 +345,6 @@ else:
LL1OptionalBlockSingleAlt(choice, expr, alts, preamble, error, followExpr) ::= <<
self.state = <choice.stateNumber>
<!_errHandler.sync(this);!>
<preamble; separator="\n">
if <expr>:
<alts; separator="\n">
@ -386,7 +383,7 @@ while True:
AltBlock(choice, preamble, alts, error) ::= <<
self.state = <choice.stateNumber>
<!_errHandler.sync(this);!>
self._errHandler.sync(this);
<if(choice.label)><labelref(choice.label)> = _input.LT(1)<endif>
<preamble; separator="\n">
la_ = self._interp.adaptivePredict(self._input,<choice.decision>,self._ctx)
@ -400,7 +397,7 @@ if la_ == <i>:
OptionalBlock(choice, alts, error) ::= <<
self.state = <choice.stateNumber>
<!_errHandler.sync(this);!>
self._errHandler.sync(this);
la_ = self._interp.adaptivePredict(self._input,<choice.decision>,self._ctx)
<alts:{alt |
if la_ == <i><if(!choice.ast.greedy)>+1<endif>:

View File

@ -80,7 +80,7 @@ public class TestRig {
public TestRig(String[] args) throws Exception {
if ( args.length < 2 ) {
System.err.println("java org.antlr.v4.runtime.misc.TestRig GrammarName startRuleName\n" +
System.err.println("java org.antlr.v4.gui.TestRig GrammarName startRuleName\n" +
" [-tokens] [-tree] [-gui] [-ps file.ps] [-encoding encodingname]\n" +
" [-trace] [-diagnostics] [-SLL]\n"+
" [input-filename(s)]");

View File

@ -372,10 +372,12 @@ public class TreeViewer extends JComponent {
JTree selectedTree = (JTree) e.getSource();
TreePath path = selectedTree.getSelectionPath();
TreeNodeWrapper treeNode = (TreeNodeWrapper) path.getLastPathComponent();
if (path!=null) {
TreeNodeWrapper treeNode = (TreeNodeWrapper) path.getLastPathComponent();
// Set the clicked AST.
viewer.setTree((Tree) treeNode.getUserObject());
// Set the clicked AST.
viewer.setTree((Tree) treeNode.getUserObject());
}
}
});