我正在开始玩具编译器,我正在做出我能想象到的最简单的事情,但它无法正常工作。
Lex编译,Yacc编译,他们链接在一起,但输出的程序没有达到我的预期。
莱克斯:
%{
#include <stdlib.h>
void yyerror(char *);
#include "y.tab.h"
%}
%%
a {
yylval = atoi(yytext);
return AAA;
}
. yyerror("invalid character");
%%
int yywrap(void) {
return 1;
}
的Yacc:
%{
void yyerror(char *);
int yylex(void);
int sym[26];
#include <stdio.h>
%}
%token AAA
%%
daaaa:
AAA {printf("%d\n", $1);}
%%
void yyerror(char *s) {
fprintf(stderr, "%s\n", s);
}
int main(void) {
yyparse();
return 0;
}
我试图用这个编译器编译的程序是一个包含a
的文件。就是这样。
我不知道发生了什么事!
澄清:我期望编译的编译器做的是接受一个文件,处理文件,并吐出该文件的编译版本。
答案 0 :(得分:2)
你能否在一个答案中解释一下你所做的,以及它是如何运作的,因为据我所知,就我所测试的问题而言,它不应该像你说的那样工作
我逐字记录了您的代码,创建了文件grammar.y
和lexer.l
。然后我编译了代码。我正在Mac OS X 10.11.4上工作,使用GCC 6.1.0,Bison 2.3(伪装成yacc
)和Flex 2.5.35(伪装成lex
)。
$ yacc -d grammar.y
$ lex lexer.l
$ gcc -o gl y.tab.c lex.yy.c
$ ./gl <<< 'a'
0
$
我随后做了两处修改。在grammar.y
中,我将main()
更改为:
int main(void) {
#if YYDEBUG
yydebug = 1;
#endif
yyparse();
return 0;
}
并在lexer.l
中,我将默认字符规则更改为:
\n|. yyerror("invalid character");
(.
不匹配换行符,因此输入中a
之后的换行符默认在原始输出中回显。)
使用类似的编译,输出变为:
$ ./gl <<< 'a'
0
invalid character
$
编译指定-DYYDEBUG
:
$ gcc -DYYDEBUG -o gl lex.yy.c y.tab.c
$
输出包含有用的调试信息:
$ ./gl <<< 'a'
Starting parse
Entering state 0
Reading a token: Next token is token AAA ()
Shifting token AAA ()
Entering state 1
Reducing stack by rule 1 (line 12):
$1 = token AAA ()
0
-> $$ = nterm daaaa ()
Stack now 0
Entering state 2
Reading a token: invalid character
Now at end of input.
Stack now 0 2
Cleanup: popping nterm daaaa ()
$ ./gl <<< 'aa'
Starting parse
Entering state 0
Reading a token: Next token is token AAA ()
Shifting token AAA ()
Entering state 1
Reducing stack by rule 1 (line 12):
$1 = token AAA ()
0
-> $$ = nterm daaaa ()
Stack now 0
Entering state 2
Reading a token: Next token is token AAA ()
syntax error
Error: popping nterm daaaa ()
Stack now 0
Cleanup: discarding lookahead token AAA ()
Stack now 0
$
输入中的第二个a
正确触发语法错误(语法不允许)。允许使用其他字符,生成无效字符&#39;消息,否则将被忽略(因此./gl <<< 'abc'
会生成3条无效的字符消息,一封用于b
,一封用于c
,另一封用于换行符。
将yylval
中的lexer.l
分配更改为:
yylval = 'a'; // atoi(yytext);
将打印的数字从0更改为97,这是ASCII,ISO 8859-1,Unicode等中'a'
的字符代码。
我一直在使用here string作为数据来源。将文件用作输入同样可行:
$ echo a > program
$ cat program
a
$ ./gl < a
Starting parse
Entering state 0
Reading a token: Next token is token AAA ()
Shifting token AAA ()
Entering state 1
Reducing stack by rule 1 (line 12):
$1 = token AAA ()
97
-> $$ = nterm daaaa ()
Stack now 0
Entering state 2
Reading a token: invalid character
Now at end of input.
Stack now 0 2
Cleanup: popping nterm daaaa ()
$
如果要在命令行上读取由name指定的文件,则必须在main()
中编写更多代码来处理这些文件。
答案 1 :(得分:1)
程序不接受文件,因为它没有被告知。
在Yacc计划中,
必须在定义部分添加extern FILE *yyin;
。
我相信就是这样。