我已经设法在我的Flex程序中有效地匹配有效的字符串字面值,但是我还想匹配未终止的字符串字面值和带有坏转义序列的字符串字面值。
例如,我的字符串字面值使用简单的正则表达式进行匹配,如下所示:
"(\.|[^\"])*"
然后我试图找到字符串字面值从"
开始,然后是一些文本,然后是n
。对于我的词法分析器来说,这是不正确的语法,我想捕获并产生一个错误。
我现在的正则表达式是这样的:
"(\.|[^\"])*n
可以正确捕获错误,但随后似乎耗尽了剩余的令牌,因为在此之后没有输出。
此外,我还希望有一个特殊情况的错误,当一个未终止的字符串字面值有一个无效的转义序列。例如:
"some text
int abc
所以我的问题归结为,是否有什么问题,我目前的匹配字符串文字的方式,影响了我的能力来捕捉这些错误,或者是我的模式匹配不必要地消耗令牌?也有可能我根本不知道自己在做什么!
字符串的一些例子:
"a correct string literal"
"an unterminated string literal
"an unterminated string literal with escape
所有字符串字面值都是单行,并遵循以下形式:
"(.*)"n
字符串字面值的正确伸缩模式是(参见下面的转义序列):
"(\(.|n)|[^\"n])*"
这与你的模式的不同之处在于它允许转义字符后面的换行符(从技术上讲,这是一个拼接,而不是字符串字面量语法的一部分[注1]),否则禁止换行符。这必须明确地完成,因为[^...]
包括换行符,除非n
是要拒绝的字符列表的一部分。只有.
隐式禁止换行符。
要匹配不正确的字符串字面值,您只需要相同的模式,但不需要终止"
:
"(\(.|n)|[^\"n])*
您不需要担心模式是否匹配正确的字符串字面量,因为flex总是选择最长的匹配,并且带有终止引号的匹配保证更长。
如果你想要更准确的转义字符,你需要这样:
"(\([abfnrtv'"?\n]|[0-7]{1,3}|x[[:xdigit:]]+|u[[:xdigit:]]{4}|U[[:xdigit:]]{8})|[^\"n])*"
您可以使用相同的技术来匹配错误,但是您可能希望区分未终止引号错误和无效转义错误,这可以通过使用两种错误模式来实现:
"(\([abfnrtv'"?\n]|[0-7]{1,3}|x[[:xdigit:]]+|u[[:xdigit:]]{4}|U[[:xdigit:]]{8})|[^\"n])*" { /* Valid string */ }
"(\([abfnrtv'"?\n]|[0-7]{1,3}|x[[:xdigit:]]+|u[[:xdigit:]]{4}|U[[:xdigit:]]{8})|[^\"n])*/\ { /* Invalid escape sequence */ }
"(\([abfnrtv'"?\n]|[0-7]{1,3}|x[[:xdigit:]]+|u[[:xdigit:]]{4}|U[[:xdigit:]]{8})|[^\"n])* { /* Missing terminating quote */ }
指出"splice"是行尾的反斜杠。您通常只在长宏的定义中看到这些,但是C允许在任何地方进行拼接:反斜杠和下面的换行符只是从程序文本中删除,因此拼接甚至可以放在标识符或多字符操作符的中间。(但不要那样做!)
使用拼接在多行上继续字符串不是好的风格;最好使用字符串连接。但是C标准允许这样做。
然而,拼接在标记化开始之前被删除,这意味着您不能在行尾转义反斜杠:
"This is a string literal which includes a \ t tab, with a splice in the middle of the escape."
也请不要在产品代码中使用:-)