Skip to content

Commit

Permalink
#2196 BNF to ANTLR: generate terminal rules in such a way so that the…
Browse files Browse the repository at this point in the history
… resulting parse tree is more manageable
  • Loading branch information
homedirectory committed Feb 23, 2024
1 parent d649809 commit 151ef6d
Showing 1 changed file with 11 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Function;

import static java.util.stream.Collectors.*;
import static org.apache.commons.lang3.StringUtils.uncapitalize;

/**
* Converts a BNF to an ANTLR grammar in the g4 format.
* <p>
* Rules with the right hand side in the form of a single terminal or an alternation between single terminals are
* generated with <a href=https://github.com/antlr/antlr4/blob/master/doc/parser-rules.md#rule-element-labels>rule element labels</a>
* to make the resulting parse trees easier to work with.
*/
public class BnfToG4 {

Expand Down Expand Up @@ -69,9 +74,10 @@ public String bnfToG4() {
}

protected String convert(ERule eRule) {
Function<String, String> labeler = isSingleTerminalRule(eRule) ? s -> "token=" + s : Function.identity();
return "%s :\n %s\n;".formatted(
convert(eRule.variable),
eRule.bodies().map(this::convert).collect(joining("\n | ")));
eRule.bodies().map(this::convert).map(labeler).collect(joining("\n | ")));
}

protected String convert(Body body) {
Expand Down Expand Up @@ -111,6 +117,10 @@ protected String convert(Quantifier quantifier) {
return quantifier.symbols().map(this::convert).collect(joining(" ", "(", ")" + q));
}

static boolean isSingleTerminalRule(final ERule rule) {
return rule.bodies().allMatch(body -> body.size() == 1 && (body.getFirst().isTerminal() || body.getFirst().isToken()));
}

protected static <T> T fail(String formatString, Object... args) {
throw new RuntimeException(String.format(formatString, args));
}
Expand Down

0 comments on commit 151ef6d

Please sign in to comment.