| /* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
| * Use of this file is governed by the BSD 3-clause license that |
| * can be found in the LICENSE.txt file in the project root. |
| */ |
| |
| #include "IntStream.h" |
| #include "atn/OrderedATNConfigSet.h" |
| #include "Token.h" |
| #include "LexerNoViableAltException.h" |
| #include "atn/RuleStopState.h" |
| #include "atn/RuleTransition.h" |
| #include "atn/SingletonPredictionContext.h" |
| #include "atn/PredicateTransition.h" |
| #include "atn/ActionTransition.h" |
| #include "atn/TokensStartState.h" |
| #include "misc/Interval.h" |
| #include "dfa/DFA.h" |
| #include "Lexer.h" |
| |
| #include "dfa/DFAState.h" |
| #include "atn/LexerATNConfig.h" |
| #include "atn/LexerActionExecutor.h" |
| #include "atn/EmptyPredictionContext.h" |
| |
| #include "atn/LexerATNSimulator.h" |
| |
| #define DEBUG_ATN 0 |
| #define DEBUG_DFA 0 |
| |
| using namespace antlr4; |
| using namespace antlr4::atn; |
| using namespace antlrcpp; |
| |
| |
| void LexerATNSimulator::SimState::reset() { |
| index = INVALID_INDEX; |
| line = 0; |
| charPos = INVALID_INDEX; |
| dfaState = nullptr; // Don't delete. It's just a reference. |
| } |
| |
| void LexerATNSimulator::SimState::InitializeInstanceFields() { |
| index = INVALID_INDEX; |
| line = 0; |
| charPos = INVALID_INDEX; |
| } |
| |
| std::atomic<int> LexerATNSimulator::match_calls(0); |
| |
| |
| LexerATNSimulator::LexerATNSimulator(const ATN &atn, std::vector<dfa::DFA> &decisionToDFA, |
| PredictionContextCache &sharedContextCache) |
| : LexerATNSimulator(nullptr, atn, decisionToDFA, sharedContextCache) { |
| } |
| |
| LexerATNSimulator::LexerATNSimulator(Lexer *recog, const ATN &atn, std::vector<dfa::DFA> &decisionToDFA, |
| PredictionContextCache &sharedContextCache) |
| : ATNSimulator(atn, sharedContextCache), _recog(recog), _decisionToDFA(decisionToDFA) { |
| InitializeInstanceFields(); |
| } |
| |
| void LexerATNSimulator::copyState(LexerATNSimulator *simulator) { |
| _charPositionInLine = simulator->_charPositionInLine; |
| _line = simulator->_line; |
| _mode = simulator->_mode; |
| _startIndex = simulator->_startIndex; |
| } |
| |
| size_t LexerATNSimulator::match(CharStream *input, size_t mode) { |
| match_calls.fetch_add(1, std::memory_order_relaxed); |
| _mode = mode; |
| ssize_t mark = input->mark(); |
| |
| auto onExit = finally([input, mark] { |
| input->release(mark); |
| }); |
| |
| _startIndex = input->index(); |
| _prevAccept.reset(); |
| const dfa::DFA &dfa = _decisionToDFA[mode]; |
| if (dfa.s0 == nullptr) { |
| return matchATN(input); |
| } else { |
| return execATN(input, dfa.s0); |
| } |
| } |
| |
| void LexerATNSimulator::reset() { |
| _prevAccept.reset(); |
| _startIndex = 0; |
| _line = 1; |
| _charPositionInLine = 0; |
| _mode = Lexer::DEFAULT_MODE; |
| } |
| |
| void LexerATNSimulator::clearDFA() { |
| size_t size = _decisionToDFA.size(); |
| _decisionToDFA.clear(); |
| for (size_t d = 0; d < size; ++d) { |
| _decisionToDFA.emplace_back(atn.getDecisionState(d), d); |
| } |
| } |
| |
| size_t LexerATNSimulator::matchATN(CharStream *input) { |
| ATNState *startState = atn.modeToStartState[_mode]; |
| |
| std::unique_ptr<ATNConfigSet> s0_closure = computeStartState(input, startState); |
| |
| bool suppressEdge = s0_closure->hasSemanticContext; |
| s0_closure->hasSemanticContext = false; |
| |
| dfa::DFAState *next = addDFAState(s0_closure.release()); |
| if (!suppressEdge) { |
| _decisionToDFA[_mode].s0 = next; |
| } |
| |
| size_t predict = execATN(input, next); |
| |
| return predict; |
| } |
| |
| size_t LexerATNSimulator::execATN(CharStream *input, dfa::DFAState *ds0) { |
| if (ds0->isAcceptState) { |
| // allow zero-length tokens |
| // ml: in Java code this method uses 3 params. The first is a member var of the class anyway (_prevAccept), so why pass it here? |
| captureSimState(input, ds0); |
| } |
| |
| size_t t = input->LA(1); |
| dfa::DFAState *s = ds0; // s is current/from DFA state |
| |
| while (true) { // while more work |
| // As we move src->trg, src->trg, we keep track of the previous trg to |
| // avoid looking up the DFA state again, which is expensive. |
| // If the previous target was already part of the DFA, we might |
| // be able to avoid doing a reach operation upon t. If s!=null, |
| // it means that semantic predicates didn't prevent us from |
| // creating a DFA state. Once we know s!=null, we check to see if |
| // the DFA state has an edge already for t. If so, we can just reuse |
| // it's configuration set; there's no point in re-computing it. |
| // This is kind of like doing DFA simulation within the ATN |
| // simulation because DFA simulation is really just a way to avoid |
| // computing reach/closure sets. Technically, once we know that |
| // we have a previously added DFA state, we could jump over to |
| // the DFA simulator. But, that would mean popping back and forth |
| // a lot and making things more complicated algorithmically. |
| // This optimization makes a lot of sense for loops within DFA. |
| // A character will take us back to an existing DFA state |
| // that already has lots of edges out of it. e.g., .* in comments. |
| dfa::DFAState *target = getExistingTargetState(s, t); |
| if (target == nullptr) { |
| target = computeTargetState(input, s, t); |
| } |
| |
| if (target == ERROR.get()) { |
| break; |
| } |
| |
| // If this is a consumable input element, make sure to consume before |
| // capturing the accept state so the input index, line, and char |
| // position accurately reflect the state of the interpreter at the |
| // end of the token. |
| if (t != Token::EOF) { |
| consume(input); |
| } |
| |
| if (target->isAcceptState) { |
| captureSimState(input, target); |
| if (t == Token::EOF) { |
| break; |
| } |
| } |
| |
| t = input->LA(1); |
| s = target; // flip; current DFA target becomes new src/from state |
| } |
| |
| return failOrAccept(input, s->configs.get(), t); |
| } |
| |
| dfa::DFAState *LexerATNSimulator::getExistingTargetState(dfa::DFAState *s, size_t t) { |
| dfa::DFAState* retval = nullptr; |
| _edgeLock.readLock(); |
| if (t <= MAX_DFA_EDGE) { |
| auto iterator = s->edges.find(t - MIN_DFA_EDGE); |
| #if DEBUG_ATN == 1 |
| if (iterator != s->edges.end()) { |
| std::cout << std::string("reuse state ") << s->stateNumber << std::string(" edge to ") << iterator->second->stateNumber << std::endl; |
| } |
| #endif |
| |
| if (iterator != s->edges.end()) |
| retval = iterator->second; |
| } |
| _edgeLock.readUnlock(); |
| return retval; |
| } |
| |
| dfa::DFAState *LexerATNSimulator::computeTargetState(CharStream *input, dfa::DFAState *s, size_t t) { |
| OrderedATNConfigSet *reach = new OrderedATNConfigSet(); /* mem-check: deleted on error or managed by new DFA state. */ |
| |
| // if we don't find an existing DFA state |
| // Fill reach starting from closure, following t transitions |
| getReachableConfigSet(input, s->configs.get(), reach, t); |
| |
| if (reach->isEmpty()) { // we got nowhere on t from s |
| if (!reach->hasSemanticContext) { |
| // we got nowhere on t, don't throw out this knowledge; it'd |
| // cause a failover from DFA later. |
| delete reach; |
| addDFAEdge(s, t, ERROR.get()); |
| } |
| |
| // stop when we can't match any more char |
| return ERROR.get(); |
| } |
| |
| // Add an edge from s to target DFA found/created for reach |
| return addDFAEdge(s, t, reach); |
| } |
| |
| size_t LexerATNSimulator::failOrAccept(CharStream *input, ATNConfigSet *reach, size_t t) { |
| if (_prevAccept.dfaState != nullptr) { |
| Ref<LexerActionExecutor> lexerActionExecutor = _prevAccept.dfaState->lexerActionExecutor; |
| accept(input, lexerActionExecutor, _startIndex, _prevAccept.index, _prevAccept.line, _prevAccept.charPos); |
| return _prevAccept.dfaState->prediction; |
| } else { |
| // if no accept and EOF is first char, return EOF |
| if (t == Token::EOF && input->index() == _startIndex) { |
| return Token::EOF; |
| } |
| |
| throw LexerNoViableAltException(_recog, input, _startIndex, reach); |
| } |
| } |
| |
| void LexerATNSimulator::getReachableConfigSet(CharStream *input, ATNConfigSet *closure_, ATNConfigSet *reach, size_t t) { |
| // this is used to skip processing for configs which have a lower priority |
| // than a config that already reached an accept state for the same rule |
| size_t skipAlt = ATN::INVALID_ALT_NUMBER; |
| |
| for (auto c : closure_->configs) { |
| bool currentAltReachedAcceptState = c->alt == skipAlt; |
| if (currentAltReachedAcceptState && (std::static_pointer_cast<LexerATNConfig>(c))->hasPassedThroughNonGreedyDecision()) { |
| continue; |
| } |
| |
| #if DEBUG_ATN == 1 |
| std::cout << "testing " << getTokenName((int)t) << " at " << c->toString(true) << std::endl; |
| #endif |
| |
| size_t n = c->state->transitions.size(); |
| for (size_t ti = 0; ti < n; ti++) { // for each transition |
| Transition *trans = c->state->transitions[ti]; |
| ATNState *target = getReachableTarget(trans, (int)t); |
| if (target != nullptr) { |
| Ref<LexerActionExecutor> lexerActionExecutor = std::static_pointer_cast<LexerATNConfig>(c)->getLexerActionExecutor(); |
| if (lexerActionExecutor != nullptr) { |
| lexerActionExecutor = lexerActionExecutor->fixOffsetBeforeMatch((int)input->index() - (int)_startIndex); |
| } |
| |
| bool treatEofAsEpsilon = t == Token::EOF; |
| Ref<LexerATNConfig> config = std::make_shared<LexerATNConfig>(std::static_pointer_cast<LexerATNConfig>(c), |
| target, lexerActionExecutor); |
| |
| if (closure(input, config, reach, currentAltReachedAcceptState, true, treatEofAsEpsilon)) { |
| // any remaining configs for this alt have a lower priority than |
| // the one that just reached an accept state. |
| skipAlt = c->alt; |
| break; |
| } |
| } |
| } |
| } |
| } |
| |
| void LexerATNSimulator::accept(CharStream *input, const Ref<LexerActionExecutor> &lexerActionExecutor, size_t /*startIndex*/, |
| size_t index, size_t line, size_t charPos) { |
| #if DEBUG_ATN == 1 |
| std::cout << "ACTION "; |
| std::cout << toString(lexerActionExecutor) << std::endl; |
| #endif |
| |
| // seek to after last char in token |
| input->seek(index); |
| _line = line; |
| _charPositionInLine = (int)charPos; |
| |
| if (lexerActionExecutor != nullptr && _recog != nullptr) { |
| lexerActionExecutor->execute(_recog, input, _startIndex); |
| } |
| } |
| |
| atn::ATNState *LexerATNSimulator::getReachableTarget(Transition *trans, size_t t) { |
| if (trans->matches(t, Lexer::MIN_CHAR_VALUE, Lexer::MAX_CHAR_VALUE)) { |
| return trans->target; |
| } |
| |
| return nullptr; |
| } |
| |
| std::unique_ptr<ATNConfigSet> LexerATNSimulator::computeStartState(CharStream *input, ATNState *p) { |
| Ref<PredictionContext> initialContext = PredictionContext::EMPTY; // ml: the purpose of this assignment is unclear |
| std::unique_ptr<ATNConfigSet> configs(new OrderedATNConfigSet()); |
| for (size_t i = 0; i < p->transitions.size(); i++) { |
| ATNState *target = p->transitions[i]->target; |
| Ref<LexerATNConfig> c = std::make_shared<LexerATNConfig>(target, (int)(i + 1), initialContext); |
| closure(input, c, configs.get(), false, false, false); |
| } |
| |
| return configs; |
| } |
| |
| bool LexerATNSimulator::closure(CharStream *input, const Ref<LexerATNConfig> &config, ATNConfigSet *configs, |
| bool currentAltReachedAcceptState, bool speculative, bool treatEofAsEpsilon) { |
| #if DEBUG_ATN == 1 |
| std::cout << "closure(" << config->toString(true) << ")" << std::endl; |
| #endif |
| |
| if (is<RuleStopState *>(config->state)) { |
| #if DEBUG_ATN == 1 |
| if (_recog != nullptr) { |
| std::cout << "closure at " << _recog->getRuleNames()[config->state->ruleIndex] << " rule stop " << config << std::endl; |
| } else { |
| std::cout << "closure at rule stop " << config << std::endl; |
| } |
| #endif |
| |
| if (config->context == nullptr || config->context->hasEmptyPath()) { |
| if (config->context == nullptr || config->context->isEmpty()) { |
| configs->add(config); |
| return true; |
| } else { |
| configs->add(std::make_shared<LexerATNConfig>(config, config->state, PredictionContext::EMPTY)); |
| currentAltReachedAcceptState = true; |
| } |
| } |
| |
| if (config->context != nullptr && !config->context->isEmpty()) { |
| for (size_t i = 0; i < config->context->size(); i++) { |
| if (config->context->getReturnState(i) != PredictionContext::EMPTY_RETURN_STATE) { |
| std::weak_ptr<PredictionContext> newContext = config->context->getParent(i); // "pop" return state |
| ATNState *returnState = atn.states[config->context->getReturnState(i)]; |
| Ref<LexerATNConfig> c = std::make_shared<LexerATNConfig>(config, returnState, newContext.lock()); |
| currentAltReachedAcceptState = closure(input, c, configs, currentAltReachedAcceptState, speculative, treatEofAsEpsilon); |
| } |
| } |
| } |
| |
| return currentAltReachedAcceptState; |
| } |
| |
| // optimization |
| if (!config->state->epsilonOnlyTransitions) { |
| if (!currentAltReachedAcceptState || !config->hasPassedThroughNonGreedyDecision()) { |
| configs->add(config); |
| } |
| } |
| |
| ATNState *p = config->state; |
| for (size_t i = 0; i < p->transitions.size(); i++) { |
| Transition *t = p->transitions[i]; |
| Ref<LexerATNConfig> c = getEpsilonTarget(input, config, t, configs, speculative, treatEofAsEpsilon); |
| if (c != nullptr) { |
| currentAltReachedAcceptState = closure(input, c, configs, currentAltReachedAcceptState, speculative, treatEofAsEpsilon); |
| } |
| } |
| |
| return currentAltReachedAcceptState; |
| } |
| |
| Ref<LexerATNConfig> LexerATNSimulator::getEpsilonTarget(CharStream *input, const Ref<LexerATNConfig> &config, Transition *t, |
| ATNConfigSet *configs, bool speculative, bool treatEofAsEpsilon) { |
| |
| Ref<LexerATNConfig> c = nullptr; |
| switch (t->getSerializationType()) { |
| case Transition::RULE: { |
| RuleTransition *ruleTransition = static_cast<RuleTransition*>(t); |
| Ref<PredictionContext> newContext = SingletonPredictionContext::create(config->context, ruleTransition->followState->stateNumber); |
| c = std::make_shared<LexerATNConfig>(config, t->target, newContext); |
| break; |
| } |
| |
| case Transition::PRECEDENCE: |
| throw UnsupportedOperationException("Precedence predicates are not supported in lexers."); |
| |
| case Transition::PREDICATE: { |
| /* Track traversing semantic predicates. If we traverse, |
| we cannot add a DFA state for this "reach" computation |
| because the DFA would not test the predicate again in the |
| future. Rather than creating collections of semantic predicates |
| like v3 and testing them on prediction, v4 will test them on the |
| fly all the time using the ATN not the DFA. This is slower but |
| semantically it's not used that often. One of the key elements to |
| this predicate mechanism is not adding DFA states that see |
| predicates immediately afterwards in the ATN. For example, |
| |
| a : ID {p1}? | ID {p2}? ; |
| |
| should create the start state for rule 'a' (to save start state |
| competition), but should not create target of ID state. The |
| collection of ATN states the following ID references includes |
| states reached by traversing predicates. Since this is when we |
| test them, we cannot cash the DFA state target of ID. |
| */ |
| PredicateTransition *pt = static_cast<PredicateTransition*>(t); |
| |
| #if DEBUG_ATN == 1 |
| std::cout << "EVAL rule " << pt->ruleIndex << ":" << pt->predIndex << std::endl; |
| #endif |
| |
| configs->hasSemanticContext = true; |
| if (evaluatePredicate(input, pt->ruleIndex, pt->predIndex, speculative)) { |
| c = std::make_shared<LexerATNConfig>(config, t->target); |
| } |
| break; |
| } |
| |
| case Transition::ACTION: |
| if (config->context == nullptr|| config->context->hasEmptyPath()) { |
| // execute actions anywhere in the start rule for a token. |
| // |
| // TODO: if the entry rule is invoked recursively, some |
| // actions may be executed during the recursive call. The |
| // problem can appear when hasEmptyPath() is true but |
| // isEmpty() is false. In this case, the config needs to be |
| // split into two contexts - one with just the empty path |
| // and another with everything but the empty path. |
| // Unfortunately, the current algorithm does not allow |
| // getEpsilonTarget to return two configurations, so |
| // additional modifications are needed before we can support |
| // the split operation. |
| Ref<LexerActionExecutor> lexerActionExecutor = LexerActionExecutor::append(config->getLexerActionExecutor(), |
| atn.lexerActions[static_cast<ActionTransition *>(t)->actionIndex]); |
| c = std::make_shared<LexerATNConfig>(config, t->target, lexerActionExecutor); |
| break; |
| } |
| else { |
| // ignore actions in referenced rules |
| c = std::make_shared<LexerATNConfig>(config, t->target); |
| break; |
| } |
| |
| case Transition::EPSILON: |
| c = std::make_shared<LexerATNConfig>(config, t->target); |
| break; |
| |
| case Transition::ATOM: |
| case Transition::RANGE: |
| case Transition::SET: |
| if (treatEofAsEpsilon) { |
| if (t->matches(Token::EOF, Lexer::MIN_CHAR_VALUE, Lexer::MAX_CHAR_VALUE)) { |
| c = std::make_shared<LexerATNConfig>(config, t->target); |
| break; |
| } |
| } |
| |
| break; |
| |
| default: // To silence the compiler. Other transition types are not used here. |
| break; |
| } |
| |
| return c; |
| } |
| |
| bool LexerATNSimulator::evaluatePredicate(CharStream *input, size_t ruleIndex, size_t predIndex, bool speculative) { |
| // assume true if no recognizer was provided |
| if (_recog == nullptr) { |
| return true; |
| } |
| |
| if (!speculative) { |
| return _recog->sempred(nullptr, ruleIndex, predIndex); |
| } |
| |
| size_t savedCharPositionInLine = _charPositionInLine; |
| size_t savedLine = _line; |
| size_t index = input->index(); |
| ssize_t marker = input->mark(); |
| |
| auto onExit = finally([this, input, savedCharPositionInLine, savedLine, index, marker] { |
| _charPositionInLine = savedCharPositionInLine; |
| _line = savedLine; |
| input->seek(index); |
| input->release(marker); |
| }); |
| |
| consume(input); |
| return _recog->sempred(nullptr, ruleIndex, predIndex); |
| } |
| |
| void LexerATNSimulator::captureSimState(CharStream *input, dfa::DFAState *dfaState) { |
| _prevAccept.index = input->index(); |
| _prevAccept.line = _line; |
| _prevAccept.charPos = _charPositionInLine; |
| _prevAccept.dfaState = dfaState; |
| } |
| |
| dfa::DFAState *LexerATNSimulator::addDFAEdge(dfa::DFAState *from, size_t t, ATNConfigSet *q) { |
| /* leading to this call, ATNConfigSet.hasSemanticContext is used as a |
| * marker indicating dynamic predicate evaluation makes this edge |
| * dependent on the specific input sequence, so the static edge in the |
| * DFA should be omitted. The target DFAState is still created since |
| * execATN has the ability to resynchronize with the DFA state cache |
| * following the predicate evaluation step. |
| * |
| * TJP notes: next time through the DFA, we see a pred again and eval. |
| * If that gets us to a previously created (but dangling) DFA |
| * state, we can continue in pure DFA mode from there. |
| */ |
| bool suppressEdge = q->hasSemanticContext; |
| q->hasSemanticContext = false; |
| |
| dfa::DFAState *to = addDFAState(q); |
| |
| if (suppressEdge) { |
| return to; |
| } |
| |
| addDFAEdge(from, t, to); |
| return to; |
| } |
| |
| void LexerATNSimulator::addDFAEdge(dfa::DFAState *p, size_t t, dfa::DFAState *q) { |
| if (/*t < MIN_DFA_EDGE ||*/ t > MAX_DFA_EDGE) { // MIN_DFA_EDGE is 0 |
| // Only track edges within the DFA bounds |
| return; |
| } |
| |
| _edgeLock.writeLock(); |
| p->edges[t - MIN_DFA_EDGE] = q; // connect |
| _edgeLock.writeUnlock(); |
| } |
| |
| dfa::DFAState *LexerATNSimulator::addDFAState(ATNConfigSet *configs) { |
| /* the lexer evaluates predicates on-the-fly; by this point configs |
| * should not contain any configurations with unevaluated predicates. |
| */ |
| assert(!configs->hasSemanticContext); |
| |
| dfa::DFAState *proposed = new dfa::DFAState(std::unique_ptr<ATNConfigSet>(configs)); /* mem-check: managed by the DFA or deleted below */ |
| Ref<ATNConfig> firstConfigWithRuleStopState = nullptr; |
| for (auto &c : configs->configs) { |
| if (is<RuleStopState *>(c->state)) { |
| firstConfigWithRuleStopState = c; |
| break; |
| } |
| } |
| |
| if (firstConfigWithRuleStopState != nullptr) { |
| proposed->isAcceptState = true; |
| proposed->lexerActionExecutor = std::dynamic_pointer_cast<LexerATNConfig>(firstConfigWithRuleStopState)->getLexerActionExecutor(); |
| proposed->prediction = atn.ruleToTokenType[firstConfigWithRuleStopState->state->ruleIndex]; |
| } |
| |
| dfa::DFA &dfa = _decisionToDFA[_mode]; |
| |
| _stateLock.writeLock(); |
| if (!dfa.states.empty()) { |
| auto iterator = dfa.states.find(proposed); |
| if (iterator != dfa.states.end()) { |
| delete proposed; |
| _stateLock.writeUnlock(); |
| return *iterator; |
| } |
| } |
| |
| proposed->stateNumber = (int)dfa.states.size(); |
| proposed->configs->setReadonly(true); |
| |
| dfa.states.insert(proposed); |
| _stateLock.writeUnlock(); |
| |
| return proposed; |
| } |
| |
| dfa::DFA& LexerATNSimulator::getDFA(size_t mode) { |
| return _decisionToDFA[mode]; |
| } |
| |
| std::string LexerATNSimulator::getText(CharStream *input) { |
| // index is first lookahead char, don't include. |
| return input->getText(misc::Interval(_startIndex, input->index() - 1)); |
| } |
| |
| size_t LexerATNSimulator::getLine() const { |
| return _line; |
| } |
| |
| void LexerATNSimulator::setLine(size_t line) { |
| _line = line; |
| } |
| |
| size_t LexerATNSimulator::getCharPositionInLine() { |
| return _charPositionInLine; |
| } |
| |
| void LexerATNSimulator::setCharPositionInLine(size_t charPositionInLine) { |
| _charPositionInLine = charPositionInLine; |
| } |
| |
| void LexerATNSimulator::consume(CharStream *input) { |
| size_t curChar = input->LA(1); |
| if (curChar == '\n') { |
| _line++; |
| _charPositionInLine = 0; |
| } else { |
| _charPositionInLine++; |
| } |
| input->consume(); |
| } |
| |
| std::string LexerATNSimulator::getTokenName(size_t t) { |
| if (t == Token::EOF) { |
| return "EOF"; |
| } |
| return std::string("'") + static_cast<char>(t) + std::string("'"); |
| } |
| |
| void LexerATNSimulator::InitializeInstanceFields() { |
| _startIndex = 0; |
| _line = 1; |
| _charPositionInLine = 0; |
| _mode = antlr4::Lexer::DEFAULT_MODE; |
| } |