2009-10-07 49 views
2

我建立了裝配自己的自定義的味道簡單的組裝編譯器,我有這樣的事情作爲實際的代碼,不會編譯:更好的方法來設計這個循環?

foreach (KeyValuePair<short, string> kvp in newCommandSet) 
    { 
     string fullCommandString = kvp.Value; 

     string instruction = fullCommandString.Split(new char[] { Convert.ToChar(" ") })[0]; 
     string[] parameters = fullCommandString.Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries); 
     // this is to remove the instruction part from the first parameter. Gonna have to ensure a well formed command at some point... 
     parameters[0] = parameters[0].Substring(instruction.Length + 1); 
     Command currentCommand = new Command(); 
     switch (instruction) 
     { 
      case "load": 
       short value = Convert.ToInt16(instruction[0]); 
       byte register = Convert.ToByte(parameters[1]); 
       currentCommand = CommandFactory.CreateLoadCommand(register, value); 
       break; 
      case "input": 
       byte channel = Convert.ToByte(parameters[0]); 
       register = Convert.ToByte(parameters[1]); 
       currentCommand = CommandFactory.CreateInputCommand(register, channel); 
       break; 
      case "output": 
       channel = Convert.ToByte(parameters[0]); 
       register = Convert.ToByte(parameters[1]); 
       currentCommand = CommandFactory.CreateInputCommand(register, channel); 
       break; 
      ... 
     } 
     ... 
    } 

感覺就像我打破約半這裏有十幾個設計規則(重複使用變量和期待合格的輸入是唯一可以發現的,但我敢打賭還有更多),但不知道如何更好地構建它。想法?

回答

5

考慮將解釋參數的邏輯推送到CommandFactory中。 switch語句如下所示:

switch(instruction) 
{ 
    case "load": 
     currentCommand = CommandFactory.CreateLoadCommand(parameters); 
     break; 
    case "input": 
     currentCommand = CommandFactory.CreateInputCommand(parameters); 
     break; 
    case "output": 
     currentCommand = CommandFactory.CreateOutputCommand(parameters); 
     break; 
} 
+0

那麼你是否也提供了可以解析字符串參數的CommandFactory函數的重載?我喜歡.... – RCIX 2009-10-07 10:02:40

4

你可能會考慮把一些東西扔在一個標記器中,它將你的程序作爲一串標記返回(你的分離器是這樣做的)。然後將其傳遞給解析器以創建解析樹和符號表。爲什麼?因爲如果不知道你的裝配風格,在某些時候你會想要跳轉到一個標籤(子程序),我會假設。或者你會希望你的跳轉指令回到開始的循環等...

如果你有你的分析樹和符號表設置,你將有所有的地址在那裏,方便插入到你的輸出文件。我寫了一個編譯器已經很長時間了,所以請原諒我小示例中的任何偏差...

+0

其實我跟以前只是一個代碼聰明一點,產生一個「跳圖」來了,這樣我就可以發出跳轉地址到我的字節碼,而不是當前的標籤。 – RCIX 2009-10-07 09:09:54

+0

雖然如果你可以指向我的一些圖書館/資源的這些東西(tokenizer,解析器),這將是很好的... – RCIX 2009-10-07 09:14:46

+0

對不起,不太熟悉.NET。既然你在這裏編寫一個非常原始的程序,你沒有理由不能自己創建。類似這樣的: 將循環拉出到「Tokenizer」類中 將所有內部代碼從您的case語句中拉出,然後返回一個常量作爲「標記」,當然,請明確定義您的常量。 解析器: 一次帶入1個令牌。跟蹤你的各種狀態(開始循環,在循環中,在子程序中啓動子程序),你應該有一個簡單的語法,即使是你的彙編語言,所以只需在分析器中寫出每個案例和組。 – Zak 2009-10-07 09:24:12

0

將指令信息移動到類/屬性包中。創建一些實用的轉換方法,讓您的生活更輕鬆。然後使用字符串 - >委託字典將指令名稱映射到創建命令。這只是一個開始,你可以重構這個簡單得多。

東西沿着這些路線,也許是:

public class InstructionData 
{ 
    public InstructionData(string fullCommandString) 
    { 
     string[] commandParts = fullCommandString.Split(new char[] {' ', ','}, StringSplitOptions.RemoveEmptyEntries); 
     this.InstructionName = commandParts[0]; 
     this.parameters = commandParts.Skip(1).ToArray(); 
    } 

    public string InstructionName { get; private set; } 
    public short InstructionInt { get { return Convert.ToInt16(InstructionName[0]); } } 
    private string[] parameters; 
    public string GetParameter(int paramNum) 
    { 
     return parameters[paramNum]; 
    } 
    public byte GetParameterAsByte(int paramNum) 
    { 
     return Convert.ToByte(parameters[paramNum]); 
    } 
} 


public class SomeClass 
{ 
    // ... 
    private Dictionary<string, Func<InstructionData, Command>> commandTranslator = new Dictionary<string, Func<InstructionData, Command>>(); 

    private static void InitializeCommandTranslator() 
    { 
     commandTranslator["load"] = ins => CommandFactory.CreateLoadCommand(ins); 
     commandTranslator["input"] = ins => CommandFactory.CreateInputCommand(ins); 
     commandTranslator["output"] = ins => CommandFactory.CreateOutputCommand(ins); 

    } 

    public void SomeMethod() 
    { 
    // ... 
     foreach (KeyValuePair<short, string> kvp in newCommandSet) 
     { 
     InstructionData currentInstruction = new InstructionData(kvp.Value); 

      if(commandTranslator.ContainsKey(currentInstruction.InstructionName)) 
      { 
       currentCommand = commandTranslator[currentInstruction.InstructionName](currentInstruction); 
      } 
     } 
    } 

    // ... 
} 
相關問題