Initial commit from sysy-main

This commit is contained in:
Lixuanwang
2025-02-27 23:14:53 +08:00
commit cc523fd30b
1125 changed files with 257793 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$/..">
<contentRoot DIR="$PROJECT_DIR$" />
</component>
</project>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/src.iml" filepath="$PROJECT_DIR$/.idea/src.iml" />
</modules>
</component>
</project>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/../../../.." vcs="Git" />
</component>
</project>

View File

@@ -0,0 +1,10 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "ANTLRErrorListener.h"
antlr4::ANTLRErrorListener::~ANTLRErrorListener()
{
}

View File

@@ -0,0 +1,167 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "RecognitionException.h"
namespace antlrcpp {
class BitSet;
}
namespace antlr4 {
/// How to emit recognition errors (an interface in Java).
class ANTLR4CPP_PUBLIC ANTLRErrorListener {
public:
virtual ~ANTLRErrorListener();
/// <summary>
/// Upon syntax error, notify any interested parties. This is not how to
/// recover from errors or compute error messages. <seealso cref="ANTLRErrorStrategy"/>
/// specifies how to recover from syntax errors and how to compute error
/// messages. This listener's job is simply to emit a computed message,
/// though it has enough information to create its own message in many cases.
/// <p/>
/// The <seealso cref="RecognitionException"/> is non-null for all syntax errors except
/// when we discover mismatched token errors that we can recover from
/// in-line, without returning from the surrounding rule (via the single
/// token insertion and deletion mechanism).
/// </summary>
/// <param name="recognizer">
/// What parser got the error. From this
/// object, you can access the context as well
/// as the input stream. </param>
/// <param name="offendingSymbol">
/// The offending token in the input token
/// stream, unless recognizer is a lexer (then it's null). If
/// no viable alternative error, {@code e} has token at which we
/// started production for the decision. </param>
/// <param name="line">
/// The line number in the input where the error occurred. </param>
/// <param name="charPositionInLine">
/// The character position within that line where the error occurred. </param>
/// <param name="msg">
/// The message to emit. </param>
/// <param name="e">
/// The exception generated by the parser that led to
/// the reporting of an error. It is null in the case where
/// the parser was able to recover in line without exiting the
/// surrounding rule. </param>
virtual void syntaxError(Recognizer *recognizer, Token *offendingSymbol, size_t line,
size_t charPositionInLine, const std::string &msg, std::exception_ptr e) = 0;
/**
* This method is called by the parser when a full-context prediction
* results in an ambiguity.
*
* <p>Each full-context prediction which does not result in a syntax error
* will call either {@link #reportContextSensitivity} or
* {@link #reportAmbiguity}.</p>
*
* <p>When {@code ambigAlts} is not null, it contains the set of potentially
* viable alternatives identified by the prediction algorithm. When
* {@code ambigAlts} is null, use {@link ATNConfigSet#getAlts} to obtain the
* represented alternatives from the {@code configs} argument.</p>
*
* <p>When {@code exact} is {@code true}, <em>all</em> of the potentially
* viable alternatives are truly viable, i.e. this is reporting an exact
* ambiguity. When {@code exact} is {@code false}, <em>at least two</em> of
* the potentially viable alternatives are viable for the current input, but
* the prediction algorithm terminated as soon as it determined that at
* least the <em>minimum</em> potentially viable alternative is truly
* viable.</p>
*
* <p>When the {@link PredictionMode#LL_EXACT_AMBIG_DETECTION} prediction
* mode is used, the parser is required to identify exact ambiguities so
* {@code exact} will always be {@code true}.</p>
*
* <p>This method is not used by lexers.</p>
*
* @param recognizer the parser instance
* @param dfa the DFA for the current decision
* @param startIndex the input index where the decision started
* @param stopIndex the input input where the ambiguity was identified
* @param exact {@code true} if the ambiguity is exactly known, otherwise
* {@code false}. This is always {@code true} when
* {@link PredictionMode#LL_EXACT_AMBIG_DETECTION} is used.
* @param ambigAlts the potentially ambiguous alternatives, or {@code null}
* to indicate that the potentially ambiguous alternatives are the complete
* set of represented alternatives in {@code configs}
* @param configs the ATN configuration set where the ambiguity was
* identified
*/
virtual void reportAmbiguity(Parser *recognizer, const dfa::DFA &dfa, size_t startIndex, size_t stopIndex, bool exact,
const antlrcpp::BitSet &ambigAlts, atn::ATNConfigSet *configs) = 0;
/**
* This method is called when an SLL conflict occurs and the parser is about
* to use the full context information to make an LL decision.
*
* <p>If one or more configurations in {@code configs} contains a semantic
* predicate, the predicates are evaluated before this method is called. The
* subset of alternatives which are still viable after predicates are
* evaluated is reported in {@code conflictingAlts}.</p>
*
* <p>This method is not used by lexers.</p>
*
* @param recognizer the parser instance
* @param dfa the DFA for the current decision
* @param startIndex the input index where the decision started
* @param stopIndex the input index where the SLL conflict occurred
* @param conflictingAlts The specific conflicting alternatives. If this is
* {@code null}, the conflicting alternatives are all alternatives
* represented in {@code configs}. At the moment, conflictingAlts is non-null
* (for the reference implementation, but Sam's optimized version can see this
* as null).
* @param configs the ATN configuration set where the SLL conflict was
* detected
*/
virtual void reportAttemptingFullContext(Parser *recognizer, const dfa::DFA &dfa, size_t startIndex, size_t stopIndex,
const antlrcpp::BitSet &conflictingAlts, atn::ATNConfigSet *configs) = 0;
/**
* This method is called by the parser when a full-context prediction has a
* unique result.
*
* <p>Each full-context prediction which does not result in a syntax error
* will call either {@link #reportContextSensitivity} or
* {@link #reportAmbiguity}.</p>
*
* <p>For prediction implementations that only evaluate full-context
* predictions when an SLL conflict is found (including the default
* {@link ParserATNSimulator} implementation), this method reports cases
* where SLL conflicts were resolved to unique full-context predictions,
* i.e. the decision was context-sensitive. This report does not necessarily
* indicate a problem, and it may appear even in completely unambiguous
* grammars.</p>
*
* <p>{@code configs} may have more than one represented alternative if the
* full-context prediction algorithm does not evaluate predicates before
* beginning the full-context prediction. In all cases, the final prediction
* is passed as the {@code prediction} argument.</p>
*
* <p>Note that the definition of "context sensitivity" in this method
* differs from the concept in {@link DecisionInfo#contextSensitivities}.
* This method reports all instances where an SLL conflict occurred but LL
* parsing produced a unique result, whether or not that unique result
* matches the minimum alternative in the SLL conflicting set.</p>
*
* <p>This method is not used by lexers.</p>
*
* @param recognizer the parser instance
* @param dfa the DFA for the current decision
* @param startIndex the input index where the decision started
* @param stopIndex the input index where the context sensitivity was
* finally determined
* @param prediction the unambiguous result of the full-context prediction
* @param configs the ATN configuration set where the unambiguous prediction
* was determined
*/
virtual void reportContextSensitivity(Parser *recognizer, const dfa::DFA &dfa, size_t startIndex, size_t stopIndex,
size_t prediction, atn::ATNConfigSet *configs) = 0;
};
} // namespace antlr4

View File

@@ -0,0 +1,10 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "ANTLRErrorStrategy.h"
antlr4::ANTLRErrorStrategy::~ANTLRErrorStrategy()
{
}

View File

@@ -0,0 +1,121 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "Token.h"
namespace antlr4 {
/// <summary>
/// The interface for defining strategies to deal with syntax errors encountered
/// during a parse by ANTLR-generated parsers. We distinguish between three
/// different kinds of errors:
///
/// <ul>
/// <li>The parser could not figure out which path to take in the ATN (none of
/// the available alternatives could possibly match)</li>
/// <li>The current input does not match what we were looking for</li>
/// <li>A predicate evaluated to false</li>
/// </ul>
///
/// Implementations of this interface report syntax errors by calling
/// <seealso cref="Parser#notifyErrorListeners"/>.
/// <p/>
/// TODO: what to do about lexers
/// </summary>
class ANTLR4CPP_PUBLIC ANTLRErrorStrategy {
public:
/// <summary>
/// Reset the error handler state for the specified {@code recognizer}. </summary>
/// <param name="recognizer"> the parser instance </param>
virtual ~ANTLRErrorStrategy();
virtual void reset(Parser *recognizer) = 0;
/**
* This method is called when an unexpected symbol is encountered during an
* inline match operation, such as {@link Parser#match}. If the error
* strategy successfully recovers from the match failure, this method
* returns the {@link Token} instance which should be treated as the
* successful result of the match.
*
* <p>This method handles the consumption of any tokens - the caller should
* <b>not</b> call {@link Parser#consume} after a successful recovery.</p>
*
* <p>Note that the calling code will not report an error if this method
* returns successfully. The error strategy implementation is responsible
* for calling {@link Parser#notifyErrorListeners} as appropriate.</p>
*
* @param recognizer the parser instance
* @throws RecognitionException if the error strategy was not able to
* recover from the unexpected input symbol
*/
virtual Token* recoverInline(Parser *recognizer) = 0;
/// <summary>
/// This method is called to recover from exception {@code e}. This method is
/// called after <seealso cref="#reportError"/> by the default exception handler
/// generated for a rule method.
/// </summary>
/// <seealso cref= #reportError
/// </seealso>
/// <param name="recognizer"> the parser instance </param>
/// <param name="e"> the recognition exception to recover from </param>
/// <exception cref="RecognitionException"> if the error strategy could not recover from
/// the recognition exception </exception>
virtual void recover(Parser *recognizer, std::exception_ptr e) = 0;
/// <summary>
/// This method provides the error handler with an opportunity to handle
/// syntactic or semantic errors in the input stream before they result in a
/// <seealso cref="RecognitionException"/>.
/// <p/>
/// The generated code currently contains calls to <seealso cref="#sync"/> after
/// entering the decision state of a closure block ({@code (...)*} or
/// {@code (...)+}).
/// <p/>
/// For an implementation based on Jim Idle's "magic sync" mechanism, see
/// <seealso cref="DefaultErrorStrategy#sync"/>.
/// </summary>
/// <seealso cref= DefaultErrorStrategy#sync
/// </seealso>
/// <param name="recognizer"> the parser instance </param>
/// <exception cref="RecognitionException"> if an error is detected by the error
/// strategy but cannot be automatically recovered at the current state in
/// the parsing process </exception>
virtual void sync(Parser *recognizer) = 0;
/// <summary>
/// Tests whether or not {@code recognizer} is in the process of recovering
/// from an error. In error recovery mode, <seealso cref="Parser#consume"/> adds
/// symbols to the parse tree by calling
/// {@link Parser#createErrorNode(ParserRuleContext, Token)} then
/// {@link ParserRuleContext#addErrorNode(ErrorNode)} instead of
/// {@link Parser#createTerminalNode(ParserRuleContext, Token)}.
/// </summary>
/// <param name="recognizer"> the parser instance </param>
/// <returns> {@code true} if the parser is currently recovering from a parse
/// error, otherwise {@code false} </returns>
virtual bool inErrorRecoveryMode(Parser *recognizer) = 0;
/// <summary>
/// This method is called by when the parser successfully matches an input
/// symbol.
/// </summary>
/// <param name="recognizer"> the parser instance </param>
virtual void reportMatch(Parser *recognizer) = 0;
/// <summary>
/// Report any kind of <seealso cref="RecognitionException"/>. This method is called by
/// the default exception handler generated for a rule method.
/// </summary>
/// <param name="recognizer"> the parser instance </param>
/// <param name="e"> the recognition exception to report </param>
virtual void reportError(Parser *recognizer, const RecognitionException &e) = 0;
};
} // namespace antlr4

View File

@@ -0,0 +1,23 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "ANTLRFileStream.h"
using namespace antlr4;
void ANTLRFileStream::loadFromFile(const std::string &fileName) {
_fileName = fileName;
if (_fileName.empty()) {
return;
}
std::ifstream stream(fileName, std::ios::binary);
ANTLRInputStream::load(stream);
}
std::string ANTLRFileStream::getSourceName() const {
return _fileName;
}

View File

@@ -0,0 +1,30 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "ANTLRInputStream.h"
namespace antlr4 {
/// This is an ANTLRInputStream that is loaded from a file all at once
/// when you construct the object (or call load()).
// TODO: this class needs testing.
class ANTLR4CPP_PUBLIC ANTLRFileStream : public ANTLRInputStream {
public:
ANTLRFileStream() = default;
ANTLRFileStream(const std::string &) = delete;
ANTLRFileStream(const char *data, size_t length) = delete;
ANTLRFileStream(std::istream &stream) = delete;
// Assumes a file name encoded in UTF-8 and file content in the same encoding (with or w/o BOM).
virtual void loadFromFile(const std::string &fileName);
virtual std::string getSourceName() const override;
private:
std::string _fileName; // UTF-8 encoded file name.
};
} // namespace antlr4

View File

@@ -0,0 +1,180 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include <string.h>
#include "Exceptions.h"
#include "misc/Interval.h"
#include "IntStream.h"
#include "support/Utf8.h"
#include "support/CPPUtils.h"
#include "ANTLRInputStream.h"
using namespace antlr4;
using namespace antlrcpp;
using misc::Interval;
ANTLRInputStream::ANTLRInputStream() {
InitializeInstanceFields();
}
ANTLRInputStream::ANTLRInputStream(std::string_view input): ANTLRInputStream() {
load(input.data(), input.length());
}
ANTLRInputStream::ANTLRInputStream(const char *data, size_t length) {
load(data, length);
}
ANTLRInputStream::ANTLRInputStream(std::istream &stream): ANTLRInputStream() {
load(stream);
}
void ANTLRInputStream::load(const std::string &input, bool lenient) {
load(input.data(), input.size(), lenient);
}
void ANTLRInputStream::load(const char *data, size_t length, bool lenient) {
// Remove the UTF-8 BOM if present.
const char *bom = "\xef\xbb\xbf";
if (length >= 3 && strncmp(data, bom, 3) == 0) {
data += 3;
length -= 3;
}
if (lenient) {
_data = Utf8::lenientDecode(std::string_view(data, length));
} else {
auto maybe_utf32 = Utf8::strictDecode(std::string_view(data, length));
if (!maybe_utf32.has_value()) {
throw IllegalArgumentException("UTF-8 string contains an illegal byte sequence");
}
_data = std::move(maybe_utf32).value();
}
p = 0;
}
void ANTLRInputStream::load(std::istream &stream, bool lenient) {
if (!stream.good() || stream.eof()) // No fail, bad or EOF.
return;
_data.clear();
std::string s((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>());
load(s.data(), s.length(), lenient);
}
void ANTLRInputStream::reset() {
p = 0;
}
void ANTLRInputStream::consume() {
if (p >= _data.size()) {
assert(LA(1) == IntStream::EOF);
throw IllegalStateException("cannot consume EOF");
}
if (p < _data.size()) {
p++;
}
}
size_t ANTLRInputStream::LA(ssize_t i) {
if (i == 0) {
return 0; // undefined
}
ssize_t position = static_cast<ssize_t>(p);
if (i < 0) {
i++; // e.g., translate LA(-1) to use offset i=0; then _data[p+0-1]
if ((position + i - 1) < 0) {
return IntStream::EOF; // invalid; no char before first char
}
}
if ((position + i - 1) >= static_cast<ssize_t>(_data.size())) {
return IntStream::EOF;
}
return _data[static_cast<size_t>((position + i - 1))];
}
size_t ANTLRInputStream::LT(ssize_t i) {
return LA(i);
}
size_t ANTLRInputStream::index() {
return p;
}
size_t ANTLRInputStream::size() {
return _data.size();
}
// Mark/release do nothing. We have entire buffer.
ssize_t ANTLRInputStream::mark() {
return -1;
}
void ANTLRInputStream::release(ssize_t /* marker */) {
}
void ANTLRInputStream::seek(size_t index) {
if (index <= p) {
p = index; // just jump; don't update stream state (line, ...)
return;
}
// seek forward, consume until p hits index or n (whichever comes first)
index = std::min(index, _data.size());
while (p < index) {
consume();
}
}
std::string ANTLRInputStream::getText(const Interval &interval) {
if (interval.a < 0 || interval.b < 0) {
return "";
}
size_t start = static_cast<size_t>(interval.a);
size_t stop = static_cast<size_t>(interval.b);
if (stop >= _data.size()) {
stop = _data.size() - 1;
}
size_t count = stop - start + 1;
if (start >= _data.size()) {
return "";
}
auto maybeUtf8 = Utf8::strictEncode(std::u32string_view(_data).substr(start, count));
if (!maybeUtf8.has_value()) {
throw IllegalArgumentException("Input stream contains invalid Unicode code points");
}
return std::move(maybeUtf8).value();
}
std::string ANTLRInputStream::getSourceName() const {
if (name.empty()) {
return IntStream::UNKNOWN_SOURCE_NAME;
}
return name;
}
std::string ANTLRInputStream::toString() const {
auto maybeUtf8 = Utf8::strictEncode(_data);
if (!maybeUtf8.has_value()) {
throw IllegalArgumentException("Input stream contains invalid Unicode code points");
}
return std::move(maybeUtf8).value();
}
void ANTLRInputStream::InitializeInstanceFields() {
p = 0;
}

View File

@@ -0,0 +1,79 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include <string_view>
#include "CharStream.h"
namespace antlr4 {
// Vacuum all input from a stream and then treat it
// like a string. Can also pass in a string or char[] to use.
// Input is expected to be encoded in UTF-8 and converted to UTF-32 internally.
class ANTLR4CPP_PUBLIC ANTLRInputStream : public CharStream {
protected:
/// The data being scanned.
// UTF-32
std::u32string _data;
/// 0..n-1 index into string of next char </summary>
size_t p;
public:
/// What is name or source of this char stream?
std::string name;
ANTLRInputStream();
ANTLRInputStream(std::string_view input);
ANTLRInputStream(const char *data, size_t length);
ANTLRInputStream(std::istream &stream);
virtual void load(const std::string &input, bool lenient);
virtual void load(const char *data, size_t length, bool lenient);
virtual void load(std::istream &stream, bool lenient);
virtual void load(const std::string &input) { load(input, false); }
virtual void load(const char *data, size_t length) { load(data, length, false); }
virtual void load(std::istream &stream) { load(stream, false); }
/// Reset the stream so that it's in the same state it was
/// when the object was created *except* the data array is not
/// touched.
virtual void reset();
virtual void consume() override;
virtual size_t LA(ssize_t i) override;
virtual size_t LT(ssize_t i);
/// <summary>
/// Return the current input symbol index 0..n where n indicates the
/// last symbol has been read. The index is the index of char to
/// be returned from LA(1).
/// </summary>
virtual size_t index() override;
virtual size_t size() override;
/// <summary>
/// mark/release do nothing; we have entire buffer </summary>
virtual ssize_t mark() override;
virtual void release(ssize_t marker) override;
/// <summary>
/// consume() ahead until p==index; can't just set p=index as we must
/// update line and charPositionInLine. If we seek backwards, just set p
/// </summary>
virtual void seek(size_t index) override;
virtual std::string getText(const misc::Interval &interval) override;
virtual std::string getSourceName() const override;
virtual std::string toString() const override;
private:
void InitializeInstanceFields();
};
} // namespace antlr4

View File

@@ -0,0 +1,61 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "Exceptions.h"
#include "ParserRuleContext.h"
#include "InputMismatchException.h"
#include "Parser.h"
#include "BailErrorStrategy.h"
using namespace antlr4;
void BailErrorStrategy::recover(Parser *recognizer, std::exception_ptr e) {
ParserRuleContext *context = recognizer->getContext();
do {
context->exception = e;
if (context->parent == nullptr)
break;
context = static_cast<ParserRuleContext *>(context->parent);
} while (true);
try {
std::rethrow_exception(e); // Throw the exception to be able to catch and rethrow nested.
#if defined(_MSC_FULL_VER) && _MSC_FULL_VER < 190023026
} catch (RecognitionException &inner) {
throw ParseCancellationException(inner.what());
#else
} catch (RecognitionException & /*inner*/) {
std::throw_with_nested(ParseCancellationException());
#endif
}
}
Token* BailErrorStrategy::recoverInline(Parser *recognizer) {
InputMismatchException e(recognizer);
std::exception_ptr exception = std::make_exception_ptr(e);
ParserRuleContext *context = recognizer->getContext();
do {
context->exception = exception;
if (context->parent == nullptr)
break;
context = static_cast<ParserRuleContext *>(context->parent);
} while (true);
try {
throw e;
#if defined(_MSC_FULL_VER) && _MSC_FULL_VER < 190023026
} catch (InputMismatchException &inner) {
throw ParseCancellationException(inner.what());
#else
} catch (InputMismatchException & /*inner*/) {
std::throw_with_nested(ParseCancellationException());
#endif
}
}
void BailErrorStrategy::sync(Parser * /*recognizer*/) {
}

View File

@@ -0,0 +1,59 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "DefaultErrorStrategy.h"
namespace antlr4 {
/**
* This implementation of {@link ANTLRErrorStrategy} responds to syntax errors
* by immediately canceling the parse operation with a
* {@link ParseCancellationException}. The implementation ensures that the
* {@link ParserRuleContext#exception} field is set for all parse tree nodes
* that were not completed prior to encountering the error.
*
* <p>
* This error strategy is useful in the following scenarios.</p>
*
* <ul>
* <li><strong>Two-stage parsing:</strong> This error strategy allows the first
* stage of two-stage parsing to immediately terminate if an error is
* encountered, and immediately fall back to the second stage. In addition to
* avoiding wasted work by attempting to recover from errors here, the empty
* implementation of {@link BailErrorStrategy#sync} improves the performance of
* the first stage.</li>
* <li><strong>Silent validation:</strong> When syntax errors are not being
* reported or logged, and the parse result is simply ignored if errors occur,
* the {@link BailErrorStrategy} avoids wasting work on recovering from errors
* when the result will be ignored either way.</li>
* </ul>
*
* <p>
* {@code myparser.setErrorHandler(new BailErrorStrategy());}</p>
*
* @see Parser#setErrorHandler(ANTLRErrorStrategy)
*/
class ANTLR4CPP_PUBLIC BailErrorStrategy : public DefaultErrorStrategy {
/// <summary>
/// Instead of recovering from exception {@code e}, re-throw it wrapped
/// in a <seealso cref="ParseCancellationException"/> so it is not caught by the
/// rule function catches. Use <seealso cref="Exception#getCause()"/> to get the
/// original <seealso cref="RecognitionException"/>.
/// </summary>
public:
virtual void recover(Parser *recognizer, std::exception_ptr e) override;
/// Make sure we don't attempt to recover inline; if the parser
/// successfully recovers, it won't throw an exception.
virtual Token* recoverInline(Parser *recognizer) override;
/// <summary>
/// Make sure we don't attempt to recover from problems in subrules. </summary>
virtual void sync(Parser *recognizer) override;
};
} // namespace antlr4

View File

@@ -0,0 +1,25 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "BaseErrorListener.h"
#include "RecognitionException.h"
using namespace antlr4;
void BaseErrorListener::syntaxError(Recognizer * /*recognizer*/, Token * /*offendingSymbol*/, size_t /*line*/,
size_t /*charPositionInLine*/, const std::string &/*msg*/, std::exception_ptr /*e*/) {
}
void BaseErrorListener::reportAmbiguity(Parser * /*recognizer*/, const dfa::DFA &/*dfa*/, size_t /*startIndex*/,
size_t /*stopIndex*/, bool /*exact*/, const antlrcpp::BitSet &/*ambigAlts*/, atn::ATNConfigSet * /*configs*/) {
}
void BaseErrorListener::reportAttemptingFullContext(Parser * /*recognizer*/, const dfa::DFA &/*dfa*/, size_t /*startIndex*/,
size_t /*stopIndex*/, const antlrcpp::BitSet &/*conflictingAlts*/, atn::ATNConfigSet * /*configs*/) {
}
void BaseErrorListener::reportContextSensitivity(Parser * /*recognizer*/, const dfa::DFA &/*dfa*/, size_t /*startIndex*/,
size_t /*stopIndex*/, size_t /*prediction*/, atn::ATNConfigSet * /*configs*/) {
}

View File

@@ -0,0 +1,36 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "ANTLRErrorListener.h"
namespace antlrcpp {
class BitSet;
}
namespace antlr4 {
/**
* Provides an empty default implementation of {@link ANTLRErrorListener}. The
* default implementation of each method does nothing, but can be overridden as
* necessary.
*/
class ANTLR4CPP_PUBLIC BaseErrorListener : public ANTLRErrorListener {
virtual void syntaxError(Recognizer *recognizer, Token * offendingSymbol, size_t line, size_t charPositionInLine,
const std::string &msg, std::exception_ptr e) override;
virtual void reportAmbiguity(Parser *recognizer, const dfa::DFA &dfa, size_t startIndex, size_t stopIndex, bool exact,
const antlrcpp::BitSet &ambigAlts, atn::ATNConfigSet *configs) override;
virtual void reportAttemptingFullContext(Parser *recognizer, const dfa::DFA &dfa, size_t startIndex, size_t stopIndex,
const antlrcpp::BitSet &conflictingAlts, atn::ATNConfigSet *configs) override;
virtual void reportContextSensitivity(Parser *recognizer, const dfa::DFA &dfa, size_t startIndex, size_t stopIndex,
size_t prediction, atn::ATNConfigSet *configs) override;
};
} // namespace antlr4

View File

@@ -0,0 +1,414 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "WritableToken.h"
#include "Lexer.h"
#include "RuleContext.h"
#include "misc/Interval.h"
#include "Exceptions.h"
#include "support/CPPUtils.h"
#include "BufferedTokenStream.h"
using namespace antlr4;
using namespace antlrcpp;
BufferedTokenStream::BufferedTokenStream(TokenSource *tokenSource) : _tokenSource(tokenSource){
InitializeInstanceFields();
}
TokenSource* BufferedTokenStream::getTokenSource() const {
return _tokenSource;
}
size_t BufferedTokenStream::index() {
return _p;
}
ssize_t BufferedTokenStream::mark() {
return 0;
}
void BufferedTokenStream::release(ssize_t /*marker*/) {
// no resources to release
}
void BufferedTokenStream::reset() {
seek(0);
}
void BufferedTokenStream::seek(size_t index) {
lazyInit();
_p = adjustSeekIndex(index);
}
size_t BufferedTokenStream::size() {
return _tokens.size();
}
void BufferedTokenStream::consume() {
bool skipEofCheck = false;
if (!_needSetup) {
if (_fetchedEOF) {
// the last token in tokens is EOF. skip check if p indexes any
// fetched token except the last.
skipEofCheck = _p < _tokens.size() - 1;
} else {
// no EOF token in tokens. skip check if p indexes a fetched token.
skipEofCheck = _p < _tokens.size();
}
} else {
// not yet initialized
skipEofCheck = false;
}
if (!skipEofCheck && LA(1) == Token::EOF) {
throw IllegalStateException("cannot consume EOF");
}
if (sync(_p + 1)) {
_p = adjustSeekIndex(_p + 1);
}
}
bool BufferedTokenStream::sync(size_t i) {
if (i + 1 < _tokens.size())
return true;
size_t n = i - _tokens.size() + 1; // how many more elements we need?
if (n > 0) {
size_t fetched = fetch(n);
return fetched >= n;
}
return true;
}
size_t BufferedTokenStream::fetch(size_t n) {
if (_fetchedEOF) {
return 0;
}
size_t i = 0;
while (i < n) {
std::unique_ptr<Token> t(_tokenSource->nextToken());
if (is<WritableToken *>(t.get())) {
(static_cast<WritableToken *>(t.get()))->setTokenIndex(_tokens.size());
}
_tokens.push_back(std::move(t));
++i;
if (_tokens.back()->getType() == Token::EOF) {
_fetchedEOF = true;
break;
}
}
return i;
}
Token* BufferedTokenStream::get(size_t i) const {
if (i >= _tokens.size()) {
throw IndexOutOfBoundsException(std::string("token index ") +
std::to_string(i) +
std::string(" out of range 0..") +
std::to_string(_tokens.size() - 1));
}
return _tokens[i].get();
}
std::vector<Token *> BufferedTokenStream::get(size_t start, size_t stop) {
std::vector<Token *> subset;
lazyInit();
if (_tokens.empty()) {
return subset;
}
if (stop >= _tokens.size()) {
stop = _tokens.size() - 1;
}
for (size_t i = start; i <= stop; i++) {
Token *t = _tokens[i].get();
if (t->getType() == Token::EOF) {
break;
}
subset.push_back(t);
}
return subset;
}
size_t BufferedTokenStream::LA(ssize_t i) {
return LT(i)->getType();
}
Token* BufferedTokenStream::LB(size_t k) {
if (k > _p) {
return nullptr;
}
return _tokens[_p - k].get();
}
Token* BufferedTokenStream::LT(ssize_t k) {
lazyInit();
if (k == 0) {
return nullptr;
}
if (k < 0) {
return LB(-k);
}
size_t i = _p + k - 1;
sync(i);
if (i >= _tokens.size()) { // return EOF token
// EOF must be last token
return _tokens.back().get();
}
return _tokens[i].get();
}
ssize_t BufferedTokenStream::adjustSeekIndex(size_t i) {
return i;
}
void BufferedTokenStream::lazyInit() {
if (_needSetup) {
setup();
}
}
void BufferedTokenStream::setup() {
_needSetup = false;
sync(0);
_p = adjustSeekIndex(0);
}
void BufferedTokenStream::setTokenSource(TokenSource *tokenSource) {
_tokenSource = tokenSource;
_tokens.clear();
_fetchedEOF = false;
_needSetup = true;
}
std::vector<Token *> BufferedTokenStream::getTokens() {
std::vector<Token *> result;
for (auto &t : _tokens)
result.push_back(t.get());
return result;
}
std::vector<Token *> BufferedTokenStream::getTokens(size_t start, size_t stop) {
return getTokens(start, stop, std::vector<size_t>());
}
std::vector<Token *> BufferedTokenStream::getTokens(size_t start, size_t stop, const std::vector<size_t> &types) {
lazyInit();
if (stop >= _tokens.size() || start >= _tokens.size()) {
throw IndexOutOfBoundsException(std::string("start ") +
std::to_string(start) +
std::string(" or stop ") +
std::to_string(stop) +
std::string(" not in 0..") +
std::to_string(_tokens.size() - 1));
}
std::vector<Token *> filteredTokens;
if (start > stop) {
return filteredTokens;
}
for (size_t i = start; i <= stop; i++) {
Token *tok = _tokens[i].get();
if (types.empty() || std::find(types.begin(), types.end(), tok->getType()) != types.end()) {
filteredTokens.push_back(tok);
}
}
return filteredTokens;
}
std::vector<Token *> BufferedTokenStream::getTokens(size_t start, size_t stop, size_t ttype) {
std::vector<size_t> s;
s.push_back(ttype);
return getTokens(start, stop, s);
}
ssize_t BufferedTokenStream::nextTokenOnChannel(size_t i, size_t channel) {
sync(i);
if (i >= size()) {
return size() - 1;
}
Token *token = _tokens[i].get();
while (token->getChannel() != channel) {
if (token->getType() == Token::EOF) {
return i;
}
i++;
sync(i);
token = _tokens[i].get();
}
return i;
}
ssize_t BufferedTokenStream::previousTokenOnChannel(size_t i, size_t channel) {
sync(i);
if (i >= size()) {
// the EOF token is on every channel
return size() - 1;
}
while (true) {
Token *token = _tokens[i].get();
if (token->getType() == Token::EOF || token->getChannel() == channel) {
return i;
}
if (i == 0)
return -1;
i--;
}
return i;
}
std::vector<Token *> BufferedTokenStream::getHiddenTokensToRight(size_t tokenIndex, ssize_t channel) {
lazyInit();
if (tokenIndex >= _tokens.size()) {
throw IndexOutOfBoundsException(std::to_string(tokenIndex) + " not in 0.." + std::to_string(_tokens.size() - 1));
}
ssize_t nextOnChannel = nextTokenOnChannel(tokenIndex + 1, Lexer::DEFAULT_TOKEN_CHANNEL);
size_t to;
size_t from = tokenIndex + 1;
// if none onchannel to right, nextOnChannel=-1 so set to = last token
if (nextOnChannel == -1) {
to = static_cast<ssize_t>(size() - 1);
} else {
to = nextOnChannel;
}
return filterForChannel(from, to, channel);
}
std::vector<Token *> BufferedTokenStream::getHiddenTokensToRight(size_t tokenIndex) {
return getHiddenTokensToRight(tokenIndex, -1);
}
std::vector<Token *> BufferedTokenStream::getHiddenTokensToLeft(size_t tokenIndex, ssize_t channel) {
lazyInit();
if (tokenIndex >= _tokens.size()) {
throw IndexOutOfBoundsException(std::to_string(tokenIndex) + " not in 0.." + std::to_string(_tokens.size() - 1));
}
if (tokenIndex == 0) {
// Obviously no tokens can appear before the first token.
return { };
}
ssize_t prevOnChannel = previousTokenOnChannel(tokenIndex - 1, Lexer::DEFAULT_TOKEN_CHANNEL);
if (prevOnChannel == static_cast<ssize_t>(tokenIndex - 1)) {
return { };
}
// if none onchannel to left, prevOnChannel=-1 then from=0
size_t from = static_cast<size_t>(prevOnChannel + 1);
size_t to = tokenIndex - 1;
return filterForChannel(from, to, channel);
}
std::vector<Token *> BufferedTokenStream::getHiddenTokensToLeft(size_t tokenIndex) {
return getHiddenTokensToLeft(tokenIndex, -1);
}
std::vector<Token *> BufferedTokenStream::filterForChannel(size_t from, size_t to, ssize_t channel) {
std::vector<Token *> hidden;
for (size_t i = from; i <= to; i++) {
Token *t = _tokens[i].get();
if (channel == -1) {
if (t->getChannel() != Lexer::DEFAULT_TOKEN_CHANNEL) {
hidden.push_back(t);
}
} else {
if (t->getChannel() == static_cast<size_t>(channel)) {
hidden.push_back(t);
}
}
}
return hidden;
}
bool BufferedTokenStream::isInitialized() const {
return !_needSetup;
}
/**
* Get the text of all tokens in this buffer.
*/
std::string BufferedTokenStream::getSourceName() const
{
return _tokenSource->getSourceName();
}
std::string BufferedTokenStream::getText() {
fill();
return getText(misc::Interval(0U, size() - 1));
}
std::string BufferedTokenStream::getText(const misc::Interval &interval) {
lazyInit();
size_t start = interval.a;
size_t stop = interval.b;
if (start == INVALID_INDEX || stop == INVALID_INDEX) {
return "";
}
sync(stop);
if (stop >= _tokens.size()) {
stop = _tokens.size() - 1;
}
std::stringstream ss;
for (size_t i = start; i <= stop; i++) {
Token *t = _tokens[i].get();
if (t->getType() == Token::EOF) {
break;
}
ss << t->getText();
}
return ss.str();
}
std::string BufferedTokenStream::getText(RuleContext *ctx) {
return getText(ctx->getSourceInterval());
}
std::string BufferedTokenStream::getText(Token *start, Token *stop) {
if (start != nullptr && stop != nullptr) {
return getText(misc::Interval(start->getTokenIndex(), stop->getTokenIndex()));
}
return "";
}
void BufferedTokenStream::fill() {
lazyInit();
const size_t blockSize = 1000;
while (true) {
size_t fetched = fetch(blockSize);
if (fetched < blockSize) {
return;
}
}
}
void BufferedTokenStream::InitializeInstanceFields() {
_needSetup = true;
_fetchedEOF = false;
}

View File

@@ -0,0 +1,200 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "TokenStream.h"
namespace antlr4 {
/**
* This implementation of {@link TokenStream} loads tokens from a
* {@link TokenSource} on-demand, and places the tokens in a buffer to provide
* access to any previous token by index.
*
* <p>
* This token stream ignores the value of {@link Token#getChannel}. If your
* parser requires the token stream filter tokens to only those on a particular
* channel, such as {@link Token#DEFAULT_CHANNEL} or
* {@link Token#HIDDEN_CHANNEL}, use a filtering token stream such a
* {@link CommonTokenStream}.</p>
*/
class ANTLR4CPP_PUBLIC BufferedTokenStream : public TokenStream {
public:
BufferedTokenStream(TokenSource *tokenSource);
BufferedTokenStream(const BufferedTokenStream& other) = delete;
BufferedTokenStream& operator = (const BufferedTokenStream& other) = delete;
virtual TokenSource* getTokenSource() const override;
virtual size_t index() override;
virtual ssize_t mark() override;
virtual void release(ssize_t marker) override;
virtual void reset();
virtual void seek(size_t index) override;
virtual size_t size() override;
virtual void consume() override;
virtual Token* get(size_t i) const override;
/// Get all tokens from start..stop inclusively.
virtual std::vector<Token *> get(size_t start, size_t stop);
virtual size_t LA(ssize_t i) override;
virtual Token* LT(ssize_t k) override;
/// Reset this token stream by setting its token source.
virtual void setTokenSource(TokenSource *tokenSource);
virtual std::vector<Token *> getTokens();
virtual std::vector<Token *> getTokens(size_t start, size_t stop);
/// <summary>
/// Given a start and stop index, return a List of all tokens in
/// the token type BitSet. Return null if no tokens were found. This
/// method looks at both on and off channel tokens.
/// </summary>
virtual std::vector<Token *> getTokens(size_t start, size_t stop, const std::vector<size_t> &types);
virtual std::vector<Token *> getTokens(size_t start, size_t stop, size_t ttype);
/// Collect all tokens on specified channel to the right of
/// the current token up until we see a token on DEFAULT_TOKEN_CHANNEL or
/// EOF. If channel is -1, find any non default channel token.
virtual std::vector<Token *> getHiddenTokensToRight(size_t tokenIndex, ssize_t channel);
/// <summary>
/// Collect all hidden tokens (any off-default channel) to the right of
/// the current token up until we see a token on DEFAULT_TOKEN_CHANNEL
/// or EOF.
/// </summary>
virtual std::vector<Token *> getHiddenTokensToRight(size_t tokenIndex);
/// <summary>
/// Collect all tokens on specified channel to the left of
/// the current token up until we see a token on DEFAULT_TOKEN_CHANNEL.
/// If channel is -1, find any non default channel token.
/// </summary>
virtual std::vector<Token *> getHiddenTokensToLeft(size_t tokenIndex, ssize_t channel);
/// <summary>
/// Collect all hidden tokens (any off-default channel) to the left of
/// the current token up until we see a token on DEFAULT_TOKEN_CHANNEL.
/// </summary>
virtual std::vector<Token *> getHiddenTokensToLeft(size_t tokenIndex);
virtual std::string getSourceName() const override;
virtual std::string getText() override;
virtual std::string getText(const misc::Interval &interval) override;
virtual std::string getText(RuleContext *ctx) override;
virtual std::string getText(Token *start, Token *stop) override;
/// Get all tokens from lexer until EOF.
virtual void fill();
protected:
/**
* The {@link TokenSource} from which tokens for this stream are fetched.
*/
TokenSource *_tokenSource;
/**
* A collection of all tokens fetched from the token source. The list is
* considered a complete view of the input once {@link #fetchedEOF} is set
* to {@code true}.
*/
std::vector<std::unique_ptr<Token>> _tokens;
/**
* The index into {@link #tokens} of the current token (next token to
* {@link #consume}). {@link #tokens}{@code [}{@link #p}{@code ]} should be
* {@link #LT LT(1)}.
*
* <p>This field is set to -1 when the stream is first constructed or when
* {@link #setTokenSource} is called, indicating that the first token has
* not yet been fetched from the token source. For additional information,
* see the documentation of {@link IntStream} for a description of
* Initializing Methods.</p>
*/
// ml: since -1 requires to make this member signed for just this single aspect we use a member _needSetup instead.
// Use bool isInitialized() to find out if this stream has started reading.
size_t _p;
/**
* Indicates whether the {@link Token#EOF} token has been fetched from
* {@link #tokenSource} and added to {@link #tokens}. This field improves
* performance for the following cases:
*
* <ul>
* <li>{@link #consume}: The lookahead check in {@link #consume} to prevent
* consuming the EOF symbol is optimized by checking the values of
* {@link #fetchedEOF} and {@link #p} instead of calling {@link #LA}.</li>
* <li>{@link #fetch}: The check to prevent adding multiple EOF symbols into
* {@link #tokens} is trivial with this field.</li>
* <ul>
*/
bool _fetchedEOF;
/// <summary>
/// Make sure index {@code i} in tokens has a token.
/// </summary>
/// <returns> {@code true} if a token is located at index {@code i}, otherwise
/// {@code false}. </returns>
/// <seealso cref= #get(int i) </seealso>
virtual bool sync(size_t i);
/// <summary>
/// Add {@code n} elements to buffer.
/// </summary>
/// <returns> The actual number of elements added to the buffer. </returns>
virtual size_t fetch(size_t n);
virtual Token* LB(size_t k);
/// Allowed derived classes to modify the behavior of operations which change
/// the current stream position by adjusting the target token index of a seek
/// operation. The default implementation simply returns {@code i}. If an
/// exception is thrown in this method, the current stream index should not be
/// changed.
/// <p/>
/// For example, <seealso cref="CommonTokenStream"/> overrides this method to ensure that
/// the seek target is always an on-channel token.
///
/// <param name="i"> The target token index. </param>
/// <returns> The adjusted target token index. </returns>
virtual ssize_t adjustSeekIndex(size_t i);
void lazyInit();
virtual void setup();
/**
* Given a starting index, return the index of the next token on channel.
* Return {@code i} if {@code tokens[i]} is on channel. Return the index of
* the EOF token if there are no tokens on channel between {@code i} and
* EOF.
*/
virtual ssize_t nextTokenOnChannel(size_t i, size_t channel);
/**
* Given a starting index, return the index of the previous token on
* channel. Return {@code i} if {@code tokens[i]} is on channel. Return -1
* if there are no tokens on channel between {@code i} and 0.
*
* <p>
* If {@code i} specifies an index at or after the EOF token, the EOF token
* index is returned. This is due to the fact that the EOF token is treated
* as though it were on every channel.</p>
*/
virtual ssize_t previousTokenOnChannel(size_t i, size_t channel);
virtual std::vector<Token *> filterForChannel(size_t from, size_t to, ssize_t channel);
bool isInitialized() const;
private:
bool _needSetup;
void InitializeInstanceFields();
};
} // namespace antlr4

View File

@@ -0,0 +1,11 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "CharStream.h"
using namespace antlr4;
CharStream::~CharStream() {
}

View File

@@ -0,0 +1,37 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "IntStream.h"
#include "misc/Interval.h"
namespace antlr4 {
/// A source of characters for an ANTLR lexer.
class ANTLR4CPP_PUBLIC CharStream : public IntStream {
public:
virtual ~CharStream();
/// This method returns the text for a range of characters within this input
/// stream. This method is guaranteed to not throw an exception if the
/// specified interval lies entirely within a marked range. For more
/// information about marked ranges, see IntStream::mark.
///
/// <param name="interval"> an interval within the stream </param>
/// <returns> the text of the specified interval
/// </returns>
/// <exception cref="NullPointerException"> if {@code interval} is {@code null} </exception>
/// <exception cref="IllegalArgumentException"> if {@code interval.a < 0}, or if
/// {@code interval.b < interval.a - 1}, or if {@code interval.b} lies at or
/// past the end of the stream </exception>
/// <exception cref="UnsupportedOperationException"> if the stream does not support
/// getting the text of the specified interval </exception>
virtual std::string getText(const misc::Interval &interval) = 0;
virtual std::string toString() const = 0;
};
} // namespace antlr4

View File

@@ -0,0 +1,193 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "TokenSource.h"
#include "CharStream.h"
#include "Recognizer.h"
#include "Vocabulary.h"
#include "misc/Interval.h"
#include "support/CPPUtils.h"
#include "support/StringUtils.h"
#include "CommonToken.h"
using namespace antlr4;
using namespace antlr4::misc;
using namespace antlrcpp;
const std::pair<TokenSource*, CharStream*> CommonToken::EMPTY_SOURCE;
CommonToken::CommonToken(size_t type) {
InitializeInstanceFields();
_type = type;
}
CommonToken::CommonToken(std::pair<TokenSource*, CharStream*> source, size_t type, size_t channel, size_t start, size_t stop) {
InitializeInstanceFields();
_source = source;
_type = type;
_channel = channel;
_start = start;
_stop = stop;
if (_source.first != nullptr) {
_line = static_cast<int>(source.first->getLine());
_charPositionInLine = source.first->getCharPositionInLine();
}
}
CommonToken::CommonToken(size_t type, const std::string &text) {
InitializeInstanceFields();
_type = type;
_channel = DEFAULT_CHANNEL;
_text = text;
_source = EMPTY_SOURCE;
}
CommonToken::CommonToken(Token *oldToken) {
InitializeInstanceFields();
_type = oldToken->getType();
_line = oldToken->getLine();
_index = oldToken->getTokenIndex();
_charPositionInLine = oldToken->getCharPositionInLine();
_channel = oldToken->getChannel();
_start = oldToken->getStartIndex();
_stop = oldToken->getStopIndex();
if (is<CommonToken *>(oldToken)) {
_text = (static_cast<CommonToken *>(oldToken))->_text;
_source = (static_cast<CommonToken *>(oldToken))->_source;
} else {
_text = oldToken->getText();
_source = { oldToken->getTokenSource(), oldToken->getInputStream() };
}
}
size_t CommonToken::getType() const {
return _type;
}
void CommonToken::setLine(size_t line) {
_line = line;
}
std::string CommonToken::getText() const {
if (!_text.empty()) {
return _text;
}
CharStream *input = getInputStream();
if (input == nullptr) {
return "";
}
size_t n = input->size();
if (_start < n && _stop < n) {
return input->getText(misc::Interval(_start, _stop));
} else {
return "<EOF>";
}
}
void CommonToken::setText(const std::string &text) {
_text = text;
}
size_t CommonToken::getLine() const {
return _line;
}
size_t CommonToken::getCharPositionInLine() const {
return _charPositionInLine;
}
void CommonToken::setCharPositionInLine(size_t charPositionInLine) {
_charPositionInLine = charPositionInLine;
}
size_t CommonToken::getChannel() const {
return _channel;
}
void CommonToken::setChannel(size_t channel) {
_channel = channel;
}
void CommonToken::setType(size_t type) {
_type = type;
}
size_t CommonToken::getStartIndex() const {
return _start;
}
void CommonToken::setStartIndex(size_t start) {
_start = start;
}
size_t CommonToken::getStopIndex() const {
return _stop;
}
void CommonToken::setStopIndex(size_t stop) {
_stop = stop;
}
size_t CommonToken::getTokenIndex() const {
return _index;
}
void CommonToken::setTokenIndex(size_t index) {
_index = index;
}
antlr4::TokenSource *CommonToken::getTokenSource() const {
return _source.first;
}
antlr4::CharStream *CommonToken::getInputStream() const {
return _source.second;
}
std::string CommonToken::toString() const {
return toString(nullptr);
}
std::string CommonToken::toString(Recognizer *r) const {
std::stringstream ss;
std::string channelStr;
if (_channel > 0) {
channelStr = ",channel=" + std::to_string(_channel);
}
std::string txt = getText();
if (!txt.empty()) {
txt = antlrcpp::escapeWhitespace(txt);
} else {
txt = "<no text>";
}
std::string typeString = std::to_string(symbolToNumeric(_type));
if (r != nullptr)
typeString = r->getVocabulary().getDisplayName(_type);
ss << "[@" << symbolToNumeric(getTokenIndex()) << "," << symbolToNumeric(_start) << ":" << symbolToNumeric(_stop)
<< "='" << txt << "',<" << typeString << ">" << channelStr << "," << _line << ":"
<< getCharPositionInLine() << "]";
return ss.str();
}
void CommonToken::InitializeInstanceFields() {
_type = 0;
_line = 0;
_charPositionInLine = INVALID_INDEX;
_channel = DEFAULT_CHANNEL;
_index = INVALID_INDEX;
_start = 0;
_stop = 0;
_source = EMPTY_SOURCE;
}

View File

@@ -0,0 +1,158 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "WritableToken.h"
namespace antlr4 {
class ANTLR4CPP_PUBLIC CommonToken : public WritableToken {
protected:
/**
* An empty {@link Pair} which is used as the default value of
* {@link #source} for tokens that do not have a source.
*/
static const std::pair<TokenSource *, CharStream *> EMPTY_SOURCE;
/**
* This is the backing field for {@link #getType} and {@link #setType}.
*/
size_t _type;
/**
* This is the backing field for {@link #getLine} and {@link #setLine}.
*/
size_t _line;
/**
* This is the backing field for {@link #getCharPositionInLine} and
* {@link #setCharPositionInLine}.
*/
size_t _charPositionInLine; // set to invalid position
/**
* This is the backing field for {@link #getChannel} and
* {@link #setChannel}.
*/
size_t _channel;
/**
* This is the backing field for {@link #getTokenSource} and
* {@link #getInputStream}.
*
* <p>
* These properties share a field to reduce the memory footprint of
* {@link CommonToken}. Tokens created by a {@link CommonTokenFactory} from
* the same source and input stream share a reference to the same
* {@link Pair} containing these values.</p>
*/
std::pair<TokenSource *, CharStream *> _source; // ml: pure references, usually from statically allocated classes.
/**
* This is the backing field for {@link #getText} when the token text is
* explicitly set in the constructor or via {@link #setText}.
*
* @see #getText()
*/
std::string _text;
/**
* This is the backing field for {@link #getTokenIndex} and
* {@link #setTokenIndex}.
*/
size_t _index;
/**
* This is the backing field for {@link #getStartIndex} and
* {@link #setStartIndex}.
*/
size_t _start;
/**
* This is the backing field for {@link #getStopIndex} and
* {@link #setStopIndex}.
*/
size_t _stop;
public:
/**
* Constructs a new {@link CommonToken} with the specified token type.
*
* @param type The token type.
*/
CommonToken(size_t type);
CommonToken(std::pair<TokenSource*, CharStream*> source, size_t type, size_t channel, size_t start, size_t stop);
/**
* Constructs a new {@link CommonToken} with the specified token type and
* text.
*
* @param type The token type.
* @param text The text of the token.
*/
CommonToken(size_t type, const std::string &text);
/**
* Constructs a new {@link CommonToken} as a copy of another {@link Token}.
*
* <p>
* If {@code oldToken} is also a {@link CommonToken} instance, the newly
* constructed token will share a reference to the {@link #text} field and
* the {@link Pair} stored in {@link #source}. Otherwise, {@link #text} will
* be assigned the result of calling {@link #getText}, and {@link #source}
* will be constructed from the result of {@link Token#getTokenSource} and
* {@link Token#getInputStream}.</p>
*
* @param oldToken The token to copy.
*/
CommonToken(Token *oldToken);
virtual size_t getType() const override;
/**
* Explicitly set the text for this token. If {code text} is not
* {@code null}, then {@link #getText} will return this value rather than
* extracting the text from the input.
*
* @param text The explicit text of the token, or {@code null} if the text
* should be obtained from the input along with the start and stop indexes
* of the token.
*/
virtual void setText(const std::string &text) override;
virtual std::string getText() const override;
virtual void setLine(size_t line) override;
virtual size_t getLine() const override;
virtual size_t getCharPositionInLine() const override;
virtual void setCharPositionInLine(size_t charPositionInLine) override;
virtual size_t getChannel() const override;
virtual void setChannel(size_t channel) override;
virtual void setType(size_t type) override;
virtual size_t getStartIndex() const override;
virtual void setStartIndex(size_t start);
virtual size_t getStopIndex() const override;
virtual void setStopIndex(size_t stop);
virtual size_t getTokenIndex() const override;
virtual void setTokenIndex(size_t index) override;
virtual TokenSource *getTokenSource() const override;
virtual CharStream *getInputStream() const override;
virtual std::string toString() const override;
virtual std::string toString(Recognizer *r) const;
private:
void InitializeInstanceFields();
};
} // namespace antlr4

View File

@@ -0,0 +1,39 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "misc/Interval.h"
#include "CommonToken.h"
#include "CharStream.h"
#include "CommonTokenFactory.h"
using namespace antlr4;
const std::unique_ptr<TokenFactory<CommonToken>> CommonTokenFactory::DEFAULT(new CommonTokenFactory);
CommonTokenFactory::CommonTokenFactory(bool copyText_) : copyText(copyText_) {
}
CommonTokenFactory::CommonTokenFactory() : CommonTokenFactory(false) {
}
std::unique_ptr<CommonToken> CommonTokenFactory::create(std::pair<TokenSource*, CharStream*> source, size_t type,
const std::string &text, size_t channel, size_t start, size_t stop, size_t line, size_t charPositionInLine) {
std::unique_ptr<CommonToken> t(new CommonToken(source, type, channel, start, stop));
t->setLine(line);
t->setCharPositionInLine(charPositionInLine);
if (text != "") {
t->setText(text);
} else if (copyText && source.second != nullptr) {
t->setText(source.second->getText(misc::Interval(start, stop)));
}
return t;
}
std::unique_ptr<CommonToken> CommonTokenFactory::create(size_t type, const std::string &text) {
return std::unique_ptr<CommonToken>(new CommonToken(type, text));
}

View File

@@ -0,0 +1,74 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "TokenFactory.h"
namespace antlr4 {
/**
* This default implementation of {@link TokenFactory} creates
* {@link CommonToken} objects.
*/
class ANTLR4CPP_PUBLIC CommonTokenFactory : public TokenFactory<CommonToken> {
public:
/**
* The default {@link CommonTokenFactory} instance.
*
* <p>
* This token factory does not explicitly copy token text when constructing
* tokens.</p>
*/
static const std::unique_ptr<TokenFactory<CommonToken>> DEFAULT;
protected:
/**
* Indicates whether {@link CommonToken#setText} should be called after
* constructing tokens to explicitly set the text. This is useful for cases
* where the input stream might not be able to provide arbitrary substrings
* of text from the input after the lexer creates a token (e.g. the
* implementation of {@link CharStream#getText} in
* {@link UnbufferedCharStream} throws an
* {@link UnsupportedOperationException}). Explicitly setting the token text
* allows {@link Token#getText} to be called at any time regardless of the
* input stream implementation.
*
* <p>
* The default value is {@code false} to avoid the performance and memory
* overhead of copying text for every token unless explicitly requested.</p>
*/
const bool copyText;
public:
/**
* Constructs a {@link CommonTokenFactory} with the specified value for
* {@link #copyText}.
*
* <p>
* When {@code copyText} is {@code false}, the {@link #DEFAULT} instance
* should be used instead of constructing a new instance.</p>
*
* @param copyText The value for {@link #copyText}.
*/
CommonTokenFactory(bool copyText);
/**
* Constructs a {@link CommonTokenFactory} with {@link #copyText} set to
* {@code false}.
*
* <p>
* The {@link #DEFAULT} instance should be used instead of calling this
* directly.</p>
*/
CommonTokenFactory();
virtual std::unique_ptr<CommonToken> create(std::pair<TokenSource*, CharStream*> source, size_t type,
const std::string &text, size_t channel, size_t start, size_t stop, size_t line, size_t charPositionInLine) override;
virtual std::unique_ptr<CommonToken> create(size_t type, const std::string &text) override;
};
} // namespace antlr4

View File

@@ -0,0 +1,78 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "Token.h"
#include "CommonTokenStream.h"
using namespace antlr4;
CommonTokenStream::CommonTokenStream(TokenSource *tokenSource) : CommonTokenStream(tokenSource, Token::DEFAULT_CHANNEL) {
}
CommonTokenStream::CommonTokenStream(TokenSource *tokenSource, size_t channel_)
: BufferedTokenStream(tokenSource), channel(channel_) {
}
ssize_t CommonTokenStream::adjustSeekIndex(size_t i) {
return nextTokenOnChannel(i, channel);
}
Token* CommonTokenStream::LB(size_t k) {
if (k == 0 || k > _p) {
return nullptr;
}
ssize_t i = static_cast<ssize_t>(_p);
size_t n = 1;
// find k good tokens looking backwards
while (n <= k) {
// skip off-channel tokens
i = previousTokenOnChannel(i - 1, channel);
n++;
}
if (i < 0) {
return nullptr;
}
return _tokens[i].get();
}
Token* CommonTokenStream::LT(ssize_t k) {
lazyInit();
if (k == 0) {
return nullptr;
}
if (k < 0) {
return LB(static_cast<size_t>(-k));
}
size_t i = _p;
ssize_t n = 1; // we know tokens[p] is a good one
// find k good tokens
while (n < k) {
// skip off-channel tokens, but make sure to not look past EOF
if (sync(i + 1)) {
i = nextTokenOnChannel(i + 1, channel);
}
n++;
}
return _tokens[i].get();
}
int CommonTokenStream::getNumberOfOnChannelTokens() {
int n = 0;
fill();
for (size_t i = 0; i < _tokens.size(); i++) {
Token *t = _tokens[i].get();
if (t->getChannel() == channel) {
n++;
}
if (t->getType() == Token::EOF) {
break;
}
}
return n;
}

View File

@@ -0,0 +1,79 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "BufferedTokenStream.h"
namespace antlr4 {
/**
* This class extends {@link BufferedTokenStream} with functionality to filter
* token streams to tokens on a particular channel (tokens where
* {@link Token#getChannel} returns a particular value).
*
* <p>
* This token stream provides access to all tokens by index or when calling
* methods like {@link #getText}. The channel filtering is only used for code
* accessing tokens via the lookahead methods {@link #LA}, {@link #LT}, and
* {@link #LB}.</p>
*
* <p>
* By default, tokens are placed on the default channel
* ({@link Token#DEFAULT_CHANNEL}), but may be reassigned by using the
* {@code ->channel(HIDDEN)} lexer command, or by using an embedded action to
* call {@link Lexer#setChannel}.
* </p>
*
* <p>
* Note: lexer rules which use the {@code ->skip} lexer command or call
* {@link Lexer#skip} do not produce tokens at all, so input text matched by
* such a rule will not be available as part of the token stream, regardless of
* channel.</p>
*/
class ANTLR4CPP_PUBLIC CommonTokenStream : public BufferedTokenStream {
public:
/**
* Constructs a new {@link CommonTokenStream} using the specified token
* source and the default token channel ({@link Token#DEFAULT_CHANNEL}).
*
* @param tokenSource The token source.
*/
CommonTokenStream(TokenSource *tokenSource);
/**
* Constructs a new {@link CommonTokenStream} using the specified token
* source and filtering tokens to the specified channel. Only tokens whose
* {@link Token#getChannel} matches {@code channel} or have the
* {@link Token#getType} equal to {@link Token#EOF} will be returned by the
* token stream lookahead methods.
*
* @param tokenSource The token source.
* @param channel The channel to use for filtering tokens.
*/
CommonTokenStream(TokenSource *tokenSource, size_t channel);
virtual Token* LT(ssize_t k) override;
/// Count EOF just once.
virtual int getNumberOfOnChannelTokens();
protected:
/**
* Specifies the channel to use for filtering tokens.
*
* <p>
* The default value is {@link Token#DEFAULT_CHANNEL}, which matches the
* default channel assigned to tokens created by the lexer.</p>
*/
size_t channel;
virtual ssize_t adjustSeekIndex(size_t i) override;
virtual Token* LB(size_t k) override;
};
} // namespace antlr4

View File

@@ -0,0 +1,15 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "ConsoleErrorListener.h"
using namespace antlr4;
ConsoleErrorListener ConsoleErrorListener::INSTANCE;
void ConsoleErrorListener::syntaxError(Recognizer * /*recognizer*/, Token * /*offendingSymbol*/,
size_t line, size_t charPositionInLine, const std::string &msg, std::exception_ptr /*e*/) {
std::cerr << "line " << line << ":" << charPositionInLine << " " << msg << std::endl;
}

View File

@@ -0,0 +1,35 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "BaseErrorListener.h"
namespace antlr4 {
class ANTLR4CPP_PUBLIC ConsoleErrorListener : public BaseErrorListener {
public:
/**
* Provides a default instance of {@link ConsoleErrorListener}.
*/
static ConsoleErrorListener INSTANCE;
/**
* {@inheritDoc}
*
* <p>
* This implementation prints messages to {@link System#err} containing the
* values of {@code line}, {@code charPositionInLine}, and {@code msg} using
* the following format.</p>
*
* <pre>
* line <em>line</em>:<em>charPositionInLine</em> <em>msg</em>
* </pre>
*/
virtual void syntaxError(Recognizer *recognizer, Token * offendingSymbol, size_t line, size_t charPositionInLine,
const std::string &msg, std::exception_ptr e) override;
};
} // namespace antlr4

View File

@@ -0,0 +1,336 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "NoViableAltException.h"
#include "misc/IntervalSet.h"
#include "atn/ParserATNSimulator.h"
#include "InputMismatchException.h"
#include "FailedPredicateException.h"
#include "ParserRuleContext.h"
#include "atn/RuleTransition.h"
#include "atn/ATN.h"
#include "atn/ATNState.h"
#include "support/StringUtils.h"
#include "support/Casts.h"
#include "Parser.h"
#include "CommonToken.h"
#include "Vocabulary.h"
#include "DefaultErrorStrategy.h"
using namespace antlr4;
using namespace antlr4::atn;
using namespace antlrcpp;
DefaultErrorStrategy::DefaultErrorStrategy() {
InitializeInstanceFields();
}
DefaultErrorStrategy::~DefaultErrorStrategy() {
}
void DefaultErrorStrategy::reset(Parser *recognizer) {
_errorSymbols.clear();
endErrorCondition(recognizer);
}
void DefaultErrorStrategy::beginErrorCondition(Parser * /*recognizer*/) {
errorRecoveryMode = true;
}
bool DefaultErrorStrategy::inErrorRecoveryMode(Parser * /*recognizer*/) {
return errorRecoveryMode;
}
void DefaultErrorStrategy::endErrorCondition(Parser * /*recognizer*/) {
errorRecoveryMode = false;
lastErrorIndex = -1;
}
void DefaultErrorStrategy::reportMatch(Parser *recognizer) {
endErrorCondition(recognizer);
}
void DefaultErrorStrategy::reportError(Parser *recognizer, const RecognitionException &e) {
// If we've already reported an error and have not matched a token
// yet successfully, don't report any errors.
if (inErrorRecoveryMode(recognizer)) {
return; // don't report spurious errors
}
beginErrorCondition(recognizer);
if (is<const NoViableAltException *>(&e)) {
reportNoViableAlternative(recognizer, static_cast<const NoViableAltException &>(e));
} else if (is<const InputMismatchException *>(&e)) {
reportInputMismatch(recognizer, static_cast<const InputMismatchException &>(e));
} else if (is<const FailedPredicateException *>(&e)) {
reportFailedPredicate(recognizer, static_cast<const FailedPredicateException &>(e));
} else if (is<const RecognitionException *>(&e)) {
recognizer->notifyErrorListeners(e.getOffendingToken(), e.what(), std::current_exception());
}
}
void DefaultErrorStrategy::recover(Parser *recognizer, std::exception_ptr /*e*/) {
if (lastErrorIndex == static_cast<int>(recognizer->getInputStream()->index()) &&
lastErrorStates.contains(recognizer->getState())) {
// uh oh, another error at same token index and previously-visited
// state in ATN; must be a case where LT(1) is in the recovery
// token set so nothing got consumed. Consume a single token
// at least to prevent an infinite loop; this is a failsafe.
recognizer->consume();
}
lastErrorIndex = static_cast<int>(recognizer->getInputStream()->index());
lastErrorStates.add(recognizer->getState());
misc::IntervalSet followSet = getErrorRecoverySet(recognizer);
consumeUntil(recognizer, followSet);
}
void DefaultErrorStrategy::sync(Parser *recognizer) {
atn::ATNState *s = recognizer->getInterpreter<atn::ATNSimulator>()->atn.states[recognizer->getState()];
// If already recovering, don't try to sync
if (inErrorRecoveryMode(recognizer)) {
return;
}
TokenStream *tokens = recognizer->getTokenStream();
size_t la = tokens->LA(1);
// try cheaper subset first; might get lucky. seems to shave a wee bit off
auto nextTokens = recognizer->getATN().nextTokens(s);
if (nextTokens.contains(Token::EPSILON) || nextTokens.contains(la)) {
return;
}
switch (s->getStateType()) {
case atn::ATNStateType::BLOCK_START:
case atn::ATNStateType::STAR_BLOCK_START:
case atn::ATNStateType::PLUS_BLOCK_START:
case atn::ATNStateType::STAR_LOOP_ENTRY:
// report error and recover if possible
if (singleTokenDeletion(recognizer) != nullptr) {
return;
}
throw InputMismatchException(recognizer);
case atn::ATNStateType::PLUS_LOOP_BACK:
case atn::ATNStateType::STAR_LOOP_BACK: {
reportUnwantedToken(recognizer);
misc::IntervalSet expecting = recognizer->getExpectedTokens();
misc::IntervalSet whatFollowsLoopIterationOrRule = expecting.Or(getErrorRecoverySet(recognizer));
consumeUntil(recognizer, whatFollowsLoopIterationOrRule);
}
break;
default:
// do nothing if we can't identify the exact kind of ATN state
break;
}
}
void DefaultErrorStrategy::reportNoViableAlternative(Parser *recognizer, const NoViableAltException &e) {
TokenStream *tokens = recognizer->getTokenStream();
std::string input;
if (tokens != nullptr) {
if (e.getStartToken()->getType() == Token::EOF) {
input = "<EOF>";
} else {
input = tokens->getText(e.getStartToken(), e.getOffendingToken());
}
} else {
input = "<unknown input>";
}
std::string msg = "no viable alternative at input " + escapeWSAndQuote(input);
recognizer->notifyErrorListeners(e.getOffendingToken(), msg, std::make_exception_ptr(e));
}
void DefaultErrorStrategy::reportInputMismatch(Parser *recognizer, const InputMismatchException &e) {
std::string msg = "mismatched input " + getTokenErrorDisplay(e.getOffendingToken()) +
" expecting " + e.getExpectedTokens().toString(recognizer->getVocabulary());
recognizer->notifyErrorListeners(e.getOffendingToken(), msg, std::make_exception_ptr(e));
}
void DefaultErrorStrategy::reportFailedPredicate(Parser *recognizer, const FailedPredicateException &e) {
const std::string& ruleName = recognizer->getRuleNames()[recognizer->getContext()->getRuleIndex()];
std::string msg = "rule " + ruleName + " " + e.what();
recognizer->notifyErrorListeners(e.getOffendingToken(), msg, std::make_exception_ptr(e));
}
void DefaultErrorStrategy::reportUnwantedToken(Parser *recognizer) {
if (inErrorRecoveryMode(recognizer)) {
return;
}
beginErrorCondition(recognizer);
Token *t = recognizer->getCurrentToken();
std::string tokenName = getTokenErrorDisplay(t);
misc::IntervalSet expecting = getExpectedTokens(recognizer);
std::string msg = "extraneous input " + tokenName + " expecting " + expecting.toString(recognizer->getVocabulary());
recognizer->notifyErrorListeners(t, msg, nullptr);
}
void DefaultErrorStrategy::reportMissingToken(Parser *recognizer) {
if (inErrorRecoveryMode(recognizer)) {
return;
}
beginErrorCondition(recognizer);
Token *t = recognizer->getCurrentToken();
misc::IntervalSet expecting = getExpectedTokens(recognizer);
std::string expectedText = expecting.toString(recognizer->getVocabulary());
std::string msg = "missing " + expectedText + " at " + getTokenErrorDisplay(t);
recognizer->notifyErrorListeners(t, msg, nullptr);
}
Token* DefaultErrorStrategy::recoverInline(Parser *recognizer) {
// Single token deletion.
Token *matchedSymbol = singleTokenDeletion(recognizer);
if (matchedSymbol) {
// We have deleted the extra token.
// Now, move past ttype token as if all were ok.
recognizer->consume();
return matchedSymbol;
}
// Single token insertion.
if (singleTokenInsertion(recognizer)) {
return getMissingSymbol(recognizer);
}
// Even that didn't work; must throw the exception.
throw InputMismatchException(recognizer);
}
bool DefaultErrorStrategy::singleTokenInsertion(Parser *recognizer) {
ssize_t currentSymbolType = recognizer->getInputStream()->LA(1);
// if current token is consistent with what could come after current
// ATN state, then we know we're missing a token; error recovery
// is free to conjure up and insert the missing token
atn::ATNState *currentState = recognizer->getInterpreter<atn::ATNSimulator>()->atn.states[recognizer->getState()];
atn::ATNState *next = currentState->transitions[0]->target;
const atn::ATN &atn = recognizer->getInterpreter<atn::ATNSimulator>()->atn;
misc::IntervalSet expectingAtLL2 = atn.nextTokens(next, recognizer->getContext());
if (expectingAtLL2.contains(currentSymbolType)) {
reportMissingToken(recognizer);
return true;
}
return false;
}
Token* DefaultErrorStrategy::singleTokenDeletion(Parser *recognizer) {
size_t nextTokenType = recognizer->getInputStream()->LA(2);
misc::IntervalSet expecting = getExpectedTokens(recognizer);
if (expecting.contains(nextTokenType)) {
reportUnwantedToken(recognizer);
recognizer->consume(); // simply delete extra token
// we want to return the token we're actually matching
Token *matchedSymbol = recognizer->getCurrentToken();
reportMatch(recognizer); // we know current token is correct
return matchedSymbol;
}
return nullptr;
}
Token* DefaultErrorStrategy::getMissingSymbol(Parser *recognizer) {
Token *currentSymbol = recognizer->getCurrentToken();
misc::IntervalSet expecting = getExpectedTokens(recognizer);
size_t expectedTokenType = expecting.getMinElement(); // get any element
std::string tokenText;
if (expectedTokenType == Token::EOF) {
tokenText = "<missing EOF>";
} else {
tokenText = "<missing " + recognizer->getVocabulary().getDisplayName(expectedTokenType) + ">";
}
Token *current = currentSymbol;
Token *lookback = recognizer->getTokenStream()->LT(-1);
if (current->getType() == Token::EOF && lookback != nullptr) {
current = lookback;
}
_errorSymbols.push_back(recognizer->getTokenFactory()->create(
{ current->getTokenSource(), current->getTokenSource()->getInputStream() },
expectedTokenType, tokenText, Token::DEFAULT_CHANNEL, INVALID_INDEX, INVALID_INDEX,
current->getLine(), current->getCharPositionInLine()));
return _errorSymbols.back().get();
}
misc::IntervalSet DefaultErrorStrategy::getExpectedTokens(Parser *recognizer) {
return recognizer->getExpectedTokens();
}
std::string DefaultErrorStrategy::getTokenErrorDisplay(Token *t) {
if (t == nullptr) {
return "<no Token>";
}
std::string s = getSymbolText(t);
if (s == "") {
if (getSymbolType(t) == Token::EOF) {
s = "<EOF>";
} else {
s = "<" + std::to_string(getSymbolType(t)) + ">";
}
}
return escapeWSAndQuote(s);
}
std::string DefaultErrorStrategy::getSymbolText(Token *symbol) {
return symbol->getText();
}
size_t DefaultErrorStrategy::getSymbolType(Token *symbol) {
return symbol->getType();
}
std::string DefaultErrorStrategy::escapeWSAndQuote(const std::string &s) const {
std::string result;
result.reserve(s.size() + 2);
result.push_back('\'');
antlrcpp::escapeWhitespace(result, s);
result.push_back('\'');
result.shrink_to_fit();
return result;
}
misc::IntervalSet DefaultErrorStrategy::getErrorRecoverySet(Parser *recognizer) {
const atn::ATN &atn = recognizer->getInterpreter<atn::ATNSimulator>()->atn;
RuleContext *ctx = recognizer->getContext();
misc::IntervalSet recoverSet;
while (ctx->invokingState != ATNState::INVALID_STATE_NUMBER) {
// compute what follows who invoked us
atn::ATNState *invokingState = atn.states[ctx->invokingState];
const atn::RuleTransition *rt = downCast<const atn::RuleTransition*>(invokingState->transitions[0].get());
misc::IntervalSet follow = atn.nextTokens(rt->followState);
recoverSet.addAll(follow);
if (ctx->parent == nullptr)
break;
ctx = static_cast<RuleContext *>(ctx->parent);
}
recoverSet.remove(Token::EPSILON);
return recoverSet;
}
void DefaultErrorStrategy::consumeUntil(Parser *recognizer, const misc::IntervalSet &set) {
size_t ttype = recognizer->getInputStream()->LA(1);
while (ttype != Token::EOF && !set.contains(ttype)) {
recognizer->consume();
ttype = recognizer->getInputStream()->LA(1);
}
}
void DefaultErrorStrategy::InitializeInstanceFields() {
errorRecoveryMode = false;
lastErrorIndex = -1;
}

View File

@@ -0,0 +1,466 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "ANTLRErrorStrategy.h"
#include "misc/IntervalSet.h"
namespace antlr4 {
/**
* This is the default implementation of {@link ANTLRErrorStrategy} used for
* error reporting and recovery in ANTLR parsers.
*/
class ANTLR4CPP_PUBLIC DefaultErrorStrategy : public ANTLRErrorStrategy {
public:
DefaultErrorStrategy();
DefaultErrorStrategy(DefaultErrorStrategy const& other) = delete;
virtual ~DefaultErrorStrategy();
DefaultErrorStrategy& operator = (DefaultErrorStrategy const& other) = delete;
protected:
/**
* Indicates whether the error strategy is currently "recovering from an
* error". This is used to suppress reporting multiple error messages while
* attempting to recover from a detected syntax error.
*
* @see #inErrorRecoveryMode
*/
bool errorRecoveryMode;
/** The index into the input stream where the last error occurred.
* This is used to prevent infinite loops where an error is found
* but no token is consumed during recovery...another error is found,
* ad nauseum. This is a failsafe mechanism to guarantee that at least
* one token/tree node is consumed for two errors.
*/
int lastErrorIndex;
misc::IntervalSet lastErrorStates;
/// <summary>
/// {@inheritDoc}
/// <p/>
/// The default implementation simply calls <seealso cref="#endErrorCondition"/> to
/// ensure that the handler is not in error recovery mode.
/// </summary>
public:
virtual void reset(Parser *recognizer) override;
/// <summary>
/// This method is called to enter error recovery mode when a recognition
/// exception is reported.
/// </summary>
/// <param name="recognizer"> the parser instance </param>
protected:
virtual void beginErrorCondition(Parser *recognizer);
/// <summary>
/// {@inheritDoc}
/// </summary>
public:
virtual bool inErrorRecoveryMode(Parser *recognizer) override;
/// <summary>
/// This method is called to leave error recovery mode after recovering from
/// a recognition exception.
/// </summary>
/// <param name="recognizer"> </param>
protected:
virtual void endErrorCondition(Parser *recognizer);
/// <summary>
/// {@inheritDoc}
/// <p/>
/// The default implementation simply calls <seealso cref="#endErrorCondition"/>.
/// </summary>
public:
virtual void reportMatch(Parser *recognizer) override;
/// {@inheritDoc}
/// <p/>
/// The default implementation returns immediately if the handler is already
/// in error recovery mode. Otherwise, it calls <seealso cref="#beginErrorCondition"/>
/// and dispatches the reporting task based on the runtime type of {@code e}
/// according to the following table.
///
/// <ul>
/// <li><seealso cref="NoViableAltException"/>: Dispatches the call to
/// <seealso cref="#reportNoViableAlternative"/></li>
/// <li><seealso cref="InputMismatchException"/>: Dispatches the call to
/// <seealso cref="#reportInputMismatch"/></li>
/// <li><seealso cref="FailedPredicateException"/>: Dispatches the call to
/// <seealso cref="#reportFailedPredicate"/></li>
/// <li>All other types: calls <seealso cref="Parser#notifyErrorListeners"/> to report
/// the exception</li>
/// </ul>
virtual void reportError(Parser *recognizer, const RecognitionException &e) override;
/// <summary>
/// {@inheritDoc}
/// <p/>
/// The default implementation resynchronizes the parser by consuming tokens
/// until we find one in the resynchronization set--loosely the set of tokens
/// that can follow the current rule.
/// </summary>
virtual void recover(Parser *recognizer, std::exception_ptr e) override;
/**
* The default implementation of {@link ANTLRErrorStrategy#sync} makes sure
* that the current lookahead symbol is consistent with what were expecting
* at this point in the ATN. You can call this anytime but ANTLR only
* generates code to check before subrules/loops and each iteration.
*
* <p>Implements Jim Idle's magic sync mechanism in closures and optional
* subrules. E.g.,</p>
*
* <pre>
* a : sync ( stuff sync )* ;
* sync : {consume to what can follow sync} ;
* </pre>
*
* At the start of a sub rule upon error, {@link #sync} performs single
* token deletion, if possible. If it can't do that, it bails on the current
* rule and uses the default error recovery, which consumes until the
* resynchronization set of the current rule.
*
* <p>If the sub rule is optional ({@code (...)?}, {@code (...)*}, or block
* with an empty alternative), then the expected set includes what follows
* the subrule.</p>
*
* <p>During loop iteration, it consumes until it sees a token that can start a
* sub rule or what follows loop. Yes, that is pretty aggressive. We opt to
* stay in the loop as long as possible.</p>
*
* <p><strong>ORIGINS</strong></p>
*
* <p>Previous versions of ANTLR did a poor job of their recovery within loops.
* A single mismatch token or missing token would force the parser to bail
* out of the entire rules surrounding the loop. So, for rule</p>
*
* <pre>
* classDef : 'class' ID '{' member* '}'
* </pre>
*
* input with an extra token between members would force the parser to
* consume until it found the next class definition rather than the next
* member definition of the current class.
*
* <p>This functionality cost a little bit of effort because the parser has to
* compare token set at the start of the loop and at each iteration. If for
* some reason speed is suffering for you, you can turn off this
* functionality by simply overriding this method as a blank { }.</p>
*/
virtual void sync(Parser *recognizer) override;
/// <summary>
/// This is called by <seealso cref="#reportError"/> when the exception is a
/// <seealso cref="NoViableAltException"/>.
/// </summary>
/// <seealso cref= #reportError
/// </seealso>
/// <param name="recognizer"> the parser instance </param>
/// <param name="e"> the recognition exception </param>
protected:
virtual void reportNoViableAlternative(Parser *recognizer, const NoViableAltException &e);
/// <summary>
/// This is called by <seealso cref="#reportError"/> when the exception is an
/// <seealso cref="InputMismatchException"/>.
/// </summary>
/// <seealso cref= #reportError
/// </seealso>
/// <param name="recognizer"> the parser instance </param>
/// <param name="e"> the recognition exception </param>
virtual void reportInputMismatch(Parser *recognizer, const InputMismatchException &e);
/// <summary>
/// This is called by <seealso cref="#reportError"/> when the exception is a
/// <seealso cref="FailedPredicateException"/>.
/// </summary>
/// <seealso cref= #reportError
/// </seealso>
/// <param name="recognizer"> the parser instance </param>
/// <param name="e"> the recognition exception </param>
virtual void reportFailedPredicate(Parser *recognizer, const FailedPredicateException &e);
/**
* This method is called to report a syntax error which requires the removal
* of a token from the input stream. At the time this method is called, the
* erroneous symbol is current {@code LT(1)} symbol and has not yet been
* removed from the input stream. When this method returns,
* {@code recognizer} is in error recovery mode.
*
* <p>This method is called when {@link #singleTokenDeletion} identifies
* single-token deletion as a viable recovery strategy for a mismatched
* input error.</p>
*
* <p>The default implementation simply returns if the handler is already in
* error recovery mode. Otherwise, it calls {@link #beginErrorCondition} to
* enter error recovery mode, followed by calling
* {@link Parser#notifyErrorListeners}.</p>
*
* @param recognizer the parser instance
*/
virtual void reportUnwantedToken(Parser *recognizer);
/**
* This method is called to report a syntax error which requires the
* insertion of a missing token into the input stream. At the time this
* method is called, the missing token has not yet been inserted. When this
* method returns, {@code recognizer} is in error recovery mode.
*
* <p>This method is called when {@link #singleTokenInsertion} identifies
* single-token insertion as a viable recovery strategy for a mismatched
* input error.</p>
*
* <p>The default implementation simply returns if the handler is already in
* error recovery mode. Otherwise, it calls {@link #beginErrorCondition} to
* enter error recovery mode, followed by calling
* {@link Parser#notifyErrorListeners}.</p>
*
* @param recognizer the parser instance
*/
virtual void reportMissingToken(Parser *recognizer);
public:
/**
* {@inheritDoc}
*
* <p>The default implementation attempts to recover from the mismatched input
* by using single token insertion and deletion as described below. If the
* recovery attempt fails, this method throws an
* {@link InputMismatchException}.</p>
*
* <p><strong>EXTRA TOKEN</strong> (single token deletion)</p>
*
* <p>{@code LA(1)} is not what we are looking for. If {@code LA(2)} has the
* right token, however, then assume {@code LA(1)} is some extra spurious
* token and delete it. Then consume and return the next token (which was
* the {@code LA(2)} token) as the successful result of the match operation.</p>
*
* <p>This recovery strategy is implemented by {@link #singleTokenDeletion}.</p>
*
* <p><strong>MISSING TOKEN</strong> (single token insertion)</p>
*
* <p>If current token (at {@code LA(1)}) is consistent with what could come
* after the expected {@code LA(1)} token, then assume the token is missing
* and use the parser's {@link TokenFactory} to create it on the fly. The
* "insertion" is performed by returning the created token as the successful
* result of the match operation.</p>
*
* <p>This recovery strategy is implemented by {@link #singleTokenInsertion}.</p>
*
* <p><strong>EXAMPLE</strong></p>
*
* <p>For example, Input {@code i=(3;} is clearly missing the {@code ')'}. When
* the parser returns from the nested call to {@code expr}, it will have
* call chain:</p>
*
* <pre>
* stat &rarr; expr &rarr; atom
* </pre>
*
* and it will be trying to match the {@code ')'} at this point in the
* derivation:
*
* <pre>
* =&gt; ID '=' '(' INT ')' ('+' atom)* ';'
* ^
* </pre>
*
* The attempt to match {@code ')'} will fail when it sees {@code ';'} and
* call {@link #recoverInline}. To recover, it sees that {@code LA(1)==';'}
* is in the set of tokens that can follow the {@code ')'} token reference
* in rule {@code atom}. It can assume that you forgot the {@code ')'}.
*/
virtual Token* recoverInline(Parser *recognizer) override;
/// <summary>
/// This method implements the single-token insertion inline error recovery
/// strategy. It is called by <seealso cref="#recoverInline"/> if the single-token
/// deletion strategy fails to recover from the mismatched input. If this
/// method returns {@code true}, {@code recognizer} will be in error recovery
/// mode.
/// <p/>
/// This method determines whether or not single-token insertion is viable by
/// checking if the {@code LA(1)} input symbol could be successfully matched
/// if it were instead the {@code LA(2)} symbol. If this method returns
/// {@code true}, the caller is responsible for creating and inserting a
/// token with the correct type to produce this behavior.
/// </summary>
/// <param name="recognizer"> the parser instance </param>
/// <returns> {@code true} if single-token insertion is a viable recovery
/// strategy for the current mismatched input, otherwise {@code false} </returns>
protected:
virtual bool singleTokenInsertion(Parser *recognizer);
/// <summary>
/// This method implements the single-token deletion inline error recovery
/// strategy. It is called by <seealso cref="#recoverInline"/> to attempt to recover
/// from mismatched input. If this method returns null, the parser and error
/// handler state will not have changed. If this method returns non-null,
/// {@code recognizer} will <em>not</em> be in error recovery mode since the
/// returned token was a successful match.
/// <p/>
/// If the single-token deletion is successful, this method calls
/// <seealso cref="#reportUnwantedToken"/> to report the error, followed by
/// <seealso cref="Parser#consume"/> to actually "delete" the extraneous token. Then,
/// before returning <seealso cref="#reportMatch"/> is called to signal a successful
/// match.
/// </summary>
/// <param name="recognizer"> the parser instance </param>
/// <returns> the successfully matched <seealso cref="Token"/> instance if single-token
/// deletion successfully recovers from the mismatched input, otherwise
/// {@code null} </returns>
virtual Token* singleTokenDeletion(Parser *recognizer);
/// <summary>
/// Conjure up a missing token during error recovery.
///
/// The recognizer attempts to recover from single missing
/// symbols. But, actions might refer to that missing symbol.
/// For example, x=ID {f($x);}. The action clearly assumes
/// that there has been an identifier matched previously and that
/// $x points at that token. If that token is missing, but
/// the next token in the stream is what we want we assume that
/// this token is missing and we keep going. Because we
/// have to return some token to replace the missing token,
/// we have to conjure one up. This method gives the user control
/// over the tokens returned for missing tokens. Mostly,
/// you will want to create something special for identifier
/// tokens. For literals such as '{' and ',', the default
/// action in the parser or tree parser works. It simply creates
/// a CommonToken of the appropriate type. The text will be the token.
/// If you change what tokens must be created by the lexer,
/// override this method to create the appropriate tokens.
/// </summary>
virtual Token* getMissingSymbol(Parser *recognizer);
virtual misc::IntervalSet getExpectedTokens(Parser *recognizer);
/// <summary>
/// How should a token be displayed in an error message? The default
/// is to display just the text, but during development you might
/// want to have a lot of information spit out. Override in that case
/// to use t.toString() (which, for CommonToken, dumps everything about
/// the token). This is better than forcing you to override a method in
/// your token objects because you don't have to go modify your lexer
/// so that it creates a new class.
/// </summary>
virtual std::string getTokenErrorDisplay(Token *t);
virtual std::string getSymbolText(Token *symbol);
virtual size_t getSymbolType(Token *symbol);
virtual std::string escapeWSAndQuote(const std::string &s) const;
/* Compute the error recovery set for the current rule. During
* rule invocation, the parser pushes the set of tokens that can
* follow that rule reference on the stack; this amounts to
* computing FIRST of what follows the rule reference in the
* enclosing rule. See LinearApproximator.FIRST().
* This local follow set only includes tokens
* from within the rule; i.e., the FIRST computation done by
* ANTLR stops at the end of a rule.
*
* EXAMPLE
*
* When you find a "no viable alt exception", the input is not
* consistent with any of the alternatives for rule r. The best
* thing to do is to consume tokens until you see something that
* can legally follow a call to r *or* any rule that called r.
* You don't want the exact set of viable next tokens because the
* input might just be missing a token--you might consume the
* rest of the input looking for one of the missing tokens.
*
* Consider grammar:
*
* a : '[' b ']'
* | '(' b ')'
* ;
* b : c '^' INT ;
* c : ID
* | INT
* ;
*
* At each rule invocation, the set of tokens that could follow
* that rule is pushed on a stack. Here are the various
* context-sensitive follow sets:
*
* FOLLOW(b1_in_a) = FIRST(']') = ']'
* FOLLOW(b2_in_a) = FIRST(')') = ')'
* FOLLOW(c_in_b) = FIRST('^') = '^'
*
* Upon erroneous input "[]", the call chain is
*
* a -> b -> c
*
* and, hence, the follow context stack is:
*
* depth follow set start of rule execution
* 0 <EOF> a (from main())
* 1 ']' b
* 2 '^' c
*
* Notice that ')' is not included, because b would have to have
* been called from a different context in rule a for ')' to be
* included.
*
* For error recovery, we cannot consider FOLLOW(c)
* (context-sensitive or otherwise). We need the combined set of
* all context-sensitive FOLLOW sets--the set of all tokens that
* could follow any reference in the call chain. We need to
* resync to one of those tokens. Note that FOLLOW(c)='^' and if
* we resync'd to that token, we'd consume until EOF. We need to
* sync to context-sensitive FOLLOWs for a, b, and c: {']','^'}.
* In this case, for input "[]", LA(1) is ']' and in the set, so we would
* not consume anything. After printing an error, rule c would
* return normally. Rule b would not find the required '^' though.
* At this point, it gets a mismatched token error and throws an
* exception (since LA(1) is not in the viable following token
* set). The rule exception handler tries to recover, but finds
* the same recovery set and doesn't consume anything. Rule b
* exits normally returning to rule a. Now it finds the ']' (and
* with the successful match exits errorRecovery mode).
*
* So, you can see that the parser walks up the call chain looking
* for the token that was a member of the recovery set.
*
* Errors are not generated in errorRecovery mode.
*
* ANTLR's error recovery mechanism is based upon original ideas:
*
* "Algorithms + Data Structures = Programs" by Niklaus Wirth
*
* and
*
* "A note on error recovery in recursive descent parsers":
* http://portal.acm.org/citation.cfm?id=947902.947905
*
* Later, Josef Grosch had some good ideas:
*
* "Efficient and Comfortable Error Recovery in Recursive Descent
* Parsers":
* ftp://www.cocolab.com/products/cocktail/doca4.ps/ell.ps.zip
*
* Like Grosch I implement context-sensitive FOLLOW sets that are combined
* at run-time upon error to avoid overhead during parsing.
*/
virtual misc::IntervalSet getErrorRecoverySet(Parser *recognizer);
/// <summary>
/// Consume tokens until one matches the given token set. </summary>
virtual void consumeUntil(Parser *recognizer, const misc::IntervalSet &set);
private:
std::vector<std::unique_ptr<Token>> _errorSymbols; // Temporarily created token.
void InitializeInstanceFields();
};
} // namespace antlr4

View File

@@ -0,0 +1,84 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "atn/PredictionContext.h"
#include "atn/ATNConfig.h"
#include "atn/ATNConfigSet.h"
#include "Parser.h"
#include "misc/Interval.h"
#include "dfa/DFA.h"
#include "DiagnosticErrorListener.h"
using namespace antlr4;
DiagnosticErrorListener::DiagnosticErrorListener() : DiagnosticErrorListener(true) {
}
DiagnosticErrorListener::DiagnosticErrorListener(bool exactOnly_) : exactOnly(exactOnly_) {
}
void DiagnosticErrorListener::reportAmbiguity(Parser *recognizer, const dfa::DFA &dfa, size_t startIndex, size_t stopIndex,
bool exact, const antlrcpp::BitSet &ambigAlts, atn::ATNConfigSet *configs) {
if (exactOnly && !exact) {
return;
}
std::string decision = getDecisionDescription(recognizer, dfa);
antlrcpp::BitSet conflictingAlts = getConflictingAlts(ambigAlts, configs);
std::string text = recognizer->getTokenStream()->getText(misc::Interval(startIndex, stopIndex));
std::string message = "reportAmbiguity d=" + decision + ": ambigAlts=" + conflictingAlts.toString() +
", input='" + text + "'";
recognizer->notifyErrorListeners(message);
}
void DiagnosticErrorListener::reportAttemptingFullContext(Parser *recognizer, const dfa::DFA &dfa, size_t startIndex,
size_t stopIndex, const antlrcpp::BitSet &/*conflictingAlts*/, atn::ATNConfigSet * /*configs*/) {
std::string decision = getDecisionDescription(recognizer, dfa);
std::string text = recognizer->getTokenStream()->getText(misc::Interval(startIndex, stopIndex));
std::string message = "reportAttemptingFullContext d=" + decision + ", input='" + text + "'";
recognizer->notifyErrorListeners(message);
}
void DiagnosticErrorListener::reportContextSensitivity(Parser *recognizer, const dfa::DFA &dfa, size_t startIndex,
size_t stopIndex, size_t /*prediction*/, atn::ATNConfigSet * /*configs*/) {
std::string decision = getDecisionDescription(recognizer, dfa);
std::string text = recognizer->getTokenStream()->getText(misc::Interval(startIndex, stopIndex));
std::string message = "reportContextSensitivity d=" + decision + ", input='" + text + "'";
recognizer->notifyErrorListeners(message);
}
std::string DiagnosticErrorListener::getDecisionDescription(Parser *recognizer, const dfa::DFA &dfa) {
size_t decision = dfa.decision;
size_t ruleIndex = (reinterpret_cast<atn::ATNState*>(dfa.atnStartState))->ruleIndex;
const std::vector<std::string>& ruleNames = recognizer->getRuleNames();
if (ruleIndex == INVALID_INDEX || ruleIndex >= ruleNames.size()) {
return std::to_string(decision);
}
std::string ruleName = ruleNames[ruleIndex];
if (ruleName == "" || ruleName.empty()) {
return std::to_string(decision);
}
return std::to_string(decision) + " (" + ruleName + ")";
}
antlrcpp::BitSet DiagnosticErrorListener::getConflictingAlts(const antlrcpp::BitSet &reportedAlts,
atn::ATNConfigSet *configs) {
if (reportedAlts.count() > 0) { // Not exactly like the original Java code, but this listener is only used
// in the TestRig (where it never provides a good alt set), so it's probably ok so.
return reportedAlts;
}
antlrcpp::BitSet result;
for (auto &config : configs->configs) {
result.set(config->alt);
}
return result;
}

View File

@@ -0,0 +1,80 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "BaseErrorListener.h"
namespace antlr4 {
/// <summary>
/// This implementation of <seealso cref="ANTLRErrorListener"/> can be used to identify
/// certain potential correctness and performance problems in grammars. "Reports"
/// are made by calling <seealso cref="Parser#notifyErrorListeners"/> with the appropriate
/// message.
///
/// <ul>
/// <li><b>Ambiguities</b>: These are cases where more than one path through the
/// grammar can match the input.</li>
/// <li><b>Weak context sensitivity</b>: These are cases where full-context
/// prediction resolved an SLL conflict to a unique alternative which equaled the
/// minimum alternative of the SLL conflict.</li>
/// <li><b>Strong (forced) context sensitivity</b>: These are cases where the
/// full-context prediction resolved an SLL conflict to a unique alternative,
/// <em>and</em> the minimum alternative of the SLL conflict was found to not be
/// a truly viable alternative. Two-stage parsing cannot be used for inputs where
/// this situation occurs.</li>
/// </ul>
///
/// @author Sam Harwell
/// </summary>
class ANTLR4CPP_PUBLIC DiagnosticErrorListener : public BaseErrorListener {
/// <summary>
/// When {@code true}, only exactly known ambiguities are reported.
/// </summary>
protected:
const bool exactOnly;
/// <summary>
/// Initializes a new instance of <seealso cref="DiagnosticErrorListener"/> which only
/// reports exact ambiguities.
/// </summary>
public:
DiagnosticErrorListener();
/// <summary>
/// Initializes a new instance of <seealso cref="DiagnosticErrorListener"/>, specifying
/// whether all ambiguities or only exact ambiguities are reported.
/// </summary>
/// <param name="exactOnly"> {@code true} to report only exact ambiguities, otherwise
/// {@code false} to report all ambiguities. </param>
DiagnosticErrorListener(bool exactOnly);
virtual void reportAmbiguity(Parser *recognizer, const dfa::DFA &dfa, size_t startIndex, size_t stopIndex, bool exact,
const antlrcpp::BitSet &ambigAlts, atn::ATNConfigSet *configs) override;
virtual void reportAttemptingFullContext(Parser *recognizer, const dfa::DFA &dfa, size_t startIndex, size_t stopIndex,
const antlrcpp::BitSet &conflictingAlts, atn::ATNConfigSet *configs) override;
virtual void reportContextSensitivity(Parser *recognizer, const dfa::DFA &dfa, size_t startIndex, size_t stopIndex,
size_t prediction, atn::ATNConfigSet *configs) override;
protected:
virtual std::string getDecisionDescription(Parser *recognizer, const dfa::DFA &dfa);
/// <summary>
/// Computes the set of conflicting or ambiguous alternatives from a
/// configuration set, if that information was not already provided by the
/// parser.
/// </summary>
/// <param name="reportedAlts"> The set of conflicting or ambiguous alternatives, as
/// reported by the parser. </param>
/// <param name="configs"> The conflicting or ambiguous configuration set. </param>
/// <returns> Returns {@code reportedAlts} if it is not {@code null}, otherwise
/// returns the set of alternatives represented in {@code configs}. </returns>
virtual antlrcpp::BitSet getConflictingAlts(const antlrcpp::BitSet &reportedAlts, atn::ATNConfigSet *configs);
};
} // namespace antlr4

View File

@@ -0,0 +1,64 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "Exceptions.h"
using namespace antlr4;
RuntimeException::RuntimeException(const std::string &msg) : std::exception(), _message(msg) {
}
const char* RuntimeException::what() const noexcept {
return _message.c_str();
}
//------------------ IOException ---------------------------------------------------------------------------------------
IOException::IOException(const std::string &msg) : std::exception(), _message(msg) {
}
const char* IOException::what() const noexcept {
return _message.c_str();
}
//------------------ IllegalStateException -----------------------------------------------------------------------------
IllegalStateException::~IllegalStateException() {
}
//------------------ IllegalArgumentException --------------------------------------------------------------------------
IllegalArgumentException::~IllegalArgumentException() {
}
//------------------ NullPointerException ------------------------------------------------------------------------------
NullPointerException::~NullPointerException() {
}
//------------------ IndexOutOfBoundsException -------------------------------------------------------------------------
IndexOutOfBoundsException::~IndexOutOfBoundsException() {
}
//------------------ UnsupportedOperationException ---------------------------------------------------------------------
UnsupportedOperationException::~UnsupportedOperationException() {
}
//------------------ EmptyStackException -------------------------------------------------------------------------------
EmptyStackException::~EmptyStackException() {
}
//------------------ CancellationException -----------------------------------------------------------------------------
CancellationException::~CancellationException() {
}
//------------------ ParseCancellationException ------------------------------------------------------------------------
ParseCancellationException::~ParseCancellationException() {
}

View File

@@ -0,0 +1,99 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "antlr4-common.h"
namespace antlr4 {
// An exception hierarchy modelled loosely after java.lang.* exceptions.
class ANTLR4CPP_PUBLIC RuntimeException : public std::exception {
private:
std::string _message;
public:
RuntimeException(const std::string &msg = "");
virtual const char* what() const noexcept override;
};
class ANTLR4CPP_PUBLIC IllegalStateException : public RuntimeException {
public:
IllegalStateException(const std::string &msg = "") : RuntimeException(msg) {}
IllegalStateException(IllegalStateException const&) = default;
~IllegalStateException();
IllegalStateException& operator=(IllegalStateException const&) = default;
};
class ANTLR4CPP_PUBLIC IllegalArgumentException : public RuntimeException {
public:
IllegalArgumentException(IllegalArgumentException const&) = default;
IllegalArgumentException(const std::string &msg = "") : RuntimeException(msg) {}
~IllegalArgumentException();
IllegalArgumentException& operator=(IllegalArgumentException const&) = default;
};
class ANTLR4CPP_PUBLIC NullPointerException : public RuntimeException {
public:
NullPointerException(const std::string &msg = "") : RuntimeException(msg) {}
NullPointerException(NullPointerException const&) = default;
~NullPointerException();
NullPointerException& operator=(NullPointerException const&) = default;
};
class ANTLR4CPP_PUBLIC IndexOutOfBoundsException : public RuntimeException {
public:
IndexOutOfBoundsException(const std::string &msg = "") : RuntimeException(msg) {}
IndexOutOfBoundsException(IndexOutOfBoundsException const&) = default;
~IndexOutOfBoundsException();
IndexOutOfBoundsException& operator=(IndexOutOfBoundsException const&) = default;
};
class ANTLR4CPP_PUBLIC UnsupportedOperationException : public RuntimeException {
public:
UnsupportedOperationException(const std::string &msg = "") : RuntimeException(msg) {}
UnsupportedOperationException(UnsupportedOperationException const&) = default;
~UnsupportedOperationException();
UnsupportedOperationException& operator=(UnsupportedOperationException const&) = default;
};
class ANTLR4CPP_PUBLIC EmptyStackException : public RuntimeException {
public:
EmptyStackException(const std::string &msg = "") : RuntimeException(msg) {}
EmptyStackException(EmptyStackException const&) = default;
~EmptyStackException();
EmptyStackException& operator=(EmptyStackException const&) = default;
};
// IOException is not a runtime exception (in the java hierarchy).
// Hence we have to duplicate the RuntimeException implementation.
class ANTLR4CPP_PUBLIC IOException : public std::exception {
private:
std::string _message;
public:
IOException(const std::string &msg = "");
virtual const char* what() const noexcept override;
};
class ANTLR4CPP_PUBLIC CancellationException : public IllegalStateException {
public:
CancellationException(const std::string &msg = "") : IllegalStateException(msg) {}
CancellationException(CancellationException const&) = default;
~CancellationException();
CancellationException& operator=(CancellationException const&) = default;
};
class ANTLR4CPP_PUBLIC ParseCancellationException : public CancellationException {
public:
ParseCancellationException(const std::string &msg = "") : CancellationException(msg) {}
ParseCancellationException(ParseCancellationException const&) = default;
~ParseCancellationException();
ParseCancellationException& operator=(ParseCancellationException const&) = default;
};
} // namespace antlr4

View File

@@ -0,0 +1,52 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "atn/ParserATNSimulator.h"
#include "Parser.h"
#include "atn/PredicateTransition.h"
#include "atn/ATN.h"
#include "atn/ATNState.h"
#include "support/Casts.h"
#include "support/CPPUtils.h"
#include "FailedPredicateException.h"
using namespace antlr4;
using namespace antlrcpp;
FailedPredicateException::FailedPredicateException(Parser *recognizer) : FailedPredicateException(recognizer, "", "") {
}
FailedPredicateException::FailedPredicateException(Parser *recognizer, const std::string &predicate): FailedPredicateException(recognizer, predicate, "") {
}
FailedPredicateException::FailedPredicateException(Parser *recognizer, const std::string &predicate, const std::string &message)
: RecognitionException(!message.empty() ? message : "failed predicate: " + predicate + "?", recognizer,
recognizer->getInputStream(), recognizer->getContext(), recognizer->getCurrentToken()) {
atn::ATNState *s = recognizer->getInterpreter<atn::ATNSimulator>()->atn.states[recognizer->getState()];
const atn::Transition *transition = s->transitions[0].get();
if (transition->getTransitionType() == atn::TransitionType::PREDICATE) {
_ruleIndex = downCast<const atn::PredicateTransition&>(*transition).getRuleIndex();
_predicateIndex = downCast<const atn::PredicateTransition&>(*transition).getPredIndex();
} else {
_ruleIndex = 0;
_predicateIndex = 0;
}
_predicate = predicate;
}
size_t FailedPredicateException::getRuleIndex() {
return _ruleIndex;
}
size_t FailedPredicateException::getPredIndex() {
return _predicateIndex;
}
std::string FailedPredicateException::getPredicate() {
return _predicate;
}

View File

@@ -0,0 +1,32 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "RecognitionException.h"
namespace antlr4 {
/// A semantic predicate failed during validation. Validation of predicates
/// occurs when normally parsing the alternative just like matching a token.
/// Disambiguating predicate evaluation occurs when we test a predicate during
/// prediction.
class ANTLR4CPP_PUBLIC FailedPredicateException : public RecognitionException {
public:
explicit FailedPredicateException(Parser *recognizer);
FailedPredicateException(Parser *recognizer, const std::string &predicate);
FailedPredicateException(Parser *recognizer, const std::string &predicate, const std::string &message);
virtual size_t getRuleIndex();
virtual size_t getPredIndex();
virtual std::string getPredicate();
private:
size_t _ruleIndex;
size_t _predicateIndex;
std::string _predicate;
};
} // namespace antlr4

View File

@@ -0,0 +1,57 @@
// Copyright 2012-2022 The ANTLR Project
//
// 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. Neither the name of the copyright holder nor the names of its contributors may be used to
// endorse or promote products derived from this software without specific prior written
// permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR
// CONTRIBUTORS 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.
#pragma once
#include "antlr4-common.h"
#if ANTLR4CPP_USING_ABSEIL
#include "absl/container/flat_hash_map.h"
#else
#include <unordered_map>
#endif
// By default ANTLRv4 uses containers provided by the C++ standard library. In most deployments this
// is fine, however in some using custom containers may be preferred. This header allows that by
// optionally supporting some alternative implementations and allowing for more easier patching of
// other alternatives.
namespace antlr4 {
#if ANTLR4CPP_USING_ABSEIL
template <typename Key, typename Value,
typename Hash = typename absl::flat_hash_map<Key, Value>::hasher,
typename Equal = typename absl::flat_hash_map<Key, Value>::key_equal,
typename Allocator = typename absl::flat_hash_map<Key, Value>::allocator_type>
using FlatHashMap = absl::flat_hash_map<Key, Value, Hash, Equal, Allocator>;
#else
template <typename Key, typename Value,
typename Hash = std::hash<Key>,
typename Equal = std::equal_to<Key>,
typename Allocator = std::allocator<std::pair<const Key, Value>>>
using FlatHashMap = std::unordered_map<Key, Value, Hash, Equal, Allocator>;
#endif
} // namespace antlr4

View File

@@ -0,0 +1,57 @@
// Copyright 2012-2022 The ANTLR Project
//
// 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. Neither the name of the copyright holder nor the names of its contributors may be used to
// endorse or promote products derived from this software without specific prior written
// permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR
// CONTRIBUTORS 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.
#pragma once
#include "antlr4-common.h"
#if ANTLR4CPP_USING_ABSEIL
#include "absl/container/flat_hash_set.h"
#else
#include <unordered_set>
#endif
// By default ANTLRv4 uses containers provided by the C++ standard library. In most deployments this
// is fine, however in some using custom containers may be preferred. This header allows that by
// optionally supporting some alternative implementations and allowing for more easier patching of
// other alternatives.
namespace antlr4 {
#if ANTLR4CPP_USING_ABSEIL
template <typename Key,
typename Hash = typename absl::flat_hash_set<Key>::hasher,
typename Equal = typename absl::flat_hash_set<Key>::key_equal,
typename Allocator = typename absl::flat_hash_set<Key>::allocator_type>
using FlatHashSet = absl::flat_hash_set<Key, Hash, Equal, Allocator>;
#else
template <typename Key,
typename Hash = std::hash<Key>,
typename Equal = std::equal_to<Key>,
typename Allocator = std::allocator<Key>>
using FlatHashSet = std::unordered_set<Key, Hash, Equal, Allocator>;
#endif
} // namespace antlr4

View File

@@ -0,0 +1,18 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "Parser.h"
#include "InputMismatchException.h"
using namespace antlr4;
InputMismatchException::InputMismatchException(Parser *recognizer)
: RecognitionException(recognizer, recognizer->getInputStream(), recognizer->getContext(),
recognizer->getCurrentToken()) {
}
InputMismatchException::~InputMismatchException() {
}

View File

@@ -0,0 +1,24 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "RecognitionException.h"
namespace antlr4 {
/// <summary>
/// This signifies any kind of mismatched input exceptions such as
/// when the current input does not match the expected token.
/// </summary>
class ANTLR4CPP_PUBLIC InputMismatchException : public RecognitionException {
public:
InputMismatchException(Parser *recognizer);
InputMismatchException(InputMismatchException const&) = default;
~InputMismatchException();
InputMismatchException& operator=(InputMismatchException const&) = default;
};
} // namespace antlr4

View File

@@ -0,0 +1,12 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "IntStream.h"
using namespace antlr4;
const std::string IntStream::UNKNOWN_SOURCE_NAME = "<unknown>";
IntStream::~IntStream() = default;

View File

@@ -0,0 +1,218 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "antlr4-common.h"
namespace antlr4 {
/// <summary>
/// A simple stream of symbols whose values are represented as integers. This
/// interface provides <em>marked ranges</em> with support for a minimum level
/// of buffering necessary to implement arbitrary lookahead during prediction.
/// For more information on marked ranges, see <seealso cref="#mark"/>.
/// <p/>
/// <strong>Initializing Methods:</strong> Some methods in this interface have
/// unspecified behavior if no call to an initializing method has occurred after
/// the stream was constructed. The following is a list of initializing methods:
///
/// <ul>
/// <li><seealso cref="#LA"/></li>
/// <li><seealso cref="#consume"/></li>
/// <li><seealso cref="#size"/></li>
/// </ul>
/// </summary>
class ANTLR4CPP_PUBLIC IntStream {
public:
static constexpr size_t EOF = std::numeric_limits<size_t>::max();
/// The value returned by <seealso cref="#LA LA()"/> when the end of the stream is
/// reached.
/// No explicit EOF definition. We got EOF on all platforms.
//static const size_t _EOF = std::ios::eofbit;
/// <summary>
/// The value returned by <seealso cref="#getSourceName"/> when the actual name of the
/// underlying source is not known.
/// </summary>
static const std::string UNKNOWN_SOURCE_NAME;
virtual ~IntStream();
/// <summary>
/// Consumes the current symbol in the stream. This method has the following
/// effects:
///
/// <ul>
/// <li><strong>Forward movement:</strong> The value of <seealso cref="#index index()"/>
/// before calling this method is less than the value of {@code index()}
/// after calling this method.</li>
/// <li><strong>Ordered lookahead:</strong> The value of {@code LA(1)} before
/// calling this method becomes the value of {@code LA(-1)} after calling
/// this method.</li>
/// </ul>
///
/// Note that calling this method does not guarantee that {@code index()} is
/// incremented by exactly 1, as that would preclude the ability to implement
/// filtering streams (e.g. <seealso cref="CommonTokenStream"/> which distinguishes
/// between "on-channel" and "off-channel" tokens).
/// </summary>
/// <exception cref="IllegalStateException"> if an attempt is made to consume the the
/// end of the stream (i.e. if {@code LA(1)==}<seealso cref="#EOF EOF"/> before calling
/// {@code consume}). </exception>
virtual void consume() = 0;
/// <summary>
/// Gets the value of the symbol at offset {@code i} from the current
/// position. When {@code i==1}, this method returns the value of the current
/// symbol in the stream (which is the next symbol to be consumed). When
/// {@code i==-1}, this method returns the value of the previously read
/// symbol in the stream. It is not valid to call this method with
/// {@code i==0}, but the specific behavior is unspecified because this
/// method is frequently called from performance-critical code.
/// <p/>
/// This method is guaranteed to succeed if any of the following are true:
///
/// <ul>
/// <li>{@code i>0}</li>
/// <li>{@code i==-1} and <seealso cref="#index index()"/> returns a value greater
/// than the value of {@code index()} after the stream was constructed
/// and {@code LA(1)} was called in that order. Specifying the current
/// {@code index()} relative to the index after the stream was created
/// allows for filtering implementations that do not return every symbol
/// from the underlying source. Specifying the call to {@code LA(1)}
/// allows for lazily initialized streams.</li>
/// <li>{@code LA(i)} refers to a symbol consumed within a marked region
/// that has not yet been released.</li>
/// </ul>
///
/// If {@code i} represents a position at or beyond the end of the stream,
/// this method returns <seealso cref="#EOF"/>.
/// <p/>
/// The return value is unspecified if {@code i<0} and fewer than {@code -i}
/// calls to <seealso cref="#consume consume()"/> have occurred from the beginning of
/// the stream before calling this method.
/// </summary>
/// <exception cref="UnsupportedOperationException"> if the stream does not support
/// retrieving the value of the specified symbol </exception>
virtual size_t LA(ssize_t i) = 0;
/// <summary>
/// A mark provides a guarantee that <seealso cref="#seek seek()"/> operations will be
/// valid over a "marked range" extending from the index where {@code mark()}
/// was called to the current <seealso cref="#index index()"/>. This allows the use of
/// streaming input sources by specifying the minimum buffering requirements
/// to support arbitrary lookahead during prediction.
/// <p/>
/// The returned mark is an opaque handle (type {@code int}) which is passed
/// to <seealso cref="#release release()"/> when the guarantees provided by the marked
/// range are no longer necessary. When calls to
/// {@code mark()}/{@code release()} are nested, the marks must be released
/// in reverse order of which they were obtained. Since marked regions are
/// used during performance-critical sections of prediction, the specific
/// behavior of invalid usage is unspecified (i.e. a mark is not released, or
/// a mark is released twice, or marks are not released in reverse order from
/// which they were created).
/// <p/>
/// The behavior of this method is unspecified if no call to an
/// <seealso cref="IntStream initializing method"/> has occurred after this stream was
/// constructed.
/// <p/>
/// This method does not change the current position in the input stream.
/// <p/>
/// The following example shows the use of <seealso cref="#mark mark()"/>,
/// <seealso cref="#release release(mark)"/>, <seealso cref="#index index()"/>, and
/// <seealso cref="#seek seek(index)"/> as part of an operation to safely work within a
/// marked region, then restore the stream position to its original value and
/// release the mark.
/// <pre>
/// IntStream stream = ...;
/// int index = -1;
/// int mark = stream.mark();
/// try {
/// index = stream.index();
/// // perform work here...
/// } finally {
/// if (index != -1) {
/// stream.seek(index);
/// }
/// stream.release(mark);
/// }
/// </pre>
/// </summary>
/// <returns> An opaque marker which should be passed to
/// <seealso cref="#release release()"/> when the marked range is no longer required. </returns>
virtual ssize_t mark() = 0;
/// <summary>
/// This method releases a marked range created by a call to
/// <seealso cref="#mark mark()"/>. Calls to {@code release()} must appear in the
/// reverse order of the corresponding calls to {@code mark()}. If a mark is
/// released twice, or if marks are not released in reverse order of the
/// corresponding calls to {@code mark()}, the behavior is unspecified.
/// <p/>
/// For more information and an example, see <seealso cref="#mark"/>.
/// </summary>
/// <param name="marker"> A marker returned by a call to {@code mark()}. </param>
/// <seealso cref= #mark </seealso>
virtual void release(ssize_t marker) = 0;
/// <summary>
/// Return the index into the stream of the input symbol referred to by
/// {@code LA(1)}.
/// <p/>
/// The behavior of this method is unspecified if no call to an
/// <seealso cref="IntStream initializing method"/> has occurred after this stream was
/// constructed.
/// </summary>
virtual size_t index() = 0;
/// <summary>
/// Set the input cursor to the position indicated by {@code index}. If the
/// specified index lies past the end of the stream, the operation behaves as
/// though {@code index} was the index of the EOF symbol. After this method
/// returns without throwing an exception, the at least one of the following
/// will be true.
///
/// <ul>
/// <li><seealso cref="#index index()"/> will return the index of the first symbol
/// appearing at or after the specified {@code index}. Specifically,
/// implementations which filter their sources should automatically
/// adjust {@code index} forward the minimum amount required for the
/// operation to target a non-ignored symbol.</li>
/// <li>{@code LA(1)} returns <seealso cref="#EOF"/></li>
/// </ul>
///
/// This operation is guaranteed to not throw an exception if {@code index}
/// lies within a marked region. For more information on marked regions, see
/// <seealso cref="#mark"/>. The behavior of this method is unspecified if no call to
/// an <seealso cref="IntStream initializing method"/> has occurred after this stream
/// was constructed.
/// </summary>
/// <param name="index"> The absolute index to seek to.
/// </param>
/// <exception cref="IllegalArgumentException"> if {@code index} is less than 0 </exception>
/// <exception cref="UnsupportedOperationException"> if the stream does not support
/// seeking to the specified index </exception>
virtual void seek(size_t index) = 0;
/// <summary>
/// Returns the total number of symbols in the stream, including a single EOF
/// symbol.
/// </summary>
/// <exception cref="UnsupportedOperationException"> if the size of the stream is
/// unknown. </exception>
virtual size_t size() = 0;
/// <summary>
/// Gets the name of the underlying symbol source. This method returns a
/// non-null, non-empty string. If such a name is not known, this method
/// returns <seealso cref="#UNKNOWN_SOURCE_NAME"/>.
/// </summary>
virtual std::string getSourceName() const = 0;
};
} // namespace antlr4

View File

@@ -0,0 +1,19 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "InterpreterRuleContext.h"
using namespace antlr4;
InterpreterRuleContext::InterpreterRuleContext() : ParserRuleContext() {
}
InterpreterRuleContext::InterpreterRuleContext(ParserRuleContext *parent, size_t invokingStateNumber, size_t ruleIndex)
: ParserRuleContext(parent, invokingStateNumber), _ruleIndex(ruleIndex) {
}
size_t InterpreterRuleContext::getRuleIndex() const {
return _ruleIndex;
}

View File

@@ -0,0 +1,45 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "ParserRuleContext.h"
namespace antlr4 {
/**
* This class extends {@link ParserRuleContext} by allowing the value of
* {@link #getRuleIndex} to be explicitly set for the context.
*
* <p>
* {@link ParserRuleContext} does not include field storage for the rule index
* since the context classes created by the code generator override the
* {@link #getRuleIndex} method to return the correct value for that context.
* Since the parser interpreter does not use the context classes generated for a
* parser, this class (with slightly more memory overhead per node) is used to
* provide equivalent functionality.</p>
*/
class ANTLR4CPP_PUBLIC InterpreterRuleContext : public ParserRuleContext {
public:
InterpreterRuleContext();
/**
* Constructs a new {@link InterpreterRuleContext} with the specified
* parent, invoking state, and rule index.
*
* @param parent The parent context.
* @param invokingStateNumber The invoking state number.
* @param ruleIndex The rule index for the current context.
*/
InterpreterRuleContext(ParserRuleContext *parent, size_t invokingStateNumber, size_t ruleIndex);
virtual size_t getRuleIndex() const override;
protected:
/** This is the backing field for {@link #getRuleIndex}. */
const size_t _ruleIndex = INVALID_INDEX;
};
} // namespace antlr4

View File

@@ -0,0 +1,294 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "atn/LexerATNSimulator.h"
#include "Exceptions.h"
#include "misc/Interval.h"
#include "CommonTokenFactory.h"
#include "LexerNoViableAltException.h"
#include "ANTLRErrorListener.h"
#include "support/CPPUtils.h"
#include "CommonToken.h"
#include "Lexer.h"
#define DEBUG_LEXER 0
using namespace antlrcpp;
using namespace antlr4;
Lexer::Lexer() : Recognizer() {
InitializeInstanceFields();
_input = nullptr;
}
Lexer::Lexer(CharStream *input) : Recognizer(), _input(input) {
InitializeInstanceFields();
}
void Lexer::reset() {
// wack Lexer state variables
_input->seek(0); // rewind the input
_syntaxErrors = 0;
token.reset();
type = Token::INVALID_TYPE;
channel = Token::DEFAULT_CHANNEL;
tokenStartCharIndex = INVALID_INDEX;
tokenStartCharPositionInLine = 0;
tokenStartLine = 0;
type = 0;
_text = "";
hitEOF = false;
mode = Lexer::DEFAULT_MODE;
modeStack.clear();
getInterpreter<atn::LexerATNSimulator>()->reset();
}
std::unique_ptr<Token> Lexer::nextToken() {
// Mark start location in char stream so unbuffered streams are
// guaranteed at least have text of current token
ssize_t tokenStartMarker = _input->mark();
auto onExit = finally([this, tokenStartMarker]{
// make sure we release marker after match or
// unbuffered char stream will keep buffering
_input->release(tokenStartMarker);
});
while (true) {
outerContinue:
if (hitEOF) {
emitEOF();
return std::move(token);
}
token.reset();
channel = Token::DEFAULT_CHANNEL;
tokenStartCharIndex = _input->index();
tokenStartCharPositionInLine = getInterpreter<atn::LexerATNSimulator>()->getCharPositionInLine();
tokenStartLine = getInterpreter<atn::LexerATNSimulator>()->getLine();
_text = "";
do {
type = Token::INVALID_TYPE;
size_t ttype;
try {
ttype = getInterpreter<atn::LexerATNSimulator>()->match(_input, mode);
} catch (LexerNoViableAltException &e) {
notifyListeners(e); // report error
recover(e);
ttype = SKIP;
}
if (_input->LA(1) == EOF) {
hitEOF = true;
}
if (type == Token::INVALID_TYPE) {
type = ttype;
}
if (type == SKIP) {
goto outerContinue;
}
} while (type == MORE);
if (token == nullptr) {
emit();
}
return std::move(token);
}
}
void Lexer::skip() {
type = SKIP;
}
void Lexer::more() {
type = MORE;
}
void Lexer::setMode(size_t m) {
mode = m;
}
void Lexer::pushMode(size_t m) {
#if DEBUG_LEXER == 1
std::cout << "pushMode " << m << std::endl;
#endif
modeStack.push_back(mode);
setMode(m);
}
size_t Lexer::popMode() {
if (modeStack.empty()) {
throw EmptyStackException();
}
#if DEBUG_LEXER == 1
std::cout << std::string("popMode back to ") << modeStack.back() << std::endl;
#endif
setMode(modeStack.back());
modeStack.pop_back();
return mode;
}
TokenFactory<CommonToken>* Lexer::getTokenFactory() {
return _factory;
}
void Lexer::setInputStream(IntStream *input) {
reset();
_input = dynamic_cast<CharStream*>(input);
}
std::string Lexer::getSourceName() {
return _input->getSourceName();
}
CharStream* Lexer::getInputStream() {
return _input;
}
void Lexer::emit(std::unique_ptr<Token> newToken) {
token = std::move(newToken);
}
Token* Lexer::emit() {
emit(_factory->create({ this, _input }, type, _text, channel,
tokenStartCharIndex, getCharIndex() - 1, tokenStartLine, tokenStartCharPositionInLine));
return token.get();
}
Token* Lexer::emitEOF() {
size_t cpos = getCharPositionInLine();
size_t line = getLine();
emit(_factory->create({ this, _input }, EOF, "", Token::DEFAULT_CHANNEL, _input->index(), _input->index() - 1, line, cpos));
return token.get();
}
size_t Lexer::getLine() const {
return getInterpreter<atn::LexerATNSimulator>()->getLine();
}
size_t Lexer::getCharPositionInLine() {
return getInterpreter<atn::LexerATNSimulator>()->getCharPositionInLine();
}
void Lexer::setLine(size_t line) {
getInterpreter<atn::LexerATNSimulator>()->setLine(line);
}
void Lexer::setCharPositionInLine(size_t charPositionInLine) {
getInterpreter<atn::LexerATNSimulator>()->setCharPositionInLine(charPositionInLine);
}
size_t Lexer::getCharIndex() {
return _input->index();
}
std::string Lexer::getText() {
if (!_text.empty()) {
return _text;
}
return getInterpreter<atn::LexerATNSimulator>()->getText(_input);
}
void Lexer::setText(const std::string &text) {
_text = text;
}
std::unique_ptr<Token> Lexer::getToken() {
return std::move(token);
}
void Lexer::setToken(std::unique_ptr<Token> newToken) {
token = std::move(newToken);
}
void Lexer::setType(size_t ttype) {
type = ttype;
}
size_t Lexer::getType() {
return type;
}
void Lexer::setChannel(size_t newChannel) {
channel = newChannel;
}
size_t Lexer::getChannel() {
return channel;
}
std::vector<std::unique_ptr<Token>> Lexer::getAllTokens() {
std::vector<std::unique_ptr<Token>> tokens;
std::unique_ptr<Token> t = nextToken();
while (t->getType() != EOF) {
tokens.push_back(std::move(t));
t = nextToken();
}
return tokens;
}
void Lexer::recover(const LexerNoViableAltException &/*e*/) {
if (_input->LA(1) != EOF) {
// skip a char and try again
getInterpreter<atn::LexerATNSimulator>()->consume(_input);
}
}
void Lexer::notifyListeners(const LexerNoViableAltException & /*e*/) {
++_syntaxErrors;
std::string text = _input->getText(misc::Interval(tokenStartCharIndex, _input->index()));
std::string msg = std::string("token recognition error at: '") + getErrorDisplay(text) + std::string("'");
ProxyErrorListener &listener = getErrorListenerDispatch();
listener.syntaxError(this, nullptr, tokenStartLine, tokenStartCharPositionInLine, msg, std::current_exception());
}
std::string Lexer::getErrorDisplay(const std::string &s) {
std::stringstream ss;
for (auto c : s) {
switch (c) {
case '\n':
ss << "\\n";
break;
case '\t':
ss << "\\t";
break;
case '\r':
ss << "\\r";
break;
default:
ss << c;
break;
}
}
return ss.str();
}
void Lexer::recover(RecognitionException * /*re*/) {
// TODO: Do we lose character or line position information?
_input->consume();
}
size_t Lexer::getNumberOfSyntaxErrors() {
return _syntaxErrors;
}
void Lexer::InitializeInstanceFields() {
_syntaxErrors = 0;
token = nullptr;
_factory = CommonTokenFactory::DEFAULT.get();
tokenStartCharIndex = INVALID_INDEX;
tokenStartLine = 0;
tokenStartCharPositionInLine = 0;
hitEOF = false;
channel = 0;
type = 0;
mode = Lexer::DEFAULT_MODE;
}

View File

@@ -0,0 +1,196 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "Recognizer.h"
#include "TokenSource.h"
#include "CharStream.h"
#include "Token.h"
namespace antlr4 {
/// A lexer is recognizer that draws input symbols from a character stream.
/// lexer grammars result in a subclass of this object. A Lexer object
/// uses simplified match() and error recovery mechanisms in the interest
/// of speed.
class ANTLR4CPP_PUBLIC Lexer : public Recognizer, public TokenSource {
public:
static constexpr size_t DEFAULT_MODE = 0;
static constexpr size_t MORE = std::numeric_limits<size_t>::max() - 1;
static constexpr size_t SKIP = std::numeric_limits<size_t>::max() - 2;
static constexpr size_t DEFAULT_TOKEN_CHANNEL = Token::DEFAULT_CHANNEL;
static constexpr size_t HIDDEN = Token::HIDDEN_CHANNEL;
static constexpr size_t MIN_CHAR_VALUE = 0;
static constexpr size_t MAX_CHAR_VALUE = 0x10FFFF;
CharStream *_input; // Pure reference, usually from statically allocated instance.
protected:
/// How to create token objects.
TokenFactory<CommonToken> *_factory;
public:
/// The goal of all lexer rules/methods is to create a token object.
/// This is an instance variable as multiple rules may collaborate to
/// create a single token. nextToken will return this object after
/// matching lexer rule(s). If you subclass to allow multiple token
/// emissions, then set this to the last token to be matched or
/// something nonnull so that the auto token emit mechanism will not
/// emit another token.
// Life cycle of a token is this:
// Created by emit() (via the token factory) or by action code, holding ownership of it.
// Ownership is handed over to the token stream when calling nextToken().
std::unique_ptr<Token> token;
/// <summary>
/// What character index in the stream did the current token start at?
/// Needed, for example, to get the text for current token. Set at
/// the start of nextToken.
/// </summary>
size_t tokenStartCharIndex;
/// <summary>
/// The line on which the first character of the token resides </summary>
size_t tokenStartLine;
/// The character position of first character within the line.
size_t tokenStartCharPositionInLine;
/// Once we see EOF on char stream, next token will be EOF.
/// If you have DONE : EOF ; then you see DONE EOF.
bool hitEOF;
/// The channel number for the current token.
size_t channel;
/// The token type for the current token.
size_t type;
// Use the vector as a stack.
std::vector<size_t> modeStack;
size_t mode;
Lexer();
Lexer(CharStream *input);
virtual ~Lexer() {}
virtual void reset();
/// Return a token from this source; i.e., match a token on the char stream.
virtual std::unique_ptr<Token> nextToken() override;
/// Instruct the lexer to skip creating a token for current lexer rule
/// and look for another token. nextToken() knows to keep looking when
/// a lexer rule finishes with token set to SKIP_TOKEN. Recall that
/// if token == null at end of any token rule, it creates one for you
/// and emits it.
virtual void skip();
virtual void more();
virtual void setMode(size_t m);
virtual void pushMode(size_t m);
virtual size_t popMode();
template<typename T1>
void setTokenFactory(TokenFactory<T1> *factory) {
this->_factory = factory;
}
virtual TokenFactory<CommonToken>* getTokenFactory() override;
/// Set the char stream and reset the lexer
virtual void setInputStream(IntStream *input) override;
virtual std::string getSourceName() override;
virtual CharStream* getInputStream() override;
/// By default does not support multiple emits per nextToken invocation
/// for efficiency reasons. Subclasses can override this method, nextToken,
/// and getToken (to push tokens into a list and pull from that list
/// rather than a single variable as this implementation does).
virtual void emit(std::unique_ptr<Token> newToken);
/// The standard method called to automatically emit a token at the
/// outermost lexical rule. The token object should point into the
/// char buffer start..stop. If there is a text override in 'text',
/// use that to set the token's text. Override this method to emit
/// custom Token objects or provide a new factory.
virtual Token* emit();
virtual Token* emitEOF();
virtual size_t getLine() const override;
virtual size_t getCharPositionInLine() override;
virtual void setLine(size_t line);
virtual void setCharPositionInLine(size_t charPositionInLine);
/// What is the index of the current character of lookahead?
virtual size_t getCharIndex();
/// Return the text matched so far for the current token or any
/// text override.
virtual std::string getText();
/// Set the complete text of this token; it wipes any previous
/// changes to the text.
virtual void setText(const std::string &text);
/// Override if emitting multiple tokens.
virtual std::unique_ptr<Token> getToken();
virtual void setToken(std::unique_ptr<Token> newToken);
virtual void setType(size_t ttype);
virtual size_t getType();
virtual void setChannel(size_t newChannel);
virtual size_t getChannel();
virtual const std::vector<std::string>& getChannelNames() const = 0;
virtual const std::vector<std::string>& getModeNames() const = 0;
/// Return a list of all Token objects in input char stream.
/// Forces load of all tokens. Does not include EOF token.
virtual std::vector<std::unique_ptr<Token>> getAllTokens();
virtual void recover(const LexerNoViableAltException &e);
virtual void notifyListeners(const LexerNoViableAltException &e);
virtual std::string getErrorDisplay(const std::string &s);
/// Lexers can normally match any char in it's vocabulary after matching
/// a token, so do the easy thing and just kill a character and hope
/// it all works out. You can instead use the rule invocation stack
/// to do sophisticated error recovery if you are in a fragment rule.
virtual void recover(RecognitionException *re);
/// <summary>
/// Gets the number of syntax errors reported during parsing. This value is
/// incremented each time <seealso cref="#notifyErrorListeners"/> is called.
/// </summary>
/// <seealso cref= #notifyListeners </seealso>
virtual size_t getNumberOfSyntaxErrors();
protected:
/// You can set the text for the current token to override what is in
/// the input char buffer (via setText()).
std::string _text;
private:
size_t _syntaxErrors;
void InitializeInstanceFields();
};
} // namespace antlr4

View File

@@ -0,0 +1,60 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "atn/ATNType.h"
#include "atn/LexerATNSimulator.h"
#include "dfa/DFA.h"
#include "Exceptions.h"
#include "Vocabulary.h"
#include "LexerInterpreter.h"
using namespace antlr4;
LexerInterpreter::LexerInterpreter(const std::string &grammarFileName, const dfa::Vocabulary &vocabulary,
const std::vector<std::string> &ruleNames, const std::vector<std::string> &channelNames, const std::vector<std::string> &modeNames,
const atn::ATN &atn, CharStream *input)
: Lexer(input), _grammarFileName(grammarFileName), _atn(atn), _ruleNames(ruleNames),
_channelNames(channelNames), _modeNames(modeNames),
_vocabulary(vocabulary) {
if (_atn.grammarType != atn::ATNType::LEXER) {
throw IllegalArgumentException("The ATN must be a lexer ATN.");
}
for (size_t i = 0; i < atn.getNumberOfDecisions(); ++i) {
_decisionToDFA.push_back(dfa::DFA(_atn.getDecisionState(i), i));
}
_interpreter = new atn::LexerATNSimulator(this, _atn, _decisionToDFA, _sharedContextCache); /* mem-check: deleted in d-tor */
}
LexerInterpreter::~LexerInterpreter()
{
delete _interpreter;
}
const atn::ATN& LexerInterpreter::getATN() const {
return _atn;
}
std::string LexerInterpreter::getGrammarFileName() const {
return _grammarFileName;
}
const std::vector<std::string>& LexerInterpreter::getRuleNames() const {
return _ruleNames;
}
const std::vector<std::string>& LexerInterpreter::getChannelNames() const {
return _channelNames;
}
const std::vector<std::string>& LexerInterpreter::getModeNames() const {
return _modeNames;
}
const dfa::Vocabulary& LexerInterpreter::getVocabulary() const {
return _vocabulary;
}

View File

@@ -0,0 +1,46 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "Lexer.h"
#include "atn/PredictionContext.h"
#include "atn/PredictionContextCache.h"
#include "Vocabulary.h"
namespace antlr4 {
class ANTLR4CPP_PUBLIC LexerInterpreter : public Lexer {
public:
LexerInterpreter(const std::string &grammarFileName, const dfa::Vocabulary &vocabulary,
const std::vector<std::string> &ruleNames, const std::vector<std::string> &channelNames,
const std::vector<std::string> &modeNames, const atn::ATN &atn, CharStream *input);
~LexerInterpreter();
virtual const atn::ATN& getATN() const override;
virtual std::string getGrammarFileName() const override;
virtual const std::vector<std::string>& getRuleNames() const override;
virtual const std::vector<std::string>& getChannelNames() const override;
virtual const std::vector<std::string>& getModeNames() const override;
virtual const dfa::Vocabulary& getVocabulary() const override;
protected:
const std::string _grammarFileName;
const atn::ATN &_atn;
const std::vector<std::string> &_ruleNames;
const std::vector<std::string> &_channelNames;
const std::vector<std::string> &_modeNames;
std::vector<dfa::DFA> _decisionToDFA;
atn::PredictionContextCache _sharedContextCache;
private:
dfa::Vocabulary _vocabulary;
};
} // namespace antlr4

View File

@@ -0,0 +1,36 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "misc/Interval.h"
#include "support/CPPUtils.h"
#include "CharStream.h"
#include "Lexer.h"
#include "LexerNoViableAltException.h"
using namespace antlr4;
LexerNoViableAltException::LexerNoViableAltException(Lexer *lexer, CharStream *input, size_t startIndex,
atn::ATNConfigSet *deadEndConfigs)
: RecognitionException(lexer, input, nullptr, nullptr), _startIndex(startIndex), _deadEndConfigs(deadEndConfigs) {
}
size_t LexerNoViableAltException::getStartIndex() {
return _startIndex;
}
atn::ATNConfigSet* LexerNoViableAltException::getDeadEndConfigs() {
return _deadEndConfigs;
}
std::string LexerNoViableAltException::toString() {
std::string symbol;
if (_startIndex < getInputStream()->size()) {
symbol = static_cast<CharStream *>(getInputStream())->getText(misc::Interval(_startIndex, _startIndex));
symbol = antlrcpp::escapeWhitespace(symbol, false);
}
std::string format = "LexerNoViableAltException('" + symbol + "')";
return format;
}

View File

@@ -0,0 +1,31 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "RecognitionException.h"
#include "atn/ATNConfigSet.h"
namespace antlr4 {
class ANTLR4CPP_PUBLIC LexerNoViableAltException : public RecognitionException {
public:
LexerNoViableAltException(Lexer *lexer, CharStream *input, size_t startIndex,
atn::ATNConfigSet *deadEndConfigs);
virtual size_t getStartIndex();
virtual atn::ATNConfigSet* getDeadEndConfigs();
virtual std::string toString();
private:
/// Matching attempted at what input index?
const size_t _startIndex;
/// Which configurations did we try at input.index() that couldn't match input.LA(1)?
atn::ATNConfigSet *_deadEndConfigs;
};
} // namespace antlr4

View File

@@ -0,0 +1,92 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "Token.h"
#include "CommonToken.h"
#include "CharStream.h"
#include "ListTokenSource.h"
using namespace antlr4;
ListTokenSource::ListTokenSource(std::vector<std::unique_ptr<Token>> tokens_) : ListTokenSource(std::move(tokens_), "") {
}
ListTokenSource::ListTokenSource(std::vector<std::unique_ptr<Token>> tokens_, const std::string &sourceName_)
: tokens(std::move(tokens_)), sourceName(sourceName_) {
InitializeInstanceFields();
if (tokens.empty()) {
throw "tokens cannot be null";
}
// Check if there is an eof token and create one if not.
if (tokens.back()->getType() != Token::EOF) {
Token *lastToken = tokens.back().get();
size_t start = INVALID_INDEX;
size_t previousStop = lastToken->getStopIndex();
if (previousStop != INVALID_INDEX) {
start = previousStop + 1;
}
size_t stop = std::max(INVALID_INDEX, start - 1);
tokens.emplace_back((_factory->create({ this, getInputStream() }, Token::EOF, "EOF",
Token::DEFAULT_CHANNEL, start, stop, static_cast<int>(lastToken->getLine()), lastToken->getCharPositionInLine())));
}
}
size_t ListTokenSource::getCharPositionInLine() {
if (i < tokens.size()) {
return tokens[i]->getCharPositionInLine();
}
return 0;
}
std::unique_ptr<Token> ListTokenSource::nextToken() {
if (i < tokens.size()) {
return std::move(tokens[i++]);
}
return nullptr;
}
size_t ListTokenSource::getLine() const {
if (i < tokens.size()) {
return tokens[i]->getLine();
}
return 1;
}
CharStream *ListTokenSource::getInputStream() {
if (i < tokens.size()) {
return tokens[i]->getInputStream();
} else if (!tokens.empty()) {
return tokens.back()->getInputStream();
}
// no input stream information is available
return nullptr;
}
std::string ListTokenSource::getSourceName() {
if (sourceName != "") {
return sourceName;
}
CharStream *inputStream = getInputStream();
if (inputStream != nullptr) {
return inputStream->getSourceName();
}
return "List";
}
TokenFactory<CommonToken>* ListTokenSource::getTokenFactory() {
return _factory;
}
void ListTokenSource::InitializeInstanceFields() {
i = 0;
_factory = CommonTokenFactory::DEFAULT.get();
}

View File

@@ -0,0 +1,88 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "TokenSource.h"
#include "CommonTokenFactory.h"
namespace antlr4 {
/// Provides an implementation of <seealso cref="TokenSource"/> as a wrapper around a list
/// of <seealso cref="Token"/> objects.
///
/// If the final token in the list is an <seealso cref="Token#EOF"/> token, it will be used
/// as the EOF token for every call to <seealso cref="#nextToken"/> after the end of the
/// list is reached. Otherwise, an EOF token will be created.
class ANTLR4CPP_PUBLIC ListTokenSource : public TokenSource {
protected:
// This list will be emptied token by token as we call nextToken().
// Token streams can be used to buffer tokens for a while.
std::vector<std::unique_ptr<Token>> tokens;
private:
/// <summary>
/// The name of the input source. If this value is {@code null}, a call to
/// <seealso cref="#getSourceName"/> should return the source name used to create the
/// the next token in <seealso cref="#tokens"/> (or the previous token if the end of
/// the input has been reached).
/// </summary>
const std::string sourceName;
protected:
/// The index into <seealso cref="#tokens"/> of token to return by the next call to
/// <seealso cref="#nextToken"/>. The end of the input is indicated by this value
/// being greater than or equal to the number of items in <seealso cref="#tokens"/>.
size_t i;
private:
/// This is the backing field for <seealso cref="#getTokenFactory"/> and
/// <seealso cref="setTokenFactory"/>.
TokenFactory<CommonToken> *_factory = CommonTokenFactory::DEFAULT.get();
public:
/// Constructs a new <seealso cref="ListTokenSource"/> instance from the specified
/// collection of <seealso cref="Token"/> objects.
///
/// <param name="tokens"> The collection of <seealso cref="Token"/> objects to provide as a
/// <seealso cref="TokenSource"/>. </param>
/// <exception cref="NullPointerException"> if {@code tokens} is {@code null} </exception>
ListTokenSource(std::vector<std::unique_ptr<Token>> tokens);
ListTokenSource(const ListTokenSource& other) = delete;
ListTokenSource& operator = (const ListTokenSource& other) = delete;
/// <summary>
/// Constructs a new <seealso cref="ListTokenSource"/> instance from the specified
/// collection of <seealso cref="Token"/> objects and source name.
/// </summary>
/// <param name="tokens"> The collection of <seealso cref="Token"/> objects to provide as a
/// <seealso cref="TokenSource"/>. </param>
/// <param name="sourceName"> The name of the <seealso cref="TokenSource"/>. If this value is
/// {@code null}, <seealso cref="#getSourceName"/> will attempt to infer the name from
/// the next <seealso cref="Token"/> (or the previous token if the end of the input has
/// been reached).
/// </param>
/// <exception cref="NullPointerException"> if {@code tokens} is {@code null} </exception>
ListTokenSource(std::vector<std::unique_ptr<Token>> tokens_, const std::string &sourceName_);
virtual size_t getCharPositionInLine() override;
virtual std::unique_ptr<Token> nextToken() override;
virtual size_t getLine() const override;
virtual CharStream* getInputStream() override;
virtual std::string getSourceName() override;
template<typename T1>
void setTokenFactory(TokenFactory<T1> *factory) {
this->_factory = factory;
}
virtual TokenFactory<CommonToken>* getTokenFactory() override;
private:
void InitializeInstanceFields();
};
} // namespace antlr4

View File

@@ -0,0 +1,46 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "Parser.h"
#include "NoViableAltException.h"
using namespace antlr4;
namespace {
// Create a normal shared pointer if the configurations are to be deleted. If not, then
// the shared pointer is created with a deleter that does nothing.
Ref<atn::ATNConfigSet> buildConfigsRef(atn::ATNConfigSet *configs, bool deleteConfigs) {
if (deleteConfigs) {
return Ref<atn::ATNConfigSet>(configs);
} else {
return Ref<atn::ATNConfigSet>(configs, [](atn::ATNConfigSet *){});
}
}
}
NoViableAltException::NoViableAltException(Parser *recognizer)
: NoViableAltException(recognizer, recognizer->getTokenStream(), recognizer->getCurrentToken(),
recognizer->getCurrentToken(), nullptr, recognizer->getContext(), false) {
}
NoViableAltException::NoViableAltException(Parser *recognizer, TokenStream *input,Token *startToken,
Token *offendingToken, atn::ATNConfigSet *deadEndConfigs, ParserRuleContext *ctx, bool deleteConfigs)
: RecognitionException("No viable alternative", recognizer, input, ctx, offendingToken),
_deadEndConfigs(buildConfigsRef(deadEndConfigs, deleteConfigs)), _startToken(startToken) {
}
NoViableAltException::~NoViableAltException() {
}
Token* NoViableAltException::getStartToken() const {
return _startToken;
}
atn::ATNConfigSet* NoViableAltException::getDeadEndConfigs() const {
return _deadEndConfigs.get();
}

View File

@@ -0,0 +1,42 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "RecognitionException.h"
#include "Token.h"
#include "atn/ATNConfigSet.h"
namespace antlr4 {
/// Indicates that the parser could not decide which of two or more paths
/// to take based upon the remaining input. It tracks the starting token
/// of the offending input and also knows where the parser was
/// in the various paths when the error. Reported by reportNoViableAlternative()
class ANTLR4CPP_PUBLIC NoViableAltException : public RecognitionException {
public:
NoViableAltException(Parser *recognizer); // LL(1) error
NoViableAltException(Parser *recognizer, TokenStream *input,Token *startToken,
Token *offendingToken, atn::ATNConfigSet *deadEndConfigs, ParserRuleContext *ctx, bool deleteConfigs);
~NoViableAltException();
virtual Token* getStartToken() const;
virtual atn::ATNConfigSet* getDeadEndConfigs() const;
private:
/// Which configurations did we try at input.index() that couldn't match input.LT(1)?
/// Shared pointer that conditionally deletes the configurations (based on flag
/// passed during construction)
Ref<atn::ATNConfigSet> _deadEndConfigs;
/// The token object at the start index; the input stream might
/// not be buffering tokens so get a reference to it. (At the
/// time the error occurred, of course the stream needs to keep a
/// buffer all of the tokens but later we might not have access to those.)
Token *_startToken;
};
} // namespace antlr4

View File

@@ -0,0 +1,670 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "atn/ATNDeserializationOptions.h"
#include "tree/pattern/ParseTreePatternMatcher.h"
#include "dfa/DFA.h"
#include "ParserRuleContext.h"
#include "tree/TerminalNode.h"
#include "tree/ErrorNodeImpl.h"
#include "Lexer.h"
#include "atn/ParserATNSimulator.h"
#include "misc/IntervalSet.h"
#include "atn/RuleStartState.h"
#include "DefaultErrorStrategy.h"
#include "atn/ATNDeserializer.h"
#include "atn/RuleTransition.h"
#include "atn/ATN.h"
#include "Exceptions.h"
#include "ANTLRErrorListener.h"
#include "tree/pattern/ParseTreePattern.h"
#include "internal/Synchronization.h"
#include "atn/ProfilingATNSimulator.h"
#include "atn/ParseInfo.h"
#include "Parser.h"
using namespace antlr4;
using namespace antlr4::atn;
using namespace antlr4::internal;
using namespace antlrcpp;
namespace {
struct BypassAltsAtnCache final {
std::shared_mutex mutex;
/// This field maps from the serialized ATN string to the deserialized <seealso cref="ATN"/> with
/// bypass alternatives.
///
/// <seealso cref= ATNDeserializationOptions#isGenerateRuleBypassTransitions() </seealso>
std::map<std::vector<int32_t>, std::unique_ptr<const atn::ATN>, std::less<>> map;
};
BypassAltsAtnCache* getBypassAltsAtnCache() {
static BypassAltsAtnCache* const instance = new BypassAltsAtnCache();
return instance;
}
}
Parser::TraceListener::TraceListener(Parser *outerInstance_) : outerInstance(outerInstance_) {
}
Parser::TraceListener::~TraceListener() {
}
void Parser::TraceListener::enterEveryRule(ParserRuleContext *ctx) {
std::cout << "enter " << outerInstance->getRuleNames()[ctx->getRuleIndex()]
<< ", LT(1)=" << outerInstance->_input->LT(1)->getText() << std::endl;
}
void Parser::TraceListener::visitTerminal(tree::TerminalNode *node) {
std::cout << "consume " << node->getSymbol() << " rule "
<< outerInstance->getRuleNames()[outerInstance->getContext()->getRuleIndex()] << std::endl;
}
void Parser::TraceListener::visitErrorNode(tree::ErrorNode * /*node*/) {
}
void Parser::TraceListener::exitEveryRule(ParserRuleContext *ctx) {
std::cout << "exit " << outerInstance->getRuleNames()[ctx->getRuleIndex()]
<< ", LT(1)=" << outerInstance->_input->LT(1)->getText() << std::endl;
}
Parser::TrimToSizeListener Parser::TrimToSizeListener::INSTANCE;
Parser::TrimToSizeListener::~TrimToSizeListener() {
}
void Parser::TrimToSizeListener::enterEveryRule(ParserRuleContext * /*ctx*/) {
}
void Parser::TrimToSizeListener::visitTerminal(tree::TerminalNode * /*node*/) {
}
void Parser::TrimToSizeListener::visitErrorNode(tree::ErrorNode * /*node*/) {
}
void Parser::TrimToSizeListener::exitEveryRule(ParserRuleContext * ctx) {
ctx->children.shrink_to_fit();
}
Parser::Parser(TokenStream *input) {
InitializeInstanceFields();
setInputStream(input);
}
Parser::~Parser() {
_tracker.reset();
delete _tracer;
}
void Parser::reset() {
if (getInputStream() != nullptr) {
getInputStream()->seek(0);
}
_errHandler->reset(this); // Watch out, this is not shared_ptr.reset().
_matchedEOF = false;
_syntaxErrors = 0;
setTrace(false);
_precedenceStack.clear();
_precedenceStack.push_back(0);
_ctx = nullptr;
_tracker.reset();
atn::ATNSimulator *interpreter = getInterpreter<atn::ParserATNSimulator>();
if (interpreter != nullptr) {
interpreter->reset();
}
}
Token* Parser::match(size_t ttype) {
Token *t = getCurrentToken();
if (t->getType() == ttype) {
if (ttype == EOF) {
_matchedEOF = true;
}
_errHandler->reportMatch(this);
consume();
} else {
t = _errHandler->recoverInline(this);
if (_buildParseTrees && t->getTokenIndex() == INVALID_INDEX) {
// we must have conjured up a new token during single token insertion
// if it's not the current symbol
_ctx->addChild(createErrorNode(t));
}
}
return t;
}
Token* Parser::matchWildcard() {
Token *t = getCurrentToken();
if (t->getType() > 0) {
_errHandler->reportMatch(this);
consume();
} else {
t = _errHandler->recoverInline(this);
if (_buildParseTrees && t->getTokenIndex() == INVALID_INDEX) {
// we must have conjured up a new token during single token insertion
// if it's not the current symbol
_ctx->addChild(createErrorNode(t));
}
}
return t;
}
void Parser::setBuildParseTree(bool buildParseTrees) {
this->_buildParseTrees = buildParseTrees;
}
bool Parser::getBuildParseTree() {
return _buildParseTrees;
}
void Parser::setTrimParseTree(bool trimParseTrees) {
if (trimParseTrees) {
if (getTrimParseTree()) {
return;
}
addParseListener(&TrimToSizeListener::INSTANCE);
} else {
removeParseListener(&TrimToSizeListener::INSTANCE);
}
}
bool Parser::getTrimParseTree() {
return std::find(getParseListeners().begin(), getParseListeners().end(), &TrimToSizeListener::INSTANCE) != getParseListeners().end();
}
std::vector<tree::ParseTreeListener *> Parser::getParseListeners() {
return _parseListeners;
}
void Parser::addParseListener(tree::ParseTreeListener *listener) {
if (!listener) {
throw NullPointerException("listener");
}
this->_parseListeners.push_back(listener);
}
void Parser::removeParseListener(tree::ParseTreeListener *listener) {
if (!_parseListeners.empty()) {
auto it = std::find(_parseListeners.begin(), _parseListeners.end(), listener);
if (it != _parseListeners.end()) {
_parseListeners.erase(it);
}
}
}
void Parser::removeParseListeners() {
_parseListeners.clear();
}
void Parser::triggerEnterRuleEvent() {
for (auto *listener : _parseListeners) {
listener->enterEveryRule(_ctx);
_ctx->enterRule(listener);
}
}
void Parser::triggerExitRuleEvent() {
// reverse order walk of listeners
for (auto it = _parseListeners.rbegin(); it != _parseListeners.rend(); ++it) {
_ctx->exitRule(*it);
(*it)->exitEveryRule(_ctx);
}
}
size_t Parser::getNumberOfSyntaxErrors() {
return _syntaxErrors;
}
TokenFactory<CommonToken>* Parser::getTokenFactory() {
return _input->getTokenSource()->getTokenFactory();
}
const atn::ATN& Parser::getATNWithBypassAlts() {
auto serializedAtn = getSerializedATN();
if (serializedAtn.empty()) {
throw UnsupportedOperationException("The current parser does not support an ATN with bypass alternatives.");
}
// XXX: using the entire serialized ATN as key into the map is a big resource waste.
// How large can that thing become?
auto *cache = getBypassAltsAtnCache();
{
std::shared_lock<std::shared_mutex> lock(cache->mutex);
auto existing = cache->map.find(serializedAtn);
if (existing != cache->map.end()) {
return *existing->second;
}
}
std::unique_lock<std::shared_mutex> lock(cache->mutex);
auto existing = cache->map.find(serializedAtn);
if (existing != cache->map.end()) {
return *existing->second;
}
atn::ATNDeserializationOptions deserializationOptions;
deserializationOptions.setGenerateRuleBypassTransitions(true);
atn::ATNDeserializer deserializer(deserializationOptions);
auto atn = deserializer.deserialize(serializedAtn);
return *cache->map.insert(std::make_pair(std::vector<int32_t>(serializedAtn.begin(), serializedAtn.end()), std::move(atn))).first->second;
}
tree::pattern::ParseTreePattern Parser::compileParseTreePattern(const std::string &pattern, int patternRuleIndex) {
if (getTokenStream() != nullptr) {
TokenSource *tokenSource = getTokenStream()->getTokenSource();
if (is<Lexer*>(tokenSource)) {
Lexer *lexer = dynamic_cast<Lexer *>(tokenSource);
return compileParseTreePattern(pattern, patternRuleIndex, lexer);
}
}
throw UnsupportedOperationException("Parser can't discover a lexer to use");
}
tree::pattern::ParseTreePattern Parser::compileParseTreePattern(const std::string &pattern, int patternRuleIndex,
Lexer *lexer) {
tree::pattern::ParseTreePatternMatcher m(lexer, this);
return m.compile(pattern, patternRuleIndex);
}
Ref<ANTLRErrorStrategy> Parser::getErrorHandler() {
return _errHandler;
}
void Parser::setErrorHandler(Ref<ANTLRErrorStrategy> const& handler) {
_errHandler = handler;
}
IntStream* Parser::getInputStream() {
return getTokenStream();
}
void Parser::setInputStream(IntStream *input) {
setTokenStream(static_cast<TokenStream*>(input));
}
TokenStream* Parser::getTokenStream() {
return _input;
}
void Parser::setTokenStream(TokenStream *input) {
_input = nullptr; // Just a reference we don't own.
reset();
_input = input;
}
Token* Parser::getCurrentToken() {
return _input->LT(1);
}
void Parser::notifyErrorListeners(const std::string &msg) {
notifyErrorListeners(getCurrentToken(), msg, nullptr);
}
void Parser::notifyErrorListeners(Token *offendingToken, const std::string &msg, std::exception_ptr e) {
_syntaxErrors++;
size_t line = offendingToken->getLine();
size_t charPositionInLine = offendingToken->getCharPositionInLine();
ProxyErrorListener &listener = getErrorListenerDispatch();
listener.syntaxError(this, offendingToken, line, charPositionInLine, msg, e);
}
Token* Parser::consume() {
Token *o = getCurrentToken();
if (o->getType() != EOF) {
getInputStream()->consume();
}
bool hasListener = _parseListeners.size() > 0 && !_parseListeners.empty();
if (_buildParseTrees || hasListener) {
if (_errHandler->inErrorRecoveryMode(this)) {
tree::ErrorNode *node = createErrorNode(o);
_ctx->addChild(node);
if (_parseListeners.size() > 0) {
for (auto *listener : _parseListeners) {
listener->visitErrorNode(node);
}
}
} else {
tree::TerminalNode *node = _ctx->addChild(createTerminalNode(o));
if (_parseListeners.size() > 0) {
for (auto *listener : _parseListeners) {
listener->visitTerminal(node);
}
}
}
}
return o;
}
void Parser::addContextToParseTree() {
// Add current context to parent if we have a parent.
if (_ctx->parent == nullptr)
return;
downCast<ParserRuleContext*>(_ctx->parent)->addChild(_ctx);
}
void Parser::enterRule(ParserRuleContext *localctx, size_t state, size_t /*ruleIndex*/) {
setState(state);
_ctx = localctx;
_ctx->start = _input->LT(1);
if (_buildParseTrees) {
addContextToParseTree();
}
if (_parseListeners.size() > 0) {
triggerEnterRuleEvent();
}
}
void Parser::exitRule() {
if (_matchedEOF) {
// if we have matched EOF, it cannot consume past EOF so we use LT(1) here
_ctx->stop = _input->LT(1); // LT(1) will be end of file
} else {
_ctx->stop = _input->LT(-1); // stop node is what we just matched
}
// trigger event on ctx, before it reverts to parent
if (_parseListeners.size() > 0) {
triggerExitRuleEvent();
}
setState(_ctx->invokingState);
_ctx = downCast<ParserRuleContext*>(_ctx->parent);
}
void Parser::enterOuterAlt(ParserRuleContext *localctx, size_t altNum) {
localctx->setAltNumber(altNum);
// if we have new localctx, make sure we replace existing ctx
// that is previous child of parse tree
if (_buildParseTrees && _ctx != localctx) {
if (_ctx->parent != nullptr) {
ParserRuleContext *parent = downCast<ParserRuleContext*>(_ctx->parent);
parent->removeLastChild();
parent->addChild(localctx);
}
}
_ctx = localctx;
}
int Parser::getPrecedence() const {
if (_precedenceStack.empty()) {
return -1;
}
return _precedenceStack.back();
}
void Parser::enterRecursionRule(ParserRuleContext *localctx, size_t ruleIndex) {
enterRecursionRule(localctx, getATN().ruleToStartState[ruleIndex]->stateNumber, ruleIndex, 0);
}
void Parser::enterRecursionRule(ParserRuleContext *localctx, size_t state, size_t /*ruleIndex*/, int precedence) {
setState(state);
_precedenceStack.push_back(precedence);
_ctx = localctx;
_ctx->start = _input->LT(1);
if (!_parseListeners.empty()) {
triggerEnterRuleEvent(); // simulates rule entry for left-recursive rules
}
}
void Parser::pushNewRecursionContext(ParserRuleContext *localctx, size_t state, size_t /*ruleIndex*/) {
ParserRuleContext *previous = _ctx;
previous->parent = localctx;
previous->invokingState = state;
previous->stop = _input->LT(-1);
_ctx = localctx;
_ctx->start = previous->start;
if (_buildParseTrees) {
_ctx->addChild(previous);
}
if (_parseListeners.size() > 0) {
triggerEnterRuleEvent(); // simulates rule entry for left-recursive rules
}
}
void Parser::unrollRecursionContexts(ParserRuleContext *parentctx) {
_precedenceStack.pop_back();
_ctx->stop = _input->LT(-1);
ParserRuleContext *retctx = _ctx; // save current ctx (return value)
// unroll so ctx is as it was before call to recursive method
if (_parseListeners.size() > 0) {
while (_ctx != parentctx) {
triggerExitRuleEvent();
_ctx = downCast<ParserRuleContext*>(_ctx->parent);
}
} else {
_ctx = parentctx;
}
// hook into tree
retctx->parent = parentctx;
if (_buildParseTrees && parentctx != nullptr) {
// add return ctx into invoking rule's tree
parentctx->addChild(retctx);
}
}
ParserRuleContext* Parser::getInvokingContext(size_t ruleIndex) {
ParserRuleContext *p = _ctx;
while (p) {
if (p->getRuleIndex() == ruleIndex) {
return p;
}
if (p->parent == nullptr)
break;
p = downCast<ParserRuleContext*>(p->parent);
}
return nullptr;
}
ParserRuleContext* Parser::getContext() {
return _ctx;
}
void Parser::setContext(ParserRuleContext *ctx) {
_ctx = ctx;
}
bool Parser::precpred(RuleContext * /*localctx*/, int precedence) {
return precedence >= _precedenceStack.back();
}
bool Parser::inContext(const std::string &/*context*/) {
// TODO: useful in parser?
return false;
}
bool Parser::isExpectedToken(size_t symbol) {
const atn::ATN &atn = getInterpreter<atn::ParserATNSimulator>()->atn;
ParserRuleContext *ctx = _ctx;
atn::ATNState *s = atn.states[getState()];
misc::IntervalSet following = atn.nextTokens(s);
if (following.contains(symbol)) {
return true;
}
if (!following.contains(Token::EPSILON)) {
return false;
}
while (ctx && ctx->invokingState != ATNState::INVALID_STATE_NUMBER && following.contains(Token::EPSILON)) {
atn::ATNState *invokingState = atn.states[ctx->invokingState];
const atn::RuleTransition *rt = static_cast<const atn::RuleTransition*>(invokingState->transitions[0].get());
following = atn.nextTokens(rt->followState);
if (following.contains(symbol)) {
return true;
}
ctx = downCast<ParserRuleContext*>(ctx->parent);
}
if (following.contains(Token::EPSILON) && symbol == EOF) {
return true;
}
return false;
}
bool Parser::isMatchedEOF() const {
return _matchedEOF;
}
misc::IntervalSet Parser::getExpectedTokens() {
return getATN().getExpectedTokens(getState(), getContext());
}
misc::IntervalSet Parser::getExpectedTokensWithinCurrentRule() {
const atn::ATN &atn = getInterpreter<atn::ParserATNSimulator>()->atn;
atn::ATNState *s = atn.states[getState()];
return atn.nextTokens(s);
}
size_t Parser::getRuleIndex(const std::string &ruleName) {
const std::map<std::string, size_t> &m = getRuleIndexMap();
auto iterator = m.find(ruleName);
if (iterator == m.end()) {
return INVALID_INDEX;
}
return iterator->second;
}
ParserRuleContext* Parser::getRuleContext() {
return _ctx;
}
std::vector<std::string> Parser::getRuleInvocationStack() {
return getRuleInvocationStack(_ctx);
}
std::vector<std::string> Parser::getRuleInvocationStack(RuleContext *p) {
std::vector<std::string> const& ruleNames = getRuleNames();
std::vector<std::string> stack;
RuleContext *run = p;
while (run != nullptr) {
// compute what follows who invoked us
size_t ruleIndex = run->getRuleIndex();
if (ruleIndex == INVALID_INDEX ) {
stack.push_back("n/a");
} else {
stack.push_back(ruleNames[ruleIndex]);
}
if (!RuleContext::is(run->parent)) {
break;
}
run = downCast<RuleContext*>(run->parent);
}
return stack;
}
std::vector<std::string> Parser::getDFAStrings() {
atn::ParserATNSimulator *simulator = getInterpreter<atn::ParserATNSimulator>();
if (!simulator->decisionToDFA.empty()) {
UniqueLock<Mutex> lck(_mutex);
std::vector<std::string> s;
for (size_t d = 0; d < simulator->decisionToDFA.size(); d++) {
dfa::DFA &dfa = simulator->decisionToDFA[d];
s.push_back(dfa.toString(getVocabulary()));
}
return s;
}
return std::vector<std::string>();
}
void Parser::dumpDFA() {
atn::ParserATNSimulator *simulator = getInterpreter<atn::ParserATNSimulator>();
if (!simulator->decisionToDFA.empty()) {
UniqueLock<Mutex> lck(_mutex);
bool seenOne = false;
for (size_t d = 0; d < simulator->decisionToDFA.size(); d++) {
dfa::DFA &dfa = simulator->decisionToDFA[d];
if (!dfa.states.empty()) {
if (seenOne) {
std::cout << std::endl;
}
std::cout << "Decision " << dfa.decision << ":" << std::endl;
std::cout << dfa.toString(getVocabulary());
seenOne = true;
}
}
}
}
std::string Parser::getSourceName() {
return _input->getSourceName();
}
atn::ParseInfo Parser::getParseInfo() const {
atn::ParserATNSimulator *simulator = getInterpreter<atn::ParserATNSimulator>();
return atn::ParseInfo(dynamic_cast<atn::ProfilingATNSimulator*>(simulator));
}
void Parser::setProfile(bool profile) {
atn::ParserATNSimulator *interp = getInterpreter<atn::ParserATNSimulator>();
atn::PredictionMode saveMode = interp != nullptr ? interp->getPredictionMode() : atn::PredictionMode::LL;
if (profile) {
if (!is<atn::ProfilingATNSimulator *>(interp)) {
setInterpreter(new atn::ProfilingATNSimulator(this)); /* mem-check: replacing existing interpreter which gets deleted. */
}
} else if (is<atn::ProfilingATNSimulator *>(interp)) {
/* mem-check: replacing existing interpreter which gets deleted. */
atn::ParserATNSimulator *sim = new atn::ParserATNSimulator(this, getATN(), interp->decisionToDFA, interp->getSharedContextCache());
setInterpreter(sim);
}
getInterpreter<atn::ParserATNSimulator>()->setPredictionMode(saveMode);
}
void Parser::setTrace(bool trace) {
if (!trace) {
if (_tracer)
removeParseListener(_tracer);
delete _tracer;
_tracer = nullptr;
} else {
if (_tracer)
removeParseListener(_tracer); // Just in case this is triggered multiple times.
_tracer = new TraceListener(this);
addParseListener(_tracer);
}
}
bool Parser::isTrace() const {
return _tracer != nullptr;
}
tree::TerminalNode *Parser::createTerminalNode(Token *t) {
return _tracker.createInstance<tree::TerminalNodeImpl>(t);
}
tree::ErrorNode *Parser::createErrorNode(Token *t) {
return _tracker.createInstance<tree::ErrorNodeImpl>(t);
}
void Parser::InitializeInstanceFields() {
_errHandler = std::make_shared<DefaultErrorStrategy>();
_precedenceStack.clear();
_precedenceStack.push_back(0);
_buildParseTrees = true;
_syntaxErrors = 0;
_matchedEOF = false;
_input = nullptr;
_tracer = nullptr;
_ctx = nullptr;
}

View File

@@ -0,0 +1,461 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "Recognizer.h"
#include "tree/ParseTreeListener.h"
#include "tree/ParseTree.h"
#include "TokenStream.h"
#include "TokenSource.h"
#include "misc/Interval.h"
namespace antlr4 {
/// This is all the parsing support code essentially; most of it is error recovery stuff.
class ANTLR4CPP_PUBLIC Parser : public Recognizer {
public:
class TraceListener : public tree::ParseTreeListener {
public:
TraceListener(Parser *outerInstance);
virtual ~TraceListener();
virtual void enterEveryRule(ParserRuleContext *ctx) override;
virtual void visitTerminal(tree::TerminalNode *node) override;
virtual void visitErrorNode(tree::ErrorNode *node) override;
virtual void exitEveryRule(ParserRuleContext *ctx) override;
private:
Parser *const outerInstance;
};
class TrimToSizeListener : public tree::ParseTreeListener {
public:
static TrimToSizeListener INSTANCE;
virtual ~TrimToSizeListener();
virtual void enterEveryRule(ParserRuleContext *ctx) override;
virtual void visitTerminal(tree::TerminalNode *node) override;
virtual void visitErrorNode(tree::ErrorNode *node) override;
virtual void exitEveryRule(ParserRuleContext *ctx) override;
};
Parser(TokenStream *input);
virtual ~Parser();
/// reset the parser's state
virtual void reset();
/// <summary>
/// Match current input symbol against {@code ttype}. If the symbol type
/// matches, <seealso cref="ANTLRErrorStrategy#reportMatch"/> and <seealso cref="#consume"/> are
/// called to complete the match process.
///
/// If the symbol type does not match,
/// <seealso cref="ANTLRErrorStrategy#recoverInline"/> is called on the current error
/// strategy to attempt recovery. If <seealso cref="#getBuildParseTree"/> is
/// {@code true} and the token index of the symbol returned by
/// <seealso cref="ANTLRErrorStrategy#recoverInline"/> is -1, the symbol is added to
/// the parse tree by calling {@link #createErrorNode(ParserRuleContext, Token)} then
/// {@link ParserRuleContext#addErrorNode(ErrorNode)}.
/// </summary>
/// <param name="ttype"> the token type to match </param>
/// <returns> the matched symbol </returns>
/// <exception cref="RecognitionException"> if the current input symbol did not match
/// {@code ttype} and the error strategy could not recover from the
/// mismatched symbol </exception>
virtual Token* match(size_t ttype);
/// <summary>
/// Match current input symbol as a wildcard. If the symbol type matches
/// (i.e. has a value greater than 0), <seealso cref="ANTLRErrorStrategy#reportMatch"/>
/// and <seealso cref="#consume"/> are called to complete the match process.
/// <p/>
/// If the symbol type does not match,
/// <seealso cref="ANTLRErrorStrategy#recoverInline"/> is called on the current error
/// strategy to attempt recovery. If <seealso cref="#getBuildParseTree"/> is
/// {@code true} and the token index of the symbol returned by
/// <seealso cref="ANTLRErrorStrategy#recoverInline"/> is -1, the symbol is added to
/// the parse tree by calling <seealso cref="ParserRuleContext#addErrorNode"/>.
/// </summary>
/// <returns> the matched symbol </returns>
/// <exception cref="RecognitionException"> if the current input symbol did not match
/// a wildcard and the error strategy could not recover from the mismatched
/// symbol </exception>
virtual Token* matchWildcard();
/// <summary>
/// Track the <seealso cref="ParserRuleContext"/> objects during the parse and hook
/// them up using the <seealso cref="ParserRuleContext#children"/> list so that it
/// forms a parse tree. The <seealso cref="ParserRuleContext"/> returned from the start
/// rule represents the root of the parse tree.
/// <p/>
/// Note that if we are not building parse trees, rule contexts only point
/// upwards. When a rule exits, it returns the context but that gets garbage
/// collected if nobody holds a reference. It points upwards but nobody
/// points at it.
/// <p/>
/// When we build parse trees, we are adding all of these contexts to
/// <seealso cref="ParserRuleContext#children"/> list. Contexts are then not candidates
/// for garbage collection.
/// </summary>
virtual void setBuildParseTree(bool buildParseTrees);
/// <summary>
/// Gets whether or not a complete parse tree will be constructed while
/// parsing. This property is {@code true} for a newly constructed parser.
/// </summary>
/// <returns> {@code true} if a complete parse tree will be constructed while
/// parsing, otherwise {@code false} </returns>
virtual bool getBuildParseTree();
/// <summary>
/// Trim the internal lists of the parse tree during parsing to conserve memory.
/// This property is set to {@code false} by default for a newly constructed parser.
/// </summary>
/// <param name="trimParseTrees"> {@code true} to trim the capacity of the <seealso cref="ParserRuleContext#children"/>
/// list to its size after a rule is parsed. </param>
virtual void setTrimParseTree(bool trimParseTrees);
/// <returns> {@code true} if the <seealso cref="ParserRuleContext#children"/> list is trimmed
/// using the default <seealso cref="Parser.TrimToSizeListener"/> during the parse process. </returns>
virtual bool getTrimParseTree();
virtual std::vector<tree::ParseTreeListener *> getParseListeners();
/// <summary>
/// Registers {@code listener} to receive events during the parsing process.
/// <p/>
/// To support output-preserving grammar transformations (including but not
/// limited to left-recursion removal, automated left-factoring, and
/// optimized code generation), calls to listener methods during the parse
/// may differ substantially from calls made by
/// <seealso cref="ParseTreeWalker#DEFAULT"/> used after the parse is complete. In
/// particular, rule entry and exit events may occur in a different order
/// during the parse than after the parser. In addition, calls to certain
/// rule entry methods may be omitted.
/// <p/>
/// With the following specific exceptions, calls to listener events are
/// <em>deterministic</em>, i.e. for identical input the calls to listener
/// methods will be the same.
///
/// <ul>
/// <li>Alterations to the grammar used to generate code may change the
/// behavior of the listener calls.</li>
/// <li>Alterations to the command line options passed to ANTLR 4 when
/// generating the parser may change the behavior of the listener calls.</li>
/// <li>Changing the version of the ANTLR Tool used to generate the parser
/// may change the behavior of the listener calls.</li>
/// </ul>
/// </summary>
/// <param name="listener"> the listener to add
/// </param>
/// <exception cref="NullPointerException"> if {@code} listener is {@code null} </exception>
virtual void addParseListener(tree::ParseTreeListener *listener);
/// <summary>
/// Remove {@code listener} from the list of parse listeners.
/// <p/>
/// If {@code listener} is {@code null} or has not been added as a parse
/// listener, this method does nothing.
/// </summary>
/// <seealso cref= #addParseListener
/// </seealso>
/// <param name="listener"> the listener to remove </param>
virtual void removeParseListener(tree::ParseTreeListener *listener);
/// <summary>
/// Remove all parse listeners.
/// </summary>
/// <seealso cref= #addParseListener </seealso>
virtual void removeParseListeners();
/// <summary>
/// Notify any parse listeners of an enter rule event.
/// </summary>
/// <seealso cref= #addParseListener </seealso>
virtual void triggerEnterRuleEvent();
/// <summary>
/// Notify any parse listeners of an exit rule event.
/// </summary>
/// <seealso cref= #addParseListener </seealso>
virtual void triggerExitRuleEvent();
/// <summary>
/// Gets the number of syntax errors reported during parsing. This value is
/// incremented each time <seealso cref="#notifyErrorListeners"/> is called.
/// </summary>
/// <seealso cref= #notifyErrorListeners </seealso>
virtual size_t getNumberOfSyntaxErrors();
virtual TokenFactory<CommonToken>* getTokenFactory() override;
/// <summary>
/// Tell our token source and error strategy about a new way to create tokens. </summary>
template<typename T1>
void setTokenFactory(TokenFactory<T1> *factory) {
_input->getTokenSource()->setTokenFactory(factory);
}
/// The ATN with bypass alternatives is expensive to create so we create it
/// lazily. The ATN is owned by us.
virtual const atn::ATN& getATNWithBypassAlts();
/// <summary>
/// The preferred method of getting a tree pattern. For example, here's a
/// sample use:
///
/// <pre>
/// ParseTree t = parser.expr();
/// ParseTreePattern p = parser.compileParseTreePattern("<ID>+0", MyParser.RULE_expr);
/// ParseTreeMatch m = p.match(t);
/// String id = m.get("ID");
/// </pre>
/// </summary>
virtual tree::pattern::ParseTreePattern compileParseTreePattern(const std::string &pattern, int patternRuleIndex);
/// <summary>
/// The same as <seealso cref="#compileParseTreePattern(String, int)"/> but specify a
/// <seealso cref="Lexer"/> rather than trying to deduce it from this parser.
/// </summary>
virtual tree::pattern::ParseTreePattern compileParseTreePattern(const std::string &pattern, int patternRuleIndex,
Lexer *lexer);
virtual Ref<ANTLRErrorStrategy> getErrorHandler();
virtual void setErrorHandler(Ref<ANTLRErrorStrategy> const& handler);
virtual IntStream* getInputStream() override;
void setInputStream(IntStream *input) override;
virtual TokenStream* getTokenStream();
/// Set the token stream and reset the parser.
virtual void setTokenStream(TokenStream *input);
/// <summary>
/// Match needs to return the current input symbol, which gets put
/// into the label for the associated token ref; e.g., x=ID.
/// </summary>
virtual Token* getCurrentToken();
void notifyErrorListeners(const std::string &msg);
virtual void notifyErrorListeners(Token *offendingToken, const std::string &msg, std::exception_ptr e);
/// Consume and return the <seealso cref="#getCurrentToken current symbol"/>.
/// <p/>
/// E.g., given the following input with {@code A} being the current
/// lookahead symbol, this function moves the cursor to {@code B} and returns
/// {@code A}.
///
/// <pre>
/// A B
/// ^
/// </pre>
///
/// If the parser is not in error recovery mode, the consumed symbol is added
/// to the parse tree using <seealso cref="ParserRuleContext#addChild(TerminalNode)"/>, and
/// <seealso cref="ParseTreeListener#visitTerminal"/> is called on any parse listeners.
/// If the parser <em>is</em> in error recovery mode, the consumed symbol is
/// added to the parse tree using {@link #createErrorNode(ParserRuleContext, Token)} then
/// {@link ParserRuleContext#addErrorNode(ErrorNode)} and
/// <seealso cref="ParseTreeListener#visitErrorNode"/> is called on any parse
/// listeners.
virtual Token* consume();
/// Always called by generated parsers upon entry to a rule. Access field
/// <seealso cref="#_ctx"/> get the current context.
virtual void enterRule(ParserRuleContext *localctx, size_t state, size_t ruleIndex);
void exitRule();
virtual void enterOuterAlt(ParserRuleContext *localctx, size_t altNum);
/**
* Get the precedence level for the top-most precedence rule.
*
* @return The precedence level for the top-most precedence rule, or -1 if
* the parser context is not nested within a precedence rule.
*/
int getPrecedence() const;
/// @deprecated Use
/// <seealso cref="#enterRecursionRule(ParserRuleContext, int, int, int)"/> instead.
virtual void enterRecursionRule(ParserRuleContext *localctx, size_t ruleIndex);
virtual void enterRecursionRule(ParserRuleContext *localctx, size_t state, size_t ruleIndex, int precedence);
/** Like {@link #enterRule} but for recursive rules.
* Make the current context the child of the incoming localctx.
*/
virtual void pushNewRecursionContext(ParserRuleContext *localctx, size_t state, size_t ruleIndex);
virtual void unrollRecursionContexts(ParserRuleContext *parentctx);
virtual ParserRuleContext* getInvokingContext(size_t ruleIndex);
virtual ParserRuleContext* getContext();
virtual void setContext(ParserRuleContext *ctx);
virtual bool precpred(RuleContext *localctx, int precedence) override;
virtual bool inContext(const std::string &context);
/// <summary>
/// Checks whether or not {@code symbol} can follow the current state in the
/// ATN. The behavior of this method is equivalent to the following, but is
/// implemented such that the complete context-sensitive follow set does not
/// need to be explicitly constructed.
///
/// <pre>
/// return getExpectedTokens().contains(symbol);
/// </pre>
/// </summary>
/// <param name="symbol"> the symbol type to check </param>
/// <returns> {@code true} if {@code symbol} can follow the current state in
/// the ATN, otherwise {@code false}. </returns>
virtual bool isExpectedToken(size_t symbol);
bool isMatchedEOF() const;
/// <summary>
/// Computes the set of input symbols which could follow the current parser
/// state and context, as given by <seealso cref="#getState"/> and <seealso cref="#getContext"/>,
/// respectively.
/// </summary>
/// <seealso cref= ATN#getExpectedTokens(int, RuleContext) </seealso>
virtual misc::IntervalSet getExpectedTokens();
virtual misc::IntervalSet getExpectedTokensWithinCurrentRule();
/// Get a rule's index (i.e., {@code RULE_ruleName} field) or INVALID_INDEX if not found.
virtual size_t getRuleIndex(const std::string &ruleName);
virtual ParserRuleContext* getRuleContext();
/// <summary>
/// Return List&lt;String&gt; of the rule names in your parser instance
/// leading up to a call to the current rule. You could override if
/// you want more details such as the file/line info of where
/// in the ATN a rule is invoked.
///
/// This is very useful for error messages.
/// </summary>
virtual std::vector<std::string> getRuleInvocationStack();
virtual std::vector<std::string> getRuleInvocationStack(RuleContext *p);
/// <summary>
/// For debugging and other purposes. </summary>
virtual std::vector<std::string> getDFAStrings();
/// <summary>
/// For debugging and other purposes. </summary>
virtual void dumpDFA();
virtual std::string getSourceName();
atn::ParseInfo getParseInfo() const;
/**
* @since 4.3
*/
void setProfile(bool profile);
/// <summary>
/// During a parse is sometimes useful to listen in on the rule entry and exit
/// events as well as token matches. This is for quick and dirty debugging.
/// </summary>
virtual void setTrace(bool trace);
/**
* Gets whether a {@link TraceListener} is registered as a parse listener
* for the parser.
*
* @see #setTrace(boolean)
*/
bool isTrace() const;
tree::ParseTreeTracker& getTreeTracker() { return _tracker; }
/** How to create a token leaf node associated with a parent.
* Typically, the terminal node to create is not a function of the parent
* but this method must still set the parent pointer of the terminal node
* returned. I would prefer having {@link ParserRuleContext#addAnyChild(ParseTree)}
* set the parent pointer, but the parent pointer is implementation dependent
* and currently there is no setParent() in {@link TerminalNode} (and can't
* add method in Java 1.7 without breaking backward compatibility).
*
* @since 4.7
*/
tree::TerminalNode *createTerminalNode(Token *t);
/** How to create an error node, given a token, associated with a parent.
* Typically, the error node to create is not a function of the parent
* but this method must still set the parent pointer of the terminal node
* returned. I would prefer having {@link ParserRuleContext#addAnyChild(ParseTree)}
* set the parent pointer, but the parent pointer is implementation dependent
* and currently there is no setParent() in {@link ErrorNode} (and can't
* add method in Java 1.7 without breaking backward compatibility).
*
* @since 4.7
*/
tree::ErrorNode *createErrorNode(Token *t);
protected:
/// The ParserRuleContext object for the currently executing rule.
/// This is always non-null during the parsing process.
// ml: this is one of the contexts tracked in _allocatedContexts.
ParserRuleContext *_ctx;
/// The error handling strategy for the parser. The default is DefaultErrorStrategy.
/// See also getErrorHandler.
Ref<ANTLRErrorStrategy> _errHandler;
/// <summary>
/// The input stream.
/// </summary>
/// <seealso cref= #getInputStream </seealso>
/// <seealso cref= #setInputStream </seealso>
TokenStream *_input;
std::vector<int> _precedenceStack;
/// <summary>
/// Specifies whether or not the parser should construct a parse tree during
/// the parsing process. The default value is {@code true}.
/// </summary>
/// <seealso cref= #getBuildParseTree </seealso>
/// <seealso cref= #setBuildParseTree </seealso>
bool _buildParseTrees;
/// The list of <seealso cref="ParseTreeListener"/> listeners registered to receive
/// events during the parse.
/// <seealso cref= #addParseListener </seealso>
std::vector<tree::ParseTreeListener *> _parseListeners;
/// <summary>
/// The number of syntax errors reported during parsing. This value is
/// incremented each time <seealso cref="#notifyErrorListeners"/> is called.
/// </summary>
size_t _syntaxErrors;
/** Indicates parser has match()ed EOF token. See {@link #exitRule()}. */
bool _matchedEOF;
virtual void addContextToParseTree();
// All rule contexts created during a parse run. This is cleared when calling reset().
tree::ParseTreeTracker _tracker;
private:
/// When setTrace(true) is called, a reference to the
/// TraceListener is stored here so it can be easily removed in a
/// later call to setTrace(false). The listener itself is
/// implemented as a parser listener so this field is not directly used by
/// other parser methods.
TraceListener *_tracer;
void InitializeInstanceFields();
};
} // namespace antlr4

View File

@@ -0,0 +1,294 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "dfa/DFA.h"
#include "atn/RuleStartState.h"
#include "InterpreterRuleContext.h"
#include "atn/ParserATNSimulator.h"
#include "ANTLRErrorStrategy.h"
#include "atn/LoopEndState.h"
#include "FailedPredicateException.h"
#include "atn/StarLoopEntryState.h"
#include "atn/AtomTransition.h"
#include "atn/RuleTransition.h"
#include "atn/PredicateTransition.h"
#include "atn/PrecedencePredicateTransition.h"
#include "atn/ActionTransition.h"
#include "atn/ATN.h"
#include "atn/RuleStopState.h"
#include "Lexer.h"
#include "Token.h"
#include "Vocabulary.h"
#include "InputMismatchException.h"
#include "CommonToken.h"
#include "tree/ErrorNode.h"
#include "support/CPPUtils.h"
#include "support/Casts.h"
#include "ParserInterpreter.h"
using namespace antlr4;
using namespace antlr4::atn;
using namespace antlr4::misc;
using namespace antlrcpp;
ParserInterpreter::ParserInterpreter(const std::string &grammarFileName, const dfa::Vocabulary &vocabulary,
const std::vector<std::string> &ruleNames, const atn::ATN &atn, TokenStream *input)
: Parser(input), _grammarFileName(grammarFileName), _atn(atn), _ruleNames(ruleNames), _vocabulary(vocabulary) {
// init decision DFA
for (size_t i = 0; i < atn.getNumberOfDecisions(); ++i) {
atn::DecisionState *decisionState = atn.getDecisionState(i);
_decisionToDFA.push_back(dfa::DFA(decisionState, i));
}
// get atn simulator that knows how to do predictions
_interpreter = new atn::ParserATNSimulator(this, atn, _decisionToDFA, _sharedContextCache); /* mem-check: deleted in d-tor */
}
ParserInterpreter::~ParserInterpreter() {
delete _interpreter;
}
void ParserInterpreter::reset() {
Parser::reset();
_overrideDecisionReached = false;
_overrideDecisionRoot = nullptr;
}
const atn::ATN& ParserInterpreter::getATN() const {
return _atn;
}
const dfa::Vocabulary& ParserInterpreter::getVocabulary() const {
return _vocabulary;
}
const std::vector<std::string>& ParserInterpreter::getRuleNames() const {
return _ruleNames;
}
std::string ParserInterpreter::getGrammarFileName() const {
return _grammarFileName;
}
ParserRuleContext* ParserInterpreter::parse(size_t startRuleIndex) {
atn::RuleStartState *startRuleStartState = _atn.ruleToStartState[startRuleIndex];
_rootContext = createInterpreterRuleContext(nullptr, atn::ATNState::INVALID_STATE_NUMBER, startRuleIndex);
if (startRuleStartState->isLeftRecursiveRule) {
enterRecursionRule(_rootContext, startRuleStartState->stateNumber, startRuleIndex, 0);
} else {
enterRule(_rootContext, startRuleStartState->stateNumber, startRuleIndex);
}
while (true) {
atn::ATNState *p = getATNState();
switch (p->getStateType()) {
case atn::ATNStateType::RULE_STOP :
// pop; return from rule
if (_ctx->isEmpty()) {
if (startRuleStartState->isLeftRecursiveRule) {
ParserRuleContext *result = _ctx;
auto parentContext = _parentContextStack.top();
_parentContextStack.pop();
unrollRecursionContexts(parentContext.first);
return result;
} else {
exitRule();
return _rootContext;
}
}
visitRuleStopState(p);
break;
default :
try {
visitState(p);
}
catch (RecognitionException &e) {
setState(_atn.ruleToStopState[p->ruleIndex]->stateNumber);
getErrorHandler()->reportError(this, e);
getContext()->exception = std::current_exception();
recover(e);
}
break;
}
}
}
void ParserInterpreter::enterRecursionRule(ParserRuleContext *localctx, size_t state, size_t ruleIndex, int precedence) {
_parentContextStack.push({ _ctx, localctx->invokingState });
Parser::enterRecursionRule(localctx, state, ruleIndex, precedence);
}
void ParserInterpreter::addDecisionOverride(int decision, int tokenIndex, int forcedAlt) {
_overrideDecision = decision;
_overrideDecisionInputIndex = tokenIndex;
_overrideDecisionAlt = forcedAlt;
}
Ref<InterpreterRuleContext> ParserInterpreter::getOverrideDecisionRoot() const {
return _overrideDecisionRoot;
}
InterpreterRuleContext* ParserInterpreter::getRootContext() {
return _rootContext;
}
atn::ATNState* ParserInterpreter::getATNState() {
return _atn.states[getState()];
}
void ParserInterpreter::visitState(atn::ATNState *p) {
size_t predictedAlt = 1;
if (DecisionState::is(p)) {
predictedAlt = visitDecisionState(downCast<DecisionState*>(p));
}
const atn::Transition *transition = p->transitions[predictedAlt - 1].get();
switch (transition->getTransitionType()) {
case atn::TransitionType::EPSILON:
if (p->getStateType() == ATNStateType::STAR_LOOP_ENTRY &&
(downCast<StarLoopEntryState *>(p))->isPrecedenceDecision &&
!LoopEndState::is(transition->target)) {
// We are at the start of a left recursive rule's (...)* loop
// and we're not taking the exit branch of loop.
InterpreterRuleContext *localctx = createInterpreterRuleContext(_parentContextStack.top().first,
_parentContextStack.top().second, static_cast<int>(_ctx->getRuleIndex()));
pushNewRecursionContext(localctx, _atn.ruleToStartState[p->ruleIndex]->stateNumber, static_cast<int>(_ctx->getRuleIndex()));
}
break;
case atn::TransitionType::ATOM:
match(static_cast<int>(static_cast<const atn::AtomTransition*>(transition)->_label));
break;
case atn::TransitionType::RANGE:
case atn::TransitionType::SET:
case atn::TransitionType::NOT_SET:
if (!transition->matches(static_cast<int>(_input->LA(1)), Token::MIN_USER_TOKEN_TYPE, Lexer::MAX_CHAR_VALUE)) {
recoverInline();
}
matchWildcard();
break;
case atn::TransitionType::WILDCARD:
matchWildcard();
break;
case atn::TransitionType::RULE:
{
atn::RuleStartState *ruleStartState = static_cast<atn::RuleStartState*>(transition->target);
size_t ruleIndex = ruleStartState->ruleIndex;
InterpreterRuleContext *newctx = createInterpreterRuleContext(_ctx, p->stateNumber, ruleIndex);
if (ruleStartState->isLeftRecursiveRule) {
enterRecursionRule(newctx, ruleStartState->stateNumber, ruleIndex, static_cast<const atn::RuleTransition*>(transition)->precedence);
} else {
enterRule(newctx, transition->target->stateNumber, ruleIndex);
}
}
break;
case atn::TransitionType::PREDICATE:
{
const atn::PredicateTransition *predicateTransition = static_cast<const atn::PredicateTransition*>(transition);
if (!sempred(_ctx, predicateTransition->getRuleIndex(), predicateTransition->getPredIndex())) {
throw FailedPredicateException(this);
}
}
break;
case atn::TransitionType::ACTION:
{
const atn::ActionTransition *actionTransition = static_cast<const atn::ActionTransition*>(transition);
action(_ctx, actionTransition->ruleIndex, actionTransition->actionIndex);
}
break;
case atn::TransitionType::PRECEDENCE:
{
if (!precpred(_ctx, static_cast<const atn::PrecedencePredicateTransition*>(transition)->getPrecedence())) {
throw FailedPredicateException(this, "precpred(_ctx, " + std::to_string(static_cast<const atn::PrecedencePredicateTransition*>(transition)->getPrecedence()) + ")");
}
}
break;
default:
throw UnsupportedOperationException("Unrecognized ATN transition type.");
}
setState(transition->target->stateNumber);
}
size_t ParserInterpreter::visitDecisionState(DecisionState *p) {
size_t predictedAlt = 1;
if (p->transitions.size() > 1) {
getErrorHandler()->sync(this);
int decision = p->decision;
if (decision == _overrideDecision && _input->index() == _overrideDecisionInputIndex && !_overrideDecisionReached) {
predictedAlt = _overrideDecisionAlt;
_overrideDecisionReached = true;
} else {
predictedAlt = getInterpreter<ParserATNSimulator>()->adaptivePredict(_input, decision, _ctx);
}
}
return predictedAlt;
}
InterpreterRuleContext* ParserInterpreter::createInterpreterRuleContext(ParserRuleContext *parent,
size_t invokingStateNumber, size_t ruleIndex) {
return _tracker.createInstance<InterpreterRuleContext>(parent, invokingStateNumber, ruleIndex);
}
void ParserInterpreter::visitRuleStopState(atn::ATNState *p) {
atn::RuleStartState *ruleStartState = _atn.ruleToStartState[p->ruleIndex];
if (ruleStartState->isLeftRecursiveRule) {
std::pair<ParserRuleContext *, size_t> parentContext = _parentContextStack.top();
_parentContextStack.pop();
unrollRecursionContexts(parentContext.first);
setState(parentContext.second);
} else {
exitRule();
}
const atn::RuleTransition *ruleTransition = static_cast<const atn::RuleTransition*>(_atn.states[getState()]->transitions[0].get());
setState(ruleTransition->followState->stateNumber);
}
void ParserInterpreter::recover(RecognitionException &e) {
size_t i = _input->index();
getErrorHandler()->recover(this, std::make_exception_ptr(e));
if (_input->index() == i) {
// no input consumed, better add an error node
if (is<InputMismatchException *>(&e)) {
InputMismatchException &ime = static_cast<InputMismatchException&>(e);
Token *tok = e.getOffendingToken();
size_t expectedTokenType = ime.getExpectedTokens().getMinElement(); // get any element
_errorToken = getTokenFactory()->create({ tok->getTokenSource(), tok->getTokenSource()->getInputStream() },
expectedTokenType, tok->getText(), Token::DEFAULT_CHANNEL, INVALID_INDEX, INVALID_INDEX, // invalid start/stop
tok->getLine(), tok->getCharPositionInLine());
_ctx->addChild(createErrorNode(_errorToken.get()));
}
else { // NoViableAlt
Token *tok = e.getOffendingToken();
_errorToken = getTokenFactory()->create({ tok->getTokenSource(), tok->getTokenSource()->getInputStream() },
Token::INVALID_TYPE, tok->getText(), Token::DEFAULT_CHANNEL, INVALID_INDEX, INVALID_INDEX, // invalid start/stop
tok->getLine(), tok->getCharPositionInLine());
_ctx->addChild(createErrorNode(_errorToken.get()));
}
}
}
Token* ParserInterpreter::recoverInline() {
return _errHandler->recoverInline(this);
}

View File

@@ -0,0 +1,173 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "Parser.h"
#include "atn/ATN.h"
#include "support/BitSet.h"
#include "atn/PredictionContext.h"
#include "atn/PredictionContextCache.h"
#include "Vocabulary.h"
namespace antlr4 {
/// <summary>
/// A parser simulator that mimics what ANTLR's generated
/// parser code does. A ParserATNSimulator is used to make
/// predictions via adaptivePredict but this class moves a pointer through the
/// ATN to simulate parsing. ParserATNSimulator just
/// makes us efficient rather than having to backtrack, for example.
///
/// This properly creates parse trees even for left recursive rules.
///
/// We rely on the left recursive rule invocation and special predicate
/// transitions to make left recursive rules work.
///
/// See TestParserInterpreter for examples.
/// </summary>
class ANTLR4CPP_PUBLIC ParserInterpreter : public Parser {
public:
ParserInterpreter(const std::string &grammarFileName, const dfa::Vocabulary &vocabulary,
const std::vector<std::string> &ruleNames, const atn::ATN &atn, TokenStream *input);
~ParserInterpreter();
virtual void reset() override;
virtual const atn::ATN& getATN() const override;
virtual const dfa::Vocabulary& getVocabulary() const override;
virtual const std::vector<std::string>& getRuleNames() const override;
virtual std::string getGrammarFileName() const override;
/// Begin parsing at startRuleIndex
virtual ParserRuleContext* parse(size_t startRuleIndex);
virtual void enterRecursionRule(ParserRuleContext *localctx, size_t state, size_t ruleIndex, int precedence) override;
/** Override this parser interpreters normal decision-making process
* at a particular decision and input token index. Instead of
* allowing the adaptive prediction mechanism to choose the
* first alternative within a block that leads to a successful parse,
* force it to take the alternative, 1..n for n alternatives.
*
* As an implementation limitation right now, you can only specify one
* override. This is sufficient to allow construction of different
* parse trees for ambiguous input. It means re-parsing the entire input
* in general because you're never sure where an ambiguous sequence would
* live in the various parse trees. For example, in one interpretation,
* an ambiguous input sequence would be matched completely in expression
* but in another it could match all the way back to the root.
*
* s : e '!'? ;
* e : ID
* | ID '!'
* ;
*
* Here, x! can be matched as (s (e ID) !) or (s (e ID !)). In the first
* case, the ambiguous sequence is fully contained only by the root.
* In the second case, the ambiguous sequences fully contained within just
* e, as in: (e ID !).
*
* Rather than trying to optimize this and make
* some intelligent decisions for optimization purposes, I settled on
* just re-parsing the whole input and then using
* {link Trees#getRootOfSubtreeEnclosingRegion} to find the minimal
* subtree that contains the ambiguous sequence. I originally tried to
* record the call stack at the point the parser detected and ambiguity but
* left recursive rules create a parse tree stack that does not reflect
* the actual call stack. That impedance mismatch was enough to make
* it it challenging to restart the parser at a deeply nested rule
* invocation.
*
* Only parser interpreters can override decisions so as to avoid inserting
* override checking code in the critical ALL(*) prediction execution path.
*
* @since 4.5.1
*/
void addDecisionOverride(int decision, int tokenIndex, int forcedAlt);
Ref<InterpreterRuleContext> getOverrideDecisionRoot() const;
/** Return the root of the parse, which can be useful if the parser
* bails out. You still can access the top node. Note that,
* because of the way left recursive rules add children, it's possible
* that the root will not have any children if the start rule immediately
* called and left recursive rule that fails.
*
* @since 4.5.1
*/
InterpreterRuleContext* getRootContext();
protected:
const std::string _grammarFileName;
const atn::ATN &_atn;
std::vector<std::string> _ruleNames;
std::vector<dfa::DFA> _decisionToDFA; // not shared like it is for generated parsers
atn::PredictionContextCache _sharedContextCache;
/** This stack corresponds to the _parentctx, _parentState pair of locals
* that would exist on call stack frames with a recursive descent parser;
* in the generated function for a left-recursive rule you'd see:
*
* private EContext e(int _p) throws RecognitionException {
* ParserRuleContext _parentctx = _ctx; // Pair.a
* int _parentState = getState(); // Pair.b
* ...
* }
*
* Those values are used to create new recursive rule invocation contexts
* associated with left operand of an alt like "expr '*' expr".
*/
std::stack<std::pair<ParserRuleContext *, size_t>> _parentContextStack;
/** We need a map from (decision,inputIndex)->forced alt for computing ambiguous
* parse trees. For now, we allow exactly one override.
*/
int _overrideDecision = -1;
size_t _overrideDecisionInputIndex = INVALID_INDEX;
size_t _overrideDecisionAlt = INVALID_INDEX;
bool _overrideDecisionReached = false; // latch and only override once; error might trigger infinite loop
/** What is the current context when we override a decision? This tells
* us what the root of the parse tree is when using override
* for an ambiguity/lookahead check.
*/
Ref<InterpreterRuleContext> _overrideDecisionRoot;
InterpreterRuleContext* _rootContext;
virtual atn::ATNState *getATNState();
virtual void visitState(atn::ATNState *p);
/** Method visitDecisionState() is called when the interpreter reaches
* a decision state (instance of DecisionState). It gives an opportunity
* for subclasses to track interesting things.
*/
size_t visitDecisionState(atn::DecisionState *p);
/** Provide simple "factory" for InterpreterRuleContext's.
* @since 4.5.1
*/
InterpreterRuleContext* createInterpreterRuleContext(ParserRuleContext *parent, size_t invokingStateNumber, size_t ruleIndex);
virtual void visitRuleStopState(atn::ATNState *p);
/** Rely on the error handler for this parser but, if no tokens are consumed
* to recover, add an error node. Otherwise, nothing is seen in the parse
* tree.
*/
void recover(RecognitionException &e);
Token* recoverInline();
private:
const dfa::Vocabulary &_vocabulary;
std::unique_ptr<Token> _errorToken;
};
} // namespace antlr4

View File

@@ -0,0 +1,138 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "tree/TerminalNode.h"
#include "tree/ErrorNode.h"
#include "misc/Interval.h"
#include "Parser.h"
#include "Token.h"
#include "support/Casts.h"
#include "support/CPPUtils.h"
#include "ParserRuleContext.h"
using namespace antlr4;
using namespace antlr4::tree;
using namespace antlrcpp;
ParserRuleContext ParserRuleContext::EMPTY;
ParserRuleContext::ParserRuleContext()
: start(nullptr), stop(nullptr) {
}
ParserRuleContext::ParserRuleContext(ParserRuleContext *parent, size_t invokingStateNumber)
: RuleContext(parent, invokingStateNumber), start(nullptr), stop(nullptr) {
}
void ParserRuleContext::copyFrom(ParserRuleContext *ctx) {
// from RuleContext
this->parent = ctx->parent;
this->invokingState = ctx->invokingState;
this->start = ctx->start;
this->stop = ctx->stop;
// copy any error nodes to alt label node
if (!ctx->children.empty()) {
for (auto *child : ctx->children) {
if (ErrorNode::is(child)) {
downCast<ErrorNode*>(child)->setParent(this);
children.push_back(child);
}
}
// Remove the just reparented error nodes from the source context.
ctx->children.erase(std::remove_if(ctx->children.begin(), ctx->children.end(), [this](tree::ParseTree *e) -> bool {
return std::find(children.begin(), children.end(), e) != children.end();
}), ctx->children.end());
}
}
void ParserRuleContext::enterRule(tree::ParseTreeListener * /*listener*/) {
}
void ParserRuleContext::exitRule(tree::ParseTreeListener * /*listener*/) {
}
tree::TerminalNode* ParserRuleContext::addChild(tree::TerminalNode *t) {
t->setParent(this);
children.push_back(t);
return t;
}
RuleContext* ParserRuleContext::addChild(RuleContext *ruleInvocation) {
children.push_back(ruleInvocation);
return ruleInvocation;
}
void ParserRuleContext::removeLastChild() {
if (!children.empty()) {
children.pop_back();
}
}
tree::TerminalNode* ParserRuleContext::getToken(size_t ttype, size_t i) const {
if (i >= children.size()) {
return nullptr;
}
size_t j = 0; // what token with ttype have we found?
for (auto *child : children) {
if (TerminalNode::is(child)) {
tree::TerminalNode *typedChild = downCast<tree::TerminalNode*>(child);
Token *symbol = typedChild->getSymbol();
if (symbol->getType() == ttype) {
if (j++ == i) {
return typedChild;
}
}
}
}
return nullptr;
}
std::vector<tree::TerminalNode *> ParserRuleContext::getTokens(size_t ttype) const {
std::vector<tree::TerminalNode*> tokens;
for (auto *child : children) {
if (TerminalNode::is(child)) {
tree::TerminalNode *typedChild = downCast<tree::TerminalNode*>(child);
Token *symbol = typedChild->getSymbol();
if (symbol->getType() == ttype) {
tokens.push_back(typedChild);
}
}
}
return tokens;
}
misc::Interval ParserRuleContext::getSourceInterval() {
if (start == nullptr) {
return misc::Interval::INVALID;
}
if (stop == nullptr || stop->getTokenIndex() < start->getTokenIndex()) {
return misc::Interval(start->getTokenIndex(), start->getTokenIndex() - 1); // empty
}
return misc::Interval(start->getTokenIndex(), stop->getTokenIndex());
}
Token* ParserRuleContext::getStart() const {
return start;
}
Token* ParserRuleContext::getStop() const {
return stop;
}
std::string ParserRuleContext::toInfoString(Parser *recognizer) {
std::vector<std::string> rules = recognizer->getRuleInvocationStack(this);
std::reverse(rules.begin(), rules.end());
std::string rulesStr = antlrcpp::arrayToString(rules);
return "ParserRuleContext" + rulesStr + "{start=" + std::to_string(start->getTokenIndex()) + ", stop=" +
std::to_string(stop->getTokenIndex()) + '}';
}

View File

@@ -0,0 +1,147 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "RuleContext.h"
#include "support/CPPUtils.h"
namespace antlr4 {
/// <summary>
/// A rule invocation record for parsing.
///
/// Contains all of the information about the current rule not stored in the
/// RuleContext. It handles parse tree children list, Any ATN state
/// tracing, and the default values available for rule invocatons:
/// start, stop, rule index, current alt number.
///
/// Subclasses made for each rule and grammar track the parameters,
/// return values, locals, and labels specific to that rule. These
/// are the objects that are returned from rules.
///
/// Note text is not an actual field of a rule return value; it is computed
/// from start and stop using the input stream's toString() method. I
/// could add a ctor to this so that we can pass in and store the input
/// stream, but I'm not sure we want to do that. It would seem to be undefined
/// to get the .text property anyway if the rule matches tokens from multiple
/// input streams.
///
/// I do not use getters for fields of objects that are used simply to
/// group values such as this aggregate. The getters/setters are there to
/// satisfy the superclass interface.
/// </summary>
class ANTLR4CPP_PUBLIC ParserRuleContext : public RuleContext {
public:
static ParserRuleContext EMPTY;
/// <summary>
/// For debugging/tracing purposes, we want to track all of the nodes in
/// the ATN traversed by the parser for a particular rule.
/// This list indicates the sequence of ATN nodes used to match
/// the elements of the children list. This list does not include
/// ATN nodes and other rules used to match rule invocations. It
/// traces the rule invocation node itself but nothing inside that
/// other rule's ATN submachine.
///
/// There is NOT a one-to-one correspondence between the children and
/// states list. There are typically many nodes in the ATN traversed
/// for each element in the children list. For example, for a rule
/// invocation there is the invoking state and the following state.
///
/// The parser setState() method updates field s and adds it to this list
/// if we are debugging/tracing.
///
/// This does not trace states visited during prediction.
/// </summary>
// public List<Integer> states;
Token *start;
Token *stop;
/// The exception that forced this rule to return. If the rule successfully
/// completed, this is "null exception pointer".
std::exception_ptr exception;
ParserRuleContext();
ParserRuleContext(ParserRuleContext *parent, size_t invokingStateNumber);
/** COPY a ctx (I'm deliberately not using copy constructor) to avoid
* confusion with creating node with parent. Does not copy children
* (except error leaves).
*/
virtual void copyFrom(ParserRuleContext *ctx);
// Double dispatch methods for listeners
virtual void enterRule(tree::ParseTreeListener *listener);
virtual void exitRule(tree::ParseTreeListener *listener);
/** Add a token leaf node child and force its parent to be this node. */
tree::TerminalNode* addChild(tree::TerminalNode *t);
RuleContext* addChild(RuleContext *ruleInvocation);
/// Used by enterOuterAlt to toss out a RuleContext previously added as
/// we entered a rule. If we have # label, we will need to remove
/// generic ruleContext object.
void removeLastChild();
tree::TerminalNode* getToken(size_t ttype, std::size_t i) const;
std::vector<tree::TerminalNode*> getTokens(size_t ttype) const;
template<typename T>
T* getRuleContext(size_t i) const {
static_assert(std::is_base_of_v<RuleContext, T>, "T must be derived from RuleContext");
size_t j = 0; // what element have we found with ctxType?
for (auto *child : children) {
if (RuleContext::is(child)) {
if (auto *typedChild = dynamic_cast<T*>(child); typedChild != nullptr) {
if (j++ == i) {
return typedChild;
}
}
}
}
return nullptr;
}
template<typename T>
std::vector<T*> getRuleContexts() const {
static_assert(std::is_base_of_v<RuleContext, T>, "T must be derived from RuleContext");
std::vector<T*> contexts;
for (auto *child : children) {
if (RuleContext::is(child)) {
if (auto *typedChild = dynamic_cast<T*>(child); typedChild != nullptr) {
contexts.push_back(typedChild);
}
}
}
return contexts;
}
virtual misc::Interval getSourceInterval() override;
/**
* Get the initial token in this context.
* Note that the range from start to stop is inclusive, so for rules that do not consume anything
* (for example, zero length or error productions) this token may exceed stop.
*/
Token* getStart() const;
/**
* Get the final token in this context.
* Note that the range from start to stop is inclusive, so for rules that do not consume anything
* (for example, zero length or error productions) this token may precede start.
*/
Token* getStop() const;
/// <summary>
/// Used for rule context info debugging during parse-time, not so much for ATN debugging </summary>
virtual std::string toInfoString(Parser *recognizer);
};
} // namespace antlr4

View File

@@ -0,0 +1,53 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "ProxyErrorListener.h"
using namespace antlr4;
void ProxyErrorListener::addErrorListener(ANTLRErrorListener *listener) {
if (listener == nullptr) {
throw "listener cannot be null.";
}
_delegates.insert(listener);
}
void ProxyErrorListener::removeErrorListener(ANTLRErrorListener *listener) {
_delegates.erase(listener);
}
void ProxyErrorListener::removeErrorListeners() {
_delegates.clear();
}
void ProxyErrorListener::syntaxError(Recognizer *recognizer, Token *offendingSymbol, size_t line,
size_t charPositionInLine, const std::string &msg, std::exception_ptr e) {
for (auto *listener : _delegates) {
listener->syntaxError(recognizer, offendingSymbol, line, charPositionInLine, msg, e);
}
}
void ProxyErrorListener::reportAmbiguity(Parser *recognizer, const dfa::DFA &dfa, size_t startIndex, size_t stopIndex,
bool exact, const antlrcpp::BitSet &ambigAlts, atn::ATNConfigSet *configs) {
for (auto *listener : _delegates) {
listener->reportAmbiguity(recognizer, dfa, startIndex, stopIndex, exact, ambigAlts, configs);
}
}
void ProxyErrorListener::reportAttemptingFullContext(Parser *recognizer, const dfa::DFA &dfa, size_t startIndex,
size_t stopIndex, const antlrcpp::BitSet &conflictingAlts, atn::ATNConfigSet *configs) {
for (auto *listener : _delegates) {
listener->reportAttemptingFullContext(recognizer, dfa, startIndex, stopIndex, conflictingAlts, configs);
}
}
void ProxyErrorListener::reportContextSensitivity(Parser *recognizer, const dfa::DFA &dfa, size_t startIndex, size_t stopIndex,
size_t prediction, atn::ATNConfigSet *configs) {
for (auto *listener : _delegates) {
listener->reportContextSensitivity(recognizer, dfa, startIndex, stopIndex, prediction, configs);
}
}

View File

@@ -0,0 +1,38 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "ANTLRErrorListener.h"
#include "Exceptions.h"
namespace antlr4 {
/// This implementation of ANTLRErrorListener dispatches all calls to a
/// collection of delegate listeners. This reduces the effort required to support multiple
/// listeners.
class ANTLR4CPP_PUBLIC ProxyErrorListener : public ANTLRErrorListener {
private:
std::set<ANTLRErrorListener *> _delegates; // Not owned.
public:
void addErrorListener(ANTLRErrorListener *listener);
void removeErrorListener(ANTLRErrorListener *listener);
void removeErrorListeners();
void syntaxError(Recognizer *recognizer, Token *offendingSymbol, size_t line, size_t charPositionInLine,
const std::string &msg, std::exception_ptr e) override;
virtual void reportAmbiguity(Parser *recognizer, const dfa::DFA &dfa, size_t startIndex, size_t stopIndex, bool exact,
const antlrcpp::BitSet &ambigAlts, atn::ATNConfigSet *configs) override;
virtual void reportAttemptingFullContext(Parser *recognizer, const dfa::DFA &dfa, size_t startIndex, size_t stopIndex,
const antlrcpp::BitSet &conflictingAlts, atn::ATNConfigSet *configs) override;
virtual void reportContextSensitivity(Parser *recognizer, const dfa::DFA &dfa, size_t startIndex, size_t stopIndex,
size_t prediction, atn::ATNConfigSet *configs) override;
};
} // namespace antlr4

View File

@@ -0,0 +1,65 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "atn/ATN.h"
#include "Recognizer.h"
#include "ParserRuleContext.h"
#include "misc/IntervalSet.h"
#include "RecognitionException.h"
using namespace antlr4;
RecognitionException::RecognitionException(Recognizer *recognizer, IntStream *input, ParserRuleContext *ctx,
Token *offendingToken)
: RecognitionException("", recognizer, input, ctx, offendingToken) {
}
RecognitionException::RecognitionException(const std::string &message, Recognizer *recognizer, IntStream *input,
ParserRuleContext *ctx, Token *offendingToken)
: RuntimeException(message), _recognizer(recognizer), _input(input), _ctx(ctx), _offendingToken(offendingToken) {
InitializeInstanceFields();
if (recognizer != nullptr) {
_offendingState = recognizer->getState();
}
}
RecognitionException::~RecognitionException() {
}
size_t RecognitionException::getOffendingState() const {
return _offendingState;
}
void RecognitionException::setOffendingState(size_t offendingState) {
_offendingState = offendingState;
}
misc::IntervalSet RecognitionException::getExpectedTokens() const {
if (_recognizer) {
return _recognizer->getATN().getExpectedTokens(_offendingState, _ctx);
}
return misc::IntervalSet::EMPTY_SET;
}
RuleContext* RecognitionException::getCtx() const {
return _ctx;
}
IntStream* RecognitionException::getInputStream() const {
return _input;
}
Token* RecognitionException::getOffendingToken() const {
return _offendingToken;
}
Recognizer* RecognitionException::getRecognizer() const {
return _recognizer;
}
void RecognitionException::InitializeInstanceFields() {
_offendingState = INVALID_INDEX;
}

View File

@@ -0,0 +1,98 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "Exceptions.h"
namespace antlr4 {
/// The root of the ANTLR exception hierarchy. In general, ANTLR tracks just
/// 3 kinds of errors: prediction errors, failed predicate errors, and
/// mismatched input errors. In each case, the parser knows where it is
/// in the input, where it is in the ATN, the rule invocation stack,
/// and what kind of problem occurred.
class ANTLR4CPP_PUBLIC RecognitionException : public RuntimeException {
private:
/// The Recognizer where this exception originated.
Recognizer *_recognizer;
IntStream *_input;
ParserRuleContext *_ctx;
/// The current Token when an error occurred. Since not all streams
/// support accessing symbols by index, we have to track the Token
/// instance itself.
Token *_offendingToken;
size_t _offendingState;
public:
RecognitionException(Recognizer *recognizer, IntStream *input, ParserRuleContext *ctx,
Token *offendingToken = nullptr);
RecognitionException(const std::string &message, Recognizer *recognizer, IntStream *input,
ParserRuleContext *ctx, Token *offendingToken = nullptr);
RecognitionException(RecognitionException const&) = default;
~RecognitionException();
RecognitionException& operator=(RecognitionException const&) = default;
/// Get the ATN state number the parser was in at the time the error
/// occurred. For NoViableAltException and
/// LexerNoViableAltException exceptions, this is the
/// DecisionState number. For others, it is the state whose outgoing
/// edge we couldn't match.
///
/// If the state number is not known, this method returns -1.
virtual size_t getOffendingState() const;
protected:
void setOffendingState(size_t offendingState);
/// Gets the set of input symbols which could potentially follow the
/// previously matched symbol at the time this exception was thrown.
///
/// If the set of expected tokens is not known and could not be computed,
/// this method returns an empty set.
///
/// @returns The set of token types that could potentially follow the current
/// state in the ATN, or an empty set if the information is not available.
public:
virtual misc::IntervalSet getExpectedTokens() const;
/// <summary>
/// Gets the <seealso cref="RuleContext"/> at the time this exception was thrown.
/// <p/>
/// If the context is not available, this method returns {@code null}.
/// </summary>
/// <returns> The <seealso cref="RuleContext"/> at the time this exception was thrown.
/// If the context is not available, this method returns {@code null}. </returns>
virtual RuleContext* getCtx() const;
/// <summary>
/// Gets the input stream which is the symbol source for the recognizer where
/// this exception was thrown.
/// <p/>
/// If the input stream is not available, this method returns {@code null}.
/// </summary>
/// <returns> The input stream which is the symbol source for the recognizer
/// where this exception was thrown, or {@code null} if the stream is not
/// available. </returns>
virtual IntStream* getInputStream() const;
virtual Token* getOffendingToken() const;
/// <summary>
/// Gets the <seealso cref="Recognizer"/> where this exception occurred.
/// <p/>
/// If the recognizer is not available, this method returns {@code null}.
/// </summary>
/// <returns> The recognizer where this exception occurred, or {@code null} if
/// the recognizer is not available. </returns>
virtual Recognizer* getRecognizer() const;
private:
void InitializeInstanceFields();
};
} // namespace antlr4

View File

@@ -0,0 +1,157 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "ConsoleErrorListener.h"
#include "RecognitionException.h"
#include "support/CPPUtils.h"
#include "Token.h"
#include "atn/ATN.h"
#include "atn/ATNSimulator.h"
#include "support/CPPUtils.h"
#include "support/StringUtils.h"
#include "Vocabulary.h"
#include "Recognizer.h"
using namespace antlr4;
using namespace antlr4::atn;
using namespace antlr4::internal;
std::map<const dfa::Vocabulary*, std::map<std::string_view, size_t>> Recognizer::_tokenTypeMapCache;
std::map<std::vector<std::string>, std::map<std::string, size_t>> Recognizer::_ruleIndexMapCache;
Recognizer::Recognizer() {
InitializeInstanceFields();
_proxListener.addErrorListener(&ConsoleErrorListener::INSTANCE);
}
Recognizer::~Recognizer() {
}
std::map<std::string_view, size_t> Recognizer::getTokenTypeMap() {
const dfa::Vocabulary& vocabulary = getVocabulary();
UniqueLock<Mutex> lck(_mutex);
std::map<std::string_view, size_t> result;
auto iterator = _tokenTypeMapCache.find(&vocabulary);
if (iterator != _tokenTypeMapCache.end()) {
result = iterator->second;
} else {
for (size_t i = 0; i <= getATN().maxTokenType; ++i) {
std::string_view literalName = vocabulary.getLiteralName(i);
if (!literalName.empty()) {
result[literalName] = i;
}
std::string_view symbolicName = vocabulary.getSymbolicName(i);
if (!symbolicName.empty()) {
result[symbolicName] = i;
}
}
result["EOF"] = EOF;
_tokenTypeMapCache[&vocabulary] = result;
}
return result;
}
std::map<std::string, size_t> Recognizer::getRuleIndexMap() {
const std::vector<std::string>& ruleNames = getRuleNames();
if (ruleNames.empty()) {
throw "The current recognizer does not provide a list of rule names.";
}
UniqueLock<Mutex> lck(_mutex);
std::map<std::string, size_t> result;
auto iterator = _ruleIndexMapCache.find(ruleNames);
if (iterator != _ruleIndexMapCache.end()) {
result = iterator->second;
} else {
result = antlrcpp::toMap(ruleNames);
_ruleIndexMapCache[ruleNames] = result;
}
return result;
}
size_t Recognizer::getTokenType(std::string_view tokenName) {
const std::map<std::string_view, size_t> &map = getTokenTypeMap();
auto iterator = map.find(tokenName);
if (iterator == map.end())
return Token::INVALID_TYPE;
return iterator->second;
}
void Recognizer::setInterpreter(atn::ATNSimulator *interpreter) {
// Usually the interpreter is set by the descendant (lexer or parser (simulator), but can also be exchanged
// by the profiling ATN simulator.
delete _interpreter;
_interpreter = interpreter;
}
std::string Recognizer::getErrorHeader(RecognitionException *e) {
// We're having issues with cross header dependencies, these two classes will need to be
// rewritten to remove that.
size_t line = e->getOffendingToken()->getLine();
size_t charPositionInLine = e->getOffendingToken()->getCharPositionInLine();
return std::string("line ") + std::to_string(line) + ":" + std::to_string(charPositionInLine);
}
std::string Recognizer::getTokenErrorDisplay(Token *t) {
if (t == nullptr) {
return "<no Token>";
}
std::string s = t->getText();
if (s == "") {
if (t->getType() == EOF) {
s = "<EOF>";
} else {
s = std::string("<") + std::to_string(t->getType()) + std::string(">");
}
}
std::string result;
result.reserve(s.size() + 2);
result.push_back('\'');
antlrcpp::escapeWhitespace(result, s);
result.push_back('\'');
result.shrink_to_fit();
return result;
}
void Recognizer::addErrorListener(ANTLRErrorListener *listener) {
_proxListener.addErrorListener(listener);
}
void Recognizer::removeErrorListener(ANTLRErrorListener *listener) {
_proxListener.removeErrorListener(listener);
}
void Recognizer::removeErrorListeners() {
_proxListener.removeErrorListeners();
}
ProxyErrorListener& Recognizer::getErrorListenerDispatch() {
return _proxListener;
}
bool Recognizer::sempred(RuleContext * /*localctx*/, size_t /*ruleIndex*/, size_t /*actionIndex*/) {
return true;
}
bool Recognizer::precpred(RuleContext * /*localctx*/, int /*precedence*/) {
return true;
}
void Recognizer::action(RuleContext * /*localctx*/, size_t /*ruleIndex*/, size_t /*actionIndex*/) {
}
void Recognizer::InitializeInstanceFields() {
_stateNumber = ATNState::INVALID_STATE_NUMBER;
_interpreter = nullptr;
}

View File

@@ -0,0 +1,160 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "ProxyErrorListener.h"
#include "support/Casts.h"
#include "atn/SerializedATNView.h"
#include "internal/Synchronization.h"
namespace antlr4 {
class ANTLR4CPP_PUBLIC Recognizer {
public:
static constexpr size_t EOF = std::numeric_limits<size_t>::max();
Recognizer();
Recognizer(Recognizer const&) = delete;
virtual ~Recognizer();
Recognizer& operator=(Recognizer const&) = delete;
virtual std::vector<std::string> const& getRuleNames() const = 0;
/**
* Get the vocabulary used by the recognizer.
*
* @return A {@link Vocabulary} instance providing information about the
* vocabulary used by the grammar.
*/
virtual dfa::Vocabulary const& getVocabulary() const = 0;
/// <summary>
/// Get a map from token names to token types.
/// <p/>
/// Used for XPath and tree pattern compilation.
/// </summary>
virtual std::map<std::string_view, size_t> getTokenTypeMap();
/// <summary>
/// Get a map from rule names to rule indexes.
/// <p/>
/// Used for XPath and tree pattern compilation.
/// </summary>
virtual std::map<std::string, size_t> getRuleIndexMap();
virtual size_t getTokenType(std::string_view tokenName);
/// <summary>
/// If this recognizer was generated, it will have a serialized ATN
/// representation of the grammar.
/// <p/>
/// For interpreters, we don't know their serialized ATN despite having
/// created the interpreter from it.
/// </summary>
virtual atn::SerializedATNView getSerializedATN() const {
throw "there is no serialized ATN";
}
/// <summary>
/// For debugging and other purposes, might want the grammar name.
/// Have ANTLR generate an implementation for this method.
/// </summary>
virtual std::string getGrammarFileName() const = 0;
/// Get the ATN interpreter (in fact one of it's descendants) used by the recognizer for prediction.
/// @returns The ATN interpreter used by the recognizer for prediction.
template <class T>
T* getInterpreter() const {
return antlrcpp::downCast<T *>(_interpreter);
}
/**
* Set the ATN interpreter used by the recognizer for prediction.
*
* @param interpreter The ATN interpreter used by the recognizer for
* prediction.
*/
void setInterpreter(atn::ATNSimulator *interpreter);
/// What is the error header, normally line/character position information?
virtual std::string getErrorHeader(RecognitionException *e);
/** How should a token be displayed in an error message? The default
* is to display just the text, but during development you might
* want to have a lot of information spit out. Override in that case
* to use t.toString() (which, for CommonToken, dumps everything about
* the token). This is better than forcing you to override a method in
* your token objects because you don't have to go modify your lexer
* so that it creates a new Java type.
*
* @deprecated This method is not called by the ANTLR 4 Runtime. Specific
* implementations of {@link ANTLRErrorStrategy} may provide a similar
* feature when necessary. For example, see
* {@link DefaultErrorStrategy#getTokenErrorDisplay}.
*/
virtual std::string getTokenErrorDisplay(Token *t);
/// <exception cref="NullPointerException"> if {@code listener} is {@code null}. </exception>
virtual void addErrorListener(ANTLRErrorListener *listener);
virtual void removeErrorListener(ANTLRErrorListener *listener);
virtual void removeErrorListeners();
virtual ProxyErrorListener& getErrorListenerDispatch();
// subclass needs to override these if there are sempreds or actions
// that the ATN interp needs to execute
virtual bool sempred(RuleContext *localctx, size_t ruleIndex, size_t actionIndex);
virtual bool precpred(RuleContext *localctx, int precedence);
virtual void action(RuleContext *localctx, size_t ruleIndex, size_t actionIndex);
size_t getState() const { return _stateNumber; }
// Get the ATN used by the recognizer for prediction.
virtual const atn::ATN& getATN() const = 0;
/// <summary>
/// Indicate that the recognizer has changed internal state that is
/// consistent with the ATN state passed in. This way we always know
/// where we are in the ATN as the parser goes along. The rule
/// context objects form a stack that lets us see the stack of
/// invoking rules. Combine this and we have complete ATN
/// configuration information.
/// </summary>
void setState(size_t atnState) { _stateNumber = atnState; }
virtual IntStream* getInputStream() = 0;
virtual void setInputStream(IntStream *input) = 0;
virtual TokenFactory<CommonToken>* getTokenFactory() = 0;
template<typename T1>
void setTokenFactory(TokenFactory<T1> *input);
protected:
atn::ATNSimulator *_interpreter; // Set and deleted in descendants (or the profiler).
// Mutex to manage synchronized access for multithreading.
internal::Mutex _mutex;
private:
static std::map<const dfa::Vocabulary*, std::map<std::string_view, size_t>> _tokenTypeMapCache;
static std::map<std::vector<std::string>, std::map<std::string, size_t>> _ruleIndexMapCache;
ProxyErrorListener _proxListener; // Manages a collection of listeners.
size_t _stateNumber;
void InitializeInstanceFields();
};
} // namespace antlr4

View File

@@ -0,0 +1,144 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "tree/Trees.h"
#include "misc/Interval.h"
#include "Parser.h"
#include "atn/ATN.h"
#include "atn/ATNState.h"
#include "tree/ParseTreeVisitor.h"
#include "RuleContext.h"
using namespace antlr4;
using namespace antlr4::atn;
using namespace antlr4::tree;
RuleContext::RuleContext() : ParseTree(ParseTreeType::RULE) {
InitializeInstanceFields();
}
RuleContext::RuleContext(RuleContext *parent_, size_t invokingState_) : ParseTree(ParseTreeType::RULE) {
InitializeInstanceFields();
this->parent = parent_;
this->invokingState = invokingState_;
}
int RuleContext::depth() {
int n = 1;
RuleContext *p = this;
while (true) {
if (p->parent == nullptr)
break;
p = static_cast<RuleContext *>(p->parent);
n++;
}
return n;
}
bool RuleContext::isEmpty() {
return invokingState == ATNState::INVALID_STATE_NUMBER;
}
misc::Interval RuleContext::getSourceInterval() {
return misc::Interval::INVALID;
}
std::string RuleContext::getText() {
if (children.empty()) {
return "";
}
std::stringstream ss;
for (size_t i = 0; i < children.size(); i++) {
ParseTree *tree = children[i];
if (tree != nullptr)
ss << tree->getText();
}
return ss.str();
}
size_t RuleContext::getRuleIndex() const {
return INVALID_INDEX;
}
size_t RuleContext::getAltNumber() const {
return atn::ATN::INVALID_ALT_NUMBER;
}
void RuleContext::setAltNumber(size_t /*altNumber*/) {
}
std::any RuleContext::accept(tree::ParseTreeVisitor *visitor) {
return visitor->visitChildren(this);
}
std::string RuleContext::toStringTree(Parser *recog, bool pretty) {
return tree::Trees::toStringTree(this, recog, pretty);
}
std::string RuleContext::toStringTree(std::vector<std::string> &ruleNames, bool pretty) {
return tree::Trees::toStringTree(this, ruleNames, pretty);
}
std::string RuleContext::toStringTree(bool pretty) {
return toStringTree(nullptr, pretty);
}
std::string RuleContext::toString(const std::vector<std::string> &ruleNames) {
return toString(ruleNames, nullptr);
}
std::string RuleContext::toString(const std::vector<std::string> &ruleNames, RuleContext *stop) {
std::stringstream ss;
RuleContext *currentParent = this;
ss << "[";
while (currentParent != stop) {
if (ruleNames.empty()) {
if (!currentParent->isEmpty()) {
ss << currentParent->invokingState;
}
} else {
size_t ruleIndex = currentParent->getRuleIndex();
std::string ruleName = (ruleIndex < ruleNames.size()) ? ruleNames[ruleIndex] : std::to_string(ruleIndex);
ss << ruleName;
}
if (currentParent->parent == nullptr) // No parent anymore.
break;
currentParent = static_cast<RuleContext *>(currentParent->parent);
if (!ruleNames.empty() || !currentParent->isEmpty()) {
ss << " ";
}
}
ss << "]";
return ss.str();
}
std::string RuleContext::toString() {
return toString(nullptr);
}
std::string RuleContext::toString(Recognizer *recog) {
return toString(recog, &ParserRuleContext::EMPTY);
}
std::string RuleContext::toString(Recognizer *recog, RuleContext *stop) {
if (recog == nullptr)
return toString(std::vector<std::string>(), stop); // Don't use an initializer {} here or we end up calling ourselve recursivly.
return toString(recog->getRuleNames(), stop);
}
void RuleContext::InitializeInstanceFields() {
invokingState = INVALID_INDEX;
}

View File

@@ -0,0 +1,141 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "tree/ParseTree.h"
namespace antlr4 {
/** A rule context is a record of a single rule invocation.
*
* We form a stack of these context objects using the parent
* pointer. A parent pointer of null indicates that the current
* context is the bottom of the stack. The ParserRuleContext subclass
* as a children list so that we can turn this data structure into a
* tree.
*
* The root node always has a null pointer and invokingState of -1.
*
* Upon entry to parsing, the first invoked rule function creates a
* context object (asubclass specialized for that rule such as
* SContext) and makes it the root of a parse tree, recorded by field
* Parser._ctx.
*
* public final SContext s() throws RecognitionException {
* SContext _localctx = new SContext(_ctx, getState()); <-- create new node
* enterRule(_localctx, 0, RULE_s); <-- push it
* ...
* exitRule(); <-- pop back to _localctx
* return _localctx;
* }
*
* A subsequent rule invocation of r from the start rule s pushes a
* new context object for r whose parent points at s and use invoking
* state is the state with r emanating as edge label.
*
* The invokingState fields from a context object to the root
* together form a stack of rule indication states where the root
* (bottom of the stack) has a -1 sentinel value. If we invoke start
* symbol s then call r1, which calls r2, the would look like
* this:
*
* SContext[-1] <- root node (bottom of the stack)
* R1Context[p] <- p in rule s called r1
* R2Context[q] <- q in rule r1 called r2
*
* So the top of the stack, _ctx, represents a call to the current
* rule and it holds the return address from another rule that invoke
* to this rule. To invoke a rule, we must always have a current context.
*
* The parent contexts are useful for computing lookahead sets and
* getting error information.
*
* These objects are used during parsing and prediction.
* For the special case of parsers, we use the subclass
* ParserRuleContext.
*
* @see ParserRuleContext
*/
class ANTLR4CPP_PUBLIC RuleContext : public tree::ParseTree {
public:
static bool is(const tree::ParseTree &parseTree) { return parseTree.getTreeType() == tree::ParseTreeType::RULE; }
static bool is(const tree::ParseTree *parseTree) { return parseTree != nullptr && is(*parseTree); }
/// 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.
size_t invokingState;
RuleContext();
RuleContext(RuleContext *parent, size_t invokingState);
virtual int depth();
/// A context is empty if there is no invoking state; meaning nobody called current context.
virtual bool isEmpty();
// satisfy the ParseTree / SyntaxTree interface
virtual misc::Interval getSourceInterval() override;
virtual std::string getText() override;
virtual size_t getRuleIndex() const;
/** For rule associated with this parse tree internal node, return
* the outer alternative number used to match the input. Default
* implementation does not compute nor store this alt num. Create
* a subclass of ParserRuleContext with backing field and set
* option contextSuperClass.
* to set it.
*
* @since 4.5.3
*/
virtual size_t getAltNumber() const;
/** Set the outer alternative number for this context node. Default
* implementation does nothing to avoid backing field overhead for
* trees that don't need it. Create
* a subclass of ParserRuleContext with backing field and set
* option contextSuperClass.
*
* @since 4.5.3
*/
virtual void setAltNumber(size_t altNumber);
virtual std::any accept(tree::ParseTreeVisitor *visitor) override;
/// <summary>
/// Print out a whole tree, not just a node, in LISP format
/// (root child1 .. childN). Print just a node if this is a leaf.
/// We have to know the recognizer so we can get rule names.
/// </summary>
virtual std::string toStringTree(Parser *recog, bool pretty = false) override;
/// <summary>
/// Print out a whole tree, not just a node, in LISP format
/// (root child1 .. childN). Print just a node if this is a leaf.
/// </summary>
virtual std::string toStringTree(std::vector<std::string> &ruleNames, bool pretty = false);
virtual std::string toStringTree(bool pretty = false) override;
virtual std::string toString() override;
std::string toString(Recognizer *recog);
std::string toString(const std::vector<std::string> &ruleNames);
// recog null unless ParserRuleContext, in which case we use subclass toString(...)
std::string toString(Recognizer *recog, RuleContext *stop);
virtual std::string toString(const std::vector<std::string> &ruleNames, RuleContext *stop);
bool operator == (const RuleContext &other) { return this == &other; } // Simple address comparison.
private:
void InitializeInstanceFields();
};
} // namespace antlr4

View File

@@ -0,0 +1,27 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "atn/ATN.h"
#include "RuleContextWithAltNum.h"
using namespace antlr4;
using namespace antlr4::atn;
RuleContextWithAltNum::RuleContextWithAltNum() : ParserRuleContext() {
altNum = ATN::INVALID_ALT_NUMBER;
}
RuleContextWithAltNum::RuleContextWithAltNum(ParserRuleContext *parent, int invokingStateNumber)
: ParserRuleContext(parent, invokingStateNumber) {
}
size_t RuleContextWithAltNum::getAltNumber() const {
return altNum;
}
void RuleContextWithAltNum::setAltNumber(size_t number) {
altNum = number;
}

View File

@@ -0,0 +1,32 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "ParserRuleContext.h"
namespace antlr4 {
/// A handy class for use with
///
/// options {contextSuperClass=org.antlr.v4.runtime.RuleContextWithAltNum;}
///
/// that provides a backing field / impl for the outer alternative number
/// matched for an internal parse tree node.
///
/// I'm only putting into Java runtime as I'm certain I'm the only one that
/// will really every use this.
class ANTLR4CPP_PUBLIC RuleContextWithAltNum : public ParserRuleContext {
public:
size_t altNum = 0;
RuleContextWithAltNum();
RuleContextWithAltNum(ParserRuleContext *parent, int invokingStateNumber);
virtual size_t getAltNumber() const override;
virtual void setAltNumber(size_t altNum) override;
};
} // namespace antlr4

View File

@@ -0,0 +1,54 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "RuntimeMetaData.h"
#include "Version.h"
using namespace antlr4;
const std::string RuntimeMetaData::VERSION = ANTLRCPP_VERSION_STRING;
std::string RuntimeMetaData::getRuntimeVersion() {
return VERSION;
}
void RuntimeMetaData::checkVersion(const std::string &generatingToolVersion, const std::string &compileTimeVersion) {
std::string runtimeVersion = VERSION;
bool runtimeConflictsWithGeneratingTool = false;
bool runtimeConflictsWithCompileTimeTool = false;
if (generatingToolVersion != "") {
runtimeConflictsWithGeneratingTool = runtimeVersion != generatingToolVersion
&& getMajorMinorVersion(runtimeVersion) != getMajorMinorVersion(generatingToolVersion);
}
runtimeConflictsWithCompileTimeTool = runtimeVersion != compileTimeVersion
&& getMajorMinorVersion(runtimeVersion) != getMajorMinorVersion(compileTimeVersion);
if (runtimeConflictsWithGeneratingTool) {
std::cerr << "ANTLR Tool version " << generatingToolVersion << " used for code generation does not match "
"the current runtime version " << runtimeVersion << std::endl;
}
if (runtimeConflictsWithCompileTimeTool) {
std::cerr << "ANTLR Runtime version " << compileTimeVersion << " used for parser compilation does not match "
"the current runtime version " << runtimeVersion << std::endl;
}
}
std::string RuntimeMetaData::getMajorMinorVersion(const std::string &version) {
size_t firstDot = version.find('.');
size_t secondDot = firstDot != std::string::npos ? version.find('.', firstDot + 1) : std::string::npos;
size_t firstDash = version.find('-');
size_t referenceLength = version.size();
if (secondDot != std::string::npos) {
referenceLength = std::min(referenceLength, secondDot);
}
if (firstDash != std::string::npos) {
referenceLength = std::min(referenceLength, firstDash);
}
return version.substr(0, referenceLength);
}

View File

@@ -0,0 +1,155 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "antlr4-common.h"
namespace antlr4 {
/// <summary>
/// This class provides access to the current version of the ANTLR 4 runtime
/// library as compile-time and runtime constants, along with methods for
/// checking for matching version numbers and notifying listeners in the case
/// where a version mismatch is detected.
///
/// <para>
/// The runtime version information is provided by <seealso cref="#VERSION"/> and
/// <seealso cref="#getRuntimeVersion()"/>. Detailed information about these values is
/// provided in the documentation for each member.</para>
///
/// <para>
/// The runtime version check is implemented by <seealso cref="#checkVersion"/>. Detailed
/// information about incorporating this call into user code, as well as its use
/// in generated code, is provided in the documentation for the method.</para>
///
/// <para>
/// Version strings x.y and x.y.z are considered "compatible" and no error
/// would be generated. Likewise, version strings x.y-SNAPSHOT and x.y.z are
/// considered "compatible" because the major and minor components x.y
/// are the same in each.</para>
///
/// <para>
/// To trap any error messages issued by this code, use System.setErr()
/// in your main() startup code.
/// </para>
///
/// @since 4.3
/// </summary>
class ANTLR4CPP_PUBLIC RuntimeMetaData {
public:
/// A compile-time constant containing the current version of the ANTLR 4
/// runtime library.
///
/// <para>
/// This compile-time constant value allows generated parsers and other
/// libraries to include a literal reference to the version of the ANTLR 4
/// runtime library the code was compiled against. At each release, we
/// change this value.</para>
///
/// <para>Version numbers are assumed to have the form
///
/// <em>major</em>.<em>minor</em>.<em>patch</em>.<em>revision</em>-<em>suffix</em>,
///
/// with the individual components defined as follows.</para>
///
/// <ul>
/// <li><em>major</em> is a required non-negative integer, and is equal to
/// {@code 4} for ANTLR 4.</li>
/// <li><em>minor</em> is a required non-negative integer.</li>
/// <li><em>patch</em> is an optional non-negative integer. When
/// <em>patch</em> is omitted, the {@code .} (dot) appearing before it is
/// also omitted.</li>
/// <li><em>revision</em> is an optional non-negative integer, and may only
/// be included when <em>patch</em> is also included. When <em>revision</em>
/// is omitted, the {@code .} (dot) appearing before it is also omitted.</li>
/// <li><em>suffix</em> is an optional string. When <em>suffix</em> is
/// omitted, the {@code -} (hyphen-minus) appearing before it is also
/// omitted.</li>
/// </ul>
static const std::string VERSION;
/// <summary>
/// Gets the currently executing version of the ANTLR 4 runtime library.
///
/// <para>
/// This method provides runtime access to the <seealso cref="#VERSION"/> field, as
/// opposed to directly referencing the field as a compile-time constant.</para>
/// </summary>
/// <returns> The currently executing version of the ANTLR 4 library </returns>
static std::string getRuntimeVersion();
/// <summary>
/// This method provides the ability to detect mismatches between the version
/// of ANTLR 4 used to generate a parser, the version of the ANTLR runtime a
/// parser was compiled against, and the version of the ANTLR runtime which
/// is currently executing.
///
/// <para>
/// The version check is designed to detect the following two specific
/// scenarios.</para>
///
/// <ul>
/// <li>The ANTLR Tool version used for code generation does not match the
/// currently executing runtime version.</li>
/// <li>The ANTLR Runtime version referenced at the time a parser was
/// compiled does not match the currently executing runtime version.</li>
/// </ul>
///
/// <para>
/// Starting with ANTLR 4.3, the code generator emits a call to this method
/// using two constants in each generated lexer and parser: a hard-coded
/// constant indicating the version of the tool used to generate the parser
/// and a reference to the compile-time constant <seealso cref="#VERSION"/>. At
/// runtime, this method is called during the initialization of the generated
/// parser to detect mismatched versions, and notify the registered listeners
/// prior to creating instances of the parser.</para>
///
/// <para>
/// This method does not perform any detection or filtering of semantic
/// changes between tool and runtime versions. It simply checks for a
/// version match and emits an error to stderr if a difference
/// is detected.</para>
///
/// <para>
/// Note that some breaking changes between releases could result in other
/// types of runtime exceptions, such as a <seealso cref="LinkageError"/>, prior to
/// calling this method. In these cases, the underlying version mismatch will
/// not be reported here. This method is primarily intended to
/// notify users of potential semantic changes between releases that do not
/// result in binary compatibility problems which would be detected by the
/// class loader. As with semantic changes, changes that break binary
/// compatibility between releases are mentioned in the release notes
/// accompanying the affected release.</para>
///
/// <para>
/// <strong>Additional note for target developers:</strong> The version check
/// implemented by this class is designed to address specific compatibility
/// concerns that may arise during the execution of Java applications. Other
/// targets should consider the implementation of this method in the context
/// of that target's known execution environment, which may or may not
/// resemble the design provided for the Java target.</para>
/// </summary>
/// <param name="generatingToolVersion"> The version of the tool used to generate a parser.
/// This value may be null when called from user code that was not generated
/// by, and does not reference, the ANTLR 4 Tool itself. </param>
/// <param name="compileTimeVersion"> The version of the runtime the parser was
/// compiled against. This should always be passed using a direct reference
/// to <seealso cref="#VERSION"/>. </param>
static void checkVersion(const std::string &generatingToolVersion, const std::string &compileTimeVersion);
/// <summary>
/// Gets the major and minor version numbers from a version string. For
/// details about the syntax of the input {@code version}.
/// E.g., from x.y.z return x.y.
/// </summary>
/// <param name="version"> The complete version string. </param>
/// <returns> A string of the form <em>major</em>.<em>minor</em> containing
/// only the major and minor components of the version string. </returns>
static std::string getMajorMinorVersion(const std::string &version);
};
} // namespace antlr4

View File

@@ -0,0 +1,9 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "Token.h"
antlr4::Token::~Token() {
}

View File

@@ -0,0 +1,92 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "IntStream.h"
namespace antlr4 {
/// A token has properties: text, type, line, character position in the line
/// (so we can ignore tabs), token channel, index, and source from which
/// we obtained this token.
class ANTLR4CPP_PUBLIC Token {
public:
static constexpr size_t INVALID_TYPE = 0;
/// During lookahead operations, this "token" signifies we hit rule end ATN state
/// and did not follow it despite needing to.
static constexpr size_t EPSILON = std::numeric_limits<size_t>::max() - 1;
static constexpr size_t MIN_USER_TOKEN_TYPE = 1;
static constexpr size_t EOF = IntStream::EOF;
virtual ~Token();
/// All tokens go to the parser (unless skip() is called in that rule)
/// on a particular "channel". The parser tunes to a particular channel
/// so that whitespace etc... can go to the parser on a "hidden" channel.
static constexpr size_t DEFAULT_CHANNEL = 0;
/// Anything on different channel than DEFAULT_CHANNEL is not parsed
/// by parser.
static constexpr size_t HIDDEN_CHANNEL = 1;
/**
* This is the minimum constant value which can be assigned to a
* user-defined token channel.
*
* <p>
* The non-negative numbers less than {@link #MIN_USER_CHANNEL_VALUE} are
* assigned to the predefined channels {@link #DEFAULT_CHANNEL} and
* {@link #HIDDEN_CHANNEL}.</p>
*
* @see Token#getChannel()
*/
static constexpr size_t MIN_USER_CHANNEL_VALUE = 2;
/// Get the text of the token.
virtual std::string getText() const = 0;
/// Get the token type of the token
virtual size_t getType() const = 0;
/// The line number on which the 1st character of this token was matched, line=1..n
virtual size_t getLine() const = 0;
/// The index of the first character of this token relative to the
/// beginning of the line at which it occurs, 0..n-1
virtual size_t getCharPositionInLine() const = 0;
/// Return the channel this token. Each token can arrive at the parser
/// on a different channel, but the parser only "tunes" to a single channel.
/// The parser ignores everything not on DEFAULT_CHANNEL.
virtual size_t getChannel() const = 0;
/// An index from 0..n-1 of the token object in the input stream.
/// This must be valid in order to print token streams and
/// use TokenRewriteStream.
///
/// Return INVALID_INDEX to indicate that this token was conjured up since
/// it doesn't have a valid index.
virtual size_t getTokenIndex() const = 0;
/// The starting character index of the token
/// This method is optional; return INVALID_INDEX if not implemented.
virtual size_t getStartIndex() const = 0;
/// The last character index of the token.
/// This method is optional; return INVALID_INDEX if not implemented.
virtual size_t getStopIndex() const = 0;
/// Gets the <seealso cref="TokenSource"/> which created this token.
virtual TokenSource *getTokenSource() const = 0;
/// Gets the <seealso cref="CharStream"/> from which this token was derived.
virtual CharStream *getInputStream() const = 0;
virtual std::string toString() const = 0;
};
} // namespace antlr4

View File

@@ -0,0 +1,30 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "antlr4-common.h"
namespace antlr4 {
/// The default mechanism for creating tokens. It's used by default in Lexer and
/// the error handling strategy (to create missing tokens). Notifying the parser
/// of a new factory means that it notifies it's token source and error strategy.
template<typename Symbol>
class ANTLR4CPP_PUBLIC TokenFactory {
public:
virtual ~TokenFactory() {}
/// This is the method used to create tokens in the lexer and in the
/// error handling strategy. If text!=null, than the start and stop positions
/// are wiped to -1 in the text override is set in the CommonToken.
virtual std::unique_ptr<Symbol> create(std::pair<TokenSource *, CharStream *> source, size_t type, const std::string &text,
size_t channel, size_t start, size_t stop, size_t line, size_t charPositionInLine) = 0;
/// Generically useful
virtual std::unique_ptr<Symbol> create(size_t type, const std::string &text) = 0;
};
} // namespace antlr4

View File

@@ -0,0 +1,9 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "TokenSource.h"
antlr4::TokenSource::~TokenSource() {
}

View File

@@ -0,0 +1,85 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "TokenFactory.h"
namespace antlr4 {
/// <summary>
/// A source of tokens must provide a sequence of tokens via <seealso cref="#nextToken()"/>
/// and also must reveal it's source of characters; <seealso cref="CommonToken"/>'s text is
/// computed from a <seealso cref="CharStream"/>; it only store indices into the char
/// stream.
/// <p/>
/// Errors from the lexer are never passed to the parser. Either you want to keep
/// going or you do not upon token recognition error. If you do not want to
/// continue lexing then you do not want to continue parsing. Just throw an
/// exception not under <seealso cref="RecognitionException"/> and Java will naturally toss
/// you all the way out of the recognizers. If you want to continue lexing then
/// you should not throw an exception to the parser--it has already requested a
/// token. Keep lexing until you get a valid one. Just report errors and keep
/// going, looking for a valid token.
/// </summary>
class ANTLR4CPP_PUBLIC TokenSource {
public:
virtual ~TokenSource();
/// Return a <seealso cref="Token"/> object from your input stream (usually a
/// <seealso cref="CharStream"/>). Do not fail/return upon lexing error; keep chewing
/// on the characters until you get a good one; errors are not passed through
/// to the parser.
virtual std::unique_ptr<Token> nextToken() = 0;
/// <summary>
/// Get the line number for the current position in the input stream. The
/// first line in the input is line 1.
/// </summary>
/// <returns> The line number for the current position in the input stream, or
/// 0 if the current token source does not track line numbers. </returns>
virtual size_t getLine() const = 0;
/// <summary>
/// Get the index into the current line for the current position in the input
/// stream. The first character on a line has position 0.
/// </summary>
/// <returns> The line number for the current position in the input stream, or
/// (sze_t)-1 if the current token source does not track character positions. </returns>
virtual size_t getCharPositionInLine() = 0;
/// <summary>
/// Get the <seealso cref="CharStream"/> from which this token source is currently
/// providing tokens.
/// </summary>
/// <returns> The <seealso cref="CharStream"/> associated with the current position in
/// the input, or {@code null} if no input stream is available for the token
/// source. </returns>
virtual CharStream* getInputStream() = 0;
/// <summary>
/// Gets the name of the underlying input source. This method returns a
/// non-null, non-empty string. If such a name is not known, this method
/// returns <seealso cref="IntStream#UNKNOWN_SOURCE_NAME"/>.
/// </summary>
virtual std::string getSourceName() = 0;
/// <summary>
/// Set the <seealso cref="TokenFactory"/> this token source should use for creating
/// <seealso cref="Token"/> objects from the input.
/// </summary>
/// <param name="factory"> The <seealso cref="TokenFactory"/> to use for creating tokens. </param>
template<typename T1>
void setTokenFactory(TokenFactory<T1> * /*factory*/) {}
/// <summary>
/// Gets the <seealso cref="TokenFactory"/> this token source is currently using for
/// creating <seealso cref="Token"/> objects from the input.
/// </summary>
/// <returns> The <seealso cref="TokenFactory"/> currently used by this token source. </returns>
virtual TokenFactory<CommonToken>* getTokenFactory() = 0;
};
} // namespace antlr4

View File

@@ -0,0 +1,11 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "TokenStream.h"
using namespace antlr4;
TokenStream::~TokenStream() {
}

View File

@@ -0,0 +1,137 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "IntStream.h"
namespace antlr4 {
/// <summary>
/// An <seealso cref="IntStream"/> whose symbols are <seealso cref="Token"/> instances.
/// </summary>
class ANTLR4CPP_PUBLIC TokenStream : public IntStream {
/// <summary>
/// Get the <seealso cref="Token"/> instance associated with the value returned by
/// <seealso cref="#LA LA(k)"/>. This method has the same pre- and post-conditions as
/// <seealso cref="IntStream#LA"/>. In addition, when the preconditions of this method
/// are met, the return value is non-null and the value of
/// {@code LT(k).getType()==LA(k)}.
/// </summary>
/// <seealso cref= IntStream#LA </seealso>
public:
virtual ~TokenStream();
virtual Token* LT(ssize_t k) = 0;
/// <summary>
/// Gets the <seealso cref="Token"/> at the specified {@code index} in the stream. When
/// the preconditions of this method are met, the return value is non-null.
/// <p/>
/// The preconditions for this method are the same as the preconditions of
/// <seealso cref="IntStream#seek"/>. If the behavior of {@code seek(index)} is
/// unspecified for the current state and given {@code index}, then the
/// behavior of this method is also unspecified.
/// <p/>
/// The symbol referred to by {@code index} differs from {@code seek()} only
/// in the case of filtering streams where {@code index} lies before the end
/// of the stream. Unlike {@code seek()}, this method does not adjust
/// {@code index} to point to a non-ignored symbol.
/// </summary>
/// <exception cref="IllegalArgumentException"> if {code index} is less than 0 </exception>
/// <exception cref="UnsupportedOperationException"> if the stream does not support
/// retrieving the token at the specified index </exception>
virtual Token* get(size_t index) const = 0;
/// Gets the underlying TokenSource which provides tokens for this stream.
virtual TokenSource* getTokenSource() const = 0;
/// <summary>
/// Return the text of all tokens within the specified {@code interval}. This
/// method behaves like the following code (including potential exceptions
/// for violating preconditions of <seealso cref="#get"/>, but may be optimized by the
/// specific implementation.
///
/// <pre>
/// TokenStream stream = ...;
/// String text = "";
/// for (int i = interval.a; i <= interval.b; i++) {
/// text += stream.get(i).getText();
/// }
/// </pre>
/// </summary>
/// <param name="interval"> The interval of tokens within this stream to get text
/// for. </param>
/// <returns> The text of all tokens within the specified interval in this
/// stream.
/// </returns>
/// <exception cref="NullPointerException"> if {@code interval} is {@code null} </exception>
virtual std::string getText(const misc::Interval &interval) = 0;
/// <summary>
/// Return the text of all tokens in the stream. This method behaves like the
/// following code, including potential exceptions from the calls to
/// <seealso cref="IntStream#size"/> and <seealso cref="#getText(Interval)"/>, but may be
/// optimized by the specific implementation.
///
/// <pre>
/// TokenStream stream = ...;
/// String text = stream.getText(new Interval(0, stream.size()));
/// </pre>
/// </summary>
/// <returns> The text of all tokens in the stream. </returns>
virtual std::string getText() = 0;
/// <summary>
/// Return the text of all tokens in the source interval of the specified
/// context. This method behaves like the following code, including potential
/// exceptions from the call to <seealso cref="#getText(Interval)"/>, but may be
/// optimized by the specific implementation.
/// </p>
/// If {@code ctx.getSourceInterval()} does not return a valid interval of
/// tokens provided by this stream, the behavior is unspecified.
///
/// <pre>
/// TokenStream stream = ...;
/// String text = stream.getText(ctx.getSourceInterval());
/// </pre>
/// </summary>
/// <param name="ctx"> The context providing the source interval of tokens to get
/// text for. </param>
/// <returns> The text of all tokens within the source interval of {@code ctx}. </returns>
virtual std::string getText(RuleContext *ctx) = 0;
/// <summary>
/// Return the text of all tokens in this stream between {@code start} and
/// {@code stop} (inclusive).
/// <p/>
/// If the specified {@code start} or {@code stop} token was not provided by
/// this stream, or if the {@code stop} occurred before the {@code start}
/// token, the behavior is unspecified.
/// <p/>
/// For streams which ensure that the <seealso cref="Token#getTokenIndex"/> method is
/// accurate for all of its provided tokens, this method behaves like the
/// following code. Other streams may implement this method in other ways
/// provided the behavior is consistent with this at a high level.
///
/// <pre>
/// TokenStream stream = ...;
/// String text = "";
/// for (int i = start.getTokenIndex(); i <= stop.getTokenIndex(); i++) {
/// text += stream.get(i).getText();
/// }
/// </pre>
/// </summary>
/// <param name="start"> The first token in the interval to get text for. </param>
/// <param name="stop"> The last token in the interval to get text for (inclusive). </param>
/// <returns> The text of all tokens lying between the specified {@code start}
/// and {@code stop} tokens.
/// </returns>
/// <exception cref="UnsupportedOperationException"> if this stream does not support
/// this method for the specified tokens </exception>
virtual std::string getText(Token *start, Token *stop) = 0;
};
} // namespace antlr4

View File

@@ -0,0 +1,425 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "Exceptions.h"
#include "misc/Interval.h"
#include "Token.h"
#include "TokenStream.h"
#include "TokenStreamRewriter.h"
using namespace antlr4;
using antlr4::misc::Interval;
TokenStreamRewriter::RewriteOperation::RewriteOperation(TokenStreamRewriter *outerInstance_, size_t index_)
: outerInstance(outerInstance_) {
InitializeInstanceFields();
this->index = index_;
}
TokenStreamRewriter::RewriteOperation::RewriteOperation(TokenStreamRewriter *outerInstance_, size_t index_,
const std::string& text_) : outerInstance(outerInstance_) {
InitializeInstanceFields();
this->index = index_;
this->text = text_;
}
TokenStreamRewriter::RewriteOperation::~RewriteOperation()
{
}
size_t TokenStreamRewriter::RewriteOperation::execute(std::string * /*buf*/) {
return index;
}
std::string TokenStreamRewriter::RewriteOperation::toString() {
std::string opName = "TokenStreamRewriter";
size_t dollarIndex = opName.find('$');
opName = opName.substr(dollarIndex + 1, opName.length() - (dollarIndex + 1));
return "<" + opName + "@" + outerInstance->tokens->get(dollarIndex)->getText() + ":\"" + text + "\">";
}
void TokenStreamRewriter::RewriteOperation::InitializeInstanceFields() {
instructionIndex = 0;
index = 0;
}
TokenStreamRewriter::InsertBeforeOp::InsertBeforeOp(TokenStreamRewriter *outerInstance_, size_t index_, const std::string& text_)
: RewriteOperation(outerInstance_, index_, text_), outerInstance(outerInstance_) {
}
size_t TokenStreamRewriter::InsertBeforeOp::execute(std::string *buf) {
buf->append(text);
if (outerInstance->tokens->get(index)->getType() != Token::EOF) {
buf->append(outerInstance->tokens->get(index)->getText());
}
return index + 1;
}
TokenStreamRewriter::ReplaceOp::ReplaceOp(TokenStreamRewriter *outerInstance_, size_t from, size_t to, const std::string& text)
: RewriteOperation(outerInstance_, from, text), outerInstance(outerInstance_) {
InitializeInstanceFields();
lastIndex = to;
}
size_t TokenStreamRewriter::ReplaceOp::execute(std::string *buf) {
buf->append(text);
return lastIndex + 1;
}
std::string TokenStreamRewriter::ReplaceOp::toString() {
if (text.empty()) {
return "<DeleteOp@" + outerInstance->tokens->get(index)->getText() + ".." + outerInstance->tokens->get(lastIndex)->getText() + ">";
}
return "<ReplaceOp@" + outerInstance->tokens->get(index)->getText() + ".." + outerInstance->tokens->get(lastIndex)->getText() + ":\"" + text + "\">";
}
void TokenStreamRewriter::ReplaceOp::InitializeInstanceFields() {
lastIndex = 0;
}
//------------------ TokenStreamRewriter -------------------------------------------------------------------------------
const std::string TokenStreamRewriter::DEFAULT_PROGRAM_NAME = "default";
TokenStreamRewriter::TokenStreamRewriter(TokenStream *tokens_) : tokens(tokens_) {
_programs[DEFAULT_PROGRAM_NAME].reserve(PROGRAM_INIT_SIZE);
}
TokenStreamRewriter::~TokenStreamRewriter() {
for (const auto &program : _programs) {
for (auto *operation : program.second) {
delete operation;
}
}
}
TokenStream *TokenStreamRewriter::getTokenStream() {
return tokens;
}
void TokenStreamRewriter::rollback(size_t instructionIndex) {
rollback(DEFAULT_PROGRAM_NAME, instructionIndex);
}
void TokenStreamRewriter::rollback(const std::string &programName, size_t instructionIndex) {
std::vector<RewriteOperation*> is = _programs[programName];
if (is.size() > 0) {
_programs.insert({ programName, std::vector<RewriteOperation*>(is.begin() + MIN_TOKEN_INDEX, is.begin() + instructionIndex) });
}
}
void TokenStreamRewriter::deleteProgram() {
deleteProgram(DEFAULT_PROGRAM_NAME);
}
void TokenStreamRewriter::deleteProgram(const std::string &programName) {
rollback(programName, MIN_TOKEN_INDEX);
}
void TokenStreamRewriter::insertAfter(Token *t, const std::string& text) {
insertAfter(DEFAULT_PROGRAM_NAME, t, text);
}
void TokenStreamRewriter::insertAfter(size_t index, const std::string& text) {
insertAfter(DEFAULT_PROGRAM_NAME, index, text);
}
void TokenStreamRewriter::insertAfter(const std::string &programName, Token *t, const std::string& text) {
insertAfter(programName, t->getTokenIndex(), text);
}
void TokenStreamRewriter::insertAfter(const std::string &programName, size_t index, const std::string& text) {
// to insert after, just insert before next index (even if past end)
insertBefore(programName, index + 1, text);
}
void TokenStreamRewriter::insertBefore(Token *t, const std::string& text) {
insertBefore(DEFAULT_PROGRAM_NAME, t, text);
}
void TokenStreamRewriter::insertBefore(size_t index, const std::string& text) {
insertBefore(DEFAULT_PROGRAM_NAME, index, text);
}
void TokenStreamRewriter::insertBefore(const std::string &programName, Token *t, const std::string& text) {
insertBefore(programName, t->getTokenIndex(), text);
}
void TokenStreamRewriter::insertBefore(const std::string &programName, size_t index, const std::string& text) {
RewriteOperation *op = new InsertBeforeOp(this, index, text); /* mem-check: deleted in d-tor */
std::vector<RewriteOperation*> &rewrites = getProgram(programName);
op->instructionIndex = rewrites.size();
rewrites.push_back(op);
}
void TokenStreamRewriter::replace(size_t index, const std::string& text) {
replace(DEFAULT_PROGRAM_NAME, index, index, text);
}
void TokenStreamRewriter::replace(size_t from, size_t to, const std::string& text) {
replace(DEFAULT_PROGRAM_NAME, from, to, text);
}
void TokenStreamRewriter::replace(Token *indexT, const std::string& text) {
replace(DEFAULT_PROGRAM_NAME, indexT, indexT, text);
}
void TokenStreamRewriter::replace(Token *from, Token *to, const std::string& text) {
replace(DEFAULT_PROGRAM_NAME, from, to, text);
}
void TokenStreamRewriter::replace(const std::string &programName, size_t from, size_t to, const std::string& text) {
if (from > to || to >= tokens->size()) {
throw IllegalArgumentException("replace: range invalid: " + std::to_string(from) + ".." + std::to_string(to) +
"(size = " + std::to_string(tokens->size()) + ")");
}
RewriteOperation *op = new ReplaceOp(this, from, to, text); /* mem-check: deleted in d-tor */
std::vector<RewriteOperation*> &rewrites = getProgram(programName);
op->instructionIndex = rewrites.size();
rewrites.push_back(op);
}
void TokenStreamRewriter::replace(const std::string &programName, Token *from, Token *to, const std::string& text) {
replace(programName, from->getTokenIndex(), to->getTokenIndex(), text);
}
void TokenStreamRewriter::Delete(size_t index) {
Delete(DEFAULT_PROGRAM_NAME, index, index);
}
void TokenStreamRewriter::Delete(size_t from, size_t to) {
Delete(DEFAULT_PROGRAM_NAME, from, to);
}
void TokenStreamRewriter::Delete(Token *indexT) {
Delete(DEFAULT_PROGRAM_NAME, indexT, indexT);
}
void TokenStreamRewriter::Delete(Token *from, Token *to) {
Delete(DEFAULT_PROGRAM_NAME, from, to);
}
void TokenStreamRewriter::Delete(const std::string &programName, size_t from, size_t to) {
std::string nullString;
replace(programName, from, to, nullString);
}
void TokenStreamRewriter::Delete(const std::string &programName, Token *from, Token *to) {
std::string nullString;
replace(programName, from, to, nullString);
}
size_t TokenStreamRewriter::getLastRewriteTokenIndex() {
return getLastRewriteTokenIndex(DEFAULT_PROGRAM_NAME);
}
size_t TokenStreamRewriter::getLastRewriteTokenIndex(const std::string &programName) {
if (_lastRewriteTokenIndexes.find(programName) == _lastRewriteTokenIndexes.end()) {
return INVALID_INDEX;
}
return _lastRewriteTokenIndexes[programName];
}
void TokenStreamRewriter::setLastRewriteTokenIndex(const std::string &programName, size_t i) {
_lastRewriteTokenIndexes.insert({ programName, i });
}
std::vector<TokenStreamRewriter::RewriteOperation*>& TokenStreamRewriter::getProgram(const std::string &name) {
auto iterator = _programs.find(name);
if (iterator == _programs.end()) {
return initializeProgram(name);
}
return iterator->second;
}
std::vector<TokenStreamRewriter::RewriteOperation*>& TokenStreamRewriter::initializeProgram(const std::string &name) {
_programs[name].reserve(PROGRAM_INIT_SIZE);
return _programs[name];
}
std::string TokenStreamRewriter::getText() {
return getText(DEFAULT_PROGRAM_NAME, Interval(0UL, tokens->size() - 1));
}
std::string TokenStreamRewriter::getText(std::string programName) {
return getText(programName, Interval(0UL, tokens->size() - 1));
}
std::string TokenStreamRewriter::getText(const Interval &interval) {
return getText(DEFAULT_PROGRAM_NAME, interval);
}
std::string TokenStreamRewriter::getText(const std::string &programName, const Interval &interval) {
std::vector<TokenStreamRewriter::RewriteOperation*> &rewrites = _programs[programName];
size_t start = interval.a;
size_t stop = interval.b;
// ensure start/end are in range
if (stop > tokens->size() - 1) {
stop = tokens->size() - 1;
}
if (start == INVALID_INDEX) {
start = 0;
}
if (rewrites.empty() || rewrites.empty()) {
return tokens->getText(interval); // no instructions to execute
}
std::string buf;
// First, optimize instruction stream
std::unordered_map<size_t, TokenStreamRewriter::RewriteOperation*> indexToOp = reduceToSingleOperationPerIndex(rewrites);
// Walk buffer, executing instructions and emitting tokens
size_t i = start;
while (i <= stop && i < tokens->size()) {
RewriteOperation *op = indexToOp[i];
indexToOp.erase(i); // remove so any left have index size-1
Token *t = tokens->get(i);
if (op == nullptr) {
// no operation at that index, just dump token
if (t->getType() != Token::EOF) {
buf.append(t->getText());
}
i++; // move to next token
}
else {
i = op->execute(&buf); // execute operation and skip
}
}
// include stuff after end if it's last index in buffer
// So, if they did an insertAfter(lastValidIndex, "foo"), include
// foo if end==lastValidIndex.
if (stop == tokens->size() - 1) {
// Scan any remaining operations after last token
// should be included (they will be inserts).
for (auto op : indexToOp) {
if (op.second->index >= tokens->size() - 1) {
buf.append(op.second->text);
}
}
}
return buf;
}
std::unordered_map<size_t, TokenStreamRewriter::RewriteOperation*> TokenStreamRewriter::reduceToSingleOperationPerIndex(
std::vector<TokenStreamRewriter::RewriteOperation*> &rewrites) {
// WALK REPLACES
for (size_t i = 0; i < rewrites.size(); ++i) {
TokenStreamRewriter::RewriteOperation *op = rewrites[i];
ReplaceOp *rop = dynamic_cast<ReplaceOp *>(op);
if (rop == nullptr)
continue;
// Wipe prior inserts within range
std::vector<InsertBeforeOp *> inserts = getKindOfOps<InsertBeforeOp>(rewrites, i);
for (auto *iop : inserts) {
if (iop->index == rop->index) {
// E.g., insert before 2, delete 2..2; update replace
// text to include insert before, kill insert
delete rewrites[iop->instructionIndex];
rewrites[iop->instructionIndex] = nullptr;
rop->text = iop->text + (!rop->text.empty() ? rop->text : "");
}
else if (iop->index > rop->index && iop->index <= rop->lastIndex) {
// delete insert as it's a no-op.
delete rewrites[iop->instructionIndex];
rewrites[iop->instructionIndex] = nullptr;
}
}
// Drop any prior replaces contained within
std::vector<ReplaceOp*> prevReplaces = getKindOfOps<ReplaceOp>(rewrites, i);
for (auto *prevRop : prevReplaces) {
if (prevRop->index >= rop->index && prevRop->lastIndex <= rop->lastIndex) {
// delete replace as it's a no-op.
delete rewrites[prevRop->instructionIndex];
rewrites[prevRop->instructionIndex] = nullptr;
continue;
}
// throw exception unless disjoint or identical
bool disjoint = prevRop->lastIndex < rop->index || prevRop->index > rop->lastIndex;
// Delete special case of replace (text==null):
// D.i-j.u D.x-y.v | boundaries overlap combine to max(min)..max(right)
if (prevRop->text.empty() && rop->text.empty() && !disjoint) {
delete rewrites[prevRop->instructionIndex];
rewrites[prevRop->instructionIndex] = nullptr; // kill first delete
rop->index = std::min(prevRop->index, rop->index);
rop->lastIndex = std::max(prevRop->lastIndex, rop->lastIndex);
std::cout << "new rop " << rop << std::endl;
}
else if (!disjoint) {
throw IllegalArgumentException("replace op boundaries of " + rop->toString() +
" overlap with previous " + prevRop->toString());
}
}
}
// WALK INSERTS
for (size_t i = 0; i < rewrites.size(); i++) {
InsertBeforeOp *iop = dynamic_cast<InsertBeforeOp *>(rewrites[i]);
if (iop == nullptr)
continue;
// combine current insert with prior if any at same index
std::vector<InsertBeforeOp *> prevInserts = getKindOfOps<InsertBeforeOp>(rewrites, i);
for (auto *prevIop : prevInserts) {
if (prevIop->index == iop->index) { // combine objects
// convert to strings...we're in process of toString'ing
// whole token buffer so no lazy eval issue with any templates
iop->text = catOpText(&iop->text, &prevIop->text);
// delete redundant prior insert
delete rewrites[prevIop->instructionIndex];
rewrites[prevIop->instructionIndex] = nullptr;
}
}
// look for replaces where iop.index is in range; error
std::vector<ReplaceOp*> prevReplaces = getKindOfOps<ReplaceOp>(rewrites, i);
for (auto *rop : prevReplaces) {
if (iop->index == rop->index) {
rop->text = catOpText(&iop->text, &rop->text);
delete rewrites[i];
rewrites[i] = nullptr; // delete current insert
continue;
}
if (iop->index >= rop->index && iop->index <= rop->lastIndex) {
throw IllegalArgumentException("insert op " + iop->toString() + " within boundaries of previous " + rop->toString());
}
}
}
std::unordered_map<size_t, TokenStreamRewriter::RewriteOperation*> m;
for (TokenStreamRewriter::RewriteOperation *op : rewrites) {
if (op == nullptr) { // ignore deleted ops
continue;
}
if (m.count(op->index) > 0) {
throw RuntimeException("should only be one op per index");
}
m[op->index] = op;
}
return m;
}
std::string TokenStreamRewriter::catOpText(std::string *a, std::string *b) {
std::string x = "";
std::string y = "";
if (a != nullptr) {
x = *a;
}
if (b != nullptr) {
y = *b;
}
return x + y;
}

View File

@@ -0,0 +1,295 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "antlr4-common.h"
namespace antlr4 {
/**
* Useful for rewriting out a buffered input token stream after doing some
* augmentation or other manipulations on it.
*
* <p>
* You can insert stuff, replace, and delete chunks. Note that the operations
* are done lazily--only if you convert the buffer to a {@link String} with
* {@link TokenStream#getText()}. This is very efficient because you are not
* moving data around all the time. As the buffer of tokens is converted to
* strings, the {@link #getText()} method(s) scan the input token stream and
* check to see if there is an operation at the current index. If so, the
* operation is done and then normal {@link String} rendering continues on the
* buffer. This is like having multiple Turing machine instruction streams
* (programs) operating on a single input tape. :)</p>
*
* <p>
* This rewriter makes no modifications to the token stream. It does not ask the
* stream to fill itself up nor does it advance the input cursor. The token
* stream {@link TokenStream#index()} will return the same value before and
* after any {@link #getText()} call.</p>
*
* <p>
* The rewriter only works on tokens that you have in the buffer and ignores the
* current input cursor. If you are buffering tokens on-demand, calling
* {@link #getText()} halfway through the input will only do rewrites for those
* tokens in the first half of the file.</p>
*
* <p>
* Since the operations are done lazily at {@link #getText}-time, operations do
* not screw up the token index values. That is, an insert operation at token
* index {@code i} does not change the index values for tokens
* {@code i}+1..n-1.</p>
*
* <p>
* Because operations never actually alter the buffer, you may always get the
* original token stream back without undoing anything. Since the instructions
* are queued up, you can easily simulate transactions and roll back any changes
* if there is an error just by removing instructions. For example,</p>
*
* <pre>
* CharStream input = new ANTLRFileStream("input");
* TLexer lex = new TLexer(input);
* CommonTokenStream tokens = new CommonTokenStream(lex);
* T parser = new T(tokens);
* TokenStreamRewriter rewriter = new TokenStreamRewriter(tokens);
* parser.startRule();
* </pre>
*
* <p>
* Then in the rules, you can execute (assuming rewriter is visible):</p>
*
* <pre>
* Token t,u;
* ...
* rewriter.insertAfter(t, "text to put after t");}
* rewriter.insertAfter(u, "text after u");}
* System.out.println(rewriter.getText());
* </pre>
*
* <p>
* You can also have multiple "instruction streams" and get multiple rewrites
* from a single pass over the input. Just name the instruction streams and use
* that name again when printing the buffer. This could be useful for generating
* a C file and also its header file--all from the same buffer:</p>
*
* <pre>
* rewriter.insertAfter("pass1", t, "text to put after t");}
* rewriter.insertAfter("pass2", u, "text after u");}
* System.out.println(rewriter.getText("pass1"));
* System.out.println(rewriter.getText("pass2"));
* </pre>
*
* <p>
* If you don't use named rewrite streams, a "default" stream is used as the
* first example shows.</p>
*/
class ANTLR4CPP_PUBLIC TokenStreamRewriter {
public:
static const std::string DEFAULT_PROGRAM_NAME;
static constexpr size_t PROGRAM_INIT_SIZE = 100;
static constexpr size_t MIN_TOKEN_INDEX = 0;
TokenStreamRewriter(TokenStream *tokens);
virtual ~TokenStreamRewriter();
TokenStream *getTokenStream();
virtual void rollback(size_t instructionIndex);
/// Rollback the instruction stream for a program so that
/// the indicated instruction (via instructionIndex) is no
/// longer in the stream. UNTESTED!
virtual void rollback(const std::string &programName, size_t instructionIndex);
virtual void deleteProgram();
/// Reset the program so that no instructions exist.
virtual void deleteProgram(const std::string &programName);
virtual void insertAfter(Token *t, const std::string& text);
virtual void insertAfter(size_t index, const std::string& text);
virtual void insertAfter(const std::string &programName, Token *t, const std::string& text);
virtual void insertAfter(const std::string &programName, size_t index, const std::string& text);
virtual void insertBefore(Token *t, const std::string& text);
virtual void insertBefore(size_t index, const std::string& text);
virtual void insertBefore(const std::string &programName, Token *t, const std::string& text);
virtual void insertBefore(const std::string &programName, size_t index, const std::string& text);
virtual void replace(size_t index, const std::string& text);
virtual void replace(size_t from, size_t to, const std::string& text);
virtual void replace(Token *indexT, const std::string& text);
virtual void replace(Token *from, Token *to, const std::string& text);
virtual void replace(const std::string &programName, size_t from, size_t to, const std::string& text);
virtual void replace(const std::string &programName, Token *from, Token *to, const std::string& text);
virtual void Delete(size_t index);
virtual void Delete(size_t from, size_t to);
virtual void Delete(Token *indexT);
virtual void Delete(Token *from, Token *to);
virtual void Delete(const std::string &programName, size_t from, size_t to);
virtual void Delete(const std::string &programName, Token *from, Token *to);
virtual size_t getLastRewriteTokenIndex();
/// Return the text from the original tokens altered per the
/// instructions given to this rewriter.
virtual std::string getText();
/** Return the text from the original tokens altered per the
* instructions given to this rewriter in programName.
*/
std::string getText(std::string programName);
/// Return the text associated with the tokens in the interval from the
/// original token stream but with the alterations given to this rewriter.
/// The interval refers to the indexes in the original token stream.
/// We do not alter the token stream in any way, so the indexes
/// and intervals are still consistent. Includes any operations done
/// to the first and last token in the interval. So, if you did an
/// insertBefore on the first token, you would get that insertion.
/// The same is true if you do an insertAfter the stop token.
virtual std::string getText(const misc::Interval &interval);
virtual std::string getText(const std::string &programName, const misc::Interval &interval);
protected:
class RewriteOperation {
public:
/// What index into rewrites List are we?
size_t index;
std::string text;
/// Token buffer index.
size_t instructionIndex;
RewriteOperation(TokenStreamRewriter *outerInstance, size_t index);
RewriteOperation(TokenStreamRewriter *outerInstance, size_t index, const std::string& text);
virtual ~RewriteOperation();
/// Execute the rewrite operation by possibly adding to the buffer.
/// Return the index of the next token to operate on.
virtual size_t execute(std::string *buf);
virtual std::string toString();
private:
TokenStreamRewriter *const outerInstance;
void InitializeInstanceFields();
};
class InsertBeforeOp : public RewriteOperation {
private:
TokenStreamRewriter *const outerInstance;
public:
InsertBeforeOp(TokenStreamRewriter *outerInstance, size_t index, const std::string& text);
virtual size_t execute(std::string *buf) override;
};
class ReplaceOp : public RewriteOperation {
private:
TokenStreamRewriter *const outerInstance;
public:
size_t lastIndex;
ReplaceOp(TokenStreamRewriter *outerInstance, size_t from, size_t to, const std::string& text);
virtual size_t execute(std::string *buf) override;
virtual std::string toString() override;
private:
void InitializeInstanceFields();
};
/// Our source stream
TokenStream *const tokens;
/// You may have multiple, named streams of rewrite operations.
/// I'm calling these things "programs."
/// Maps String (name) -> rewrite (List)
std::map<std::string, std::vector<RewriteOperation*>> _programs;
/// <summary>
/// Map String (program name) -> Integer index </summary>
std::map<std::string, size_t> _lastRewriteTokenIndexes;
virtual size_t getLastRewriteTokenIndex(const std::string &programName);
virtual void setLastRewriteTokenIndex(const std::string &programName, size_t i);
virtual std::vector<RewriteOperation*>& getProgram(const std::string &name);
/// <summary>
/// We need to combine operations and report invalid operations (like
/// overlapping replaces that are not completed nested). Inserts to
/// same index need to be combined etc... Here are the cases:
///
/// I.i.u I.j.v leave alone, nonoverlapping
/// I.i.u I.i.v combine: Iivu
///
/// R.i-j.u R.x-y.v | i-j in x-y delete first R
/// R.i-j.u R.i-j.v delete first R
/// R.i-j.u R.x-y.v | x-y in i-j ERROR
/// R.i-j.u R.x-y.v | boundaries overlap ERROR
///
/// Delete special case of replace (text==null):
/// D.i-j.u D.x-y.v | boundaries overlap combine to max(min)..max(right)
///
/// I.i.u R.x-y.v | i in (x+1)-y delete I (since insert before
/// we're not deleting i)
/// I.i.u R.x-y.v | i not in (x+1)-y leave alone, nonoverlapping
/// R.x-y.v I.i.u | i in x-y ERROR
/// R.x-y.v I.x.u R.x-y.uv (combine, delete I)
/// R.x-y.v I.i.u | i not in x-y leave alone, nonoverlapping
///
/// I.i.u = insert u before op @ index i
/// R.x-y.u = replace x-y indexed tokens with u
///
/// First we need to examine replaces. For any replace op:
///
/// 1. wipe out any insertions before op within that range.
/// 2. Drop any replace op before that is contained completely within
/// that range.
/// 3. Throw exception upon boundary overlap with any previous replace.
///
/// Then we can deal with inserts:
///
/// 1. for any inserts to same index, combine even if not adjacent.
/// 2. for any prior replace with same left boundary, combine this
/// insert with replace and delete this replace.
/// 3. throw exception if index in same range as previous replace
///
/// Don't actually delete; make op null in list. Easier to walk list.
/// Later we can throw as we add to index -> op map.
///
/// Note that I.2 R.2-2 will wipe out I.2 even though, technically, the
/// inserted stuff would be before the replace range. But, if you
/// add tokens in front of a method body '{' and then delete the method
/// body, I think the stuff before the '{' you added should disappear too.
///
/// Return a map from token index to operation.
/// </summary>
virtual std::unordered_map<size_t, RewriteOperation*> reduceToSingleOperationPerIndex(std::vector<RewriteOperation*> &rewrites);
virtual std::string catOpText(std::string *a, std::string *b);
/// Get all operations before an index of a particular kind.
template <typename T>
std::vector<T *> getKindOfOps(std::vector<RewriteOperation *> rewrites, size_t before) {
std::vector<T *> ops;
for (size_t i = 0; i < before && i < rewrites.size(); i++) {
T *op = dynamic_cast<T *>(rewrites[i]);
if (op == nullptr) { // ignore deleted or non matching entries
continue;
}
ops.push_back(op);
}
return ops;
}
private:
std::vector<RewriteOperation *>& initializeProgram(const std::string &name);
};
} // namespace antlr4

View File

@@ -0,0 +1,208 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "misc/Interval.h"
#include "Exceptions.h"
#include "support/Utf8.h"
#include "UnbufferedCharStream.h"
using namespace antlrcpp;
using namespace antlr4;
using namespace antlr4::misc;
UnbufferedCharStream::UnbufferedCharStream(std::wistream &input)
: _p(0), _numMarkers(0), _lastChar(0), _lastCharBufferStart(0), _currentCharIndex(0), _input(input) {
// The vector's size is what used to be n in Java code.
fill(1); // prime
}
void UnbufferedCharStream::consume() {
if (LA(1) == EOF) {
throw IllegalStateException("cannot consume EOF");
}
// buf always has at least data[p==0] in this method due to ctor
_lastChar = _data[_p]; // track last char for LA(-1)
if (_p == _data.size() - 1 && _numMarkers == 0) {
size_t capacity = _data.capacity();
_data.clear();
_data.reserve(capacity);
_p = 0;
_lastCharBufferStart = _lastChar;
} else {
_p++;
}
_currentCharIndex++;
sync(1);
}
void UnbufferedCharStream::sync(size_t want) {
if (_p + want <= _data.size()) // Already enough data loaded?
return;
fill(_p + want - _data.size());
}
size_t UnbufferedCharStream::fill(size_t n) {
for (size_t i = 0; i < n; i++) {
if (_data.size() > 0 && _data.back() == 0xFFFF) {
return i;
}
try {
char32_t c = nextChar();
add(c);
#if defined(_MSC_FULL_VER) && _MSC_FULL_VER < 190023026
} catch (IOException &ioe) {
// throw_with_nested is not available before VS 2015.
throw ioe;
#else
} catch (IOException & /*ioe*/) {
std::throw_with_nested(RuntimeException());
#endif
}
}
return n;
}
char32_t UnbufferedCharStream::nextChar() {
return _input.get();
}
void UnbufferedCharStream::add(char32_t c) {
_data += c;
}
size_t UnbufferedCharStream::LA(ssize_t i) {
if (i == -1) { // special case
return _lastChar;
}
// We can look back only as many chars as we have buffered.
ssize_t index = static_cast<ssize_t>(_p) + i - 1;
if (index < 0) {
throw IndexOutOfBoundsException();
}
if (i > 0) {
sync(static_cast<size_t>(i)); // No need to sync if we look back.
}
if (static_cast<size_t>(index) >= _data.size()) {
return EOF;
}
if (_data[static_cast<size_t>(index)] == std::char_traits<wchar_t>::eof()) {
return EOF;
}
return _data[static_cast<size_t>(index)];
}
ssize_t UnbufferedCharStream::mark() {
if (_numMarkers == 0) {
_lastCharBufferStart = _lastChar;
}
ssize_t mark = -static_cast<ssize_t>(_numMarkers) - 1;
_numMarkers++;
return mark;
}
void UnbufferedCharStream::release(ssize_t marker) {
ssize_t expectedMark = -static_cast<ssize_t>(_numMarkers);
if (marker != expectedMark) {
throw IllegalStateException("release() called with an invalid marker.");
}
_numMarkers--;
if (_numMarkers == 0 && _p > 0) {
_data.erase(0, _p);
_p = 0;
_lastCharBufferStart = _lastChar;
}
}
size_t UnbufferedCharStream::index() {
return _currentCharIndex;
}
void UnbufferedCharStream::seek(size_t index) {
if (index == _currentCharIndex) {
return;
}
if (index > _currentCharIndex) {
sync(index - _currentCharIndex);
index = std::min(index, getBufferStartIndex() + _data.size() - 1);
}
// index == to bufferStartIndex should set p to 0
ssize_t i = static_cast<ssize_t>(index) - static_cast<ssize_t>(getBufferStartIndex());
if (i < 0) {
throw IllegalArgumentException(std::string("cannot seek to negative index ") + std::to_string(index));
} else if (i >= static_cast<ssize_t>(_data.size())) {
throw UnsupportedOperationException("Seek to index outside buffer: " + std::to_string(index) +
" not in " + std::to_string(getBufferStartIndex()) + ".." +
std::to_string(getBufferStartIndex() + _data.size()));
}
_p = static_cast<size_t>(i);
_currentCharIndex = index;
if (_p == 0) {
_lastChar = _lastCharBufferStart;
} else {
_lastChar = _data[_p - 1];
}
}
size_t UnbufferedCharStream::size() {
throw UnsupportedOperationException("Unbuffered stream cannot know its size");
}
std::string UnbufferedCharStream::getSourceName() const {
if (name.empty()) {
return UNKNOWN_SOURCE_NAME;
}
return name;
}
std::string UnbufferedCharStream::getText(const misc::Interval &interval) {
if (interval.a < 0 || interval.b < interval.a - 1) {
throw IllegalArgumentException("invalid interval");
}
size_t bufferStartIndex = getBufferStartIndex();
if (!_data.empty() && _data.back() == 0xFFFF) {
if (interval.a + interval.length() > bufferStartIndex + _data.size()) {
throw IllegalArgumentException("the interval extends past the end of the stream");
}
}
if (interval.a < static_cast<ssize_t>(bufferStartIndex) || interval.b >= ssize_t(bufferStartIndex + _data.size())) {
throw UnsupportedOperationException("interval " + interval.toString() + " outside buffer: " +
std::to_string(bufferStartIndex) + ".." + std::to_string(bufferStartIndex + _data.size() - 1));
}
// convert from absolute to local index
size_t i = interval.a - bufferStartIndex;
auto maybeUtf8 = Utf8::strictEncode(std::u32string_view(_data).substr(i, interval.length()));
if (!maybeUtf8.has_value()) {
throw IllegalArgumentException("Unbuffered stream contains invalid Unicode code points");
}
return std::move(maybeUtf8).value();
}
std::string UnbufferedCharStream::toString() const {
throw UnsupportedOperationException("Unbuffered stream cannot be materialized to a string");
}
size_t UnbufferedCharStream::getBufferStartIndex() const {
return _currentCharIndex - _p;
}

View File

@@ -0,0 +1,117 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "CharStream.h"
namespace antlr4 {
/// Do not buffer up the entire char stream. It does keep a small buffer
/// for efficiency and also buffers while a mark exists (set by the
/// lookahead prediction in parser). "Unbuffered" here refers to fact
/// that it doesn't buffer all data, not that's it's on demand loading of char.
class ANTLR4CPP_PUBLIC UnbufferedCharStream : public CharStream {
public:
/// The name or source of this char stream.
std::string name;
explicit UnbufferedCharStream(std::wistream &input);
void consume() override;
size_t LA(ssize_t i) override;
/// <summary>
/// Return a marker that we can release later.
/// <p/>
/// The specific marker value used for this class allows for some level of
/// protection against misuse where {@code seek()} is called on a mark or
/// {@code release()} is called in the wrong order.
/// </summary>
ssize_t mark() override;
/// <summary>
/// Decrement number of markers, resetting buffer if we hit 0. </summary>
/// <param name="marker"> </param>
void release(ssize_t marker) override;
size_t index() override;
/// <summary>
/// Seek to absolute character index, which might not be in the current
/// sliding window. Move {@code p} to {@code index-bufferStartIndex}.
/// </summary>
void seek(size_t index) override;
size_t size() override;
std::string getSourceName() const override;
std::string getText(const misc::Interval &interval) override;
std::string toString() const override;
protected:
/// A moving window buffer of the data being scanned. While there's a marker,
/// we keep adding to buffer. Otherwise, <seealso cref="#consume consume()"/> resets so
/// we start filling at index 0 again.
// UTF-32 encoded.
std::u32string _data;
typedef char32_t storage_type;
/// <summary>
/// 0..n-1 index into <seealso cref="#data data"/> of next character.
/// <p/>
/// The {@code LA(1)} character is {@code data[p]}. If {@code p == n}, we are
/// out of buffered characters.
/// </summary>
size_t _p;
/// <summary>
/// Count up with <seealso cref="#mark mark()"/> and down with
/// <seealso cref="#release release()"/>. When we {@code release()} the last mark,
/// {@code numMarkers} reaches 0 and we reset the buffer. Copy
/// {@code data[p]..data[n-1]} to {@code data[0]..data[(n-1)-p]}.
/// </summary>
size_t _numMarkers;
/// This is the {@code LA(-1)} character for the current position.
size_t _lastChar; // UTF-32
/// <summary>
/// When {@code numMarkers > 0}, this is the {@code LA(-1)} character for the
/// first character in <seealso cref="#data data"/>. Otherwise, this is unspecified.
/// </summary>
size_t _lastCharBufferStart; // UTF-32
/// <summary>
/// Absolute character index. It's the index of the character about to be
/// read via {@code LA(1)}. Goes from 0 to the number of characters in the
/// entire stream, although the stream size is unknown before the end is
/// reached.
/// </summary>
size_t _currentCharIndex;
std::wistream &_input;
/// <summary>
/// Make sure we have 'want' elements from current position <seealso cref="#p p"/>.
/// Last valid {@code p} index is {@code data.length-1}. {@code p+need-1} is
/// the char index 'need' elements ahead. If we need 1 element,
/// {@code (p+1-1)==p} must be less than {@code data.length}.
/// </summary>
virtual void sync(size_t want);
/// <summary>
/// Add {@code n} characters to the buffer. Returns the number of characters
/// actually added to the buffer. If the return value is less than {@code n},
/// then EOF was reached before {@code n} characters could be added.
/// </summary>
virtual size_t fill(size_t n);
/// Override to provide different source of characters than
/// <seealso cref="#input input"/>.
virtual char32_t nextChar();
virtual void add(char32_t c);
size_t getBufferStartIndex() const;
};
} // namespace antlr4

View File

@@ -0,0 +1,270 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "Token.h"
#include "Exceptions.h"
#include "assert.h"
#include "TokenSource.h"
#include "support/Arrays.h"
#include "misc/Interval.h"
#include "RuleContext.h"
#include "WritableToken.h"
#include "UnbufferedTokenStream.h"
using namespace antlr4;
UnbufferedTokenStream::UnbufferedTokenStream(TokenSource *tokenSource) : UnbufferedTokenStream(tokenSource, 256) {
}
UnbufferedTokenStream::UnbufferedTokenStream(TokenSource *tokenSource, int /*bufferSize*/)
: _tokenSource(tokenSource), _lastToken(nullptr), _lastTokenBufferStart(nullptr)
{
InitializeInstanceFields();
fill(1); // prime the pump
}
UnbufferedTokenStream::~UnbufferedTokenStream() {
}
Token* UnbufferedTokenStream::get(size_t i) const
{ // get absolute index
size_t bufferStartIndex = getBufferStartIndex();
if (i < bufferStartIndex || i >= bufferStartIndex + _tokens.size()) {
throw IndexOutOfBoundsException(std::string("get(") + std::to_string(i) + std::string(") outside buffer: ")
+ std::to_string(bufferStartIndex) + std::string("..") + std::to_string(bufferStartIndex + _tokens.size()));
}
return _tokens[i - bufferStartIndex].get();
}
Token* UnbufferedTokenStream::LT(ssize_t i)
{
if (i == -1) {
return _lastToken;
}
sync(i);
ssize_t index = static_cast<ssize_t>(_p) + i - 1;
if (index < 0) {
throw IndexOutOfBoundsException(std::string("LT(") + std::to_string(i) + std::string(") gives negative index"));
}
if (index >= static_cast<ssize_t>(_tokens.size())) {
assert(_tokens.size() > 0 && _tokens.back()->getType() == EOF);
return _tokens.back().get();
}
return _tokens[static_cast<size_t>(index)].get();
}
size_t UnbufferedTokenStream::LA(ssize_t i)
{
return LT(i)->getType();
}
TokenSource* UnbufferedTokenStream::getTokenSource() const
{
return _tokenSource;
}
std::string UnbufferedTokenStream::getText()
{
return "";
}
std::string UnbufferedTokenStream::getText(RuleContext* ctx)
{
return getText(ctx->getSourceInterval());
}
std::string UnbufferedTokenStream::getText(Token *start, Token *stop)
{
return getText(misc::Interval(start->getTokenIndex(), stop->getTokenIndex()));
}
void UnbufferedTokenStream::consume()
{
if (LA(1) == EOF) {
throw IllegalStateException("cannot consume EOF");
}
// buf always has at least tokens[p==0] in this method due to ctor
_lastToken = _tokens[_p].get(); // track last token for LT(-1)
// if we're at last token and no markers, opportunity to flush buffer
if (_p == _tokens.size() - 1 && _numMarkers == 0) {
_tokens.clear();
_p = 0;
_lastTokenBufferStart = _lastToken;
} else {
++_p;
}
++_currentTokenIndex;
sync(1);
}
/// <summary>
/// Make sure we have 'need' elements from current position <seealso cref="#p p"/>. Last valid
/// {@code p} index is {@code tokens.length-1}. {@code p+need-1} is the tokens index 'need' elements
/// ahead. If we need 1 element, {@code (p+1-1)==p} must be less than {@code tokens.length}.
/// </summary>
void UnbufferedTokenStream::sync(ssize_t want)
{
ssize_t need = (static_cast<ssize_t>(_p) + want - 1) - static_cast<ssize_t>(_tokens.size()) + 1; // how many more elements we need?
if (need > 0) {
fill(static_cast<size_t>(need));
}
}
/// <summary>
/// Add {@code n} elements to the buffer. Returns the number of tokens
/// actually added to the buffer. If the return value is less than {@code n},
/// then EOF was reached before {@code n} tokens could be added.
/// </summary>
size_t UnbufferedTokenStream::fill(size_t n)
{
for (size_t i = 0; i < n; i++) {
if (_tokens.size() > 0 && _tokens.back()->getType() == EOF) {
return i;
}
add(_tokenSource->nextToken());
}
return n;
}
void UnbufferedTokenStream::add(std::unique_ptr<Token> t)
{
WritableToken *writable = dynamic_cast<WritableToken *>(t.get());
if (writable != nullptr) {
writable->setTokenIndex(int(getBufferStartIndex() + _tokens.size()));
}
_tokens.push_back(std::move(t));
}
/// <summary>
/// Return a marker that we can release later.
/// <p/>
/// The specific marker value used for this class allows for some level of
/// protection against misuse where {@code seek()} is called on a mark or
/// {@code release()} is called in the wrong order.
/// </summary>
ssize_t UnbufferedTokenStream::mark()
{
if (_numMarkers == 0) {
_lastTokenBufferStart = _lastToken;
}
int mark = -_numMarkers - 1;
_numMarkers++;
return mark;
}
void UnbufferedTokenStream::release(ssize_t marker)
{
ssize_t expectedMark = -_numMarkers;
if (marker != expectedMark) {
throw IllegalStateException("release() called with an invalid marker.");
}
_numMarkers--;
if (_numMarkers == 0) { // can we release buffer?
if (_p > 0) {
// Copy tokens[p]..tokens[n-1] to tokens[0]..tokens[(n-1)-p], reset ptrs
// p is last valid token; move nothing if p==n as we have no valid char
_tokens.erase(_tokens.begin(), _tokens.begin() + static_cast<ssize_t>(_p));
_p = 0;
}
_lastTokenBufferStart = _lastToken;
}
}
size_t UnbufferedTokenStream::index()
{
return _currentTokenIndex;
}
void UnbufferedTokenStream::seek(size_t index)
{ // seek to absolute index
if (index == _currentTokenIndex) {
return;
}
if (index > _currentTokenIndex) {
sync(ssize_t(index - _currentTokenIndex));
index = std::min(index, getBufferStartIndex() + _tokens.size() - 1);
}
size_t bufferStartIndex = getBufferStartIndex();
if (bufferStartIndex > index) {
throw IllegalArgumentException(std::string("cannot seek to negative index ") + std::to_string(index));
}
size_t i = index - bufferStartIndex;
if (i >= _tokens.size()) {
throw UnsupportedOperationException(std::string("seek to index outside buffer: ") + std::to_string(index) +
" not in " + std::to_string(bufferStartIndex) + ".." + std::to_string(bufferStartIndex + _tokens.size()));
}
_p = i;
_currentTokenIndex = index;
if (_p == 0) {
_lastToken = _lastTokenBufferStart;
} else {
_lastToken = _tokens[_p - 1].get();
}
}
size_t UnbufferedTokenStream::size()
{
throw UnsupportedOperationException("Unbuffered stream cannot know its size");
}
std::string UnbufferedTokenStream::getSourceName() const
{
return _tokenSource->getSourceName();
}
std::string UnbufferedTokenStream::getText(const misc::Interval &interval)
{
size_t bufferStartIndex = getBufferStartIndex();
size_t bufferStopIndex = bufferStartIndex + _tokens.size() - 1;
size_t start = interval.a;
size_t stop = interval.b;
if (start < bufferStartIndex || stop > bufferStopIndex) {
throw UnsupportedOperationException(std::string("interval ") + interval.toString() +
" not in token buffer window: " + std::to_string(bufferStartIndex) + ".." + std::to_string(bufferStopIndex));
}
size_t a = start - bufferStartIndex;
size_t b = stop - bufferStartIndex;
std::stringstream ss;
for (size_t i = a; i <= b; i++) {
Token *t = _tokens[i].get();
if (i > 0)
ss << ", ";
ss << t->getText();
}
return ss.str();
}
size_t UnbufferedTokenStream::getBufferStartIndex() const
{
return _currentTokenIndex - _p;
}
void UnbufferedTokenStream::InitializeInstanceFields()
{
_p = 0;
_numMarkers = 0;
_currentTokenIndex = 0;
}

View File

@@ -0,0 +1,115 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "TokenStream.h"
namespace antlr4 {
class ANTLR4CPP_PUBLIC UnbufferedTokenStream : public TokenStream {
public:
UnbufferedTokenStream(TokenSource *tokenSource);
UnbufferedTokenStream(TokenSource *tokenSource, int bufferSize);
UnbufferedTokenStream(const UnbufferedTokenStream& other) = delete;
virtual ~UnbufferedTokenStream();
UnbufferedTokenStream& operator = (const UnbufferedTokenStream& other) = delete;
virtual Token* get(size_t i) const override;
virtual Token* LT(ssize_t i) override;
virtual size_t LA(ssize_t i) override;
virtual TokenSource* getTokenSource() const override;
virtual std::string getText(const misc::Interval &interval) override;
virtual std::string getText() override;
virtual std::string getText(RuleContext *ctx) override;
virtual std::string getText(Token *start, Token *stop) override;
virtual void consume() override;
/// <summary>
/// Return a marker that we can release later.
/// <p/>
/// The specific marker value used for this class allows for some level of
/// protection against misuse where {@code seek()} is called on a mark or
/// {@code release()} is called in the wrong order.
/// </summary>
virtual ssize_t mark() override;
virtual void release(ssize_t marker) override;
virtual size_t index() override;
virtual void seek(size_t index) override;
virtual size_t size() override;
virtual std::string getSourceName() const override;
protected:
/// Make sure we have 'need' elements from current position p. Last valid
/// p index is tokens.length - 1. p + need - 1 is the tokens index 'need' elements
/// ahead. If we need 1 element, (p+1-1)==p must be less than tokens.length.
TokenSource *_tokenSource;
/// <summary>
/// A moving window buffer of the data being scanned. While there's a marker,
/// we keep adding to buffer. Otherwise, <seealso cref="#consume consume()"/> resets so
/// we start filling at index 0 again.
/// </summary>
std::vector<std::unique_ptr<Token>> _tokens;
/// <summary>
/// 0..n-1 index into <seealso cref="#tokens tokens"/> of next token.
/// <p/>
/// The {@code LT(1)} token is {@code tokens[p]}. If {@code p == n}, we are
/// out of buffered tokens.
/// </summary>
size_t _p;
/// <summary>
/// Count up with <seealso cref="#mark mark()"/> and down with
/// <seealso cref="#release release()"/>. When we {@code release()} the last mark,
/// {@code numMarkers} reaches 0 and we reset the buffer. Copy
/// {@code tokens[p]..tokens[n-1]} to {@code tokens[0]..tokens[(n-1)-p]}.
/// </summary>
int _numMarkers;
/// <summary>
/// This is the {@code LT(-1)} token for the current position.
/// </summary>
Token *_lastToken;
/// <summary>
/// When {@code numMarkers > 0}, this is the {@code LT(-1)} token for the
/// first token in <seealso cref="#tokens"/>. Otherwise, this is {@code null}.
/// </summary>
Token *_lastTokenBufferStart;
/// <summary>
/// Absolute token index. It's the index of the token about to be read via
/// {@code LT(1)}. Goes from 0 to the number of tokens in the entire stream,
/// although the stream size is unknown before the end is reached.
/// <p/>
/// This value is used to set the token indexes if the stream provides tokens
/// that implement <seealso cref="WritableToken"/>.
/// </summary>
size_t _currentTokenIndex;
virtual void sync(ssize_t want);
/// <summary>
/// Add {@code n} elements to the buffer. Returns the number of tokens
/// actually added to the buffer. If the return value is less than {@code n},
/// then EOF was reached before {@code n} tokens could be added.
/// </summary>
virtual size_t fill(size_t n);
virtual void add(std::unique_ptr<Token> t);
size_t getBufferStartIndex() const;
private:
void InitializeInstanceFields();
};
} // namespace antlr4

View File

@@ -0,0 +1,42 @@
// Copyright 2012-2022 The ANTLR Project
//
// 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. Neither the name of the copyright holder nor the names of its contributors may be used to
// endorse or promote products derived from this software without specific prior written
// permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR
// CONTRIBUTORS 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.
#pragma once
#include "antlr4-common.h"
#define ANTLRCPP_VERSION_MAJOR 4
#define ANTLRCPP_VERSION_MINOR 12
#define ANTLRCPP_VERSION_PATCH 0
#define ANTLRCPP_MAKE_VERSION(major, minor, patch) ((major) * 100000 + (minor) * 1000 + (patch))
#define ANTLRCPP_VERSION \
ANTLRCPP_MAKE_VERSION(ANTLR4CPP_VERSION_MAJOR, ANTLR4CPP_VERSION_MINOR, ANTLR4CPP_VERSION_PATCH)
#define ANTLRCPP_VERSION_STRING \
ANTLR4CPP_STRINGIFY(ANTLR4CPP_VERSION_MAJOR) "." \
ANTLR4CPP_STRINGIFY(ANTLR4CPP_VERSION_MINOR) "." \
ANTLR4CPP_STRINGIFY(ANTLR4CPP_VERSION_PATCH)

View File

@@ -0,0 +1,64 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "Token.h"
#include "Vocabulary.h"
using namespace antlr4::dfa;
const Vocabulary Vocabulary::EMPTY_VOCABULARY;
Vocabulary::Vocabulary(std::vector<std::string> literalNames, std::vector<std::string> symbolicNames)
: Vocabulary(std::move(literalNames), std::move(symbolicNames), {}) {
}
Vocabulary::Vocabulary(std::vector<std::string> literalNames,
std::vector<std::string> symbolicNames, std::vector<std::string> displayNames)
: _literalNames(std::move(literalNames)), _symbolicNames(std::move(symbolicNames)), _displayNames(std::move(displayNames)),
_maxTokenType(std::max(_displayNames.size(), std::max(_literalNames.size(), _symbolicNames.size())) - 1) {
// See note here on -1 part: https://github.com/antlr/antlr4/pull/1146
}
std::string_view Vocabulary::getLiteralName(size_t tokenType) const {
if (tokenType < _literalNames.size()) {
return _literalNames[tokenType];
}
return "";
}
std::string_view Vocabulary::getSymbolicName(size_t tokenType) const {
if (tokenType == Token::EOF) {
return "EOF";
}
if (tokenType < _symbolicNames.size()) {
return _symbolicNames[tokenType];
}
return "";
}
std::string Vocabulary::getDisplayName(size_t tokenType) const {
if (tokenType < _displayNames.size()) {
std::string_view displayName = _displayNames[tokenType];
if (!displayName.empty()) {
return std::string(displayName);
}
}
std::string_view literalName = getLiteralName(tokenType);
if (!literalName.empty()) {
return std::string(literalName);
}
std::string_view symbolicName = getSymbolicName(tokenType);
if (!symbolicName.empty()) {
return std::string(symbolicName);
}
return std::to_string(tokenType);
}

View File

@@ -0,0 +1,177 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "antlr4-common.h"
namespace antlr4 {
namespace dfa {
/// This class provides a default implementation of the <seealso cref="Vocabulary"/>
/// interface.
class ANTLR4CPP_PUBLIC Vocabulary final {
public:
/// Gets an empty <seealso cref="Vocabulary"/> instance.
///
/// <para>
/// No literal or symbol names are assigned to token types, so
/// <seealso cref="#getDisplayName(int)"/> returns the numeric value for all tokens
/// except <seealso cref="Token#EOF"/>.</para>
[[deprecated("Use the default constructor of Vocabulary instead.")]] static const Vocabulary EMPTY_VOCABULARY;
Vocabulary() {}
Vocabulary(const Vocabulary&) = default;
/// <summary>
/// Constructs a new instance of <seealso cref="Vocabulary"/> from the specified
/// literal and symbolic token names.
/// </summary>
/// <param name="literalNames"> The literal names assigned to tokens, or {@code null}
/// if no literal names are assigned. </param>
/// <param name="symbolicNames"> The symbolic names assigned to tokens, or
/// {@code null} if no symbolic names are assigned.
/// </param>
/// <seealso cref= #getLiteralName(int) </seealso>
/// <seealso cref= #getSymbolicName(int) </seealso>
Vocabulary(std::vector<std::string> literalNames, std::vector<std::string> symbolicNames);
/// <summary>
/// Constructs a new instance of <seealso cref="Vocabulary"/> from the specified
/// literal, symbolic, and display token names.
/// </summary>
/// <param name="literalNames"> The literal names assigned to tokens, or {@code null}
/// if no literal names are assigned. </param>
/// <param name="symbolicNames"> The symbolic names assigned to tokens, or
/// {@code null} if no symbolic names are assigned. </param>
/// <param name="displayNames"> The display names assigned to tokens, or {@code null}
/// to use the values in {@code literalNames} and {@code symbolicNames} as
/// the source of display names, as described in
/// <seealso cref="#getDisplayName(int)"/>.
/// </param>
/// <seealso cref= #getLiteralName(int) </seealso>
/// <seealso cref= #getSymbolicName(int) </seealso>
/// <seealso cref= #getDisplayName(int) </seealso>
Vocabulary(std::vector<std::string> literalNames, std::vector<std::string> symbolicNames,
std::vector<std::string> displayNames);
/// <summary>
/// Returns the highest token type value. It can be used to iterate from
/// zero to that number, inclusively, thus querying all stored entries. </summary>
/// <returns> the highest token type value </returns>
constexpr size_t getMaxTokenType() const { return _maxTokenType; }
/// <summary>
/// Gets the string literal associated with a token type. The string returned
/// by this method, when not {@code null}, can be used unaltered in a parser
/// grammar to represent this token type.
///
/// <para>The following table shows examples of lexer rules and the literal
/// names assigned to the corresponding token types.</para>
///
/// <table>
/// <tr>
/// <th>Rule</th>
/// <th>Literal Name</th>
/// <th>Java String Literal</th>
/// </tr>
/// <tr>
/// <td>{@code THIS : 'this';}</td>
/// <td>{@code 'this'}</td>
/// <td>{@code "'this'"}</td>
/// </tr>
/// <tr>
/// <td>{@code SQUOTE : '\'';}</td>
/// <td>{@code '\''}</td>
/// <td>{@code "'\\''"}</td>
/// </tr>
/// <tr>
/// <td>{@code ID : [A-Z]+;}</td>
/// <td>n/a</td>
/// <td>{@code null}</td>
/// </tr>
/// </table>
/// </summary>
/// <param name="tokenType"> The token type.
/// </param>
/// <returns> The string literal associated with the specified token type, or
/// {@code null} if no string literal is associated with the type. </returns>
std::string_view getLiteralName(size_t tokenType) const;
/// <summary>
/// Gets the symbolic name associated with a token type. The string returned
/// by this method, when not {@code null}, can be used unaltered in a parser
/// grammar to represent this token type.
///
/// <para>This method supports token types defined by any of the following
/// methods:</para>
///
/// <ul>
/// <li>Tokens created by lexer rules.</li>
/// <li>Tokens defined in a <code>tokens{}</code> block in a lexer or parser
/// grammar.</li>
/// <li>The implicitly defined {@code EOF} token, which has the token type
/// <seealso cref="Token#EOF"/>.</li>
/// </ul>
///
/// <para>The following table shows examples of lexer rules and the literal
/// names assigned to the corresponding token types.</para>
///
/// <table>
/// <tr>
/// <th>Rule</th>
/// <th>Symbolic Name</th>
/// </tr>
/// <tr>
/// <td>{@code THIS : 'this';}</td>
/// <td>{@code THIS}</td>
/// </tr>
/// <tr>
/// <td>{@code SQUOTE : '\'';}</td>
/// <td>{@code SQUOTE}</td>
/// </tr>
/// <tr>
/// <td>{@code ID : [A-Z]+;}</td>
/// <td>{@code ID}</td>
/// </tr>
/// </table>
/// </summary>
/// <param name="tokenType"> The token type.
/// </param>
/// <returns> The symbolic name associated with the specified token type, or
/// {@code null} if no symbolic name is associated with the type. </returns>
std::string_view getSymbolicName(size_t tokenType) const;
/// <summary>
/// Gets the display name of a token type.
///
/// <para>ANTLR provides a default implementation of this method, but
/// applications are free to override the behavior in any manner which makes
/// sense for the application. The default implementation returns the first
/// result from the following list which produces a non-{@code null}
/// result.</para>
///
/// <ol>
/// <li>The result of <seealso cref="#getLiteralName"/></li>
/// <li>The result of <seealso cref="#getSymbolicName"/></li>
/// <li>The result of <seealso cref="Integer#toString"/></li>
/// </ol>
/// </summary>
/// <param name="tokenType"> The token type.
/// </param>
/// <returns> The display name of the token type, for use in error reporting or
/// other user-visible messages which reference specific token types. </returns>
std::string getDisplayName(size_t tokenType) const;
private:
std::vector<std::string> const _literalNames;
std::vector<std::string> const _symbolicNames;
std::vector<std::string> const _displayNames;
const size_t _maxTokenType = 0;
};
} // namespace atn
} // namespace antlr4

View File

@@ -0,0 +1,9 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "WritableToken.h"
antlr4::WritableToken::~WritableToken() {
}

View File

@@ -0,0 +1,23 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "Token.h"
namespace antlr4 {
class ANTLR4CPP_PUBLIC WritableToken : public Token {
public:
virtual ~WritableToken();
virtual void setText(const std::string &text) = 0;
virtual void setType(size_t ttype) = 0;
virtual void setLine(size_t line) = 0;
virtual void setCharPositionInLine(size_t pos) = 0;
virtual void setChannel(size_t channel) = 0;
virtual void setTokenIndex(size_t index) = 0;
};
} // namespace antlr4

View File

@@ -0,0 +1,101 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include <algorithm>
#include <any>
#include <atomic>
#include <bitset>
#include <cassert>
#include <climits>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <exception>
#include <fstream>
#include <iostream>
#include <iterator>
#include <limits>
#include <map>
#include <memory>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <string_view>
#include <typeinfo>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
// Defines for the Guid class and other platform dependent stuff.
#ifdef _WIN32
#ifdef _MSC_VER
#pragma warning (disable: 4250) // Class inherits by dominance.
#pragma warning (disable: 4512) // assignment operator could not be generated
#if _MSC_VER < 1900
// Before VS 2015 code like "while (true)" will create a (useless) warning in level 4.
#pragma warning (disable: 4127) // conditional expression is constant
#endif
#endif
#ifdef _WIN64
typedef __int64 ssize_t;
#else
typedef __int32 ssize_t;
#endif
#ifdef ANTLR4CPP_EXPORTS
#define ANTLR4CPP_PUBLIC __declspec(dllexport)
#else
#ifdef ANTLR4CPP_STATIC
#define ANTLR4CPP_PUBLIC
#else
#define ANTLR4CPP_PUBLIC __declspec(dllimport)
#endif
#endif
#elif defined(__APPLE__)
#if __GNUC__ >= 4
#define ANTLR4CPP_PUBLIC __attribute__ ((visibility ("default")))
#else
#define ANTLR4CPP_PUBLIC
#endif
#else
#if __GNUC__ >= 6
#define ANTLR4CPP_PUBLIC __attribute__ ((visibility ("default")))
#else
#define ANTLR4CPP_PUBLIC
#endif
#endif
#ifdef __has_builtin
#define ANTLR4CPP_HAVE_BUILTIN(x) __has_builtin(x)
#else
#define ANTLR4CPP_HAVE_BUILTIN(x) 0
#endif
#define ANTLR4CPP_INTERNAL_STRINGIFY(x) #x
#define ANTLR4CPP_STRINGIFY(x) ANTLR4CPP_INTERNAL_STRINGIFY(x)
// We use everything from the C++ standard library by default.
#ifndef ANTLR4CPP_USING_ABSEIL
#define ANTLR4CPP_USING_ABSEIL 0
#endif
#include "support/Declarations.h"
// We have to undefine this symbol as ANTLR will use this name for own members and even
// generated functions. Because EOF is a global macro we cannot use e.g. a namespace scope to disambiguate.
#ifdef EOF
#undef EOF
#endif
#define INVALID_INDEX std::numeric_limits<size_t>::max()
template<class T> using Ref = std::shared_ptr<T>;

View File

@@ -0,0 +1,168 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
// This is the umbrella header for all ANTLR4 C++ runtime headers.
#include "antlr4-common.h"
#include "ANTLRErrorListener.h"
#include "ANTLRErrorStrategy.h"
#include "ANTLRFileStream.h"
#include "ANTLRInputStream.h"
#include "BailErrorStrategy.h"
#include "BaseErrorListener.h"
#include "BufferedTokenStream.h"
#include "CharStream.h"
#include "CommonToken.h"
#include "CommonTokenFactory.h"
#include "CommonTokenStream.h"
#include "ConsoleErrorListener.h"
#include "DefaultErrorStrategy.h"
#include "DiagnosticErrorListener.h"
#include "Exceptions.h"
#include "FailedPredicateException.h"
#include "InputMismatchException.h"
#include "IntStream.h"
#include "InterpreterRuleContext.h"
#include "Lexer.h"
#include "LexerInterpreter.h"
#include "LexerNoViableAltException.h"
#include "ListTokenSource.h"
#include "NoViableAltException.h"
#include "Parser.h"
#include "ParserInterpreter.h"
#include "ParserRuleContext.h"
#include "ProxyErrorListener.h"
#include "RecognitionException.h"
#include "Recognizer.h"
#include "RuleContext.h"
#include "RuleContextWithAltNum.h"
#include "RuntimeMetaData.h"
#include "Token.h"
#include "TokenFactory.h"
#include "TokenSource.h"
#include "TokenStream.h"
#include "TokenStreamRewriter.h"
#include "UnbufferedCharStream.h"
#include "UnbufferedTokenStream.h"
#include "Version.h"
#include "Vocabulary.h"
#include "Vocabulary.h"
#include "WritableToken.h"
#include "atn/ATN.h"
#include "atn/ATNConfig.h"
#include "atn/ATNConfigSet.h"
#include "atn/ATNDeserializationOptions.h"
#include "atn/ATNDeserializer.h"
#include "atn/ATNSimulator.h"
#include "atn/ATNState.h"
#include "atn/ATNType.h"
#include "atn/ActionTransition.h"
#include "atn/AmbiguityInfo.h"
#include "atn/ArrayPredictionContext.h"
#include "atn/AtomTransition.h"
#include "atn/BasicBlockStartState.h"
#include "atn/BasicState.h"
#include "atn/BlockEndState.h"
#include "atn/BlockStartState.h"
#include "atn/ContextSensitivityInfo.h"
#include "atn/DecisionEventInfo.h"
#include "atn/DecisionInfo.h"
#include "atn/DecisionState.h"
#include "atn/EpsilonTransition.h"
#include "atn/ErrorInfo.h"
#include "atn/LL1Analyzer.h"
#include "atn/LexerATNConfig.h"
#include "atn/LexerATNSimulator.h"
#include "atn/LexerAction.h"
#include "atn/LexerActionExecutor.h"
#include "atn/LexerActionType.h"
#include "atn/LexerChannelAction.h"
#include "atn/LexerCustomAction.h"
#include "atn/LexerIndexedCustomAction.h"
#include "atn/LexerModeAction.h"
#include "atn/LexerMoreAction.h"
#include "atn/LexerPopModeAction.h"
#include "atn/LexerPushModeAction.h"
#include "atn/LexerSkipAction.h"
#include "atn/LexerTypeAction.h"
#include "atn/LookaheadEventInfo.h"
#include "atn/LoopEndState.h"
#include "atn/NotSetTransition.h"
#include "atn/OrderedATNConfigSet.h"
#include "atn/ParseInfo.h"
#include "atn/ParserATNSimulator.h"
#include "atn/ParserATNSimulatorOptions.h"
#include "atn/PlusBlockStartState.h"
#include "atn/PlusLoopbackState.h"
#include "atn/PrecedencePredicateTransition.h"
#include "atn/PredicateEvalInfo.h"
#include "atn/PredicateTransition.h"
#include "atn/PredictionContext.h"
#include "atn/PredictionContextCache.h"
#include "atn/PredictionContextMergeCache.h"
#include "atn/PredictionContextMergeCacheOptions.h"
#include "atn/PredictionMode.h"
#include "atn/ProfilingATNSimulator.h"
#include "atn/RangeTransition.h"
#include "atn/RuleStartState.h"
#include "atn/RuleStopState.h"
#include "atn/RuleTransition.h"
#include "atn/SemanticContext.h"
#include "atn/SerializedATNView.h"
#include "atn/SetTransition.h"
#include "atn/SingletonPredictionContext.h"
#include "atn/StarBlockStartState.h"
#include "atn/StarLoopEntryState.h"
#include "atn/StarLoopbackState.h"
#include "atn/TokensStartState.h"
#include "atn/Transition.h"
#include "atn/WildcardTransition.h"
#include "dfa/DFA.h"
#include "dfa/DFASerializer.h"
#include "dfa/DFAState.h"
#include "dfa/LexerDFASerializer.h"
#include "misc/InterpreterDataReader.h"
#include "misc/Interval.h"
#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/Casts.h"
#include "support/CPPUtils.h"
#include "tree/AbstractParseTreeVisitor.h"
#include "tree/ErrorNode.h"
#include "tree/ErrorNodeImpl.h"
#include "tree/ParseTree.h"
#include "tree/ParseTreeListener.h"
#include "tree/ParseTreeProperty.h"
#include "tree/ParseTreeVisitor.h"
#include "tree/ParseTreeWalker.h"
#include "tree/TerminalNode.h"
#include "tree/TerminalNodeImpl.h"
#include "tree/Trees.h"
#include "tree/pattern/Chunk.h"
#include "tree/pattern/ParseTreeMatch.h"
#include "tree/pattern/ParseTreePattern.h"
#include "tree/pattern/ParseTreePatternMatcher.h"
#include "tree/pattern/RuleTagToken.h"
#include "tree/pattern/TagChunk.h"
#include "tree/pattern/TextChunk.h"
#include "tree/pattern/TokenTagToken.h"
#include "tree/xpath/XPath.h"
#include "tree/xpath/XPathElement.h"
#include "tree/xpath/XPathLexer.h"
#include "tree/xpath/XPathLexerErrorListener.h"
#include "tree/xpath/XPathRuleAnywhereElement.h"
#include "tree/xpath/XPathRuleElement.h"
#include "tree/xpath/XPathTokenAnywhereElement.h"
#include "tree/xpath/XPathTokenElement.h"
#include "tree/xpath/XPathWildcardAnywhereElement.h"
#include "tree/xpath/XPathWildcardElement.h"
#include "internal/Synchronization.h"

View File

@@ -0,0 +1,159 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "atn/LL1Analyzer.h"
#include "Token.h"
#include "atn/RuleTransition.h"
#include "misc/IntervalSet.h"
#include "RuleContext.h"
#include "atn/DecisionState.h"
#include "Recognizer.h"
#include "atn/ATNType.h"
#include "Exceptions.h"
#include "support/CPPUtils.h"
#include "atn/ATN.h"
using namespace antlr4;
using namespace antlr4::atn;
using namespace antlr4::internal;
using namespace antlrcpp;
ATN::ATN() : ATN(ATNType::LEXER, 0) {}
ATN::ATN(ATNType grammarType_, size_t maxTokenType_) : grammarType(grammarType_), maxTokenType(maxTokenType_) {}
ATN::~ATN() {
for (ATNState *state : states) {
delete state;
}
}
misc::IntervalSet ATN::nextTokens(ATNState *s, RuleContext *ctx) const {
LL1Analyzer analyzer(*this);
return analyzer.LOOK(s, ctx);
}
misc::IntervalSet const& ATN::nextTokens(ATNState *s) const {
if (!s->_nextTokenUpdated) {
UniqueLock<Mutex> lock(_mutex);
if (!s->_nextTokenUpdated) {
s->_nextTokenWithinRule = nextTokens(s, nullptr);
s->_nextTokenUpdated = true;
}
}
return s->_nextTokenWithinRule;
}
void ATN::addState(ATNState *state) {
if (state != nullptr) {
//state->atn = this;
state->stateNumber = static_cast<int>(states.size());
}
states.push_back(state);
}
void ATN::removeState(ATNState *state) {
delete states.at(state->stateNumber);// just free mem, don't shift states in list
states.at(state->stateNumber) = nullptr;
}
int ATN::defineDecisionState(DecisionState *s) {
decisionToState.push_back(s);
s->decision = static_cast<int>(decisionToState.size() - 1);
return s->decision;
}
DecisionState *ATN::getDecisionState(size_t decision) const {
if (!decisionToState.empty()) {
return decisionToState[decision];
}
return nullptr;
}
size_t ATN::getNumberOfDecisions() const {
return decisionToState.size();
}
misc::IntervalSet ATN::getExpectedTokens(size_t stateNumber, RuleContext *context) const {
if (stateNumber == ATNState::INVALID_STATE_NUMBER || stateNumber >= states.size()) {
throw IllegalArgumentException("Invalid state number.");
}
RuleContext *ctx = context;
ATNState *s = states.at(stateNumber);
misc::IntervalSet following = nextTokens(s);
if (!following.contains(Token::EPSILON)) {
return following;
}
misc::IntervalSet expected;
expected.addAll(following);
expected.remove(Token::EPSILON);
while (ctx && ctx->invokingState != ATNState::INVALID_STATE_NUMBER && following.contains(Token::EPSILON)) {
ATNState *invokingState = states.at(ctx->invokingState);
const RuleTransition *rt = static_cast<const RuleTransition*>(invokingState->transitions[0].get());
following = nextTokens(rt->followState);
expected.addAll(following);
expected.remove(Token::EPSILON);
if (ctx->parent == nullptr) {
break;
}
ctx = static_cast<RuleContext *>(ctx->parent);
}
if (following.contains(Token::EPSILON)) {
expected.add(Token::EOF);
}
return expected;
}
std::string ATN::toString() const {
std::stringstream ss;
std::string type;
switch (grammarType) {
case ATNType::LEXER:
type = "LEXER ";
break;
case ATNType::PARSER:
type = "PARSER ";
break;
default:
break;
}
ss << "(" << type << "ATN " << std::hex << this << std::dec << ") maxTokenType: " << maxTokenType << std::endl;
ss << "states (" << states.size() << ") {" << std::endl;
size_t index = 0;
for (auto *state : states) {
if (state == nullptr) {
ss << " " << index++ << ": nul" << std::endl;
} else {
std::string text = state->toString();
ss << " " << index++ << ": " << indent(text, " ", false) << std::endl;
}
}
index = 0;
for (auto *state : decisionToState) {
if (state == nullptr) {
ss << " " << index++ << ": nul" << std::endl;
} else {
std::string text = state->toString();
ss << " " << index++ << ": " << indent(text, " ", false) << std::endl;
}
}
ss << "}";
return ss.str();
}

View File

@@ -0,0 +1,133 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "RuleContext.h"
#include "internal/Synchronization.h"
// GCC generates a warning when forward-declaring ATN if ATN has already been
// declared due to the attributes added by ANTLR4CPP_PUBLIC.
// See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39159
// Add constant that can be checked so forward-declarations can be omitted.
#define ANTLR4CPP_ATN_DECLARED
namespace antlr4 {
namespace atn {
class LexerATNSimulator;
class ParserATNSimulator;
class ANTLR4CPP_PUBLIC ATN {
public:
static constexpr size_t INVALID_ALT_NUMBER = 0;
/// Used for runtime deserialization of ATNs from strings.
ATN();
ATN(ATNType grammarType, size_t maxTokenType);
ATN(const ATN&) = delete;
ATN(ATN&&) = delete;
~ATN();
ATN& operator=(const ATN&) = delete;
ATN& operator=(ATN&&) = delete;
std::vector<ATNState *> states;
/// Each subrule/rule is a decision point and we must track them so we
/// can go back later and build DFA predictors for them. This includes
/// all the rules, subrules, optional blocks, ()+, ()* etc...
std::vector<DecisionState *> decisionToState;
/// Maps from rule index to starting state number.
std::vector<RuleStartState *> ruleToStartState;
/// Maps from rule index to stop state number.
std::vector<RuleStopState *> ruleToStopState;
/// The type of the ATN.
ATNType grammarType;
/// The maximum value for any symbol recognized by a transition in the ATN.
size_t maxTokenType;
/// <summary>
/// For lexer ATNs, this maps the rule index to the resulting token type.
/// For parser ATNs, this maps the rule index to the generated bypass token
/// type if the
/// <seealso cref="ATNDeserializationOptions#isGenerateRuleBypassTransitions"/>
/// deserialization option was specified; otherwise, this is {@code null}.
/// </summary>
std::vector<size_t> ruleToTokenType;
/// For lexer ATNs, this is an array of {@link LexerAction} objects which may
/// be referenced by action transitions in the ATN.
std::vector<Ref<const LexerAction>> lexerActions;
std::vector<TokensStartState *> modeToStartState;
/// <summary>
/// Compute the set of valid tokens that can occur starting in state {@code s}.
/// If {@code ctx} is null, the set of tokens will not include what can follow
/// the rule surrounding {@code s}. In other words, the set will be
/// restricted to tokens reachable staying within {@code s}'s rule.
/// </summary>
misc::IntervalSet nextTokens(ATNState *s, RuleContext *ctx) const;
/// <summary>
/// Compute the set of valid tokens that can occur starting in {@code s} and
/// staying in same rule. <seealso cref="Token#EPSILON"/> is in set if we reach end of
/// rule.
/// </summary>
misc::IntervalSet const& nextTokens(ATNState *s) const;
void addState(ATNState *state);
void removeState(ATNState *state);
int defineDecisionState(DecisionState *s);
DecisionState *getDecisionState(size_t decision) const;
size_t getNumberOfDecisions() const;
/// <summary>
/// Computes the set of input symbols which could follow ATN state number
/// {@code stateNumber} in the specified full {@code context}. This method
/// considers the complete parser context, but does not evaluate semantic
/// predicates (i.e. all predicates encountered during the calculation are
/// assumed true). If a path in the ATN exists from the starting state to the
/// <seealso cref="RuleStopState"/> of the outermost context without matching any
/// symbols, <seealso cref="Token#EOF"/> is added to the returned set.
/// <p/>
/// If {@code context} is {@code null}, it is treated as
/// <seealso cref="ParserRuleContext#EMPTY"/>.
/// </summary>
/// <param name="stateNumber"> the ATN state number </param>
/// <param name="context"> the full parse context </param>
/// <returns> The set of potentially valid input symbols which could follow the
/// specified state in the specified context. </returns>
/// <exception cref="IllegalArgumentException"> if the ATN does not contain a state with
/// number {@code stateNumber} </exception>
misc::IntervalSet getExpectedTokens(size_t stateNumber, RuleContext *context) const;
std::string toString() const;
private:
friend class LexerATNSimulator;
friend class ParserATNSimulator;
mutable internal::Mutex _mutex;
mutable internal::SharedMutex _stateMutex;
mutable internal::SharedMutex _edgeMutex;
};
} // namespace atn
} // namespace antlr4

View File

@@ -0,0 +1,106 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "misc/MurmurHash.h"
#include "atn/PredictionContext.h"
#include "SemanticContext.h"
#include "atn/ATNConfig.h"
using namespace antlr4::atn;
namespace {
/**
* This field stores the bit mask for implementing the
* {@link #isPrecedenceFilterSuppressed} property as a bit within the
* existing {@link #reachesIntoOuterContext} field.
*/
inline constexpr size_t SUPPRESS_PRECEDENCE_FILTER = 0x40000000;
}
ATNConfig::ATNConfig(ATNState *state, size_t alt, Ref<const PredictionContext> context)
: ATNConfig(state, alt, std::move(context), 0, SemanticContext::Empty::Instance) {}
ATNConfig::ATNConfig(ATNState *state, size_t alt, Ref<const PredictionContext> context, Ref<const SemanticContext> semanticContext)
: ATNConfig(state, alt, std::move(context), 0, std::move(semanticContext)) {}
ATNConfig::ATNConfig(ATNConfig const& other, Ref<const SemanticContext> semanticContext)
: ATNConfig(other.state, other.alt, other.context, other.reachesIntoOuterContext, std::move(semanticContext)) {}
ATNConfig::ATNConfig(ATNConfig const& other, ATNState *state)
: ATNConfig(state, other.alt, other.context, other.reachesIntoOuterContext, other.semanticContext) {}
ATNConfig::ATNConfig(ATNConfig const& other, ATNState *state, Ref<const SemanticContext> semanticContext)
: ATNConfig(state, other.alt, other.context, other.reachesIntoOuterContext, std::move(semanticContext)) {}
ATNConfig::ATNConfig(ATNConfig const& other, ATNState *state, Ref<const PredictionContext> context)
: ATNConfig(state, other.alt, std::move(context), other.reachesIntoOuterContext, other.semanticContext) {}
ATNConfig::ATNConfig(ATNConfig const& other, ATNState *state, Ref<const PredictionContext> context, Ref<const SemanticContext> semanticContext)
: ATNConfig(state, other.alt, std::move(context), other.reachesIntoOuterContext, std::move(semanticContext)) {}
ATNConfig::ATNConfig(ATNState *state, size_t alt, Ref<const PredictionContext> context, size_t reachesIntoOuterContext, Ref<const SemanticContext> semanticContext)
: state(state), alt(alt), context(std::move(context)), reachesIntoOuterContext(reachesIntoOuterContext), semanticContext(std::move(semanticContext)) {}
size_t ATNConfig::hashCode() const {
size_t hashCode = misc::MurmurHash::initialize(7);
hashCode = misc::MurmurHash::update(hashCode, state->stateNumber);
hashCode = misc::MurmurHash::update(hashCode, alt);
hashCode = misc::MurmurHash::update(hashCode, context);
hashCode = misc::MurmurHash::update(hashCode, semanticContext);
hashCode = misc::MurmurHash::finish(hashCode, 4);
return hashCode;
}
size_t ATNConfig::getOuterContextDepth() const {
return reachesIntoOuterContext & ~SUPPRESS_PRECEDENCE_FILTER;
}
bool ATNConfig::isPrecedenceFilterSuppressed() const {
return (reachesIntoOuterContext & SUPPRESS_PRECEDENCE_FILTER) != 0;
}
void ATNConfig::setPrecedenceFilterSuppressed(bool value) {
if (value) {
reachesIntoOuterContext |= SUPPRESS_PRECEDENCE_FILTER;
} else {
reachesIntoOuterContext &= ~SUPPRESS_PRECEDENCE_FILTER;
}
}
bool ATNConfig::operator==(const ATNConfig &other) const {
return state->stateNumber == other.state->stateNumber && alt == other.alt &&
((context == other.context) || (*context == *other.context)) &&
*semanticContext == *other.semanticContext &&
isPrecedenceFilterSuppressed() == other.isPrecedenceFilterSuppressed();
}
std::string ATNConfig::toString() const {
return toString(true);
}
std::string ATNConfig::toString(bool showAlt) const {
std::stringstream ss;
ss << "(";
ss << state->toString();
if (showAlt) {
ss << "," << alt;
}
if (context) {
ss << ",[" << context->toString() << "]";
}
if (semanticContext != nullptr && semanticContext != SemanticContext::Empty::Instance) {
ss << "," << semanticContext->toString();
}
if (getOuterContextDepth() > 0) {
ss << ",up=" << getOuterContextDepth();
}
ss << ")";
return ss.str();
}

View File

@@ -0,0 +1,157 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include <cassert>
#include "antlr4-common.h"
#include "atn/SemanticContext.h"
namespace antlr4 {
namespace atn {
/// <summary>
/// A tuple: (ATN state, predicted alt, syntactic, semantic context).
/// The syntactic context is a graph-structured stack node whose
/// path(s) to the root is the rule invocation(s)
/// chain used to arrive at the state. The semantic context is
/// the tree of semantic predicates encountered before reaching
/// an ATN state.
/// </summary>
class ANTLR4CPP_PUBLIC ATNConfig {
public:
struct Hasher
{
size_t operator()(Ref<ATNConfig> const& k) const {
return k->hashCode();
}
size_t operator()(ATNConfig const& k) const {
return k.hashCode();
}
};
struct Comparer {
bool operator()(Ref<ATNConfig> const& lhs, Ref<ATNConfig> const& rhs) const {
return (lhs == rhs) || (*lhs == *rhs);
}
bool operator()(ATNConfig const& lhs, ATNConfig const& rhs) const {
return (&lhs == &rhs) || (lhs == rhs);
}
};
using Set = std::unordered_set<Ref<ATNConfig>, Hasher, Comparer>;
/// The ATN state associated with this configuration.
ATNState *state = nullptr;
/// What alt (or lexer rule) is predicted by this configuration.
const size_t alt = 0;
/// The stack of invoking states leading to the rule/states associated
/// with this config. We track only those contexts pushed during
/// execution of the ATN simulator.
///
/// Can be shared between multiple ANTConfig instances.
Ref<const PredictionContext> context;
/**
* We cannot execute predicates dependent upon local context unless
* we know for sure we are in the correct context. Because there is
* no way to do this efficiently, we simply cannot evaluate
* dependent predicates unless we are in the rule that initially
* invokes the ATN simulator.
*
* <p>
* closure() tracks the depth of how far we dip into the outer context:
* depth > 0. Note that it may not be totally accurate depth since I
* don't ever decrement. TODO: make it a boolean then</p>
*
* <p>
* For memory efficiency, the {@link #isPrecedenceFilterSuppressed} method
* is also backed by this field. Since the field is publicly accessible, the
* highest bit which would not cause the value to become negative is used to
* store this field. This choice minimizes the risk that code which only
* compares this value to 0 would be affected by the new purpose of the
* flag. It also ensures the performance of the existing {@link ATNConfig}
* constructors as well as certain operations like
* {@link ATNConfigSet#add(ATNConfig, DoubleKeyMap)} method are
* <em>completely</em> unaffected by the change.</p>
*/
size_t reachesIntoOuterContext = 0;
/// Can be shared between multiple ATNConfig instances.
Ref<const SemanticContext> semanticContext;
ATNConfig(ATNState *state, size_t alt, Ref<const PredictionContext> context);
ATNConfig(ATNState *state, size_t alt, Ref<const PredictionContext> context, Ref<const SemanticContext> semanticContext);
ATNConfig(ATNConfig const& other, Ref<const SemanticContext> semanticContext);
ATNConfig(ATNConfig const& other, ATNState *state);
ATNConfig(ATNConfig const& other, ATNState *state, Ref<const SemanticContext> semanticContext);
ATNConfig(ATNConfig const& other, ATNState *state, Ref<const PredictionContext> context);
ATNConfig(ATNConfig const& other, ATNState *state, Ref<const PredictionContext> context, Ref<const SemanticContext> semanticContext);
ATNConfig(ATNConfig const&) = default;
ATNConfig(ATNConfig&&) = default;
virtual ~ATNConfig() = default;
virtual size_t hashCode() const;
/**
* This method gets the value of the {@link #reachesIntoOuterContext} field
* as it existed prior to the introduction of the
* {@link #isPrecedenceFilterSuppressed} method.
*/
size_t getOuterContextDepth() const;
bool isPrecedenceFilterSuppressed() const;
void setPrecedenceFilterSuppressed(bool value);
/// An ATN configuration is equal to another if both have
/// the same state, they predict the same alternative, and
/// syntactic/semantic contexts are the same.
bool operator==(const ATNConfig &other) const;
bool operator!=(const ATNConfig &other) const;
virtual std::string toString() const;
std::string toString(bool showAlt) const;
private:
ATNConfig(ATNState *state, size_t alt, Ref<const PredictionContext> context, size_t reachesIntoOuterContext, Ref<const SemanticContext> semanticContext);
};
} // namespace atn
} // namespace antlr4
// Hash function for ATNConfig.
namespace std {
using antlr4::atn::ATNConfig;
template <> struct hash<ATNConfig>
{
size_t operator() (const ATNConfig &x) const
{
return x.hashCode();
}
};
template <> struct hash<std::vector<Ref<ATNConfig>>>
{
size_t operator() (const std::vector<Ref<ATNConfig>> &vector) const
{
std::size_t seed = 0;
for (const auto &config : vector) {
seed ^= config->hashCode() + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
return seed;
}
};
}

View File

@@ -0,0 +1,233 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "atn/PredictionContext.h"
#include "atn/ATNConfig.h"
#include "atn/ATNSimulator.h"
#include "Exceptions.h"
#include "atn/SemanticContext.h"
#include "support/Arrays.h"
#include "atn/ATNConfigSet.h"
using namespace antlr4::atn;
using namespace antlrcpp;
namespace {
}
ATNConfigSet::ATNConfigSet() : ATNConfigSet(true) {}
ATNConfigSet::ATNConfigSet(const ATNConfigSet &other)
: fullCtx(other.fullCtx), _configLookup(other._configLookup.bucket_count(), ATNConfigHasher{this}, ATNConfigComparer{this}) {
addAll(other);
uniqueAlt = other.uniqueAlt;
conflictingAlts = other.conflictingAlts;
hasSemanticContext = other.hasSemanticContext;
dipsIntoOuterContext = other.dipsIntoOuterContext;
}
ATNConfigSet::ATNConfigSet(bool fullCtx)
: fullCtx(fullCtx), _configLookup(0, ATNConfigHasher{this}, ATNConfigComparer{this}) {}
bool ATNConfigSet::add(const Ref<ATNConfig> &config) {
return add(config, nullptr);
}
bool ATNConfigSet::add(const Ref<ATNConfig> &config, PredictionContextMergeCache *mergeCache) {
assert(config);
if (_readonly) {
throw IllegalStateException("This set is readonly");
}
if (config->semanticContext != SemanticContext::Empty::Instance) {
hasSemanticContext = true;
}
if (config->getOuterContextDepth() > 0) {
dipsIntoOuterContext = true;
}
auto existing = _configLookup.find(config.get());
if (existing == _configLookup.end()) {
_configLookup.insert(config.get());
_cachedHashCode = 0;
configs.push_back(config); // track order here
return true;
}
// a previous (s,i,pi,_), merge with it and save result
bool rootIsWildcard = !fullCtx;
Ref<const PredictionContext> merged = PredictionContext::merge((*existing)->context, config->context, rootIsWildcard, mergeCache);
// no need to check for existing.context, config.context in cache
// since only way to create new graphs is "call rule" and here. We
// cache at both places.
(*existing)->reachesIntoOuterContext = std::max((*existing)->reachesIntoOuterContext, config->reachesIntoOuterContext);
// make sure to preserve the precedence filter suppression during the merge
if (config->isPrecedenceFilterSuppressed()) {
(*existing)->setPrecedenceFilterSuppressed(true);
}
(*existing)->context = std::move(merged); // replace context; no need to alt mapping
return true;
}
bool ATNConfigSet::addAll(const ATNConfigSet &other) {
for (const auto &c : other.configs) {
add(c);
}
return false;
}
std::vector<ATNState*> ATNConfigSet::getStates() const {
std::vector<ATNState*> states;
states.reserve(configs.size());
for (const auto &c : configs) {
states.push_back(c->state);
}
return states;
}
/**
* Gets the complete set of represented alternatives for the configuration
* set.
*
* @return the set of represented alternatives in this configuration set
*
* @since 4.3
*/
BitSet ATNConfigSet::getAlts() const {
BitSet alts;
for (const auto &config : configs) {
alts.set(config->alt);
}
return alts;
}
std::vector<Ref<const SemanticContext>> ATNConfigSet::getPredicates() const {
std::vector<Ref<const SemanticContext>> preds;
preds.reserve(configs.size());
for (const auto &c : configs) {
if (c->semanticContext != SemanticContext::Empty::Instance) {
preds.push_back(c->semanticContext);
}
}
return preds;
}
const Ref<ATNConfig>& ATNConfigSet::get(size_t i) const {
return configs[i];
}
void ATNConfigSet::optimizeConfigs(ATNSimulator *interpreter) {
assert(interpreter);
if (_readonly) {
throw IllegalStateException("This set is readonly");
}
if (_configLookup.empty())
return;
for (const auto &config : configs) {
config->context = interpreter->getCachedContext(config->context);
}
}
bool ATNConfigSet::equals(const ATNConfigSet &other) const {
if (&other == this) {
return true;
}
if (configs.size() != other.configs.size())
return false;
if (fullCtx != other.fullCtx || uniqueAlt != other.uniqueAlt ||
conflictingAlts != other.conflictingAlts || hasSemanticContext != other.hasSemanticContext ||
dipsIntoOuterContext != other.dipsIntoOuterContext) // includes stack context
return false;
return Arrays::equals(configs, other.configs);
}
size_t ATNConfigSet::hashCode() const {
size_t cachedHashCode = _cachedHashCode.load(std::memory_order_relaxed);
if (!isReadonly() || cachedHashCode == 0) {
cachedHashCode = 1;
for (const auto &i : configs) {
cachedHashCode = 31 * cachedHashCode + i->hashCode(); // Same as Java's list hashCode impl.
}
_cachedHashCode.store(cachedHashCode, std::memory_order_relaxed);
}
return cachedHashCode;
}
size_t ATNConfigSet::size() const {
return configs.size();
}
bool ATNConfigSet::isEmpty() const {
return configs.empty();
}
void ATNConfigSet::clear() {
if (_readonly) {
throw IllegalStateException("This set is readonly");
}
configs.clear();
_cachedHashCode = 0;
_configLookup.clear();
}
bool ATNConfigSet::isReadonly() const {
return _readonly;
}
void ATNConfigSet::setReadonly(bool readonly) {
_readonly = readonly;
LookupContainer(0, ATNConfigHasher{this}, ATNConfigComparer{this}).swap(_configLookup);
}
std::string ATNConfigSet::toString() const {
std::stringstream ss;
ss << "[";
for (size_t i = 0; i < configs.size(); i++) {
if ( i>0 ) ss << ", ";
ss << configs[i]->toString();
}
ss << "]";
if (hasSemanticContext) {
ss << ",hasSemanticContext=" << (hasSemanticContext?"true":"false");
}
if (uniqueAlt != ATN::INVALID_ALT_NUMBER) {
ss << ",uniqueAlt=" << uniqueAlt;
}
if (conflictingAlts.count() > 0) {
ss << ",conflictingAlts=";
ss << conflictingAlts.toString();
}
if (dipsIntoOuterContext) {
ss << ",dipsIntoOuterContext";
}
return ss.str();
}
size_t ATNConfigSet::hashCode(const ATNConfig &other) const {
size_t hashCode = 7;
hashCode = 31 * hashCode + other.state->stateNumber;
hashCode = 31 * hashCode + other.alt;
hashCode = 31 * hashCode + other.semanticContext->hashCode();
return hashCode;
}
bool ATNConfigSet::equals(const ATNConfig &lhs, const ATNConfig &rhs) const {
return lhs.state->stateNumber == rhs.state->stateNumber && lhs.alt == rhs.alt && *lhs.semanticContext == *rhs.semanticContext;
}

View File

@@ -0,0 +1,157 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include <cassert>
#include "support/BitSet.h"
#include "atn/PredictionContext.h"
#include "atn/ATNConfig.h"
#include "FlatHashSet.h"
namespace antlr4 {
namespace atn {
/// Specialized set that can track info about the set, with support for combining similar configurations using a
/// graph-structured stack.
class ANTLR4CPP_PUBLIC ATNConfigSet {
public:
/// Track the elements as they are added to the set; supports get(i)
std::vector<Ref<ATNConfig>> configs;
// TODO: these fields make me pretty uncomfortable but nice to pack up info together, saves recomputation
// TODO: can we track conflicts as they are added to save scanning configs later?
size_t uniqueAlt = 0;
/** Currently this is only used when we detect SLL conflict; this does
* not necessarily represent the ambiguous alternatives. In fact,
* I should also point out that this seems to include predicated alternatives
* that have predicates that evaluate to false. Computed in computeTargetState().
*/
antlrcpp::BitSet conflictingAlts;
// Used in parser and lexer. In lexer, it indicates we hit a pred
// while computing a closure operation. Don't make a DFA state from this.
bool hasSemanticContext = false;
bool dipsIntoOuterContext = false;
/// Indicates that this configuration set is part of a full context
/// LL prediction. It will be used to determine how to merge $. With SLL
/// it's a wildcard whereas it is not for LL context merge.
const bool fullCtx = true;
ATNConfigSet();
ATNConfigSet(const ATNConfigSet &other);
ATNConfigSet(ATNConfigSet&&) = delete;
explicit ATNConfigSet(bool fullCtx);
virtual ~ATNConfigSet() = default;
bool add(const Ref<ATNConfig> &config);
/// <summary>
/// Adding a new config means merging contexts with existing configs for
/// {@code (s, i, pi, _)}, where {@code s} is the
/// <seealso cref="ATNConfig#state"/>, {@code i} is the <seealso cref="ATNConfig#alt"/>, and
/// {@code pi} is the <seealso cref="ATNConfig#semanticContext"/>. We use
/// {@code (s,i,pi)} as key.
/// <p/>
/// This method updates <seealso cref="#dipsIntoOuterContext"/> and
/// <seealso cref="#hasSemanticContext"/> when necessary.
/// </summary>
bool add(const Ref<ATNConfig> &config, PredictionContextMergeCache *mergeCache);
bool addAll(const ATNConfigSet &other);
std::vector<ATNState*> getStates() const;
/**
* Gets the complete set of represented alternatives for the configuration
* set.
*
* @return the set of represented alternatives in this configuration set
*
* @since 4.3
*/
antlrcpp::BitSet getAlts() const;
std::vector<Ref<const SemanticContext>> getPredicates() const;
const Ref<ATNConfig>& get(size_t i) const;
void optimizeConfigs(ATNSimulator *interpreter);
size_t size() const;
bool isEmpty() const;
void clear();
bool isReadonly() const;
void setReadonly(bool readonly);
virtual size_t hashCode() const;
virtual bool equals(const ATNConfigSet &other) const;
virtual std::string toString() const;
private:
struct ATNConfigHasher final {
const ATNConfigSet* atnConfigSet;
size_t operator()(const ATNConfig *other) const {
assert(other != nullptr);
return atnConfigSet->hashCode(*other);
}
};
struct ATNConfigComparer final {
const ATNConfigSet* atnConfigSet;
bool operator()(const ATNConfig *lhs, const ATNConfig *rhs) const {
assert(lhs != nullptr);
assert(rhs != nullptr);
return atnConfigSet->equals(*lhs, *rhs);
}
};
mutable std::atomic<size_t> _cachedHashCode = 0;
/// Indicates that the set of configurations is read-only. Do not
/// allow any code to manipulate the set; DFA states will point at
/// the sets and they must not change. This does not protect the other
/// fields; in particular, conflictingAlts is set after
/// we've made this readonly.
bool _readonly = false;
virtual size_t hashCode(const ATNConfig &atnConfig) const;
virtual bool equals(const ATNConfig &lhs, const ATNConfig &rhs) const;
using LookupContainer = FlatHashSet<ATNConfig*, ATNConfigHasher, ATNConfigComparer>;
/// All configs but hashed by (s, i, _, pi) not including context. Wiped out
/// when we go readonly as this set becomes a DFA state.
LookupContainer _configLookup;
};
inline bool operator==(const ATNConfigSet &lhs, const ATNConfigSet &rhs) { return lhs.equals(rhs); }
inline bool operator!=(const ATNConfigSet &lhs, const ATNConfigSet &rhs) { return !operator==(lhs, rhs); }
} // namespace atn
} // namespace antlr4
namespace std {
template <>
struct hash<::antlr4::atn::ATNConfigSet> {
size_t operator()(const ::antlr4::atn::ATNConfigSet &atnConfigSet) const {
return atnConfigSet.hashCode();
}
};
} // namespace std

View File

@@ -0,0 +1,39 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#include "atn/ATNDeserializationOptions.h"
#include "Exceptions.h"
using namespace antlr4;
using namespace antlr4::atn;
ATNDeserializationOptions::ATNDeserializationOptions(ATNDeserializationOptions *options)
: _readOnly(false), _verifyATN(options->_verifyATN),
_generateRuleBypassTransitions(options->_generateRuleBypassTransitions) {}
const ATNDeserializationOptions& ATNDeserializationOptions::getDefaultOptions() {
static const ATNDeserializationOptions* const defaultOptions = new ATNDeserializationOptions();
return *defaultOptions;
}
void ATNDeserializationOptions::makeReadOnly() {
_readOnly = true;
}
void ATNDeserializationOptions::setVerifyATN(bool verify) {
throwIfReadOnly();
_verifyATN = verify;
}
void ATNDeserializationOptions::setGenerateRuleBypassTransitions(bool generate) {
throwIfReadOnly();
_generateRuleBypassTransitions = generate;
}
void ATNDeserializationOptions::throwIfReadOnly() const {
if (isReadOnly()) {
throw IllegalStateException("ATNDeserializationOptions is read only.");
}
}

View File

@@ -0,0 +1,48 @@
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
#pragma once
#include "antlr4-common.h"
namespace antlr4 {
namespace atn {
class ANTLR4CPP_PUBLIC ATNDeserializationOptions final {
public:
ATNDeserializationOptions()
: _readOnly(false), _verifyATN(true), _generateRuleBypassTransitions(false) {}
// TODO: Is this useful? If so we should mark it as explicit, otherwise remove it.
ATNDeserializationOptions(ATNDeserializationOptions *options);
ATNDeserializationOptions(const ATNDeserializationOptions&) = default;
ATNDeserializationOptions& operator=(const ATNDeserializationOptions&) = default;
static const ATNDeserializationOptions& getDefaultOptions();
bool isReadOnly() const { return _readOnly; }
void makeReadOnly();
bool isVerifyATN() const { return _verifyATN; }
void setVerifyATN(bool verify);
bool isGenerateRuleBypassTransitions() const { return _generateRuleBypassTransitions; }
void setGenerateRuleBypassTransitions(bool generate);
private:
void throwIfReadOnly() const;
bool _readOnly;
bool _verifyATN;
bool _generateRuleBypassTransitions;
};
} // namespace atn
} // namespace antlr4

Some files were not shown because too many files have changed in this diff Show More