0

我正在尝试为一个程序编写一个 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;}     
%%

我的问题是:我应该使用哪种函数来连接最终字符串的值?或者我应该使用哪种数据类型、结构、联合等?提前感谢您的答案。

4

2 回答 2

1

唔。
据我了解您的语法,您刚开始使用 yacc。为此,这还不错,所以我只给你一些提示如何继续
...... 您知道,目前您的所有表达式只能是常量,因为您在编译时评估它们,例如您在 plus-case 中编写{$$ = $1 + $3},并且在 yacc 运行时评估此表达式。如果您希望在运行时对其进行评估,则需要发出正确的汇编程序指令{emit ("add", allocReg(), $1, $3);},例如这个要编写的函数emit在开始时可能只期望在$1and中的寄存器名称$3
湾。然后,如果您要更改数字案例中的操作以将数字加载到寄存器中(您需要为此做一些内务处理),也就是说,数字的操作将是

{reg=allocReg();
 emit ("mov", reg, $$);
}

(当然,当它们不再使用时,您需要释放所有已分配的寄存器,例如在它们作为加法在加法运算中使用之后)。
C。在您可以根据条件进行跳转之前,您需要发出一些比较指令。比较,例如cmp $1, $3
d. 使用 yacc 时,您通过将数据分配给 $$ 来“向上”传输数据,并使用其他规则生成的 $1...$n。这些数据可以有不同的类型,具体取决于规则。因此,您为此使用联合的想法是一种方法(所有内容都在您的语法文件中):

typedef union {
  int                number;
  char               singleChar;
  VarName            *var;
  ...
} dataVariant;
#undef YYSTYPE
#define YYSTYPE dataVariant

有了这个,你可以在你的语法中写出类似 $$.number=$1.number 的东西。yacc 里面还有一个 %union-construct 更舒服,你可以在那里读到一些关于它的东西:Lex and YACC prime

于 2012-12-01T18:19:32.217 回答
1

好吧,对于一个while循环,你想要的是这样的:

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你用来从一堆其他字符串中构建字符串的东西在哪里。

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

于 2012-12-02T01:52:44.213 回答