2013-10-31 9 views
5

私は学校プロジェクトのためにC#でコンパイラーをやっています。どうすればいいのか不思議に思って止めることはできません。そのHaskellの。例えばHaskellでコンパイラを書くには? C#で私は多くの状態を使用しています

:あなたが、私は方法の非常に中央でjumpToTheEndのコードを挿入する方法を見ることができます

public override void generateCode(Compiler compiler) 
    { 
     int jumpToTheBeginningInstructionIndex = compiler.getIndexOfNextActionInCurrentFunction(); 
     MachineInstructions.JMP jumpTotheBeginning = new MachineInstructions.JMP(jumpToTheBeginningInstructionIndex); 
     MachineInstructions.JMPF jumpToTheEnd = new MachineInstructions.JMPF(); 

     booleanExpression.generateCode(compiler); 

     //I insert the jump to the end here: 
     compiler.addAction(jumpToTheEnd); 

     foreach(IAction action in this.thenActions) 
     { 
      action.generateCode(compiler); 
     } 
     compiler.addAction(jumpTotheBeginning); 

     //...But is here where I know where should it jump to: 
     jumpToTheEnd.whereToJump = compiler.getIndexOfNextActionInCurrentFunction(); 
    } 

、しかしまでではありません。

Whileループのための私のコード生成があります私がジャンプがジャンプする行を知っている終わり。幸いにも、私はそのジャンプへのポインタを保持し、メソッドの最後にwhereToJump属性を簡単に設定できます。

ハスケルではどうしますか? お勧めチュートリアル?

+0

単純な方法の1つは、関数の構造化テーブルを作成し、それを順番に呼び出すことです(HOFを展開する)。 –

+0

ここに興味のある読書がありますhttp://en.wikibooks.org/wiki/Write_Yourself_a_Scheme_in_48_Hours –

+1

@PedroRodriguesこれはインターピターであり、質問の主題であるコードジェニック段階が欠けています – jozefg

答えて

8

I dunno。私はHaskellでこれと同じようにcode-genフェーズを構造化したいとは思っていません。しかし、あなたがしたことを前提に、あなたのラベルを怠けた状態のモナドとtie the knotに入れて、mfixを使ってラベルを貼ることができます。

このテクニックの完全な実行可能な例を次に示します。 whileループと何もしないステートメントだけで簡単なASTができます。ラベル、ジャンプ、および何もしないステートメントだけの単純な命令タイプです。私たちのコンパイラは、いくつかの状態で最新の割り当てられたラベルを維持します。それから私はあなたの質問は、まだ割り当てられていないラベルに "前方"ジャンプを生成する方法であると思う。

{-# LANGUAGE FlexibleContexts #-} 
import Control.Monad.State 
import Control.Monad.Writer 

data Instruction = Nop | Jump Int | Label Int deriving (Eq, Ord, Show, Read) 
data AST = While AST AST | Rest    deriving (Eq, Ord, Show, Read) 
type Compiler = StateT Int (Writer [Instruction]) 

generateLabel :: Compiler Int 
generateLabel = do 
    v <- get 
    put (v+1) 
    tell [Label v] 
    return v 

compile :: AST -> Compiler() 
compile Rest = tell [Nop] 
compile (While b c) = do 
    start <- generateLabel 
    compile b 
    mfix $ \end -> do 
     tell [Jump end] -- here we generate a forward jump 
     compile c 
     tell [Jump start] 
     generateLabel -- here we allocate the label we're forward-jumping to 
    return() 

runCompiler :: Compiler() -> [Instruction] 
runCompiler = execWriter . flip evalStateT 0 

ghciでは、最も簡単な例として、runCompiler (compile (While Rest Rest))を試してください。

+0

あなたはどうしますかコードジェン? –

関連する問題