0

単純な while ステートメントを C 言語 (ANSI 89 としましょう) からアセンブリ at&t に変換するプログラムの yacc ソース ファイルを作成しようとしています。以下は私の文法であり、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を使い始めたばかりです。そのため、悪くはないので、先に進むためのヒントをいくつか紹介します
。コンパイル時に式を評価しているため、現在はすべての式が定数であることに注意してください。たとえば、プラスの場合{$$ = $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を使用します。このデータは、ルールに応じてさまざまなタイプを持つことができます。したがって、そのためにユニオンを使用するというあなたのアイデアは、それを行う方法です(すべてが文法ファイルのどこかにあります):

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

これを使用すると、$$。number =$1.numberのような文法を書くことができます。yaccの中には%union-constructもあり、より快適です。そこで何かを読むことができます:LexとYACC入門書

于 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:"); }

whereconcatenateは、他の文字列の束から文字列を作成するために使用しているものです。

これは、文字列を連結してアセンブリ コードを構築していると仮定しています (これは、疑似コードから実行しようとしているように見えます)。また、複数のループを許可する場合は、'固定文字列を使用するのではなく、それぞれに使用する一意のラベルを作成する必要があります。

于 2012-12-02T01:52:44.213 に答える