Bison:如果一个标记不符合规则,如何忽略它

7
我正在编写一个处理评论以及其他一些内容的程序。如果评论位于特定位置,那么我的程序会执行某些操作。
Flex在找到评论时传递一个标记,然后Bison查看该标记是否符合特定规则。如果是,则采取与该规则相关联的操作。
问题在于:我接收到的输入可能实际上在错误的位置有注释。在这种情况下,我只想忽略注释而不是标记一个错误。
我的问题是:
如何在令牌符合规则的情况下使用它,但在不符合规则的情况下忽略它? 我可以使令牌“可选”吗?
(注:我现在能想到的唯一方法是在每个可能的规则中的每个可能位置散布注释令牌。 必须有比这更好的解决方案。 也许是涉及根的某个规则?)
2个回答

5

一种解决方案可能是使用bison的错误恢复功能(请参见Bison手册)。

bison将终端令牌error定义为表示错误的符号(例如,一个在错误位置返回的注释令牌)。这样,您可以在找到错误的注释后关闭括号或花括号。然而,这种方法可能会丢弃一定量的分析,因为我认为bison无法“撤消”规约。(与向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,所以出现了移位/规约冲突。此外,在最后一个pleaseEOF之间没有适配注释的规则。但总体来说,我认为这是一个很好的例子。


1

在词法分析器级别将注释视为空格。 但保留两个单独的规则,一个用于空格,另一个用于注释,两者都返回相同的令牌ID。

  • 注释(+可选空格)的规则在专用结构中跟踪注释。
  • 空格的规则重置该结构。

当您进入“特定位置”时,请查看最后一个空格是否为注释或触发错误。


许多(大多数?)语法在空格上根本不返回标记。编写空格作为标记的规则很棘手。考虑:a = b + c ;a=b+c;...痛苦! - Jonathan Leffler
精确。如果您不返回空格,解决方案仍然有效。 这有点狡猾,但大多数具有模糊注释定义的语言也是如此。 - fra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接