BISON 和 YACC - 如何输入完整的语句
BISON and YACC - How to input a complete statement
这是我第一次尝试 BISON,我一直在努力弄清楚如何获取完整的语句,例如 astros = 2
。每当我尝试这样做时,我都没有得到任何输出。但是如果我分别尝试每个部分,那么我会得到每个部分的输出。我的代码如下,当然只是其中的一部分:
.y 文件
%token ASSIGNMENT
%token <intToken> INTNUMBER
%token <intToken> INTTOKEN
%type <statement> STATEMENT
STATEMENT: '\n'
| INTTOKEN STATEMENT {printf("Token");}
| INTNUMBER STATEMENT {printf("Number");}
| STATEMENT ASSIGNMENT STATEMENT{printf("Assinging");}
| INTTOKEN '\t' ASSIGNMENT '\t' INTNUMBER STATEMENT {printf("FULL STATEMENT COMPLETE");}
|error {yyerror("ERROR");}
我的 .l 文件:
"=" return ASSIGNMENT;
[0-9]+ { ECHO; yylval.integer = atoi(yytext); return INTNUMBER; }
[a-fA-F]+[a-zA-Z]+ { ECHO; yylval.variableInteger = yytext; return INTTOKEN; }
此外,如果有人可以向我解释代币规则的工作原理,那就太好了。也许那样我可以自己想出来。
规则很简单,Lex 依次搜索正则表达式、匹配标记并将它们交给Yacc。为此,Yacc 使用 yylex()
函数。
你的问题不完整。 Yacc 文件中还有其他内容吗?
yacc文件由三部分组成:
- C 代码稍后位于 y.tab.c 文件(由 Yacc 生成)开始附近的某个位置,在文件的这一部分您需要声明
extern int yylex(void)
函数。 Yacc 实际上需要两件事才能工作,第一个是 yylex()
,第二个是 yyerror()
。
第二部分是语法规则和动作
第三部分是调用 yyparse() 的主要函数。
至于标记和类型的声明,可以在文件的 %{ %}
部分之前或之后完成。一些基本的 Yacc 代码如下所示:
%{
#include <stdio.h>
#include ...
/* Extern keyword is just good practice, it doesn't have to be written */
extern int yylex(void);
void yyerror(char *string){
fprintf(stderr,"Syntax error: %s", string);
exit(EXIT_FAILURE);
}
%}
%%
/* Grammar with actions */
%%
int main(){
yyparse();
return 0;
}
那么这是如何工作的呢? Yacc 使用 yylex()
函数来获取标记,然后使用他的语法来确定其他所有内容。为了使其工作,您必须将使用 flex 生成的 lex.yy.c
和使用 yacc 生成的 y.tab.c
编译为目标文件,然后将这两个目标文件编译为一个可执行文件。
例如:
yacc program.y
flex program.lex
gcc -c y.tab.c -o y.tab.o
gcc -c lex.yy.c -o lex.yy.o
gcc y.tab.o lex.yy.o -o program
注意: 如果你在 Yacc
文件中声明标记,你需要在 运行 Yacc 命令时生成 y.tab.h
文件yacc -d program.y
然后将此文件包含在您的 Lex 中。选项 -d 就是为了这个。
这是我第一次尝试 BISON,我一直在努力弄清楚如何获取完整的语句,例如 astros = 2
。每当我尝试这样做时,我都没有得到任何输出。但是如果我分别尝试每个部分,那么我会得到每个部分的输出。我的代码如下,当然只是其中的一部分:
.y 文件
%token ASSIGNMENT
%token <intToken> INTNUMBER
%token <intToken> INTTOKEN
%type <statement> STATEMENT
STATEMENT: '\n'
| INTTOKEN STATEMENT {printf("Token");}
| INTNUMBER STATEMENT {printf("Number");}
| STATEMENT ASSIGNMENT STATEMENT{printf("Assinging");}
| INTTOKEN '\t' ASSIGNMENT '\t' INTNUMBER STATEMENT {printf("FULL STATEMENT COMPLETE");}
|error {yyerror("ERROR");}
我的 .l 文件:
"=" return ASSIGNMENT;
[0-9]+ { ECHO; yylval.integer = atoi(yytext); return INTNUMBER; }
[a-fA-F]+[a-zA-Z]+ { ECHO; yylval.variableInteger = yytext; return INTTOKEN; }
此外,如果有人可以向我解释代币规则的工作原理,那就太好了。也许那样我可以自己想出来。
规则很简单,Lex 依次搜索正则表达式、匹配标记并将它们交给Yacc。为此,Yacc 使用 yylex()
函数。
你的问题不完整。 Yacc 文件中还有其他内容吗?
yacc文件由三部分组成:
- C 代码稍后位于 y.tab.c 文件(由 Yacc 生成)开始附近的某个位置,在文件的这一部分您需要声明
extern int yylex(void)
函数。 Yacc 实际上需要两件事才能工作,第一个是yylex()
,第二个是yyerror()
。 第二部分是语法规则和动作
第三部分是调用 yyparse() 的主要函数。
至于标记和类型的声明,可以在文件的 %{ %}
部分之前或之后完成。一些基本的 Yacc 代码如下所示:
%{
#include <stdio.h>
#include ...
/* Extern keyword is just good practice, it doesn't have to be written */
extern int yylex(void);
void yyerror(char *string){
fprintf(stderr,"Syntax error: %s", string);
exit(EXIT_FAILURE);
}
%}
%%
/* Grammar with actions */
%%
int main(){
yyparse();
return 0;
}
那么这是如何工作的呢? Yacc 使用 yylex()
函数来获取标记,然后使用他的语法来确定其他所有内容。为了使其工作,您必须将使用 flex 生成的 lex.yy.c
和使用 yacc 生成的 y.tab.c
编译为目标文件,然后将这两个目标文件编译为一个可执行文件。
例如:
yacc program.y
flex program.lex
gcc -c y.tab.c -o y.tab.o
gcc -c lex.yy.c -o lex.yy.o
gcc y.tab.o lex.yy.o -o program
注意: 如果你在 Yacc
文件中声明标记,你需要在 运行 Yacc 命令时生成 y.tab.h
文件yacc -d program.y
然后将此文件包含在您的 Lex 中。选项 -d 就是为了这个。