私にできることは、著者 (Appel) の IR ツリー言語のルールを読むことだけです。
文法の場合:
<ADDEXPR> ::= <EXPR> + <EXPR>
<EXPR> ::= IDENTIFIER
| LITERAL
AST ツリーは次のようになります。
BINOPEXPR(+, EXPR(IDENTIFIER(k)), EXPR(LITERAL(1)))
または、IdentifierExpression と LiteralExpression が含まれている可能性があるため、次のようになります。
BINOPEXPR(+, IDENT_EXPR(k), LITERAL_EXPR(1))
しかし、AST と IR ツリーは別物です。したがって、Appel の本によると、C バージョンのセクション 7.1 には次のように記載されています。
NAME(n) = アセンブリ言語ラベルに対応するサンボリック定数 n。
MEM(e) = アドレス e から始まるメモリの wordSize バイトの内容。MEM() が MOVE() の左の子として使用される場合、それは「ストア」を意味しますが、それ以外の場合は「フェッチ」を意味します。
LABEL(n) = 名前 n の定数値を現在のマシン コード アドレスとして定義します。これは、アセンブリ言語でのラベル定義のようなものです。値 NAME(n) は、ジャンプ、呼び出しなどのターゲットになる場合があります。
彼のルールを考えると、NAME() は変数 k に必要なものではなく、name はコード ラベルに使用されます。
彼の読みに基づく私の推測では、k が変数であり、この場合は r 値である場合、単純に MEM(e) を使用しますが、e はローカル変数 (ローカル スタック フレーム内) またはグローバル変数、または一時的な変数です。したがって、「k + 1」の変換は、「k」がどこに割り当てられているかによって異なります。ローカル スタック フレームにある場合、k は次のとおりです。
MEM(BINOP(+, TEMP fp, CONST (address of k)))
したがって、k + 1 は次のようになります。
BINOP(+, MEM(BINOP(+, TEMP fp, CONST (address of k))), 1)
そのため、変数にストレージを割り当てる方法を明確にする必要があります。これは、識別子のシンボル テーブルにあります。
私は少なくとも 20 冊のコンパイラの本を持っていますが、正直なところ、Appel の本はわかりにくく、いくつかの点で簡潔すぎると思います。彼は、学生が従わないような概念的な跳躍を行い、場所によってはもう少し精緻化することができます。私は実際に IR ツリーを実装したことがないので (私は常に、さまざまなスコープの変数の宣言とシンボリック一時変数の両方をアセンブラーがサポートするテキスト中間言語に書き込んでいます)、彼が何を意味しているのかはっきりとは言えません。そのため、教授に確認することをお勧めします。彼はおそらく以前にその本で教えたことがあり、それをよりよく知っているかもしれません.
それが役立つことを願っています。