问题描述
我正在尝试为 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 c[]);
char quadruple_entry_loop();
char quadruple_entry_do();
void three_address_code();
int q_index = 0;
char result[3] = {'t','0','\0'};
char result2[3] = {'L','\0'};
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($1,'=',$3); }
| ID OP ID { quadruple_entry($1,$2,$3); }
;
expr : expr '+' expr { quadruple_entry($1,'+',$3); strcpy($$,temp); }
| expr '-' expr { quadruple_entry($1,'-',temp); }
| expr '/' expr { quadruple_entry($1,'/',temp); }
| expr '*' expr { quadruple_entry($1,'*',temp); }
| '(' expr ')' { strcpy($$,$2); }
| ID { strcpy($$,$1); }
;
%%
char result_gen() {
strcpy(temp,result);
result[1]++;
}
char quadruple_entry(char a[],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 c[]) {
char tempLocal[3] = {' ',' ','\0'};
strcpy(quadruple[q_index].arg1,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
条件放置的内容为赋值,而这不是您作为输入编写的内容。
在我看来,你应该分两个阶段实现这个编译器......首先尝试进行完整的语言解析(因为它是一个单独的、不相关的、完全不同的问题),一旦你让解析器做出正确的语法树(您可以尝试构建正确的语法树并打印它),一旦它工作……然后您就可以散布代码生成代码。