我正在编写一个处理评论的程序以及其他一些东西。如果评论在特定的地方,那么我的程序会做一些事情。
Flex在发现评论时传递令牌,然后Bison会查看该令牌是否符合特定规则。如果是,则需要与该规则相关联的操作。
这就是事情:我收到的输入实际上可能在错误的地方有评论。在这种情况下,我只想忽略评论而不是标记错误。
我的问题:
如果令牌符合规则,我如何使用令牌,但如果不符合则忽略它?我可以将令牌设为“可选”吗?
(注意:我现在想到的唯一方法是在每个可能的规则中将评论标记分散在每个可能的位置。必须有一个比这更好的解决方案。也许有一些涉及根的规则?)< / p>
答案 0 :(得分:4)
一种解决方案可能是使用bison的错误恢复(参见Bison manual)。
总而言之,bison定义终端令牌error
来表示错误(例如,在错误的位置返回的注释令牌)。这样,您可以(例如)在找到任意评论后关闭括号或括号。但是,这种方法可能会丢弃一定量的解析,因为我不认为野牛可以“撤消”减少。 (“标记”错误,就像将消息打印到stderr一样,与此无关:您可以 错误而不打印错误 - 这取决于如何你定义yyerror
。)
您可能希望将每个终端包装在特殊的非终端中:
term_wrap: comment TERM
这有效地做了你害怕做的事情(在每条规则中加上评论),但它在更少的地方做到了。
为了强迫自己吃自己的狗粮,我为自己制作了一种愚蠢的语言。唯一的语法是print <number> please
,但如果在数字和##
之间(至少)有一条注释(please
),则会以十六进制格式打印数字。
像这样:
print 1 please
1
## print 2 please
2
print ## 3 please
3
print 4 ## please
0x4
print 5 ## ## please
0x5
print 6 please ##
6
我的词霸:
%{
#include <stdio.h>
#include <stdlib.h>
#include "y.tab.h"
%}
%%
print return PRINT;
[[:digit:]]+ yylval = atoi(yytext); return NUMBER;
please return PLEASE;
## return COMMENT;
[[:space:]]+ /* ignore */
. /* ditto */
和解析器:
%debug
%error-verbose
%verbose
%locations
%{
#include <stdio.h>
#include <string.h>
void yyerror(const char *str) {
fprintf(stderr, "error: %s\n", str);
}
int yywrap() {
return 1;
}
extern int yydebug;
int main(void) {
yydebug = 0;
yyparse();
}
%}
%token PRINT NUMBER COMMENT PLEASE
%%
commands: /* empty */
|
commands command
;
command: print number comment please {
if ($3) {
printf("%#x", $2);
} else {
printf("%d", $2);
}
printf("\n");
}
;
print: comment PRINT
;
number: comment NUMBER {
$$ = $2;
}
;
please: comment PLEASE
;
comment: /* empty */ {
$$ = 0;
}
|
comment COMMENT {
$$ = 1;
}
;
所以,正如你所看到的,不完全是火箭科学,但它确实可以解决问题。由于在多个位置匹配comment
的空字符串,因此存在移位/减少冲突。此外,最终please
和EOF
之间没有适合评论的规则。但总的来说,我认为这是一个很好的例子。
答案 1 :(得分:1)
将评论视为词法分析者级别的空白。 但是保留两个单独的规则,一个用于空白,一个用于注释,两者都返回相同的令牌ID。
当您输入“特定地点”时,查看最后一个空格是评论还是触发错误。