Bison 使用yacc将while语句从c转换为程序集
我正在尝试为一个程序编写一个yacc源文件,该程序将一个简单的while语句从C语言(比如ANSI 89)转换为汇编at&t。 下面是我的语法,yacc文件的中心部分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
%%
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的代码相同。