WHILE 循环和语句的 YACC 语法不起作用
YACC grammar for WHILE loop and statements wouldn't work
我正在尝试为 while 循环和一般语句生成以下语法的中间代码,但我一直遇到语法错误。虽然早些时候,语句和表达式的语法可以工作,但是在添加了 while 循环的产生式之后,这个程序就不能工作了。
这是我的 lex.l 文件
%{
#include "y.tab.h"
%}
NUMBER [0-9]
ALPHABET [a-zA-Z]
%%
[\t];
{NUMBER}+ { strcpy(yylval.str, yytext); return ID; }
{ALPHABET} { strcpy(yylval.str, yytext); return ID; }
"while" { return WHILE; }
"do" { return DO; }
"<" { yylval.symbol=yytext[0]; return OP; }
">" { yylval.symbol=yytext[0]; return OP; }
"!=" { yylval.symbol=yytext[0]; return OP; }
"==" { yylval.symbol=yytext[0]; return OP; }
[\n];
. { return yytext[0]; }
%%
这是我的 yacc.y 文件
%{
#include <stdio.h>
#include <string.h>
char result_gen();
char quadruple_entry(char a[], char b, char c[]);
char quadruple_entry_assign(char a[], char b, char c[]);
char quadruple_entry_loop();
char quadruple_entry_do();
void three_address_code();
int q_index = 0;
char result[3] = {'t','0','[=11=]'};
char result2[3] = {'L','0','[=11=]'};
char temp[3];
char temp2[3];
struct QuadrupleStructure {
char arg1[10];
char op;
char arg2[10];
char rslt[3];
}quadruple[25];
%}
%union {
char str[10];
char symbol;
}
%token WHILE DO
%token <str> ID
%token <symbol> OP
%type <str> expr
%right '='
%left '+' '-'
%left '/' '*'
%%
wstmt : WHILE { quadruple_entry_loop(); } stmt DO { quadruple_entry_do(); }
;
stmt : ID '=' expr { quadruple_entry_assign(, '=', ); }
| ID OP ID { quadruple_entry(,,); }
;
expr : expr '+' expr { quadruple_entry(, '+', ); strcpy($$,temp); }
| expr '-' expr { quadruple_entry(, '-', ); strcpy($$,temp); }
| expr '/' expr { quadruple_entry(, '/', ); strcpy($$,temp); }
| expr '*' expr { quadruple_entry(, '*', ); strcpy($$,temp); }
| '(' expr ')' { strcpy($$,); }
| ID { strcpy($$,); }
;
%%
char result_gen() {
strcpy(temp,result);
result[1]++;
}
char quadruple_entry(char a[], char b, char c[]) {
result_gen();
strcpy(quadruple[q_index].arg1, a);
quadruple[q_index].op = b;
strcpy(quadruple[q_index].arg2, c);
strcpy(quadruple[q_index].rslt, temp);
q_index++;
}
char quadruple_entry_assign(char a[], char b, char c[]) {
char tempLocal[3] = {' ',' ','[=11=]'};
strcpy(quadruple[q_index].arg1, a);
quadruple[q_index].op = b;
strcpy(quadruple[q_index].arg2, c);
strcpy(quadruple[q_index].rslt, tempLocal);
q_index++;
}
char quadruple_entry_loop() {
char tempLocal[3];
strcpy(tempLocal, result2);
char tempLocal2[] = " if ";
char tempLocal3 = ' ';
char tempLocal4[] = " ";
strcpy(quadruple[q_index].rslt, tempLocal);
strcpy(quadruple[q_index].arg1, tempLocal4);
quadruple[q_index].op = tempLocal3;
strcpy(quadruple[q_index].arg2, tempLocal2);
q_index++;
}
char quadruple_entry_do() {
char tempLocal[4];
strcpy(tempLocal, result2);
tempLocal[3] = ':';
strcpy(quadruple[q_index].arg1,tempLocal);
char tempLocal2[] = " ";
char tempLocal3 = ' ';
quadruple[q_index].op = tempLocal3;
strcpy(quadruple[q_index].arg2, tempLocal2);
q_index++;
result2[1]++;
char tempLocal4[4];
strcpy(tempLocal4, result2);
tempLocal4[3] = ':';
strcpy(quadruple[q_index].arg1,tempLocal4);
char tempLocal5[] = " ";
char tempLocal6 = ' ';
quadruple[q_index].op = tempLocal6;
strcpy(quadruple[q_index].arg2, tempLocal5);
q_index++;
result2[1]++;
}
void three_address_code() {
int i;
for(i=0 ; i<q_index ; i++)
printf("\n%s := %s %c %s", quadruple[i].rslt, quadruple[i].arg1, quadruple[i].op, quadruple[i].arg2);
}
void yyerror(char *s){
printf("Errror %s",s);
}
int yywrap() {
return 1;
}
int main() {
yyparse();
three_address_code();
return 0;
}
输入:
i=2*5-10
while i<5 do
输出:
Errror syntax error
如果有人能找出语法错误的地方,或者我的代码是错误的,那将非常有帮助。
您的起始符号是 wstmt
,因此程序接受单个 while 语句作为输入。如果需要接受语句序列,则需要一个扩展为语句序列的符号作为起始符号。
此外,您的词法分析器不会吞噬空格,因此任何包含空格的程序都会出错。
在我看来,你的规则
wstmt : WHILE { quadruple_entry_loop(); } stmt DO { quadruple_entry_do(); }
;
错了。由于您的 stmt
仅考虑赋值表达式,因此您应该在表达式中包含 stmt
以使语法有效。
你的 wstmt
的语法规则是:
wstmt : WHILE stmt DO ;
你应该把它改成:
wstmt : WHILE expr DO stmt ;
正确输出代码的精确点应该是:
wstmt: WHILE {
/* get a new label and place it at
* this point, you'll need to jump
* here, push the label name in a
* stack */
}
expr {
/* include code here to evaluate
* (probably you do it inside expr */
}
DO {
/* get a new label but don't place it
* yet, and push it's name in the
* stack */
}
stmt {
/* a jump to the first label you
* pushed (the one that is already
* placed), then emit code for the
* second label (the one that is not
* placed yet */
};
(并且您还应该包括使用 <
和 >
的可能性以及在 expr
语法中评估布尔运算符)
stmt
非终结符强制将您作为 while
条件输入的内容作为赋值,而这不是您作为输入编写的内容。
以我的愚见,你应该分两个阶段实现这个编译器....首先尝试进行完整的语言解析(因为它是一个单独的、不相关的、完全不同的问题),一旦你有了解析器制作正确的语法树(你可以尝试构建正确的语法树并打印它),一旦你让它工作......然后你可以穿插代码生成代码。
我正在尝试为 while 循环和一般语句生成以下语法的中间代码,但我一直遇到语法错误。虽然早些时候,语句和表达式的语法可以工作,但是在添加了 while 循环的产生式之后,这个程序就不能工作了。
这是我的 lex.l 文件
%{
#include "y.tab.h"
%}
NUMBER [0-9]
ALPHABET [a-zA-Z]
%%
[\t];
{NUMBER}+ { strcpy(yylval.str, yytext); return ID; }
{ALPHABET} { strcpy(yylval.str, yytext); return ID; }
"while" { return WHILE; }
"do" { return DO; }
"<" { yylval.symbol=yytext[0]; return OP; }
">" { yylval.symbol=yytext[0]; return OP; }
"!=" { yylval.symbol=yytext[0]; return OP; }
"==" { yylval.symbol=yytext[0]; return OP; }
[\n];
. { return yytext[0]; }
%%
这是我的 yacc.y 文件
%{
#include <stdio.h>
#include <string.h>
char result_gen();
char quadruple_entry(char a[], char b, char c[]);
char quadruple_entry_assign(char a[], char b, char c[]);
char quadruple_entry_loop();
char quadruple_entry_do();
void three_address_code();
int q_index = 0;
char result[3] = {'t','0','[=11=]'};
char result2[3] = {'L','0','[=11=]'};
char temp[3];
char temp2[3];
struct QuadrupleStructure {
char arg1[10];
char op;
char arg2[10];
char rslt[3];
}quadruple[25];
%}
%union {
char str[10];
char symbol;
}
%token WHILE DO
%token <str> ID
%token <symbol> OP
%type <str> expr
%right '='
%left '+' '-'
%left '/' '*'
%%
wstmt : WHILE { quadruple_entry_loop(); } stmt DO { quadruple_entry_do(); }
;
stmt : ID '=' expr { quadruple_entry_assign(, '=', ); }
| ID OP ID { quadruple_entry(,,); }
;
expr : expr '+' expr { quadruple_entry(, '+', ); strcpy($$,temp); }
| expr '-' expr { quadruple_entry(, '-', ); strcpy($$,temp); }
| expr '/' expr { quadruple_entry(, '/', ); strcpy($$,temp); }
| expr '*' expr { quadruple_entry(, '*', ); strcpy($$,temp); }
| '(' expr ')' { strcpy($$,); }
| ID { strcpy($$,); }
;
%%
char result_gen() {
strcpy(temp,result);
result[1]++;
}
char quadruple_entry(char a[], char b, char c[]) {
result_gen();
strcpy(quadruple[q_index].arg1, a);
quadruple[q_index].op = b;
strcpy(quadruple[q_index].arg2, c);
strcpy(quadruple[q_index].rslt, temp);
q_index++;
}
char quadruple_entry_assign(char a[], char b, char c[]) {
char tempLocal[3] = {' ',' ','[=11=]'};
strcpy(quadruple[q_index].arg1, a);
quadruple[q_index].op = b;
strcpy(quadruple[q_index].arg2, c);
strcpy(quadruple[q_index].rslt, tempLocal);
q_index++;
}
char quadruple_entry_loop() {
char tempLocal[3];
strcpy(tempLocal, result2);
char tempLocal2[] = " if ";
char tempLocal3 = ' ';
char tempLocal4[] = " ";
strcpy(quadruple[q_index].rslt, tempLocal);
strcpy(quadruple[q_index].arg1, tempLocal4);
quadruple[q_index].op = tempLocal3;
strcpy(quadruple[q_index].arg2, tempLocal2);
q_index++;
}
char quadruple_entry_do() {
char tempLocal[4];
strcpy(tempLocal, result2);
tempLocal[3] = ':';
strcpy(quadruple[q_index].arg1,tempLocal);
char tempLocal2[] = " ";
char tempLocal3 = ' ';
quadruple[q_index].op = tempLocal3;
strcpy(quadruple[q_index].arg2, tempLocal2);
q_index++;
result2[1]++;
char tempLocal4[4];
strcpy(tempLocal4, result2);
tempLocal4[3] = ':';
strcpy(quadruple[q_index].arg1,tempLocal4);
char tempLocal5[] = " ";
char tempLocal6 = ' ';
quadruple[q_index].op = tempLocal6;
strcpy(quadruple[q_index].arg2, tempLocal5);
q_index++;
result2[1]++;
}
void three_address_code() {
int i;
for(i=0 ; i<q_index ; i++)
printf("\n%s := %s %c %s", quadruple[i].rslt, quadruple[i].arg1, quadruple[i].op, quadruple[i].arg2);
}
void yyerror(char *s){
printf("Errror %s",s);
}
int yywrap() {
return 1;
}
int main() {
yyparse();
three_address_code();
return 0;
}
输入:
i=2*5-10
while i<5 do
输出:
Errror syntax error
如果有人能找出语法错误的地方,或者我的代码是错误的,那将非常有帮助。
您的起始符号是 wstmt
,因此程序接受单个 while 语句作为输入。如果需要接受语句序列,则需要一个扩展为语句序列的符号作为起始符号。
此外,您的词法分析器不会吞噬空格,因此任何包含空格的程序都会出错。
在我看来,你的规则
wstmt : WHILE { quadruple_entry_loop(); } stmt DO { quadruple_entry_do(); }
;
错了。由于您的 stmt
仅考虑赋值表达式,因此您应该在表达式中包含 stmt
以使语法有效。
你的 wstmt
的语法规则是:
wstmt : WHILE stmt DO ;
你应该把它改成:
wstmt : WHILE expr DO stmt ;
正确输出代码的精确点应该是:
wstmt: WHILE {
/* get a new label and place it at
* this point, you'll need to jump
* here, push the label name in a
* stack */
}
expr {
/* include code here to evaluate
* (probably you do it inside expr */
}
DO {
/* get a new label but don't place it
* yet, and push it's name in the
* stack */
}
stmt {
/* a jump to the first label you
* pushed (the one that is already
* placed), then emit code for the
* second label (the one that is not
* placed yet */
};
(并且您还应该包括使用 <
和 >
的可能性以及在 expr
语法中评估布尔运算符)
stmt
非终结符强制将您作为 while
条件输入的内容作为赋值,而这不是您作为输入编写的内容。
以我的愚见,你应该分两个阶段实现这个编译器....首先尝试进行完整的语言解析(因为它是一个单独的、不相关的、完全不同的问题),一旦你有了解析器制作正确的语法树(你可以尝试构建正确的语法树并打印它),一旦你让它工作......然后你可以穿插代码生成代码。