parent
34b4484709
commit
90dc2ff8de
Binary file not shown.
@ -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()
|
||||
{
|
||||
}
|
||||
@ -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()
|
||||
{
|
||||
}
|
||||
@ -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
|
||||
@ -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;
|
||||
}
|
||||
@ -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
|
||||
@ -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;
|
||||
}
|
||||
@ -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
|
||||
@ -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() {
|
||||
}
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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;
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
@ -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
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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
|
||||
@ -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);
|
||||
}
|
||||
@ -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
|
||||
@ -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() {
|
||||
}
|
||||
@ -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() {
|
||||
}
|
||||
@ -0,0 +1,428 @@
|
||||
/* 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) {
|
||||
|
||||
// Reset the instructionIndex
|
||||
for (size_t i = 0; i < rewrites.size(); ++i) {
|
||||
rewrites[i]->instructionIndex = i;
|
||||
}
|
||||
|
||||
// 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
|
||||
rop->text = iop->text + (!rop->text.empty() ? rop->text : "");
|
||||
rewrites[iop->instructionIndex] = nullptr;
|
||||
delete iop;
|
||||
}
|
||||
else if (iop->index > rop->index && iop->index <= rop->lastIndex) {
|
||||
// delete insert as it's a no-op.
|
||||
rewrites[iop->instructionIndex] = nullptr;
|
||||
delete iop;
|
||||
}
|
||||
}
|
||||
// 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.
|
||||
rewrites[prevRop->instructionIndex] = nullptr;
|
||||
delete prevRop;
|
||||
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) {
|
||||
rop->index = std::min(prevRop->index, rop->index);
|
||||
rop->lastIndex = std::max(prevRop->lastIndex, rop->lastIndex);
|
||||
rewrites[prevRop->instructionIndex] = nullptr; // kill first delete
|
||||
delete prevRop;
|
||||
}
|
||||
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
|
||||
rewrites[prevIop->instructionIndex] = nullptr;
|
||||
delete prevIop;
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
@ -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 13
|
||||
#define ANTLRCPP_VERSION_PATCH 2
|
||||
|
||||
#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)
|
||||
@ -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);
|
||||
}
|
||||
@ -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
|
||||
@ -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() {
|
||||
}
|
||||
@ -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>;
|
||||
@ -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"
|
||||
@ -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();
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue