Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port action templates functionality to ANTLR5 #51

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 85 additions & 5 deletions doc/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Set the superclass of the generated parser or lexer. For combined grammars, it s
$ cat Hi.g4
grammar Hi;
a : 'hi' ;
$ antlr4 -DsuperClass=XX Hi.g4
$ antlr5 -DsuperClass=XX Hi.g4
$ grep 'public class' HiParser.java
public class HiParser extends XX {
$ grep 'public class' HiLexer.java
Expand All @@ -32,10 +32,90 @@ public class HiLexer extends Lexer {
Generate code in the indicated language, if ANTLR is able to do so. Otherwise, you will see an error message like this:

```
$ antlr4 -Dlanguage=C MyGrammar.g4
$ antlr5 -Dlanguage=C MyGrammar.g4
error(31): ANTLR cannot generate C code as of version 4.0
```

### `actionTemplates`

This option uses the provided [StringTemplate](https://www.stringtemplate.org/) group file (`*.stg`) to render templates inside the action blocks of an ANTLR grammar.

This enables you to provide target-specific action logic by providing different `.stg` files for each target language.

The syntax of group files is [described](https://github.com/antlr/stringtemplate4/blob/master/doc/groups.md) in the StringTemplate documentation.

For example, if you provide the following group file when generating Java code:

`ActionTemplates.stg`:
```string-template
normalize(s) ::= <<Normalizer.normalize(<s>, Form.NFKC)>>
setText(s) ::= <<setText(<s>);>>
getText() ::= <<getText()>>
normalizerImports ::= <<
import java.text.Normalizer;
import java.text.Normalizer.Form;
>>
```

You can use the templates like so in your ANTLR grammar:

```antlrv4
ID:
(ID_START ID_CONTINUE* | '_' ID_CONTINUE+) {
<setText(normalize(getText())>
};
```

The ANTLR tool must be invoked by providing the target language and StringTemplate group file:

```bash
$ antlr5 -Dlanguage=Java -DactionTemplates=ActionTemplates.stg MyGrammar.g4
```

The templates will be expanded into the following before the grammar is used to generate the target code:

```antlrv4
ID:
(ID_START ID_CONTINUE* | '_' ID_CONTINUE+) {
setText(Normalizer.normalize(getText(), Form.NFKC));
};
```

Templates can also be used in named actions, such as the `@header` or `@members` block, for example:

```antlrv4
@lexer::header {
<normalizerImports()>
}
```

To use the same grammar to generate a different target language, you can provide a different StringTemplate group file.

For example, to generate JavaScript code equivalent to the previous example the following group file could be used instead:

`ActionTemplates.stg`:
```string-template
normalize(s) ::= <<<s>.normalize("NFKC")>>
setText(s) ::= <<this.text = <s>;>>
getText() ::= <<this.text>>
normalizerImports ::= ""
```

Now you can invoke the ANTLR tool with the new target language and your alternate StringTemplate group file:

```bash
$ antlr5 -Dlanguage=JavaScript -DactionTemplates=ActionTemplates.stg MyGrammar.g4
```

These templates will expand into the following before the grammar is used to generate the target code:

```antlrv4
ID:
(ID_START ID_CONTINUE* | '_' ID_CONTINUE+) {
this.text = this.text.normalize("NFKC");
};
```

### `tokenVocab`

ANTLR assigns token type numbers to the tokens as it encounters them in a file. To use different token type values, such as with a separate lexer, use this option to have ANTLR pull in the <fileextension>tokens</fileextension> file. ANTLR generates a <fileextension>tokens</fileextension> file from each grammar.
Expand All @@ -49,10 +129,10 @@ parser grammar R;
options {tokenVocab=SomeLexer;}
tokens {A,B,C} // normally, these would be token types 1, 2, 3
a : ID ;
$ antlr4 SomeLexer.g4
$ antlr5 SomeLexer.g4
$ cat SomeLexer.tokens
ID=1
$ antlr4 R.g4
$ antlr5 R.g4
$ cat R.tokens
A=2
B=3
Expand All @@ -69,7 +149,7 @@ $ cat T2.g4
grammar T2;
options {TokenLabelType=MyToken;}
a : x=ID ;
$ antlr4 T2.g4
$ antlr5 T2.g4
$ grep MyToken T2Parser.java
public MyToken x;
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,15 @@ public static GeneratedState generate(RunOptions runOptions, String language, St
options.add("-DsuperClass=" + superClass);
}

if (runOptions.libDir != null && !runOptions.libDir.isEmpty()) {
options.add("-lib");
options.add(runOptions.libDir);
}

if (runOptions.actionTemplates != null && !runOptions.actionTemplates.isEmpty()) {
options.add("-DactionTemplates=" + runOptions.actionTemplates);
}

if (extraOptions != null) {
options.addAll(Arrays.asList(extraOptions));
}
Expand Down
11 changes: 10 additions & 1 deletion runtime-testsuite/test/org/antlr/v5/test/runtime/RunOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public class RunOptions {
public final String superClass;
public final PredictionMode predictionMode;
public final boolean buildParseTree;
public final String libDir;
public final String actionTemplates;
public final String[] extraGenerationOptions;

public static RunOptions createGenerationOptions(String[] grammars, String[] slaveGrammars, boolean useListener, boolean useVisitor,
Expand All @@ -39,6 +41,8 @@ public static RunOptions createGenerationOptions(String[] grammars, String[] sla
false,
Stage.Generate,
superClass,
null,
null,
PredictionMode.LL,
false,
extraGenerationOptions
Expand All @@ -60,6 +64,8 @@ public static RunOptions createCompilationOptions(String[] grammars, String[] sl
false,
Stage.Compile,
superClass,
null,
null,
PredictionMode.LL,
false,
extraGenerationOptions
Expand All @@ -70,7 +76,8 @@ public RunOptions(String[] grammars, String[] slaveGrammars,
boolean useListener, boolean useVisitor, String startRuleName,
String input, boolean profile, boolean showDiagnosticErrors,
boolean traceATN, boolean showDFA, Stage endStage,
String superClass, PredictionMode predictionMode, boolean buildParseTree,
String superClass, String libDir, String actionTemplates,
PredictionMode predictionMode, boolean buildParseTree,
String[] extraGenerationOptions) {
this.grammars = grammars;
this.slaveGrammars = slaveGrammars;
Expand All @@ -84,6 +91,8 @@ public RunOptions(String[] grammars, String[] slaveGrammars,
this.showDFA = showDFA;
this.endStage = endStage;
this.superClass = superClass;
this.libDir = libDir;
this.actionTemplates = actionTemplates;
this.predictionMode = predictionMode;
this.buildParseTree = buildParseTree;
this.extraGenerationOptions = extraGenerationOptions;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ private static void test(RuntimeTestDescriptor descriptor, RuntimeRunner runner)
descriptor.showDFA,
Stage.Execute,
null,
null,
null,
descriptor.predictionMode,
descriptor.buildParseTree,
null
Expand Down
Loading