你如何编写一个省略尾随字符的语法规则?
How do you write a grammar rule which leaves off a trailing character?
我基本上是想说“匹配一些字母或换行符,除了忽略最后一个换行符”。我怎样才能用正则表达式做到这一点?或者如果不是正则表达式,我怎样才能更正式地使用语法规则(例如使用 BNF 语法)?
如果 a
和 b
是字母,而 c
是新行,那么我会尝试像 /abc+[^c]/
这样的正则表达式,但这不太正确,它只会匹配 abcccccb
例如,不会忽略最后的 c
.
我尝试使用更 DSL 的方法:
rule match-multiline-string
match multiple
match or
match letters
match line-break
这将匹配尾随的换行符,而我只想匹配直到最后一个换行符的所有内容。那么我试试:
rule match-multiline-string
match multiple
match or
match letters
match line-break
match line-break
consume false
这似乎会得到它,但实施起来会很棘手。语法通常如何处理这种情况?
在 (f)lex 中,您可以使用 trailing context operator 执行此操作,使用如下规则:
[[:alpha:]\n]+/\n { yylval = strdup(yytext); return ML_STRING; }
(在 (f)lex 中,$
运算符 完全 与 /\n
相同,所以我通常会将该特定规则写为 [[:alpha:]\n]+$
。但这似乎有点难以理解。)
我不知道这是否真的是您要找的,因为我想您实际上并没有使用 (f)lex。但同样的原则应该适用于任何基于正则表达式的扫描器。尾随上下文是通过匹配来实现的,就好像 /
不存在一样(因此匹配的实际正则表达式是 [[:alpha:]\n]+\n
),然后在返回之前备份尾随上下文的长度。这意味着最大咀嚼规则(如果有多个正则表达式匹配,则采用文件中与最长前缀匹配的第一个规则)被解释为好像尾随上下文是模式的一部分。这通常很方便,尽管它可能看起来违反直觉。
如果尾随上下文的长度可变,情况会稍微复杂一些,但这在这里并不重要。不过,为了以防万一,实际使用的算法是在每次 DFA 执行从 /
之前的状态到 /
之后的状态的转换时记录匹配位置;最后,扫描仪返回到最后记录的匹配位置。这个和scanner实现maximal munch的方式类似,就是每次达到accepting状态,记录最后一次匹配的位置。
我基本上是想说“匹配一些字母或换行符,除了忽略最后一个换行符”。我怎样才能用正则表达式做到这一点?或者如果不是正则表达式,我怎样才能更正式地使用语法规则(例如使用 BNF 语法)?
如果 a
和 b
是字母,而 c
是新行,那么我会尝试像 /abc+[^c]/
这样的正则表达式,但这不太正确,它只会匹配 abcccccb
例如,不会忽略最后的 c
.
我尝试使用更 DSL 的方法:
rule match-multiline-string
match multiple
match or
match letters
match line-break
这将匹配尾随的换行符,而我只想匹配直到最后一个换行符的所有内容。那么我试试:
rule match-multiline-string
match multiple
match or
match letters
match line-break
match line-break
consume false
这似乎会得到它,但实施起来会很棘手。语法通常如何处理这种情况?
在 (f)lex 中,您可以使用 trailing context operator 执行此操作,使用如下规则:
[[:alpha:]\n]+/\n { yylval = strdup(yytext); return ML_STRING; }
(在 (f)lex 中,$
运算符 完全 与 /\n
相同,所以我通常会将该特定规则写为 [[:alpha:]\n]+$
。但这似乎有点难以理解。)
我不知道这是否真的是您要找的,因为我想您实际上并没有使用 (f)lex。但同样的原则应该适用于任何基于正则表达式的扫描器。尾随上下文是通过匹配来实现的,就好像 /
不存在一样(因此匹配的实际正则表达式是 [[:alpha:]\n]+\n
),然后在返回之前备份尾随上下文的长度。这意味着最大咀嚼规则(如果有多个正则表达式匹配,则采用文件中与最长前缀匹配的第一个规则)被解释为好像尾随上下文是模式的一部分。这通常很方便,尽管它可能看起来违反直觉。
如果尾随上下文的长度可变,情况会稍微复杂一些,但这在这里并不重要。不过,为了以防万一,实际使用的算法是在每次 DFA 执行从 /
之前的状态到 /
之后的状态的转换时记录匹配位置;最后,扫描仪返回到最后记录的匹配位置。这个和scanner实现maximal munch的方式类似,就是每次达到accepting状态,记录最后一次匹配的位置。