C 在bison中使用字符文字作为终端

C 在bison中使用字符文字作为终端,c,bison,yacc,lex,flex-lexer,C,Bison,Yacc,Lex,Flex Lexer,我试图理解flex/bison,但是文档对我来说有点困难,我可能严重误解了一些东西。下面是一个测试用例: 文件“a”包含单个字符“a”。“foo.y”的语法很简单,如下所示: %% file: 'a' ; 生成的解析器无法解析文件“a”;它给出了一个语法错误 语法“bar.y”几乎相同,只是我更改了命名标记的字符文字: %token TOK_A; %% file: TOK_A; 然后在bar.lex中: a { return TOK_A; } 这个很好用 在文档中直接使用

我试图理解flex/bison,但是文档对我来说有点困难,我可能严重误解了一些东西。下面是一个测试用例:

文件“a”包含单个字符“a”。“foo.y”的语法很简单,如下所示:

%%

file: 'a' ;
生成的解析器无法解析文件“a”;它给出了一个语法错误

语法“bar.y”几乎相同,只是我更改了命名标记的字符文字:

%token TOK_A;

%%

file: TOK_A;
然后在bar.lex中:

a       { return TOK_A; }
这个很好用

在文档中直接使用字符文本作为bison终端时,我做错了什么

我希望我的语法看起来像“语句:选择器'{'property':'value';''}',而不是“语句:选择器LBRACE属性冒号值SEMIC RBRACE”

我正在debian wheezy中运行bison 2.5和flex 2.5.35。

重写

这是一个运行时问题,而不是编译时问题

问题是你有两个完全不同的词法分析器

bar.lex
分析器识别输入中的
a
,并将其作为TOK_a返回,忽略所有其他内容

foo.lex
分析器会回显每个字符,但仅此而已

foo.lex-如书面所示 foo.lex-等效 foo.lex-必需
工作代码 这里有一些诊断打印到位的工作代码

foo lex.l 福伊
细节问题:那个空行是如何进入输出的?答:词法分析器把它放在那里。模式
与换行符不匹配,因此换行符被视为存在规则:

\n    { ECHO; }
这就是接受输入的原因。如果将
foo lex.l
文件更改为:

%%
.       { printf("Flex-1: %d\n", *yytext); return *yytext; }
\n      { printf("Flex-2: %d\n", *yytext); return *yytext; }
然后重新编译并再次运行,输出为:

$ echo a | ./foo
Flex-1: 97
Bison: got file!
Flex-2: 10
syntax error
$

没有空行。这是因为语法不允许在有效的“文件”中出现换行符。

如果你真的不想使用lexer,那么根本不用麻烦使用.l文件——只需将
int-yylex(){return getchar();}
放在.y文件的第三部分。@chrisdd:几乎-你必须将EOF映射到0:
int-yylex(void){int-c=getchar();如果(c==EOF)返回0;否则返回c;}
。这也会将ASCII NUL
'\0'
报告为EOF。您不必将0映射到EOF,Bison的解析器会将0识别为EOF。@akim:True;所有基于Yacc的解析器都将令牌值0视为“令牌流的结束”。问题是,当您使用
return getchar();
,EOF返回的值为负值(通常为-1),而这并没有被基于Yacc的解析器识别为“令牌流的结尾”。@JonathanLeffler你是对的。事实上,我个人不鼓励直接使用char作为
yylex
的返回值。使用枚举类型更安全。是的,我的意思是你不应该
返回“+”;
,而应该是
返回PLUS;
,这是正确的扫描器中有更多的代码。但这也更安全,因为您不会因为向解析器提供不存在的令牌类型而有阻塞解析器的风险。
%%
. { printf("Flex: %d\n", *yytext); return *yytext; }
%{
#include <stdio.h>
void yyerror(char *s);
%}

%%

file: 'a' { printf("Bison: got file!\n") }
    ;

%%

int main(void)
{
    yyparse();
}

void yyerror(char *s)
{
    fprintf(stderr, "%s\n", s);
}
$ flex foo-lex.l
$ bison foo.y
$ gcc -o foo foo.tab.c lex.yy.c -lfl
$ echo a | ./foo
Flex: 97
Bison: got file!

$
\n    { ECHO; }
%%
.       { printf("Flex-1: %d\n", *yytext); return *yytext; }
\n      { printf("Flex-2: %d\n", *yytext); return *yytext; }
$ echo a | ./foo
Flex-1: 97
Bison: got file!
Flex-2: 10
syntax error
$