Rework of the visitor implementation

The translation from Java generics to templates in C++ lead to the need of virtual template functions, which is not supported by C++. Instead we use now the Any class for results of visits and no longer need templates for that part.
This commit is contained in:
Mike Lischke 2016-07-30 20:03:20 +02:00
parent 51b91f4d1b
commit 8a5f6815fe
16 changed files with 223 additions and 80 deletions

View File

@ -881,6 +881,7 @@
27DB44D81D0463DB007E790B /* XPathWildcardAnywhereElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 27DB449A1D045537007E790B /* XPathWildcardAnywhereElement.h */; };
27DB44D91D0463DB007E790B /* XPathWildcardElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27DB449B1D045537007E790B /* XPathWildcardElement.cpp */; };
27DB44DA1D0463DB007E790B /* XPathWildcardElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 27DB449C1D045537007E790B /* XPathWildcardElement.h */; };
27F4A8561D4CEB2A00E067EE /* Any.h in Headers */ = {isa = PBXBuildFile; fileRef = 27F4A8551D4CEB2A00E067EE /* Any.h */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@ -1118,7 +1119,7 @@
276E5CFE1CDB57AA003FF4B4 /* ParseTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParseTree.h; sourceTree = "<group>"; wrapsLines = 0; };
276E5D001CDB57AA003FF4B4 /* ParseTreeListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParseTreeListener.h; sourceTree = "<group>"; };
276E5D021CDB57AA003FF4B4 /* ParseTreeProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParseTreeProperty.h; sourceTree = "<group>"; };
276E5D031CDB57AA003FF4B4 /* ParseTreeVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParseTreeVisitor.h; sourceTree = "<group>"; };
276E5D031CDB57AA003FF4B4 /* ParseTreeVisitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParseTreeVisitor.h; sourceTree = "<group>"; wrapsLines = 0; };
276E5D041CDB57AA003FF4B4 /* ParseTreeWalker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParseTreeWalker.cpp; sourceTree = "<group>"; };
276E5D051CDB57AA003FF4B4 /* ParseTreeWalker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParseTreeWalker.h; sourceTree = "<group>"; };
276E5D071CDB57AA003FF4B4 /* Chunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Chunk.h; sourceTree = "<group>"; };
@ -1179,6 +1180,7 @@
27DB449C1D045537007E790B /* XPathWildcardElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XPathWildcardElement.h; sourceTree = "<group>"; wrapsLines = 0; };
27DB44AF1D0463CC007E790B /* XPathLexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = XPathLexer.cpp; sourceTree = "<group>"; };
27DB44B01D0463CC007E790B /* XPathLexer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XPathLexer.h; sourceTree = "<group>"; wrapsLines = 0; };
27F4A8551D4CEB2A00E067EE /* Any.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Any.h; sourceTree = "<group>"; };
37C147171B4D5A04008EDDDB /* libantlr4-runtime.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libantlr4-runtime.a"; sourceTree = BUILT_PRODUCTS_DIR; };
37D727AA1867AF1E007B6D10 /* libantlr4-runtime.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = "libantlr4-runtime.dylib"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
@ -1483,6 +1485,7 @@
276E5CE41CDB57AA003FF4B4 /* support */ = {
isa = PBXGroup;
children = (
27F4A8551D4CEB2A00E067EE /* Any.h */,
276E5CE51CDB57AA003FF4B4 /* Arrays.cpp */,
276E5CE61CDB57AA003FF4B4 /* Arrays.h */,
276E5CE71CDB57AA003FF4B4 /* BitSet.h */,
@ -2085,6 +2088,7 @@
27DB44A81D045537007E790B /* XPathTokenAnywhereElement.h in Headers */,
276E5FD41CDB57AA003FF4B4 /* TokenFactory.h in Headers */,
276E5EF91CDB57AA003FF4B4 /* CommonTokenStream.h in Headers */,
27F4A8561D4CEB2A00E067EE /* Any.h in Headers */,
276E5EB11CDB57AA003FF4B4 /* StarBlockStartState.h in Headers */,
276E5F6E1CDB57AA003FF4B4 /* MurmurHash.h in Headers */,
276E601F1CDB57AA003FF4B4 /* ParseTreePatternMatcher.h in Headers */,

View File

@ -33,6 +33,7 @@
#include "misc/Interval.h"
#include "Parser.h"
#include "atn/ATN.h"
#include "tree/ParseTreeVisitor.h"
#include "RuleContext.h"
@ -112,6 +113,10 @@ std::size_t RuleContext::getChildCount() {
return 0;
}
antlrcpp::Any RuleContext::accept(tree::ParseTreeVisitor *visitor) {
return visitor->visitChildren(this);
}
std::string RuleContext::toStringTree(Parser *recog) {
return tree::Trees::toStringTree(shared_from_this(), recog);
}

View File

@ -136,10 +136,7 @@ namespace antlr4 {
virtual std::size_t getChildCount() override;
template<typename T, typename T1>
T accept(tree::ParseTreeVisitor<T1> *visitor) {
return visitor->visitChildren(this);
}
virtual antlrcpp::Any accept(tree::ParseTreeVisitor *visitor) override;
/// <summary>
/// Print out a whole tree, not just a node, in LISP format

View File

@ -48,6 +48,7 @@
#include <stack>
#include <string>
#include <typeinfo>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>

View File

@ -152,6 +152,7 @@
#include "misc/IntervalSet.h"
#include "misc/MurmurHash.h"
#include "misc/Predicate.h"
#include "support/Any.h"
#include "support/Arrays.h"
#include "support/BitSet.h"
#include "support/CPPUtils.h"

View File

@ -0,0 +1,152 @@
/*
* [The "BSD license"]
* Copyright (c) 2016 Mike Lischke
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// A standard C++ class loosely modeled after boost::Any.
#pragma once
#include "antlr4-common.h"
namespace antlrcpp {
template<class T>
using StorageType = typename std::decay<T>::type;
struct Any
{
bool isNull() const { return !_ptr; }
bool isNotNull() const { return _ptr; }
Any() : _ptr(nullptr) {
}
Any(Any& that) : _ptr(that.clone()) {
}
Any(Any&& that) : _ptr(that._ptr) {
that._ptr = nullptr;
}
Any(const Any& that) : _ptr(that.clone()) {
}
Any(const Any&& that) : _ptr(that.clone()) {
}
template<typename U> Any(U&& value) : _ptr(new Derived<StorageType<U>>(std::forward<U>(value))) {
}
template<class U> bool is() const {
typedef StorageType<U> T;
auto derived = dynamic_cast<Derived<T> *>(_ptr);
return derived;
}
template<class U>
StorageType<U>& as() {
typedef StorageType<U> T;
auto derived = dynamic_cast<Derived<T>*>(_ptr);
if (!derived)
throw std::bad_cast();
return derived->value;
}
template<class U>
operator U() {
return as<StorageType<U>>();
}
Any& operator = (const Any& a) {
if (_ptr == a._ptr)
return *this;
auto old_ptr = _ptr;
_ptr = a.clone();
if (old_ptr)
delete old_ptr;
return *this;
}
Any& operator = (Any&& a) {
if (_ptr == a._ptr)
return *this;
std::swap(_ptr, a._ptr);
return *this;
}
virtual ~Any() {
delete _ptr;
}
virtual bool equals(Any other) const {
return _ptr == other._ptr;
}
private:
struct Base {
virtual ~Base() { }
virtual Base* clone() const = 0;
};
template<typename T>
struct Derived : Base
{
template<typename U> Derived(U&& value) : value(std::forward<U>(value)) {
}
T value;
Base* clone() const {
return new Derived<T>(value);
}
};
Base* clone() const
{
if (_ptr)
return _ptr->clone();
else
return nullptr;
}
Base *_ptr;
};
} // namespace antlrcpp

View File

@ -153,13 +153,13 @@ namespace antlr4 {
class Vocabulary;
}
namespace tree {
template <typename t> class AbstractParseTreeVisitor;
class AbstractParseTreeVisitor;
class ErrorNode;
class ErrorNodeImpl;
class ParseTree;
class ParseTreeListener;
template<typename T> class ParseTreeProperty;
template<typename T> class ParseTreeVisitor;
class ParseTreeVisitor;
class ParseTreeWalker;
class RuleNode;
class SyntaxTree;

View File

@ -37,16 +37,11 @@
namespace antlr4 {
namespace tree {
template<typename T>
class ANTLR4CPP_PUBLIC AbstractParseTreeVisitor : public ParseTreeVisitor<T> {
/// <summary>
/// {@inheritDoc}
/// <p/>
class ANTLR4CPP_PUBLIC AbstractParseTreeVisitor : public ParseTreeVisitor {
public:
/// The default implementation calls <seealso cref="ParseTree#accept"/> on the
/// specified tree.
/// </summary>
public:
virtual T* visit(ParseTree *tree) override {
virtual antlrcpp::Any visit(ParseTree *tree) override {
return tree->accept(this);
}
@ -63,8 +58,8 @@ namespace tree {
* the tree structure. Visitors that modify the tree should override this
* method to behave properly in respect to the specific algorithm in use.</p>
*/
virtual T* visitChildren(RuleNode *node) override {
T* result = defaultResult();
virtual antlrcpp::Any visitChildren(RuleNode *node) override {
antlrcpp::Any result = defaultResult();
size_t n = node->getChildCount();
for (size_t i = 0; i < n; i++) {
if (!shouldVisitNextChild(node, result)) {
@ -72,33 +67,26 @@ namespace tree {
}
Ref<ParseTree> c = node->getChild(i);
T childResult = c->accept(this);
antlrcpp::Any childResult = c->accept(this);
result = aggregateResult(result, childResult);
}
return result;
}
/// <summary>
/// {@inheritDoc}
/// <p/>
/// The default implementation returns the result of
/// <seealso cref="#defaultResult defaultResult"/>.
/// </summary>
virtual T* visitTerminal(TerminalNode * /*node*/) override {
virtual antlrcpp::Any visitTerminal(TerminalNode * /*node*/) override {
return defaultResult();
}
/// <summary>
/// {@inheritDoc}
/// <p/>
/// The default implementation returns the result of
/// <seealso cref="#defaultResult defaultResult"/>.
/// </summary>
virtual T* visitErrorNode(ErrorNode * /*node*/) override {
virtual antlrcpp::Any visitErrorNode(ErrorNode * /*node*/) override {
return defaultResult();
}
protected:
/// <summary>
/// Gets the default value returned by visitor methods. This value is
/// returned by the default implementations of
@ -109,9 +97,8 @@ namespace tree {
/// The base implementation returns {@code null}.
/// </summary>
/// <returns> The default value returned by visitor methods. </returns>
protected:
virtual T* defaultResult() {
return nullptr;
virtual antlrcpp::Any defaultResult() {
return 0;
}
/// <summary>
@ -132,7 +119,7 @@ namespace tree {
/// a child node.
/// </param>
/// <returns> The updated aggregate result. </returns>
virtual T* aggregateResult(T* /*aggregate*/, T* nextResult) {
virtual antlrcpp::Any aggregateResult(antlrcpp::Any /*aggregate*/, antlrcpp::Any nextResult) {
return nextResult;
}
@ -159,7 +146,7 @@ namespace tree {
/// <returns> {@code true} to continue visiting children. Otherwise return
/// {@code false} to stop visiting children and immediately return the
/// current aggregate result from <seealso cref="#visitChildren"/>. </returns>
virtual bool shouldVisitNextChild(RuleNode * /*node*/, T /*currentResult*/) {
virtual bool shouldVisitNextChild(RuleNode * /*node*/, antlrcpp::Any /*currentResult*/) {
return true;
}

View File

@ -30,6 +30,7 @@
*/
#include "Exceptions.h"
#include "tree/ParseTreeVisitor.h"
#include "tree/ErrorNodeImpl.h"
@ -39,3 +40,7 @@ using namespace antlr4::tree;
ErrorNodeImpl::ErrorNodeImpl(Token *token) : TerminalNodeImpl(token) {
}
antlrcpp::Any ErrorNodeImpl::accept(ParseTreeVisitor *visitor) {
return visitor->visitErrorNode(this);
}

View File

@ -35,6 +35,8 @@
#include "tree/TerminalNodeImpl.h"
#include "misc/Interval.h"
#include "support/Any.h"
namespace antlr4 {
namespace tree {
@ -49,10 +51,7 @@ namespace tree {
public:
ErrorNodeImpl(Token *token);
template<typename T, typename T1>
T accept(ParseTreeVisitor<T1> *visitor) {
return visitor->visitErrorNode(this);
}
virtual antlrcpp::Any accept(ParseTreeVisitor *visitor) override;
};
} // namespace tree

View File

@ -32,6 +32,7 @@
#pragma once
#include "tree/SyntaxTree.h"
#include "support/any.h"
namespace antlr4 {
namespace tree {
@ -45,27 +46,22 @@ namespace tree {
/// The payload is either a <seealso cref="Token"/> or a <seealso cref="RuleContext"/> object.
/// </summary>
class ANTLR4CPP_PUBLIC ParseTree : public SyntaxTree {
// the following methods narrow the return type; they are not additional methods
public:
// the following methods narrow the return type; they are not additional methods
std::weak_ptr<ParseTree> getParent() { return std::dynamic_pointer_cast<ParseTree>(getParentReference().lock()); };
virtual Ref<ParseTree> getChild(size_t i) { return std::dynamic_pointer_cast<ParseTree>(getChildReference(i)); };
/// <summary>
/// The <seealso cref="ParseTreeVisitor"/> needs a double dispatch method. </summary>
template<typename T, typename T1>
T *accept(ParseTreeVisitor<T1> *visitor);
/// The <seealso cref="ParseTreeVisitor"/> needs a double dispatch method.
// ml: This has been changed to use Any instead of a template parameter, to avoid the need of a virtual template function.
virtual antlrcpp::Any accept(ParseTreeVisitor *visitor) = 0;
/// <summary>
/// Return the combined text of all leaf nodes. Does not get any
/// off-channel tokens (if any) so won't return whitespace and
/// comments if they are sent to parser on hidden channel.
/// </summary>
/// off-channel tokens (if any) so won't return whitespace and
/// comments if they are sent to parser on hidden channel.
virtual std::string getText() = 0;
/// <summary>
/// Specialize toStringTree so that it can print out more information
/// based upon the parser.
/// </summary>
/// based upon the parser.
virtual std::string toStringTree(Parser *parser) = 0;
using Tree::toStringTree;
};

View File

@ -31,7 +31,7 @@
#pragma once
#include "antlr4-common.h"
#include "support/Any.h"
namespace antlr4 {
namespace tree {
@ -43,7 +43,7 @@ namespace tree {
/// </summary>
/// @param <T> The return type of the visit operation. Use <seealso cref="Void"/> for
/// operations with no return type. </param>
template<typename T>
// ml: no template parameter here, to avoid the need for virtual template functions. Instead we have our Any class.
class ANTLR4CPP_PUBLIC ParseTreeVisitor {
public:
virtual ~ParseTreeVisitor() {}
@ -53,7 +53,7 @@ namespace tree {
/// </summary>
/// <param name="tree"> The <seealso cref="ParseTree"/> to visit. </param>
/// <returns> The result of visiting the parse tree. </returns>
virtual T* visit(ParseTree *tree) = 0;
virtual antlrcpp::Any visit(ParseTree *tree) = 0;
/// <summary>
/// Visit the children of a node, and return a user-defined result of the
@ -61,21 +61,21 @@ namespace tree {
/// </summary>
/// <param name="node"> The <seealso cref="RuleNode"/> whose children should be visited. </param>
/// <returns> The result of visiting the children of the node. </returns>
virtual T* visitChildren(RuleNode *node) = 0;
virtual antlrcpp::Any visitChildren(RuleNode *node) = 0;
/// <summary>
/// Visit a terminal node, and return a user-defined result of the operation.
/// </summary>
/// <param name="node"> The <seealso cref="TerminalNode"/> to visit. </param>
/// <returns> The result of visiting the node. </returns>
virtual T* visitTerminal(TerminalNode *node) = 0;
virtual antlrcpp::Any visitTerminal(TerminalNode *node) = 0;
/// <summary>
/// Visit an error node, and return a user-defined result of the operation.
/// </summary>
/// <param name="node"> The <seealso cref="ErrorNode"/> to visit. </param>
/// <returns> The result of visiting the node. </returns>
virtual T* visitErrorNode(ErrorNode *node) = 0;
virtual antlrcpp::Any visitErrorNode(ErrorNode *node) = 0;
};

View File

@ -31,6 +31,7 @@
#include "misc/Interval.h"
#include "Token.h"
#include "tree/ParseTreeVisitor.h"
#include "tree/TerminalNodeImpl.h"
@ -57,6 +58,10 @@ std::size_t TerminalNodeImpl::getChildCount() {
return 0;
}
antlrcpp::Any TerminalNodeImpl::accept(ParseTreeVisitor *visitor) {
return visitor->visitTerminal(this);
}
std::string TerminalNodeImpl::getText() {
return symbol->getText();
}

View File

@ -48,10 +48,7 @@ namespace tree {
virtual std::size_t getChildCount() override;
template<typename T, typename T1>
T accept(ParseTreeVisitor<T1> *visitor) {
return visitor->visitTerminal(this);
}
virtual antlrcpp::Any accept(ParseTreeVisitor *visitor) override;
virtual std::string getText() override;
virtual std::string toStringTree(Parser *parser) override;

View File

@ -1044,15 +1044,17 @@ void <parser.name>::<struct.name>::<if (method.isEnter)>enter<else>exit<endif>Ru
VisitorDispatchMethodHeader(method) ::= <<
template \<typename T>
T* accept(tree::ParseTreeVisitor\<T> *visitor) {
if (dynamic_cast\<<parser.grammarName>Visitor\<T>*>(visitor) != nullptr)
return ((<parser.grammarName>Visitor\<T> *)visitor)->visit<struct.derivedFromName; format="cap">(this);
virtual antlrcpp::Any accept(tree::ParseTreeVisitor *visitor) override;
>>
VisitorDispatchMethod(method) ::= <<
antlrcpp::Any <parser.name>::<struct.name>::accept(tree::ParseTreeVisitor *visitor) {
if (dynamic_cast\<<parser.grammarName>Visitor*>(visitor) != nullptr)
return ((<parser.grammarName>Visitor *)visitor)->visit<struct.derivedFromName; format="cap">(this);
else
return visitor->visitChildren(this);
}
>>
VisitorDispatchMethod(method) ::= "<! Template function, must be implemented in the header. !>"
AttributeDeclHeader(d) ::= "<d.type> <d.name><if(d.initValue)> = <d.initValue><endif>"
AttributeDecl(d) ::= "<d.type> <d.name>"

View File

@ -90,8 +90,6 @@ using namespace antlr4;
<if (file.genPackage)>namespace <file.genPackage> {<endif>
template \<typename T>
class <file.grammarName>Visitor;
<parser>
<if (file.genPackage)>
@ -104,7 +102,8 @@ ParserFile(file, parser, namedActions, contextSuperClass) ::= <<
<namedActions.preinclude>
<if (file.genListener)>#include "<file.grammarName>BaseListener.h"<endif>
<if (file.genListener)>#include "<file.grammarName>Listener.h"<endif>
<if (file.genVisitor)>#include "<file.grammarName>Visitor.h"<endif>
#include "<file.parser.name>.h"
@ -252,17 +251,14 @@ namespace <file.genPackage> {
/**
* This class provides an empty implementation of <file.grammarName>Visitor, which can be
* extended to create a visitor which only needs to handle a subset of the available methods.
*
* @param \<T> The return type of the visit operation. Use void for operations with no return type.
*/
template \<typename T>
class <file.grammarName>BaseVisitor : public tree::AbstractParseTreeVisitor\<T>, public <file.grammarName>Visitor\<T> {
class <file.grammarName>BaseVisitor : public <file.grammarName>Visitor {
public:
<namedActions.basevisitordeclarations>
<file.visitorNames: { lname |
virtual T* visit<lname; format = "cap">(<file.parserName>::<lname; format = "cap">Context *ctx) override {
return tree::AbstractParseTreeVisitor\<T>::visitChildren(ctx);
virtual antlrcpp::Any visit<lname; format = "cap">(<file.parserName>::<lname; format = "cap">Context *ctx) override {
return visitChildren(ctx);
\}
}; separator="\n">
@ -309,14 +305,10 @@ VisitorFileHeader(file, header, namedActions) ::= <<
<if(file.genPackage)>namespace <file.genPackage> {<endif>
/**
* This template class defines an abstract visitor for a parse tree
* This class defines an abstract visitor for a parse tree
* produced by <file.parserName>.
*
* @param \<T> The return type of the visit operation. Use void for
* operations with no return type.
*/
template \<typename T>
class <file.grammarName>Visitor : public antlr4::tree::ParseTreeVisitor\<T> {
class <file.grammarName>Visitor : public antlr4::tree::AbstractParseTreeVisitor {
public:
<namedActions.visitordeclarations>
@ -324,7 +316,7 @@ public:
* Visit parse trees produced by <file.parserName>.
*/
<file.visitorNames: {lname |
virtual T* visit<lname; format = "cap">(<file.parserName>::<lname; format = "cap">Context *context) = 0;
virtual antlrcpp::Any visit<lname; format = "cap">(<file.parserName>::<lname; format = "cap">Context *context) = 0;
}; separator="\n">
<if (namedActions.visitormembers)>