More optimizations of the runtime.

- Lesser use of shared_ptr, e.g. in listeners and some loops.
- Removed useless access methods for children in ParseRuleContext. The child list is public. Fixed initialization for start and stop nodes.
- Simplified parent + child organization in Tree and all derived classes. Instead of using overridable functions in various descendants we have now central parent + child fields in the base tree class (where they belong actually, considering this is about forming a tree). Users have to cast to the appropriate classes if necessary.
- Removed obsolete getChildren() function in Trees helper. We can just return the child vector.
- Changed edges member to an unordered_map, as this is a sparse container. This speeds up certain grammars by 1000% (e.g. highly recursive expression rules) and avoids wasting a lot of memory. This change also simplifies handling significantly.
This commit is contained in:
Mike Lischke 2016-08-22 12:12:22 +02:00
parent ee2510e654
commit 6f62821573
34 changed files with 123 additions and 245 deletions

View File

@ -60,7 +60,7 @@ void ANTLRInputStream::load(const std::string &input) {
// Remove the UTF-8 BOM if present.
const char bom[4] = "\xef\xbb\xbf";
if (input.compare(0, 3, bom, 3) == 0)
_data = antlrcpp::utfConverter.from_bytes(input.substr(3, std::string::npos));
_data = antlrcpp::utfConverter.from_bytes(input.data() + 3, input.data() + input.size() - 3);
else
_data = antlrcpp::utfConverter.from_bytes(input);
p = 0;

View File

@ -39,12 +39,12 @@
using namespace antlr4;
void BailErrorStrategy::recover(Parser *recognizer, std::exception_ptr e) {
Ref<ParserRuleContext> context = recognizer->getContext();
ParserRuleContext *context = recognizer->getContext().get();
do {
context->exception = e;
if (context->getParent().expired())
if (context->parent.expired())
break;
context = context->getParent().lock();
context = (ParserRuleContext *)context->parent.lock().get();
} while (true);
try {
@ -63,12 +63,12 @@ Token* BailErrorStrategy::recoverInline(Parser *recognizer) {
InputMismatchException e(recognizer);
std::exception_ptr exception = std::make_exception_ptr(e);
Ref<ParserRuleContext> context = recognizer->getContext();
ParserRuleContext *context = recognizer->getContext().get();
do {
context->exception = exception;
if (context->getParent().expired())
if (context->parent.expired())
break;
context = context->getParent().lock();
context = (ParserRuleContext *)context->parent.lock().get();
} while (true);
try {

View File

@ -329,7 +329,7 @@ std::string DefaultErrorStrategy::escapeWSAndQuote(const std::string &s) const {
misc::IntervalSet DefaultErrorStrategy::getErrorRecoverySet(Parser *recognizer) {
const atn::ATN &atn = recognizer->getInterpreter<atn::ATNSimulator>()->atn;
Ref<RuleContext> ctx = recognizer->getContext();
RuleContext *ctx = recognizer->getContext().get();
misc::IntervalSet recoverSet;
while (ctx->invokingState >= 0) {
// compute what follows who invoked us
@ -340,7 +340,7 @@ misc::IntervalSet DefaultErrorStrategy::getErrorRecoverySet(Parser *recognizer)
if (ctx->parent.expired())
break;
ctx = ctx->parent.lock();
ctx = (RuleContext *)ctx->parent.lock().get();
}
recoverSet.remove(Token::EPSILON);

View File

@ -66,6 +66,7 @@ void Lexer::reset() {
tokenStartCharIndex = -1;
tokenStartCharPositionInLine = 0;
tokenStartLine = 0;
type = 0;
_text = "";
hitEOF = false;

View File

@ -64,12 +64,12 @@ void Parser::TraceListener::enterEveryRule(ParserRuleContext *ctx) {
<< ", LT(1)=" << outerInstance->_input->LT(1)->getText() << std::endl;
}
void Parser::TraceListener::visitTerminal(Ref<tree::TerminalNode> const& node) {
void Parser::TraceListener::visitTerminal(tree::TerminalNode *node) {
std::cout << "consume " << node->getSymbol() << " rule "
<< outerInstance->getRuleNames()[(size_t)outerInstance->getContext()->getRuleIndex()] << std::endl;
}
void Parser::TraceListener::visitErrorNode(Ref<tree::ErrorNode> const& /*node*/) {
void Parser::TraceListener::visitErrorNode(tree::ErrorNode * /*node*/) {
}
void Parser::TraceListener::exitEveryRule(ParserRuleContext *ctx) {
@ -82,10 +82,10 @@ Parser::TrimToSizeListener Parser::TrimToSizeListener::INSTANCE;
void Parser::TrimToSizeListener::enterEveryRule(ParserRuleContext * /*ctx*/) {
}
void Parser::TrimToSizeListener::visitTerminal(Ref<tree::TerminalNode> const& /*node*/) {
void Parser::TrimToSizeListener::visitTerminal(tree::TerminalNode * /*node*/) {
}
void Parser::TrimToSizeListener::visitErrorNode(Ref<tree::ErrorNode> const& /*node*/) {
void Parser::TrimToSizeListener::visitErrorNode(tree::ErrorNode * /*node*/) {
}
void Parser::TrimToSizeListener::exitEveryRule(ParserRuleContext * ctx) {
@ -107,6 +107,7 @@ void Parser::reset() {
}
_errHandler->reset(this); // Watch out, this is not shared_ptr.reset().
_matchedEOF = false;
_syntaxErrors = 0;
setTrace(false);
_precedenceStack.clear();
@ -320,14 +321,14 @@ Token* Parser::consume() {
Ref<tree::ErrorNode> node = _ctx->addErrorNode(o);
if (_parseListeners.size() > 0) {
for (auto listener : _parseListeners) {
listener->visitErrorNode(node);
listener->visitErrorNode(node.get());
}
}
} else {
Ref<tree::TerminalNode> node = _ctx->addChild(o);
if (_parseListeners.size() > 0) {
for (auto listener : _parseListeners) {
listener->visitTerminal(node);
listener->visitTerminal(node.get());
}
}
}
@ -517,7 +518,7 @@ bool Parser::isMatchedEOF() const {
}
misc::IntervalSet Parser::getExpectedTokens() {
return getATN().getExpectedTokens(getState(), getContext());
return getATN().getExpectedTokens(getState(), getContext().get());
}
misc::IntervalSet Parser::getExpectedTokensWithinCurrentRule() {
@ -557,7 +558,7 @@ std::vector<std::string> Parser::getRuleInvocationStack(Ref<RuleContext> const&
}
if (p->parent.expired())
break;
run = run->parent.lock().get();
run = (RuleContext *)run->parent.lock().get();
}
return stack;
}

View File

@ -49,8 +49,8 @@ namespace antlr4 {
virtual ~TraceListener() {};
virtual void enterEveryRule(ParserRuleContext *ctx) override;
virtual void visitTerminal(Ref<tree::TerminalNode> const& node) override;
virtual void visitErrorNode(Ref<tree::ErrorNode> const& node) override;
virtual void visitTerminal(tree::TerminalNode *node) override;
virtual void visitErrorNode(tree::ErrorNode *node) override;
virtual void exitEveryRule(ParserRuleContext *ctx) override;
private:
@ -64,8 +64,8 @@ namespace antlr4 {
virtual ~TrimToSizeListener() {};
virtual void enterEveryRule(ParserRuleContext *ctx) override;
virtual void visitTerminal(Ref<tree::TerminalNode> const& node) override;
virtual void visitErrorNode(Ref<tree::ErrorNode> const& node) override;
virtual void visitTerminal(tree::TerminalNode *node) override;
virtual void visitErrorNode(tree::ErrorNode *node) override;
virtual void exitEveryRule(ParserRuleContext *ctx) override;
};

View File

@ -42,7 +42,7 @@ using namespace antlrcpp;
const Ref<ParserRuleContext> ParserRuleContext::EMPTY = std::make_shared<ParserRuleContext>();
ParserRuleContext::ParserRuleContext() {
ParserRuleContext::ParserRuleContext() : start(nullptr), stop(nullptr) {
}
void ParserRuleContext::copyFrom(Ref<ParserRuleContext> const& ctx) {
@ -94,10 +94,6 @@ Ref<tree::ErrorNode> ParserRuleContext::addErrorNode(Token *badToken) {
return t;
}
Ref<tree::Tree> ParserRuleContext::getChildReference(std::size_t i) {
return children[i];
}
Ref<tree::TerminalNode> ParserRuleContext::getToken(int ttype, std::size_t i) {
if (i >= children.size()) {
return nullptr;
@ -134,10 +130,6 @@ std::vector<Ref<tree::TerminalNode>> ParserRuleContext::getTokens(int ttype) {
return tokens;
}
std::size_t ParserRuleContext::getChildCount() {
return children.size();
}
misc::Interval ParserRuleContext::getSourceInterval() {
if (start == nullptr) {
return misc::Interval::INVALID;

View File

@ -63,13 +63,6 @@ namespace antlr4 {
public:
static const Ref<ParserRuleContext> EMPTY;
/// If we are debugging or building a parse tree for a visitor,
/// we need to track all of the tokens and rule invocations associated
/// with this rule's context. This is empty for parsing w/o tree constr.
/// operation because we don't the need to track the details about
/// how we parse this rule.
std::vector<Ref<ParseTree>> children;
/// <summary>
/// For debugging/tracing purposes, we want to track all of the nodes in
/// the ATN traversed by the parser for a particular rule.
@ -125,10 +118,6 @@ namespace antlr4 {
virtual Ref<tree::TerminalNode> addChild(Token *matchedToken);
virtual Ref<tree::ErrorNode> addErrorNode(Token *badToken);
std::weak_ptr<ParserRuleContext> getParent() {
return std::dynamic_pointer_cast<ParserRuleContext>(getParentReference().lock());
};
virtual Ref<tree::TerminalNode> getToken(int ttype, std::size_t i);
virtual std::vector<Ref<tree::TerminalNode>> getTokens(int ttype);
@ -162,7 +151,6 @@ namespace antlr4 {
return contexts;
}
virtual std::size_t getChildCount() override;
virtual misc::Interval getSourceInterval() override;
/**
@ -182,9 +170,6 @@ namespace antlr4 {
/// <summary>
/// Used for rule context info debugging during parse-time, not so much for ATN debugging </summary>
virtual std::string toInfoString(Parser *recognizer);
protected:
virtual Ref<Tree> getChildReference(size_t i) override;
};
} // namespace antlr4

View File

@ -63,7 +63,7 @@ void RecognitionException::setOffendingState(int offendingState) {
misc::IntervalSet RecognitionException::getExpectedTokens() const {
if (_recognizer) {
return _recognizer->getATN().getExpectedTokens(_offendingState, _ctx);
return _recognizer->getATN().getExpectedTokens(_offendingState, _ctx.get());
}
return misc::IntervalSet::EMPTY_SET;
}

View File

@ -51,11 +51,11 @@ RuleContext::RuleContext(std::weak_ptr<RuleContext> parent, int invokingState) {
int RuleContext::depth() {
int n = 1;
Ref<RuleContext> p = shared_from_this();
RuleContext *p = this;
while (true) {
if (p->parent.expired())
break;
p = p->parent.lock();
p = (RuleContext *)p->parent.lock().get();
n++;
}
return n;
@ -73,21 +73,19 @@ Ref<RuleContext> RuleContext::getRuleContext() {
return shared_from_this();
}
std::weak_ptr<tree::Tree> RuleContext::getParentReference()
{
return std::dynamic_pointer_cast<tree::Tree>(parent.lock());
}
std::string RuleContext::getText() {
if (getChildCount() == 0) {
if (children.empty()) {
return "";
}
std::stringstream ss;
for (size_t i = 0; i < getChildCount(); i++) {
for (size_t i = 0; i < children.size(); i++) {
if (i > 0)
ss << ", ";
ss << getChild(i)->getText();
Ref<ParseTree> tree = std::dynamic_pointer_cast<ParseTree>(children[i]);
if (tree != nullptr)
ss << tree->getText();
}
return ss.str();
@ -97,11 +95,6 @@ ssize_t RuleContext::getRuleIndex() const {
return -1;
}
Ref<tree::Tree> RuleContext::getChildReference(size_t /*i*/) {
return Ref<tree::Tree>();
}
int RuleContext::getAltNumber() const {
return atn::ATN::INVALID_ALT_NUMBER;
}
@ -109,10 +102,6 @@ int RuleContext::getAltNumber() const {
void RuleContext::setAltNumber(int /*altNumber*/) {
}
std::size_t RuleContext::getChildCount() {
return 0;
}
antlrcpp::Any RuleContext::accept(tree::ParseTreeVisitor *visitor) {
return visitor->visitChildren(this);
}
@ -138,9 +127,9 @@ std::string RuleContext::toString(const std::vector<std::string> &ruleNames) {
std::string RuleContext::toString(const std::vector<std::string> &ruleNames, Ref<RuleContext> const& stop) {
std::stringstream ss;
Ref<RuleContext> currentParent = shared_from_this();
RuleContext *currentParent = this;
ss << "[";
while (currentParent != stop) {
while (currentParent != stop.get()) {
if (ruleNames.empty()) {
if (!currentParent->isEmpty()) {
ss << currentParent->invokingState;
@ -154,7 +143,7 @@ std::string RuleContext::toString(const std::vector<std::string> &ruleNames, Ref
if (currentParent->parent.expired()) // No parent anymore.
break;
currentParent = currentParent->parent.lock();
currentParent = (RuleContext *)currentParent->parent.lock().get();
if (!ruleNames.empty() || !currentParent->isEmpty()) {
ss << " ";
}

View File

@ -87,9 +87,6 @@ namespace antlr4 {
*/
class ANTLR4CPP_PUBLIC RuleContext : public tree::RuleNode, public std::enable_shared_from_this<RuleContext> {
public:
/// What context invoked this rule?
std::weak_ptr<RuleContext> parent;
/// What state invoked the rule associated with this context?
/// The "return address" is the followState of invokingState
/// If parent is null, this should be -1 and this context object represents the start rule.
@ -134,8 +131,6 @@ namespace antlr4 {
*/
virtual void setAltNumber(int altNumber);
virtual std::size_t getChildCount() override;
virtual antlrcpp::Any accept(tree::ParseTreeVisitor *visitor) override;
/// <summary>
@ -163,10 +158,6 @@ namespace antlr4 {
bool operator == (const RuleContext &other) { return this == &other; } // Simple address comparison.
protected:
virtual std::weak_ptr<Tree> getParentReference() override;
virtual Ref<Tree> getChildReference(size_t i) override;
private:
void InitializeInstanceFields();
};

View File

@ -150,12 +150,12 @@ int ATN::getNumberOfDecisions() const {
return (int)decisionToState.size();
}
misc::IntervalSet ATN::getExpectedTokens(int stateNumber, Ref<RuleContext> const& context) const {
misc::IntervalSet ATN::getExpectedTokens(int stateNumber, RuleContext *context) const {
if (stateNumber < 0 || stateNumber >= (int)states.size()) {
throw IllegalArgumentException("Invalid state number.");
}
Ref<RuleContext> ctx = context;
RuleContext *ctx = context;
ATNState *s = states.at((size_t)stateNumber);
misc::IntervalSet following = nextTokens(s);
if (!following.contains(Token::EPSILON)) {
@ -175,7 +175,7 @@ misc::IntervalSet ATN::getExpectedTokens(int stateNumber, Ref<RuleContext> const
if (ctx->parent.expired()) {
break;
}
ctx = ctx->parent.lock();
ctx = (RuleContext *)ctx->parent.lock().get();
}
if (following.contains(Token::EPSILON)) {

View File

@ -126,7 +126,7 @@ namespace atn {
/// specified state in the specified context. </returns>
/// <exception cref="IllegalArgumentException"> if the ATN does not contain a state with
/// number {@code stateNumber} </exception>
virtual misc::IntervalSet getExpectedTokens(int stateNumber, Ref<RuleContext> const& context) const;
virtual misc::IntervalSet getExpectedTokens(int stateNumber, RuleContext *context) const;
std::string toString() const;
};

View File

@ -52,7 +52,6 @@
#define DEBUG_ATN 0
#define DEBUG_DFA 0
using namespace antlr4;
using namespace antlr4::atn;
using namespace antlrcpp;
@ -114,8 +113,7 @@ int LexerATNSimulator::match(CharStream *input, size_t mode) {
void LexerATNSimulator::reset() {
_prevAccept.reset();
_startIndex = 0; // Originally -1, but that would require a signed type with many casts.
// The initial value is never tested, so it doesn't matter which value is set here.
_startIndex = -1;
_line = 1;
_charPositionInLine = 0;
_mode = Lexer::DEFAULT_MODE;
@ -551,11 +549,7 @@ void LexerATNSimulator::addDFAEdge(dfa::DFAState *p, ssize_t t, dfa::DFAState *q
}
std::lock_guard<std::recursive_mutex> lck(mtx);
if (p->edges.empty()) {
// make room for tokens 1..n and -1 masquerading as index 0
p->edges.resize(MAX_DFA_EDGE - MIN_DFA_EDGE + 1);
}
p->edges[(size_t)(t - MIN_DFA_EDGE)] = q; // connect
p->edges[t - MIN_DFA_EDGE] = q; // connect
}
dfa::DFAState *LexerATNSimulator::addDFAState(ATNConfigSet *configs) {

View File

@ -270,12 +270,12 @@ int ParserATNSimulator::execATN(dfa::DFA &dfa, dfa::DFAState *s0, TokenStream *i
}
dfa::DFAState *ParserATNSimulator::getExistingTargetState(dfa::DFAState *previousD, ssize_t t) {
std::vector<dfa::DFAState *> edges = previousD->edges;
if (edges.size() == 0 || t + 1 < 0 || t + 1 >= (ssize_t)edges.size()) {
auto iterator = previousD->edges.find(t);
if (iterator == previousD->edges.end()) {
return nullptr;
}
return edges[(size_t)t + 1];
return iterator->second;
}
dfa::DFAState *ParserATNSimulator::computeTargetState(dfa::DFA &dfa, dfa::DFAState *previousD, ssize_t t) {
@ -1181,9 +1181,7 @@ dfa::DFAState *ParserATNSimulator::addDFAEdge(dfa::DFA &dfa, dfa::DFAState *from
{
std::lock_guard<std::recursive_mutex> lck(mtx);
if (from->edges.empty())
from->edges.resize(atn.maxTokenType + 1 + 1);
from->edges[(size_t)(t + 1)] = to; // connect
from->edges[t] = to; // connect
}
#if DEBUG_DFA == 1

View File

@ -67,7 +67,7 @@ Ref<PredictionContext> PredictionContext::fromRuleContext(const ATN &atn, const
}
// If we have a parent, convert it to a PredictionContext graph
Ref<PredictionContext> parent = PredictionContext::fromRuleContext(atn, outerContext->parent.lock());
Ref<PredictionContext> parent = PredictionContext::fromRuleContext(atn, std::dynamic_pointer_cast<RuleContext>(outerContext->parent.lock()));
ATNState *state = atn.states.at((size_t)outerContext->invokingState);
RuleTransition *transition = (RuleTransition *)state->transition(0);

View File

@ -83,16 +83,13 @@ bool DFA::isPrecedenceDfa() const {
}
DFAState* DFA::getPrecedenceStartState(int precedence) const {
if (!isPrecedenceDfa()) {
throw IllegalStateException("Only precedence DFAs may contain a precedence start state.");
}
assert(_precedenceDfa); // Only precedence DFAs may contain a precedence start state.
// s0.edges is never null for a precedence DFA
if (precedence < 0 || precedence >= (int)s0->edges.size()) {
auto iterator = s0->edges.find(precedence);
if (iterator == s0->edges.end())
return nullptr;
}
return s0->edges[precedence];
return iterator->second;
}
void DFA::setPrecedenceStartState(int precedence, DFAState *startState) {
@ -104,13 +101,8 @@ void DFA::setPrecedenceStartState(int precedence, DFAState *startState) {
return;
}
std::unique_lock<std::recursive_mutex> lock(_lock);
{
// s0.edges is never null for a precedence DFA
if (precedence >= (int)s0->edges.size()) {
s0->edges.resize(precedence + 1);
}
std::unique_lock<std::recursive_mutex> lock(_lock);
s0->edges[precedence] = startState;
}
}

View File

@ -81,11 +81,10 @@ namespace dfa {
std::unique_ptr<atn::ATNConfigSet> configs;
/// <summary>
/// {@code edges[symbol]} points to target of symbol. Shift up by 1 so (-1)
/// <seealso cref="Token#EOF"/> maps to {@code edges[0]}.
/// </summary>
std::vector<DFAState *> edges;
// ml: this is a sparse list, so we use a map instead of a vector.
std::unordered_map<ssize_t, DFAState *> edges;
bool isAcceptState;

View File

@ -60,13 +60,13 @@ namespace tree {
*/
virtual antlrcpp::Any visitChildren(RuleNode *node) override {
antlrcpp::Any result = defaultResult();
size_t n = node->getChildCount();
size_t n = node->children.size();
for (size_t i = 0; i < n; i++) {
if (!shouldVisitNextChild(node, result)) {
break;
}
Ref<ParseTree> c = node->getChild(i);
Ref<ParseTree> c = std::dynamic_pointer_cast<ParseTree>(node->children[i]);
antlrcpp::Any childResult = c->accept(this);
result = aggregateResult(result, childResult);
}

View File

@ -37,20 +37,14 @@
namespace antlr4 {
namespace tree {
/// <summary>
/// An interface to access the tree of <seealso cref="RuleContext"/> objects created
/// during a parse that makes the data structure look like a simple parse tree.
/// This node represents both internal nodes, rule invocations,
/// and leaf nodes, token matches.
/// <p/>
/// The payload is either a <seealso cref="Token"/> or a <seealso cref="RuleContext"/> object.
/// </summary>
/// during a parse that makes the data structure look like a simple parse tree.
/// This node represents both internal nodes, rule invocations,
/// and leaf nodes, token matches.
///
/// The payload is either a <seealso cref="Token"/> or a <seealso cref="RuleContext"/> object.
class ANTLR4CPP_PUBLIC ParseTree : public SyntaxTree {
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)); };
/// 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;

View File

@ -51,8 +51,8 @@ namespace tree {
public:
virtual ~ParseTreeListener() {};
virtual void visitTerminal(Ref<TerminalNode> const& node) = 0;
virtual void visitErrorNode(Ref<ErrorNode> const& node) = 0;
virtual void visitTerminal(TerminalNode *node) = 0;
virtual void visitErrorNode(ErrorNode *node) = 0;
virtual void enterEveryRule(ParserRuleContext *ctx) = 0;
virtual void exitEveryRule(ParserRuleContext *ctx) = 0;

View File

@ -41,30 +41,30 @@ using namespace antlrcpp;
ParseTreeWalker ParseTreeWalker::DEFAULT;
void ParseTreeWalker::walk(ParseTreeListener *listener, Ref<ParseTree> const& t) {
if (is<ErrorNode>(t)) {
listener->visitErrorNode(std::dynamic_pointer_cast<ErrorNode>(t));
void ParseTreeWalker::walk(ParseTreeListener *listener, ParseTree *t) const {
if (is<ErrorNode *>(t)) {
listener->visitErrorNode(dynamic_cast<ErrorNode *>(t));
return;
} else if (is<TerminalNode>(t)) {
listener->visitTerminal(std::dynamic_pointer_cast<TerminalNode>(t));
} else if (is<TerminalNode *>(t)) {
listener->visitTerminal(dynamic_cast<TerminalNode *>(t));
return;
}
Ref<RuleNode> r = std::dynamic_pointer_cast<RuleNode>(t);
RuleNode *r = dynamic_cast<RuleNode *>(t);
enterRule(listener, r);
std::size_t n = r->getChildCount();
for (std::size_t i = 0; i < n; i++) {
walk(listener, r->getChild(i));
for (auto &child : r->children) {
walk(listener, dynamic_cast<ParseTree *>(child.get()));
}
exitRule(listener, r);
}
void ParseTreeWalker::enterRule(ParseTreeListener *listener, Ref<RuleNode> const& r) {
void ParseTreeWalker::enterRule(ParseTreeListener *listener, RuleNode *r) const {
Ref<ParserRuleContext> ctx = std::dynamic_pointer_cast<ParserRuleContext>(r->getRuleContext());
listener->enterEveryRule(ctx.get());
ctx->enterRule(listener);
}
void ParseTreeWalker::exitRule(ParseTreeListener *listener, Ref<RuleNode> const& r) {
void ParseTreeWalker::exitRule(ParseTreeListener *listener, RuleNode *r) const {
Ref<ParserRuleContext> ctx = std::dynamic_pointer_cast<ParserRuleContext>(r->getRuleContext());
ctx->exitRule(listener);
listener->exitEveryRule(ctx.get());

View File

@ -40,16 +40,15 @@ namespace tree {
virtual ~ParseTreeWalker() {};
virtual void walk(ParseTreeListener *listener, Ref<ParseTree> const& t);
virtual void walk(ParseTreeListener *listener, ParseTree *t) const;
protected:
/// The discovery of a rule node, involves sending two events: the generic
/// <seealso cref="ParseTreeListener#enterEveryRule"/> and a
/// <seealso cref="RuleContext"/>-specific event. First we trigger the generic and then
/// the rule specific. We do them in reverse order upon finishing the node.
protected:
virtual void enterRule(ParseTreeListener *listener, Ref<RuleNode> const& r);
virtual void exitRule(ParseTreeListener *listener, Ref<RuleNode> const& r);
virtual void enterRule(ParseTreeListener *listener, RuleNode *r) const;
virtual void exitRule(ParseTreeListener *listener, RuleNode *r) const;
};
} // namespace tree

View File

@ -54,10 +54,6 @@ misc::Interval TerminalNodeImpl::getSourceInterval() {
return misc::Interval(tokenIndex, tokenIndex);
}
std::size_t TerminalNodeImpl::getChildCount() {
return 0;
}
antlrcpp::Any TerminalNodeImpl::accept(ParseTreeVisitor *visitor) {
return visitor->visitTerminal(this);
}
@ -80,11 +76,3 @@ std::string TerminalNodeImpl::toString() {
std::string TerminalNodeImpl::toStringTree() {
return toString();
}
std::weak_ptr<Tree> TerminalNodeImpl::getParentReference() {
return parent;
}
Ref<Tree> TerminalNodeImpl::getChildReference(size_t /*i*/) {
return Ref<Tree>();
}

View File

@ -39,15 +39,12 @@ namespace tree {
class ANTLR4CPP_PUBLIC TerminalNodeImpl : public virtual TerminalNode {
public:
Token *symbol;
std::weak_ptr<ParseTree> parent;
TerminalNodeImpl(Token *symbol);
virtual Token* getSymbol() override;
virtual misc::Interval getSourceInterval() override;
virtual std::size_t getChildCount() override;
virtual antlrcpp::Any accept(ParseTreeVisitor *visitor) override;
virtual std::string getText() override;
@ -55,9 +52,6 @@ namespace tree {
virtual std::string toString() override;
virtual std::string toStringTree() override;
protected:
virtual std::weak_ptr<Tree> getParentReference() override;
virtual Ref<Tree> getChildReference(size_t i) override;
};
} // namespace tree

View File

@ -36,52 +36,30 @@
namespace antlr4 {
namespace tree {
/// <summary>
/// The basic notion of a tree has a parent, a payload, and a list of children.
/// It is the most abstract interface for all the trees used by ANTLR.
/// </summary>
/// It is the most abstract interface for all the trees used by ANTLR.
// ml: deviating from Java here. This class forms a tree? Then it should also manage parent + children.
class ANTLR4CPP_PUBLIC Tree {
public:
virtual ~Tree() {};
/// The parent of this node. If the return value is null, then this
/// node is the root of the tree.
std::weak_ptr<Tree> getParent() { return getParentReference(); };
/// node is the root of the tree.
std::weak_ptr<Tree> parent;
/// <summary>
/// This method returns whatever object represents the data at this note. For
/// example, for parse trees, the payload can be a <seealso cref="Token"/> representing
/// a leaf node or a <seealso cref="RuleContext"/> object representing a rule
/// invocation. For abstract syntax trees (ASTs), this is a <seealso cref="Token"/>
/// object.
/// </summary>
/// If we are debugging or building a parse tree for a visitor,
/// we need to track all of the tokens and rule invocations associated
/// with this rule's context. This is empty for parsing w/o tree constr.
/// operation because we don't the need to track the details about
/// how we parse this rule.
std::vector<Ref<Tree>> children;
// ml: there are actually only 2 occurences where this method was implemented. We use direct access instead.
//virtual void *getPayload() = 0;
/// <summary>
/// If there are children, get the {@code i}th value indexed from 0. </summary>
Ref<Tree> getChild(size_t i) { return getChildReference(i); };
/// <summary>
/// How many children are there? If there is none, then this
/// node represents a leaf node.
/// </summary>
virtual std::size_t getChildCount() = 0;
/// <summary>
/// Print out a whole tree, not just a node, in LISP format
/// {@code (root child1 .. childN)}. Print just a node if this is a leaf.
/// </summary>
/// {@code (root child1 .. childN)}. Print just a node if this is a leaf.
virtual std::string toStringTree() = 0;
virtual std::string toString() = 0;
virtual bool operator == (const Tree &other) const;
protected:
virtual std::weak_ptr<Tree> getParentReference() = 0;
virtual Ref<Tree> getChildReference(size_t i) = 0;
};
} // namespace tree

View File

@ -63,32 +63,25 @@ std::string Trees::toStringTree(Ref<Tree> const& t, Parser *recog) {
std::string Trees::toStringTree(Ref<Tree> const& t, const std::vector<std::string> &ruleNames) {
std::string temp = antlrcpp::escapeWhitespace(Trees::getNodeText(t, ruleNames), false);
if (t->getChildCount() == 0) {
if (t->children.empty()) {
return temp;
}
std::stringstream ss;
ss << "(" << temp << ' ';
/*
for (size_t i = 0; i < t->getChildCount(); i++) {
if (i > 0) {
ss << ' ';
}
ss << toStringTree(t->getChild(i), ruleNames);
}
*/
// Implement the recursive walk as iteration to avoid trouble we deep nesting.
// Implement the recursive walk as iteration to avoid trouble with deep nesting.
std::stack<size_t> stack;
size_t childIndex = 0;
Ref<Tree> run = t;
while (childIndex < run->getChildCount()) {
while (childIndex < run->children.size()) {
if (childIndex > 0) {
ss << ' ';
}
Ref<Tree> child = run->getChild(childIndex);
Ref<Tree> child = run->children[childIndex];
std::weak_ptr<Tree> parent = child->parent;
temp = antlrcpp::escapeWhitespace(Trees::getNodeText(child, ruleNames), false);
if (child->getChildCount() > 0) {
if (!child->children.empty()) {
// Go deeper one level.
stack.push(childIndex);
run = child;
@ -96,12 +89,12 @@ std::string Trees::toStringTree(Ref<Tree> const& t, const std::vector<std::strin
ss << "(" << temp << " ";
} else {
ss << temp;
while (++childIndex == run->getChildCount()) {
while (++childIndex == run->children.size()) {
if (stack.size() > 0) {
// Reached the end of the current level. See if we can step up from here.
childIndex = stack.top();
stack.pop();
run = run->getParent().lock();
run = run->parent.lock();
ss << ")";
} else {
break;
@ -152,20 +145,12 @@ std::string Trees::getNodeText(Ref<Tree> const& t, const std::vector<std::string
return "";
}
std::vector<Ref<Tree>> Trees::getChildren(Ref<Tree> const& t) {
std::vector<Ref<Tree>> kids;
for (size_t i = 0; i < t->getChildCount(); i++) {
kids.push_back(t->getChild(i));
}
return kids;
}
std::vector<std::weak_ptr<Tree>> Trees::getAncestors(Ref<Tree> const& t) {
std::vector<std::weak_ptr<Tree>> ancestors;
std::weak_ptr<Tree> parent = t->getParent();
std::weak_ptr<Tree> parent = t->parent;
while (!parent.expired()) {
ancestors.insert(ancestors.begin(), parent); // insert at start
parent = parent.lock()->getParent();
parent = parent.lock()->parent;
}
return ancestors;
}
@ -185,22 +170,22 @@ static void _findAllNodes(Ref<ParseTree> const& t, int index, bool findTokens, s
}
}
// check children
for (size_t i = 0; i < t->getChildCount(); i++) {
_findAllNodes(t->getChild(i), index, findTokens, nodes);
for (size_t i = 0; i < t->children.size(); i++) {
_findAllNodes(std::dynamic_pointer_cast<ParseTree>(t->children[i]), index, findTokens, nodes);
}
}
bool Trees::isAncestorOf(Ref<Tree> const& t, Ref<Tree> const& u) {
if (t == nullptr || u == nullptr || t->getParent().expired()) {
if (t == nullptr || u == nullptr || t->parent.expired()) {
return false;
}
Ref<Tree> p = u->getParent().lock();
Ref<Tree> p = u->parent.lock();
while (p != nullptr) {
if (t == p) {
return true;
}
p = p->getParent().lock();
p = p->parent.lock();
}
return false;
}
@ -222,9 +207,9 @@ std::vector<Ref<ParseTree>> Trees::findAllNodes(Ref<ParseTree> const& t, int ind
std::vector<Ref<ParseTree>> Trees::getDescendants(Ref<ParseTree> const& t) {
std::vector<Ref<ParseTree>> nodes;
nodes.push_back(t);
std::size_t n = t->getChildCount();
std::size_t n = t->children.size();
for (size_t i = 0 ; i < n ; i++) {
auto descentants = getDescendants(t->getChild(i));
auto descentants = getDescendants(std::dynamic_pointer_cast<ParseTree>(t->children[i]));
for (auto entry: descentants) {
nodes.push_back(entry);
}
@ -238,9 +223,9 @@ std::vector<Ref<ParseTree>> Trees::descendants(Ref<ParseTree> const& t) {
Ref<ParserRuleContext> Trees::getRootOfSubtreeEnclosingRegion(Ref<ParseTree> const& t, size_t startTokenIndex,
size_t stopTokenIndex) {
size_t n = t->getChildCount();
for (size_t i = 0; i<n; i++) {
Ref<ParseTree> child = t->getChild(i);
size_t n = t->children.size();
for (size_t i = 0; i < n; i++) {
Ref<ParseTree> child = std::dynamic_pointer_cast<ParseTree>(t->children[i]);
Ref<ParserRuleContext> r = getRootOfSubtreeEnclosingRegion(child, startTokenIndex, stopTokenIndex);
if (r != nullptr) {
return r;
@ -263,9 +248,9 @@ Ref<Tree> Trees::findNodeSuchThat(Ref<Tree> const& t, Ref<Predicate<Tree>> const
return t;
}
size_t n = t->getChildCount();
size_t n = t->children.size();
for (size_t i = 0 ; i < n ; ++i) {
Ref<Tree> u = findNodeSuchThat(t->getChild(i), pred);
Ref<Tree> u = findNodeSuchThat(t->children[i], pred);
if (u != nullptr) {
return u;
}

View File

@ -58,9 +58,6 @@ namespace tree {
static std::string getNodeText(Ref<Tree> const& t, Parser *recog);
static std::string getNodeText(Ref<Tree> const& t, const std::vector<std::string> &ruleNames);
/// Return ordered list of all children of this node.
static std::vector<Ref<Tree>> getChildren(Ref<Tree> const& t);
/// Return a list of all ancestors of this node. The first node of
/// list is the root and the last is the parent of this node.
static std::vector<std::weak_ptr<Tree>> getAncestors(Ref<Tree> const& t);

View File

@ -214,7 +214,7 @@ Ref<ParseTree> ParseTreePatternMatcher::matchImpl(Ref<ParseTree> const& tree,
}
// (expr ...) and (expr ...)
if (r1->getChildCount() != r2->getChildCount()) {
if (r1->children.size() != r2->children.size()) {
if (mismatchedNode == nullptr) {
mismatchedNode = r1;
}
@ -222,9 +222,10 @@ Ref<ParseTree> ParseTreePatternMatcher::matchImpl(Ref<ParseTree> const& tree,
return mismatchedNode;
}
std::size_t n = r1->getChildCount();
std::size_t n = r1->children.size();
for (size_t i = 0; i < n; i++) {
Ref<ParseTree> childMatch = matchImpl(r1->getChild(i), patternTree->getChild(i), labels);
Ref<ParseTree> childMatch = matchImpl(std::dynamic_pointer_cast<ParseTree>(r1->children[i]),
std::dynamic_pointer_cast<ParseTree>(patternTree->children[i]), labels);
if (childMatch) {
return childMatch;
}
@ -240,8 +241,8 @@ Ref<ParseTree> ParseTreePatternMatcher::matchImpl(Ref<ParseTree> const& tree,
RuleTagToken* ParseTreePatternMatcher::getRuleTagToken(Ref<ParseTree> const& t) {
if (is<RuleNode>(t)) {
Ref<RuleNode> r = std::dynamic_pointer_cast<RuleNode>(t);
if (r->getChildCount() == 1 && is<TerminalNode>(r->getChild(0))) {
Ref<TerminalNode> c = std::dynamic_pointer_cast<TerminalNode>(r->getChild(0));
if (r->children.size() == 1 && is<TerminalNode>(r->children[0])) {
Ref<TerminalNode> c = std::dynamic_pointer_cast<TerminalNode>(r->children[0]);
if (is<RuleTagToken *>(c->getSymbol())) {
return dynamic_cast<RuleTagToken *>(c->getSymbol());
}

View File

@ -163,7 +163,7 @@ std::vector<Ref<ParseTree>> XPath::evaluate(const Ref<ParseTree> &t) {
while (i < _elements.size()) {
std::vector<Ref<ParseTree>> next;
for (auto node : work) {
if (node->getChildCount() > 0) {
if (!node->children.empty()) {
// only try to match next element if it has children
// e.g., //func/*/stat might have a token node for which
// we can't go looking for stat nodes.

View File

@ -44,7 +44,7 @@ XPathRuleElement::XPathRuleElement(const std::string &ruleName, int ruleIndex) :
std::vector<Ref<ParseTree>> XPathRuleElement::evaluate(const Ref<ParseTree> &t) {
// return all children of t that match nodeName
std::vector<Ref<ParseTree>> nodes;
for (auto c : Trees::getChildren(t)) {
for (auto c : t->children) {
if (antlrcpp::is<ParserRuleContext>(c)) {
Ref<ParserRuleContext> ctx = std::static_pointer_cast<ParserRuleContext>(c);
if ((ctx->getRuleIndex() == _ruleIndex && !_invert) || (ctx->getRuleIndex() != _ruleIndex && _invert)) {

View File

@ -47,7 +47,7 @@ XPathTokenElement::XPathTokenElement(const std::string &tokenName, int tokenType
std::vector<Ref<ParseTree>> XPathTokenElement::evaluate(const std::shared_ptr<ParseTree> &t) {
// return all children of t that match nodeName
std::vector<Ref<ParseTree>> nodes;
for (auto c : Trees::getChildren(t)) {
for (auto c : t->children) {
if (antlrcpp::is<TerminalNode>(c)) {
Ref<TerminalNode> tnode = std::static_pointer_cast<TerminalNode>(c);
if ((tnode->getSymbol()->getType() == _tokenType && !_invert) || (tnode->getSymbol()->getType() != _tokenType && _invert)) {

View File

@ -46,7 +46,7 @@ std::vector<Ref<ParseTree>> XPathWildcardElement::evaluate(const Ref<ParseTree>
return {}; // !* is weird but valid (empty)
}
std::vector<Ref<ParseTree>> kids;
for (auto c : Trees::getChildren(t)) {
for (auto c : t->children) {
kids.push_back(std::static_pointer_cast<ParseTree>(c));
}
return kids;

View File

@ -147,8 +147,8 @@ public:
virtual void enterEveryRule(ParserRuleContext * /*ctx*/) override { }
virtual void exitEveryRule(ParserRuleContext * /*ctx*/) override { }
virtual void visitTerminal(Ref\<tree::TerminalNode> const& /*node*/) override { }
virtual void visitErrorNode(Ref\<tree::ErrorNode> const& /*node*/) override { }
virtual void visitTerminal(tree::TerminalNode * /*node*/) override { }
virtual void visitErrorNode(tree::ErrorNode * /*node*/) override { }
<if (namedActions.baselistenermembers)>
private: