PLY - 转义 C 风格注释中的新行

PLY - escaping new line in C-style comments

我正在使用 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 结尾吗?

Python 正则表达式不会产生最长匹配。 Python 正则表达式中的交替 (|) 是 有序的 ;如果您使用模式 .|\\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]|.)*',它允许 \ 转义任何内容,包括它本身。您使用的正则表达式不允许您在评论行的结尾:

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

另外,尾随的 \n 无论如何都会被忽略,所以没有明显的理由将它包含在模式中,如果注释正好在输入的末尾,它可能无法匹配输入不以换行符终止。