3

現在のアプローチでは、対応するコードを生成する前に子の実際のタイプをチェックするために複数の条件ステートメントを使用する必要があるため、ビジターパターンを使用するようにコンパイラのコードジェネレータを変更したいと思います。ただし、訪問後に子の属性を取得するのに問題があります。たとえば、バイナリ式では次のように使用します。

LHSCode := GenerateExpressionCode(LHSNode);
RHSCode := GenerateExpressionCode(RHSNode);
CreateBinaryExpression(Self,LHS,RHS);

ビジターパターンでは、visitメソッドは通常無効であるため、LHSおよびRHSから式コードを取得できません。式コードの生成は再帰的であり、変数に保持されている以前の値を消去する可能性があるため、共有グローバル変数を保持することはオプションではありません。

これは(今のところ)最も複雑な部分であるため、バイナリ式を示します。

function TLLVMCodeGenerator.GenerateExpressionCode(
  Expr: TASTExpression): TLLVMValue;
var
  BinExpr: TASTBinaryExpression;
  UnExpr: TASTUnaryExpression;
  LHSCode, RHSCode, ExprCode: TLLVMValue;
  VarExpr: TASTVariableExpression;
begin
  if Expr is TASTBinaryExpression then begin
    BinExpr := Expr as TASTBinaryExpression;
    LHSCode := GenerateExpressionCode(BinExpr.LHS);
    RHSCode := GenerateExpressionCode(BinExpr.RHS);
    case BinExpr.Op of
      '<': Result := FBuilder.CreateICmp(ccSLT, LHSCode, RHSCode);
      '<=': Result := FBuilder.CreateICmp(ccSLE, LHSCode, RHSCode);
      '>': Result := FBuilder.CreateICmp(ccSGT, LHSCode, RHSCode);
      '>=': Result := FBuilder.CreateICmp(ccSGE, LHSCode, RHSCode);
      '==': Result := FBuilder.CreateICmp(ccEQ, LHSCode, RHSCode);
      '<>': Result := FBuilder.CreateICmp(ccNE, LHSCode, RHSCode);
      '/\': Result := FBuilder.CreateAnd(LHSCode, RHSCode);
      '\/': Result := FBuilder.CreateOr(LHSCode, RHSCode);
      '+': Result := FBuilder.CreateAdd(LHSCode, RHSCode);
      '-': Result := FBuilder.CreateSub(LHSCode, RHSCode);
      '*': Result := FBuilder.CreateMul(LHSCode, RHSCode);
      '/': Result := FBuilder.CreateSDiv(LHSCode, RHSCode);
    end;
  end else if Expr is TASTPrimaryExpression then
    if Expr is TASTBooleanConstant then
      with Expr as TASTBooleanConstant do
        Result := FBuilder.CreateConstant(Ord(Value), ltI1)
    else if Expr is TASTIntegerConstant then
      with Expr as TASTIntegerConstant do
        Result := FBuilder.CreateConstant(Value, ltI32)
    else if Expr is TASTUnaryExpression then begin
      UnExpr := Expr as TASTUnaryExpression;
      ExprCode := GenerateExpressionCode(UnExpr.Expr);
      case UnExpr.Op of
        '~': Result := FBuilder.CreateXor(
            FBuilder.CreateConstant(1, ltI1), ExprCode);
        '-': Result := FBuilder.CreateSub(
            FBuilder.CreateConstant(0, ltI32), ExprCode);
      end;
    end else if Expr is TASTVariableExpression then begin
      VarExpr := Expr as TASTVariableExpression;
      with VarExpr.VarDecl do
        Result := FBuilder.CreateVar(Ident, BaseTypeLLVMTypeMap[BaseType]);
    end;
end;

あなたがそれを理解することを願っています:)

4

1 に答える 1

4

ビジターパターンでは、visitメソッドは通常無効であるため、LHSおよびRHSから式コードを取得できません。式コードの生成は再帰的であり、変数に保持されている以前の値を消去する可能性があるため、共有グローバル変数を保持することはオプションではありません。

子属性にアクセスしたときに子属性を取得し、必要な属性を保持し、必要なときに子属性を保持していることを確認する必要があります。それはあなたの訪問者の内部構造をもう少し複雑にするかもしれません、しかしそれは確かに実行可能です。コード生成は間違いなくVisitorパターンの一般的な使用法です。

通常、属性を保持する必要はありませんが、中間結果を保持し、他のオブジェクトへのアクセスでそれらを他の中間結果に結合する必要があります。これはここに当てはまると思いますが、相互作用は少し混乱するほど複雑です。

私はObjectPascalの専門家ではないので、実際のコードを書くのではなく、それをどのように処理するかを説明します。

この場合、おそらく中間結果を保持するスタックを使用します。

トラバーサル順序は、ノードのacceptメソッド、ビジターのvisitメソッド、または外部イテレーターで駆動できます。簡単にするために、acceptメソッドでそれを想定します。

単純なオブジェクトのacceptメソッドでは、単純に標準を実行しますvisitor.visit(this)(ただし、Object Pascalでそれを言います)。

あなたのような単純なオブジェクトのvisitメソッドではTASTBooleanConstant、適切なメソッドを呼び出します。この場合FBuilder.CreateConstant、オブジェクトからプルした値を使用して、そのメソッドの結果を訪問者のスタックにプッシュします。

のようなより複雑なオブジェクトのacceptメソッドでは、TASTBinaryExpression最初に子に対してacceptメソッドを呼び出し、次に標準を実行しvisitor.visit(this)て、子が最初に訪問されるようにします。

次に、子が最初に訪問されたため、複雑なオブジェクトのvisitメソッドが呼び出されたときに、子の結果がスタックにあるはずです。FBuilder.CreateXxxそのvisitメソッドでは、適切な結果をスタックからローカル変数にポップし、使用している演算子に基づいて適切なメソッドを呼び出し、それらの値をパラメーターとして渡して、結果をスタックに配置します。

オブジェクトのTASTUnaryExpression場合も同様ですが、acceptメソッドで心配する子は1つだけであり、スタックからポップしてvisitメソッドで使用する中間結果は1つだけです。

クライアントコードで、ビジターを作成し、ビジターを引数として渡すトップノードのacceptメソッドを呼び出します。すべての再帰が完了した後、スタックには最終結果のみが含まれる必要があり、ビジタークラスはgetResult、クライアントがそれを取得できるようにするメソッドを提供する必要があります。

申し訳ありませんが、これは非常に時間がかかります-コードではより明確かもしれませんが、うまくいけば、これはこれに対処する方法のアイデアをあなたに与えるでしょう。

このような既存のコードにパターンを導入するためのリファクタリングの方法を学ぶための優れたリソースは、JoshuaKerievskyの著書「RefactoringtoPatterns」です。

于 2011-01-14T12:36:56.003 に答える