Lex和Yacc做编译器?

时间:2016-05-09 19:15:54

标签: yacc lex

我正在开始玩具编译器,我正在做出我能想象到的最简单的事情,但它无法正常工作。

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的文件。就是这样。

我不知道发生了什么事!

澄清:我期望编译的编译器做的是接受一个文件,处理文件,并吐出该文件的编译版本。

2 个答案:

答案 0 :(得分:2)

  

你能否在一个答案中解释一下你所做的,以及它是如何运作的,因为据我所知,就我所测试的问题而言,它不应该像你说的那样工作

我逐字记录了您的代码,创建了文件grammar.ylexer.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;

我相信就是这样。