From 3cb4dc299155a56044f73f0355adf560f5fb2daf Mon Sep 17 00:00:00 2001 From: Ross Patterson Date: Mon, 1 Aug 2022 17:33:20 -0400 Subject: [PATCH] Fix #3508: Document the $parser attribute and its use in target-agnostic grammars. Signed-off-by: Ross Patterson Signed-off-by: Eric Vergnaud --- doc/actions.md | 1 + doc/python-target.md | 33 +++++++++++++++++++++++++++++---- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/doc/actions.md b/doc/actions.md index 35455cb2f2..cb0e0be8d0 100644 --- a/doc/actions.md +++ b/doc/actions.md @@ -98,6 +98,7 @@ returnStat : 'return' expr {System.out.println("first token "+$start.getText()); |start|Token|The first token to be potentially matched by the rule that is on the main token channel; in other words, this attribute is never a hidden token. For rules that end up matching no tokens, this attribute points at the first token that could have been matched by this rule. When referring to the current rule, this attribute is available to any action within the rule.| |stop|Token|The last nonhidden channel token to be matched by the rule. When referring to the current rule, this attribute is available only to the after and finally actions.| |ctx|ParserRuleContext|The rule context object associated with a rule invocation. All of the other attributes are available through this attribute. For example, `$ctx.start` accesses the start field within the current rules context object. It’s the same as `$start`.| +|parser|Parser|The parser itself. This attribute can be used, for example, to invoke a method defined in the parser's `@members` section from a semantic predicate.| ## Dynamically-Scoped Attributes diff --git a/doc/python-target.md b/doc/python-target.md index 7ed73c281e..6f7f6a84a9 100644 --- a/doc/python-target.md +++ b/doc/python-target.md @@ -116,14 +116,39 @@ If your grammar is targeted to Python only, you may ignore the following. But if ID {$text.equals("test")}? ``` -Unfortunately, this is not portable, but you can work around it. The trick involves: +Unfortunately, this is not portable, as Java and Python (and other target languages) have different syntaxes for all but the simplest language elements. But you can work around it. The trick involves: * deriving your parser from a parser you provide, such as BaseParser -* implementing utility methods in this BaseParser, such as "isEqualText" -* adding a "self" field to the Java/C# BaseParser, and initialize it with "this" +* implementing utility methods, such as "isEqualText", in this BaseParser, in different files for each target language +* invoking your utility methods in the semantic predicate from the `$parser` object Thanks to the above, you should be able to rewrite the above semantic predicate as follows: +File `MyGrammarParser.g4`: ``` -ID {$self.isEqualText($text,"test")}? +options { superClass = MyGrammarBaseParser; } +... +ID {$parser.isEqualText($text,"test")}? +``` + +File `MyGrammarBaseParser.py`: +```python +from antlr4 import * + +class MyGrammarBaseParser(Parser): + + def isEqualText(a, b): + return a is b +``` + +File `MyGrammarBaseParser.java`: +```java +import org.antlr.v4.runtime.*; + +public abstract class MyGrammarBaseParser extends Parser { + + public static boolean isEqualText(a, b) { + return a.equals(b); + } +} ```