Bison 使用yacc将while语句从c转换为程序集

Bison 使用yacc将while语句从c转换为程序集,bison,yacc,lex,flex-lexer,att,Bison,Yacc,Lex,Flex Lexer,Att,我正在尝试为一个程序编写一个yacc源文件,该程序将一个简单的while语句从C语言(比如ANSI 89)转换为汇编at&t。 下面是我的语法,yacc文件的中心部分 %% while_statement : 'w' 'h' 'i' 'l' 'e' '(' control_statement ')' '{' block '}' {printing of the assembly code;} control_statement : expression '>' exp

我正在尝试为一个程序编写一个yacc源文件,该程序将一个简单的while语句从C语言(比如ANSI 89)转换为汇编at&t。 下面是我的语法,yacc文件的中心部分

%%
while_statement     :   'w' 'h' 'i' 'l' 'e' '(' control_statement ')' '{'  block '}'
{printing of the assembly code;}
control_statement   :   expression '>' expression   { $$ = strcat(write exp jg back,) ;}
        |   expression '<' expression   { $$ = strcat(write exp jl back,) ;}
        |   expression '==' expression  { $$ = strcat(write exp je back,) ;}
        |   expression '<=' expression  { $$ = strcat(write exp jle back,) ;}
        |   expression '>=' expression  { $$ = strcat(write exp jge back,) ;}
        |   expression '!=' expression  { $$ = strcat(write exp jne back,) ;}
        |   expression { $$ = $1;}

block           :   expression ';'
        |   block expression ';'

expression      :       expression '+' expression   { $$ = $1 + $3;}
        |       expression '-' expression   { $$ = $1 - $3;}
        |       expression '*' expression   { $$ = $1 * $3;}
        |       expression '/' expression   { if($3 == 0)
                                yyerror("divide by zero");
                              else
                                $$ = $1 / $3;}
        |       '-' expression          { $$ = -$2;}
        |       '(' expression ')'      { $$ = $2;}
        |   string '=' expression       { create new variable called string with expression value }
        |       number              { $$ = $1;}

string          :   letter {$$ = $1;}
        |   string letter {strcat($$, ??;}

letter          :   A {strcat($$, 'A');}
        .........

number          :   digit       { $$ = $$ + $1;}
        |       number digit    { $$ = ($1 * 10) + $2;}

digit   : '0' {$$ = 0;}
| '1' {$$ = 1;} 
| '2' {$$ = 2;}
| '3' {$$ = 3;}
| '4' {$$ = 4;}
| '5' {$$ = 5;}
| '6' {$$ = 6;}
| '7' {$$ = 7;}
| '8' {$$ = 8;}
| '9' {$$ = 9;}     
%%
%%
while_语句:“w”“h”“i”“l”“e”(“控制_语句”)”{“块”}
{打印汇编代码;}
control_语句:表达式'>'表达式{$$=strcat(write exp jg back,);}
|表达式'Hmm.
据我所知,你的语法还处于使用yacc的最开始阶段。因此,这并不坏,所以我给你一些提示,告诉你如何继续…
A.您知道,当前所有表达式只能是常量,因为您是在编译时对它们求值的,例如,您使用加号形式编写
{$$=$1+$3}
,并且在yacc运行时对该表达式求值。如果希望在运行时对其进行评估,则需要发出正确的汇编指令,如
{emit(“add”,allocReg(),$1,$3);}
,其中要编写的函数
emit
一开始可能只希望寄存器名在
$1
$3

B然后,如果您要更改数字案例中的操作,将数字加载到寄存器中(您需要对其进行一些整理),也就是说,数字的操作将是

{reg=allocReg();
 emit ("mov", reg, $$);
}
(当然,当不再使用所有已分配的寄存器时,例如在加法操作中将它们用作求和之后,您需要释放它们)。
C在对条件进行跳转之前,需要发出一些比较指令。比较,例如,
cmp$1,$3

D使用yacc时,通过将数据分配给$$来“向上”传输数据,并使用其他规则生成的$1…$n。根据规则,此数据可以有不同的类型。因此,您使用union的想法就是一种实现这一点的方法(所有内容都在您的语法文件中的某个地方):


有了它,您可以在语法中编写类似$$.number=$1.number的内容。yacc内部还有一个%union构造,它更舒适,您可以在那里阅读有关它的内容:

好吧,在一段时间内,您想要的是:

start-label:
code to evaluate condition
conditional branch if-false to end-label
code for the body of the loop
unconditional branch to start-label
end-label:
while_statement: WHILE '(' condition ')' '{' block '}'
    { $$ = concatenate("start-label:", $3, "jfalse end-label", $6, "jmp start-label", "end-label:"); }
所以在伪代码中,它看起来像:

start-label:
code to evaluate condition
conditional branch if-false to end-label
code for the body of the loop
unconditional branch to start-label
end-label:
while_statement: WHILE '(' condition ')' '{' block '}'
    { $$ = concatenate("start-label:", $3, "jfalse end-label", $6, "jmp start-label", "end-label:"); }
其中,
concatenate
是用于从一组其他字符串中构建字符串的内容


这是假设您正在通过将字符串串联在一起来构建汇编代码(这似乎是您试图从伪代码中执行的操作)。此外,如果您希望允许多个循环,则需要为每个循环创建唯一的标签,不要使用固定字符串。

+1但最好将条件测试放在末尾,然后从分支开始。这样,每次迭代只有一次跳跃;此外,通过添加初始跳转,它与do/while的代码相同。