为什么这会在yacc / bison

时间:2018-03-01 11:35:50

标签: bison yacc shift-reduce-conflict

我想解析一个从/etc/hosts.allow格式派生的简单语法。 我正在yacc上转换/减少冲突。我可以忽略转换/减少冲突警告,还是可以以某种方式修改它?:

%token ALLOW
%token DENY
%token COMMENT
%token DEFAULT
%token HOSTUSER
%token PRODUCT

%%
lines: line
    | lines line
line: product_line
    | default_line

product_line: PRODUCT ':' user_host_list ':' allow_deny
            { printf("product line\n"); }
default_line: DEFAULT  ':'  allow_deny
            { printf ("default line\n"); }
allow_deny: ALLOW
            | DENY
user_host_list:
        | HOSTUSER
        | user_host_list HOSTUSER
%%
#include <stdio.h>
extern FILE *yyin;
extern char *yytext;

main(argc, argv)
int argc;
char **argv;


   while(yyparse() && !feof(yyin))
    ;
   return 0;
}

示例文件看起来像这样:

# comments
# comments

DEFAULT : DENY
<some_product_code> : <list_of_users_hosts> : ALLOW
<some_product_code> : <list_of_users_hosts> : ALLOW

(N.B。:评论行#被lexer“吃掉”)

我也会添加词法分析器:

%{
#include <stdio.h>
#include "y.tab.h"

int debug=0;
#define P1(x) if(debug)printf(x)
#define P2(x,y) if(debug)printf(x,y)
#ifdef TEST_LEXER

main()
{
   debug=1;
   while(yylex())
     ;
   return 0;
}
#endif

%}
%option caseless
/*
  "EX-P00V10000-NT-xx"
  "FX-P05E64001-NT-xx"
  "NX-P07E03400-NT-xx"
  "BX-P00B00000-NT-xx"
  "VX-P02E08000-NT-xx"
*/
deny DENY
allow ALLOW
default DEFAULT
product [BCEFKNV][X]-[P][0-9][0-9][EBPV]([0-9]{5,})-NT-xx
name [A-Z_0-9][A-Z_\-0-9\.]*
%%
{product} { P1("PRODUCT! ");return PRODUCT;}
{allow} { P1("ALLOW!\n");return ALLOW; }
{deny} { P1("DENY!\n");return DENY; }
{default}  { P1("DEFAULT!\n");return DEFAULT; }
\*|\\\\{name}|\\\\{name}\\{name}|\\\\{name}\\\*|{name} { P2("HOSTUSER![%s]",yytext); }
#.*(\n|\r\n)  {P1("COMMENT!\n");;}
\n|\r\n|[ ]|\t|, { ; }
.  { P2("[%02hx]",(unsigned char)yytext[0]);return yytext[0]; }

%%
yyerror(char *s) { fprintf(stderr,"Zeile %d: %s[%s]\n",
                                yylineno,s,yytext); fflush(stdout);}
yywrap() { return 1; }

样本输入:

# blah blah hello
DEFAULT : DENY
BX-P00B00000-NT-xx : \\host\user \\another\user1 user2 user3 : allow
BX-P00E00003-NT-xx : * : allow
BX-P01B03000-NT-xx : \\host\* : allow # comment here should work, too
BX-P01B03000-NT-xx : \\host\* : allow
# continuation lines too:
BX-P01B03000-NT-xx : user1
                     user2
                     \\host\* : allow

1 个答案:

答案 0 :(得分:1)

您的user_host_list定义:

user_host_list:
        | HOSTUSER
        | user_host_list HOSTUSER

以您可能不想要的|开头。它包含3条规则。第一个规则是空的,因此空令牌序列可以减少到user_host_list。这是导致冲突的不必要的减少。

如果您打算要求至少1 HOSTUSER,请按以下方式编写:

user_host_list:
        HOSTUSER
        | user_host_list HOSTUSER

如果您打算允许空列表,请按以下方式编写:

user_host_list:
        /* empty */
        | user_host_list HOSTUSER