{"record":{"id":"018998d453baf425","repo":"antlr/antlr4","slug":"empty-stack","errorCode":null,"errorMessage":"Empty Stack","messagePattern":"Empty Stack","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"runtime/Python3/src/antlr4/Lexer.py","lineNumber":183,"sourceCode":"    #/\n    def skip(self):\n        self._type = self.SKIP\n\n    def more(self):\n        self._type = self.MORE\n\n    def mode(self, m:int):\n        self._mode = m\n\n    def pushMode(self, m:int):\n        if self._interp.debug:\n            print(\"pushMode \" + str(m), file=self._output)\n        self._modeStack.append(self._mode)\n        self.mode(m)\n\n    def popMode(self):\n        if len(self._modeStack)==0:\n            raise Exception(\"Empty Stack\")\n        if self._interp.debug:\n            print(\"popMode back to \"+ self._modeStack[:-1], file=self._output)\n        self.mode( self._modeStack.pop() )\n        return self._mode\n\n    # Set the char stream and reset the lexer#/\n    @property\n    def inputStream(self):\n        return self._input\n\n    @inputStream.setter\n    def inputStream(self, input:InputStream):\n        self._input = None\n        self._tokenFactorySourcePair = (self, self._input)\n        self.reset()\n        self._input = input\n        self._tokenFactorySourcePair = (self, self._input)\n","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/antlr/antlr4/blob/7d5770395bb7b02eb56e7c62662cb1d7c08f42a3/runtime/Python3/src/antlr4/Lexer.py#L165-L201","documentation":"Lexer.popMode() raises Exception('Empty Stack') when the lexer mode stack is empty — a popMode action (or 'mode stack' manipulation in a member/embedded action) executed while still in the default mode. The mode stack is only populated by pushMode; pops must be balanced with pushes within the token stream.","triggerScenarios":"A lexer grammar rule containing -> popMode that matches while in DEFAULT_MODE (no prior pushMode); two rules with popMode in the same mode where only one push occurred; generated-code paths where a skip/More rule with popMode fires repeatedly on the same construct.","commonSituations":"Lexer grammars for string interpolation or heredocs where the closing rule pops a mode but the opening rule forgot pushMode (or was skipped); editing modes and forgetting the push side; tokens reachable both inside and outside the pushed mode.","solutions":["Fix the grammar: every -> popMode must be reachable only from a mode entered with -> pushMode(<mode>)","Guard pops in embedded Python actions: pop only if len(self._modeStack) > 0, else -> mode(DEFAULT_MODE) via the lexer's mode()","Trace with lexer debug output or a lexer listener to see which token pops an empty stack, then move that rule into the correct mode section"],"exampleFix":"// grammar before\nSTRING_START : '\"' -> pushMode(STR);\nmode STR;\nSTRING_END : '\"' -> popMode;\nESC : '\\\\' '\"' -> popMode;  // second pop on \\\\\" pops empty stack\n\n// grammar after\nSTRING_START : '\"' -> pushMode(STR);\nmode STR;\nSTRING_END : '\"' -> popMode;\nESC_QUOTE : '\\\\' '\"' -> more;  // stay in STR, no pop","handlingStrategy":"validation","validationCode":"# Python: in an embedded lexer action, pop only when a mode is pushed\nif len(self._modeStack) > 0:\n    self.popMode()\nelse:\n    self.mode(Lexer.DEFAULT_MODE)  # or report a grammar bug","typeGuard":null,"tryCatchPattern":"try:\n    lexer.nextToken()\nexcept Exception as ex:\n    if str(ex) == \"Empty Stack\":\n        raise SyntaxError(f\"grammar bug: popMode with empty mode stack near char {lexer.column}\") from ex\n    raise","preventionTips":["Audit every -> popMode and ensure its rule lives only inside a -> pushMode'd mode","Test each lexer mode in isolation with minimal inputs that exercise close-delimiters","Prefer -> more for escape sequences inside pushed modes instead of extra pops"],"tags":["antlr","python","lexer","modes","grammar"],"backgroundTag":null,"analyzedSha":"7d5770395bb7b02eb56e7c62662cb1d7c08f42a3","analyzedAt":"2026-08-14T14:47:56.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}