为什么不能在 yacc/bison 文件中使用括号字符?

Why cannot use brackets character in yacc/bison file?

来源

ini.l

%option yylineno

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

int yywrap(void) {
    return 1;
}

void yyerror(const char* s) {
    printf("%d: %s at %s\n", yylineno, s, yytext);
}

#if defined YYDEBUG
extern int yydebug;
#endif

#define CASE_RETURN(token) do { case token: return #token; } while(0)

char *get_tokenname(token) {
    switch(token) {
        CASE_RETURN( IDENTIFIER     );
        CASE_RETURN( BRACKETS_LEFT  );
        CASE_RETURN( BRACKETS_RIGHT );
        CASE_RETURN( EQ             );
        default: return "Unknown";
    }
}

int main(void) {
    int token;
#if defined YYDEBUG
    yydebug = 1;
    while ((token = yylex()) != 0)
        printf("Token: %d/%-20s (%s)\n", token, get_tokenname(token), yytext);
#else
    yyparse();
#endif
    return 0;
}
%}

%%

[_a-zA-Z0-9]+           { yylval.str = strdup(yytext); return IDENTIFIER; }
"["                     { return BRACKETS_LEFT; }
"]"                     { return BRACKETS_RIGHT; }
"="                     { return EQ; }
[ \t\r\n]               { }

%%

ini.y

%{
#include <stdio.h>
#include <string.h>
%}

%union {
    char* str;    
}

%token <str> IDENTIFIER
%token BRACKETS_LEFT BRACKETS_RIGHT EQ

%%

input
    : /* empty */
    | input line
    | line
    ;

line
    : BRACKETS_LEFT section BRACKETS_RIGHT
    | key EQ value
    ;

section : IDENTIFIER { printf("section: %s\n" , ); } ;
key     : IDENTIFIER { printf("key: %s, "     , ); } ;
value   : IDENTIFIER { printf("value: %s\n"   , ); } ;

%%

生成文件

CC              = gcc
LEX             = flex
YACC            = bison

TARGET          = a.out

LEX_SRC         = $(wildcard *.l)
YACC_SRC        = $(wildcard *.y)
SRC             = $(patsubst %.y,%.tab.c,$(YACC_SRC)) $(patsubst %.l,%.yy.c,$(LEX_SRC))
INC             = $(patsubst %.y,%.tab.h,$(YACC_SRC)) $(patsubst %.l,%.yy.h,$(LEX_SRC))

DEBUG           = -DYYDEBUG -DYYERROR_VERBOSE
LDFLAGS         = -L/usr/local/opt/bison/lib \
                -L/usr/local/opt/flex/lib \
                -I/usr/local/opt/flex/include

all: $(SRC)
    $(CC) $(FLAGS) $(SRC) -o $(TARGET)

debug: $(SRC)
    $(CC) $(FLAGS) $(SRC) -o $(TARGET) $(DEBUG)

.PRECIOUS: %.yy.c

%.yy.c: %.l
    $(LEX) -t $< > $@

.PRECIOUS: %.tab.c

%.tab.c:%.y
    $(YACC) -o $@ -d $<

clean:
    rm -rf $(TARGET) $(SRC) $(INC) *.output 

sample.ini

[foobar]
foo=bar

测试

$ make clean && make
$ ./a.out < sample.ini
section: foobar
key: foo, value: bar

一切正常

$ make clean && make debug
$ ./a.out < sample.ini
Token: 259/BRACKETS_LEFT        ([)
Token: 258/IDENTIFIER           (foobar)
Token: 260/BRACKETS_RIGHT       (])
Token: 258/IDENTIFIER           (foo)
Token: 261/EQ                   (=)
Token: 258/IDENTIFIER           (bar)

然后我把BRACKETS_LEFT改成了'['

$ git diff -U0
diff --git a/ini.l b/ini.l
index 2538353..12b2524 100644
--- a/ini.l
+++ b/ini.l
@@ -24 +23,0 @@ char *get_tokenname(token) {
-        CASE_RETURN( BRACKETS_LEFT  );
@@ -47 +45,0 @@ int main(void) {
-"["                     { return BRACKETS_LEFT; }
diff --git a/ini.y b/ini.y
index c605ea4..1498ff5 100644
--- a/ini.y
+++ b/ini.y
@@ -11 +11 @@
-%token BRACKETS_LEFT BRACKETS_RIGHT EQ
+%token BRACKETS_RIGHT EQ
@@ -22 +22 @@ line
-    : BRACKETS_LEFT section BRACKETS_RIGHT
+    : '[' section BRACKETS_RIGHT

野牛报错

$ make clean && make debug
$ ./a.out < sample.ini
1: syntax error at [

$ make clean && make debug
$ ./a.out < sample.ini
[Token: 258/IDENTIFIER           (foobar)
Token: 259/BRACKETS_RIGHT       (])
Token: 258/IDENTIFIER           (foo)
Token: 260/EQ                   (=)
Token: 258/IDENTIFIER           (bar)

:(

为了使 bison 能够使用像“[”这样的字符标记,扫描器必须 return 恰好是“[”。

您的扫描仪似乎return 无法识别未知字符。您需要添加默认规则:

.    { return yytext[0]; }

我建议始终使用 flex nodefault 选项来捕获此类错误。另外,编译时 gcc 的 -Wall 选项。并查看 flex 和 bison 的文档,了解如何使用它们的调试跟踪,而不是构建自己的调试跟踪。 built-in 调试易于使用并产生相当完整的输出。