首页 > 解决方案 > PLY - 在 C 样式注释中转义新行

问题描述

我正在使用 PLY 编写一个简单的解析器。我的评论可能看起来像这样

# this is a single line comment \
with an escaped new line

我的尝试是在这里使用状态。我有

states = (
    ('COMMENT', 'exclusive'),
)
tokens = ('COMMENT')

def t_begin_COMMENT(t):
    r'\#'
    t.lexer.begin('COMMENT')


def t_COMMENT_contents(t):
    r'.|\\\n'


t_COMMENT_ignore = r' '

def t_COMMENT_error(t):
    pass


def t_COMMENT_end(t):
    r'\n'
    t.lexer.begin('INITIAL')

当我做

lexer = lex.lex()
string = "# test \\\ns \n4"
lexer.input(string)
for tok in lexer:
    print(tok)

它应该打印 4 (我有另一个令牌,但现在无关紧要)但我明白了s4哪里s还有评论。如何为内容编写正则表达式?这是因为COMMENT以 结尾\n吗?

标签: ply

解决方案


Python 正则表达式不会产生最长的匹配。Python 正则表达式中的Alternation( |) 是有序的;如果您使用模式.|\\\n.则将始终匹配(除非字符串为空),因此\\\n永远不会尝试。如果没有转义符号,这更容易看到:

>>> import re
>>> re.match(r'.|ab', 'ab')
<_sre.SRE_Match object; span=(0, 1), match='a'>
>>> re.match(r'ab|.', 'ab')
<_sre.SRE_Match object; span=(0, 2), match='ab'>

我完全不清楚为什么要进行所有这些工作,而不是使用单个正则表达式而不必求助于词法分析器状态。

def t_comment(t):
    r'\#(\\\n|.)*\n'
    pass

(注意:我更喜欢正则表达式r'\#(\\[\s\S]|.)*',它允许 a\转义任何内容,包括它自己。您使用的正则表达式不允许您在注释行的末尾放置反斜杠:

# This will continue, perhaps unexpectedly: \\
still a comment

此外,无论如何都将忽略尾随\n,因此没有明显的理由将其包含在模式中,如果注释位于输入的末尾并且输入没有以换行符终止,则它可能无法匹配。


推荐阅读