如何定义lex模式()或(/ * rem /)和(/ foo / 100 / foo * /) 在使用gnu(f)lex工具。
_space [ \t]
id [a-zA-Z_]+[a-zA-Z0-9_]
digit [0-9]
math_ops [\+\-\/\*\^\%]
rem_expr (({_space}*)*|("/*".*"*/")*|("//".*)*|([\n]*))*
arr_digid ("("*({digit}*|{id}*)*")"*){arr_expr1}*{math_ops}+
arr_expr1 {rem_expr}*{digit}*{rem_expr}*
arr_expr2 {rem_expr}*
%%
\({arr_expr2}*\) {
return _REM_;
}
\({arr_expr1}*\) {
return _PATTERN2_;
}
答案 0 :(得分:1)
通常,您不会从词法分析器返回注释或空格。你为什么这样?根据定义,它们不是您尝试解析的程序语义的一部分。
总的来说,处理它们的最简单方法就是忽略它们。下面,第一个模式匹配除换行符之外的任何空格字符(使用[[:space:]]
也忽略换行符),第二个模式是匹配C样式注释的方式。 ("/*".*"*/"
不起作用,因为它会从一行的第一条评论的开头到最后一条评论的结尾匹配。)
[[:blank:]] ;
[/][*][^*]*[*]+([^/*][^*]*[*]+)[/] ;
模式没有动作(或者,通常在动作中没有return
语句)这一事实意味着(f)lex生成的扫描程序将简单地继续分析下一个令牌。
其他一些说明:
没有必要为每个模式定义快捷方式。将模式直接放在lex动作中没有问题。而且您当然不需要为已经有快捷方式的字符类定义快捷方式(例如[[:blank:]]
和[[:digit:]]
。
您不需要在字符类中反斜杠转义字符,尽管有几个字符顺序很重要。 (这就是我在C-comment模式中使用[*]
的原因;我同样可以使用"*"
或\*
,但我个人更喜欢[*]
。)所以你可以定义:
math_ops [+/*^%-]
- 必须位于列表的结尾或开头; ^ 不能在开头就行,而且(虽然你不能使用它)] 必须在开头。唯一需要反斜杠转义的字符就是反斜杠本身。
但是,我最好总是让单个字符标记在最后用一个默认规则处理:
. { return yytext[0]; }
这更易于维护,并且无需为单字符标记创建任意标记名称。您可以在bison / yacc文件中使用单引号字符。