|
|
@@ -0,0 +1,74 @@
|
|
|
+package net.ranides.assira.g4.antlr;
|
|
|
+
|
|
|
+
|
|
|
+import net.ranides.assira.collection.maps.CrossMap;
|
|
|
+import net.ranides.assira.collection.maps.OpenCrossMap;
|
|
|
+import net.ranides.assira.g4.G4Parser;
|
|
|
+import org.antlr.runtime.RecognitionException;
|
|
|
+import org.antlr.v4.runtime.CharStreams;
|
|
|
+import org.antlr.v4.runtime.CommonTokenStream;
|
|
|
+import org.antlr.v4.runtime.LexerInterpreter;
|
|
|
+import org.antlr.v4.runtime.ParserInterpreter;
|
|
|
+import org.antlr.v4.runtime.ParserRuleContext;
|
|
|
+import org.antlr.v4.runtime.misc.Pair;
|
|
|
+import org.antlr.v4.tool.Grammar;
|
|
|
+import org.antlr.v4.tool.Rule;
|
|
|
+import org.antlr.v4.tool.ast.AltAST;
|
|
|
+
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+public class BasicParser implements G4Parser {
|
|
|
+
|
|
|
+ protected final Grammar grammar;
|
|
|
+
|
|
|
+ public BasicParser(String grammar) {
|
|
|
+ try {
|
|
|
+ this.grammar = new Grammar(grammar);
|
|
|
+ } catch (RecognitionException e) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public NodeForRule parse(String rule, String text) {
|
|
|
+ return new Shared(grammar, rule, text).root;
|
|
|
+ }
|
|
|
+
|
|
|
+ static class Shared {
|
|
|
+
|
|
|
+ protected final Grammar grammar;
|
|
|
+ protected final LexerInterpreter lexer;
|
|
|
+ protected final CommonTokenStream tokens;
|
|
|
+ protected final ParserInterpreter parser;
|
|
|
+ protected final ParserRuleContext tree;
|
|
|
+ protected final NodeForRule root;
|
|
|
+ protected final CrossMap<Integer, Integer, String> labels;
|
|
|
+
|
|
|
+ public Shared(Grammar grammar, String rule, String text) {
|
|
|
+ this.grammar = grammar;
|
|
|
+ this.lexer = grammar.createLexerInterpreter(CharStreams.fromString(text));
|
|
|
+ this.tokens = new CommonTokenStream(lexer);
|
|
|
+ this.parser = grammar.createGrammarParserInterpreter(tokens);
|
|
|
+
|
|
|
+ this.tree = parser.parse(grammar.getRule(rule).index);
|
|
|
+ this.root = new NodeForRule(this, this.tree);
|
|
|
+
|
|
|
+ this.labels = new OpenCrossMap<>();
|
|
|
+
|
|
|
+ // tricky fragment: we deduce alternative labels for every rule
|
|
|
+
|
|
|
+ for(Rule currentRule : grammar.rules.values()) {
|
|
|
+ Map<String, List<Pair<Integer, AltAST>>> altLabels = currentRule.getAltLabels();
|
|
|
+ if(altLabels != null) {
|
|
|
+ for(List<Pair<Integer, AltAST>> list : altLabels.values()) {
|
|
|
+ for(Pair<Integer, AltAST> pair : list) {
|
|
|
+ labels.put(currentRule.index, pair.a, pair.b.altLabel.toString());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+}
|