您在词法分析器而不是解析器中处理缩进的方法是正确的。好吧,这两种方法都是可行的,但这通常是更简单的方法,而且 Python 本身(或至少 CPython 和 PyPy)就是这样做的。
我对 JFlex 了解不多,您也没有给我们任何代码来使用,但我可以笼统地解释一下。
对于您的第一个问题,您已经在换行符之后将词法分析器置于特殊状态,因此“抓取 0 个或更多空格”应该可以通过逃避正常的事物流程并仅针对该行运行正则表达式来实现。
对于第二个问题,最简单的解决方案(也是 Python 使用的一个)是保留一堆缩进。我将演示一些比 Python 所做的更简单的事情。
第一的:
indents = [0]
在每个换行符之后,抓取 0 个或更多空格作为spaces
. 然后:
if len(spaces) == indents[-1]:
pass
elif len(spaces) > indents[-1]:
indents.append(len(spaces))
emit(INDENT_TOKEN)
else:
while len(spaces) != indents[-1]:
indents.pop()
emit(DEDENT_TOKEN)
现在您的解析器只看到INDENT_TOKEN
and DEDENT_TOKEN
,这OPEN_BRACE_TOKEN
与CLOSE_BRACE_TOKEN
类似 C 语言的 and 没有什么不同。
你想要更好的错误处理——引发某种标记器错误而不是隐含的IndexError
,也许使用<
而不是!=
这样你就可以检测到你已经走得太远而不是耗尽堆栈(如果你想继续更好的错误恢复发出进一步的错误,而不是在第一个错误时放弃)等。
对于现实生活中的示例代码(带有错误处理、制表符和空格、反斜杠换行符以及处理括号表达式内的非语法缩进等),请参阅标准库中的tokenize
文档和源代码。