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 条件输入的内容作为赋值,而这不是您作为输入编写的内容。

以我的愚见,你应该分两个阶段实现这个编译器....首先尝试进行完整的语言解析(因为它是一个单独的、不相关的、完全不同的问题),一旦你有了解析器制作正确的语法树(你可以尝试构建正确的语法树并打印它),一旦你让它工作......然后你可以穿插代码生成代码。