ANTLR PopMode: InvalidOperationException

0

I've been trying to debug this error, but am at a loss for what the cause is. From what I can tell through the stack trace, it is occurring when the PopMode action occurs. The exception occurs when I begin to walk the tree. If I remove the PopMode action then there is no exception, but the tokenization isn't done correctly. What am I doing wrong when popping back the default mode?

Lexer grammar:

lexer grammar BlockLexer;

P_START                 : '!(:' -> pushMode(P_BLOCK);
LINE_START              : '!';
SEPARATOR               : ',' WS* | WS+;
WS                      : ' '   -> channel(HIDDEN);
NEWLINE                 : ((RETURN_CHAR? NEWLINE_CHAR) | RETURN_CHAR) -> popMode;

mode P_BLOCK;
P_CONTENTS              : (LETTER | DIGIT)+ SEPARATOR (LETTER | DIGIT)+ SEPARATOR;

fragment RETURN_CHAR    : '\\r' | '\r';
fragment NEWLINE_CHAR   : '\\n' | '\n';
fragment DIGIT          : [0-9];
fragment LETTER         : [a-zA-Z];

Parser grammar:

grammar BlockParser;
options { tokenVocab = BlockLexer; }

block           : comment_line* unit_info_line? comment_line* date_line comment_line*;
p_line          : P_START P_CONTENTS NEWLINE;
comment_line    : LINE_START .*? NEWLINE;

Here is my C# code to do the parsing:

var lexer = new BlockLexer(new AntlrInputStream(text));
var parser = new BlockParser(new CommonTokenStream(lexer));
var listener = new BlockListener();
new ParseTreeWalker().Walk(listener, parser.block());

Stack trace:

System.InvalidOperationException
    HResult=0x80131509
    Message=Operation is not valid due to the current state of the object.
    Source=Antlr4.Runtime
    StackTrace:
        at Antlr4.Runtime.Lexer.PopMode()
        at Antlr4.Runtime.Atn.LexerPopModeAction.Execute(Lexer lexer)
        at Antlr4.Runtime.Atn.LexerActionExecutor.Execute(Lexer lexer, ICharStream input, Int32 startIndex)
        at Antlr4.Runtime.Atn.LexerATNSimulator.Accept(ICharStream input, LexerActionExecutor lexerActionExecutor, Int32 startIndex, Int32 index, Int32 line, Int32 charPos)
        at Antlr4.Runtime.Atn.LexerATNSimulator.FailOrAccept(SimState prevAccept, ICharStream input, ATNConfigSet reach, Int32 t)
        at Antlr4.Runtime.Atn.LexerATNSimulator.ExecATN(ICharStream input, DFAState ds0)
        at Antlr4.Runtime.Atn.LexerATNSimulator.Match(ICharStream input, Int32 mode)
        at Antlr4.Runtime.Lexer.NextToken()
        at Antlr4.Runtime.BufferedTokenStream.Fetch(Int32 n)
        at Antlr4.Runtime.BufferedTokenStream.Sync(Int32 i)
        at Antlr4.Runtime.BufferedTokenStream.Consume()
        at Antlr4.Runtime.Atn.ParserATNSimulator.ExecATN(DFA dfa, ITokenStream input, Int32 startIndex, SimulatorState initialState)
        at Antlr4.Runtime.Atn.ParserATNSimulator.ExecDFA(DFA dfa, ITokenStream input, Int32 startIndex, SimulatorState state)
        at Antlr4.Runtime.Atn.ParserATNSimulator.AdaptivePredict(ITokenStream input, Int32 decision, ParserRuleContext outerContext, Boolean useContext)
        at Antlr4.Runtime.Atn.ParserATNSimulator.AdaptivePredict(ITokenStream input, Int32 decision, ParserRuleContext outerContext)
        at MyLibrary.Parser.BlockParser.block() in C:\Projects\mylibrary\MyLibrary.Parser\obj\Debug\BlockParser.cs:line 143
antlr
antlr4
asked on Stack Overflow Jan 24, 2020 by mdmnd18

1 Answer

1

You can't pop an empty stack, so you're only allowed to invoke popMode if you've used pushMode before (and only as often as you've pushed).

In your code, you're invoking popMode when you see a newline in the default mode (and never when you're in block mode, so you can never actually leave block mode), which can only happen when the stack is empty (because you never push the default mode, so you can only be in the default mode if nothing has been pushed yet), so encountering a newline in default mode will always lead to an exception because you're popping an empty stack.

answered on Stack Overflow Jan 24, 2020 by sepp2k

User contributions licensed under CC BY-SA 3.0