2012-01-10 37 views
0

我目前正在進行一項任務,以創建一個包含8個關鍵字(不區分大小寫)和4個算術運算符的基本解釋器。在這門語言的程序會是這個樣子(類似於BASIC的語法真的):用java編寫一個解釋器,使用多重陣列表或字符串排序器

# (signals start of a comment line) 
LET 
INTEGER 
STRING 
PRINT 
END 

所以無論如何,我目前正試圖來標記要分析的文本行。我已經將所有文本行解析爲一個ArrayList並標記了字符串。我現在的問題是,StringTokenizer預先標記所有的字符串(我使用空格作爲分隔符),當我需要的是它找到我的關鍵字,它始終是代碼行開頭的第一個字,並且某些問題使得這不合要求;我不認爲使用String.split()也會有很大的幫助。

我打算這樣做的方法是讓解釋器找到我的第一個標記,然後從那裏通過HashMap到相應的類(參考我以前關於在這裏爲我的解釋器使用switch語句的問題: Switch or if statements in writing an interpreter in java;其他成員建議我使用Map)刪除關鍵字標記並執行。設置第二個臨時ArrayList或數組來保存變量是個好主意嗎?我不想或不需要它太複雜。

在此先感謝您的建議。

public static void main (String[]args) 
    { 
     try 
     { 
      ArrayList<String> demo= new ArrayList <String>(); 
      FileReader fr= new FileReader("hi.tpl"); 
      BufferedReader reader= new BufferedReader(fr); 
      String line; 
      while ((line=reader.readLine()) !=null)//read file line by line 
       { 
        //Add to ArrayList 
        demo.add(line); 
       } 

      reader.close(); 

      boolean checkEnd= demo.contains("END");//check if arraylist contains END statement 
        if(line=null && checkEnd== false) 
         { 
          System.out.println(" Unexpected end of file: no END statement"); 
          System.exit(0); 
         } 

      ListIterator<String>arrayListIt=demo.listIterator(); 
      while (arrayListIt.hasNext()) 
      for (String file: demo)// begin interpreting the program file here 
       {    
        StringTokenizer st=new StringTokenizer(file); 
        while(st.hasMoreTokens()) 
         { 

          int firstWord=file.indexOf(); 
          String command = file; 
          if (firstSpace > 0) 
          { 
           command= file.substring(0, firstSpace); 
          } 
          TokenHandler tokens= tokens.get(command.toUpperCase()); 
          if(tokens != null) 
          { 
           tokens.execute(file); 
          } 

         } 
+0

目前尚不清楚你的問題是什麼。 – 2012-01-10 18:31:29

+0

@JBNizet我在問我是否應該考慮解析方法中的參數,或者解析所有的參數,並將其放入一個單獨的ArrayList中,這個ArrayList包含了一個擁有腳本行的ArrayList。 – Luinithil 2012-01-10 18:49:39

回答

1

所以,如果我這樣做,我會使用更多的OO方法。

如果您爲所有實現相同接口的每個命令創建了一個「類」,該怎麼辦?接口 - 我們稱之爲CommandObject將有一個execute()方法。

然後,您可以使用預先加載的映射,將「Let」這樣的命令映射到Let類的實例。

現在你的主循環變得像這樣(僞):

for(line:lineList) 
    CommandObject commandObject=map.get(line.split()[0]) // do this more clearly 
    commandObject.execute(variableHash, line) // Parse and execute the line 

這些命令對象必須共享一組變量 - 製作一個單獨的工作,但有些的反模式,我建議你將它們作爲hashmap(上面的變量hash)來代替。

這種方法的好處是添加一個新的「命令」非常簡單,而且大多是獨立的。

編輯(再評論):

你會做的第一件事是創建一個HashMap和「安裝」,您的每一個命令。例如:(仍然psudeo碼,我想你更願意做自己分配)

map = new HashMap<String, CommandObject> 

那麼每個類的實例添加到地圖:

map.put("LET", new LetCommand()); 
map.put("INTEGER", new Integercommand()); 

在右手動類實現「CommandObject」接口。

請注意,由於每個CommandObject都是一個實例,每次找到該關鍵字時都應該重新使用該實例,您應該不會存儲任何狀態(沒有任何實例變量),這意味着您的CommandObject只需要一個方法是這樣的:

execute(String commandLine, HashMap variables); 

這可能是最簡單的方法(我編輯的文本從上面我原來的建議,反映了這一點)。

如果這個解析器變得更加複雜,那麼爲「CommandObject」添加更多功能將是完全有效的,只要您有reset()方法(我的原始建議,但似乎過於複雜你在做什麼)

請注意,命令對象的關鍵字映射可以用反射代替,但不要試圖爲學校作業做這件事,反射的複雜性使得它不值得你花時間,這很可能是你因爲老師不理解它會被降級。我實現了一個像這樣的系統,每個關鍵字鏈接到一個測試(允許你鏈接測試,循環測試,甚至定義和攜帶傳入並由這些測試操作的變量 - 在這種情況下,反射是值得的,因爲添加新的測試不需要更新緩存)

+0

這是我剛剛嘗試拍攝的內容:我想要添加新關鍵字的操作非常簡單。雖然,你能否解釋更多有關將命令作爲散列表傳遞的信息?謝謝! – Luinithil 2012-01-10 19:46:37

+0

非常感謝@Bill K,這真棒。我已經開始使用HashMap了。 – Luinithil 2012-01-10 21:55:36

0

聽起來像是正確的設計將延遲解析這些參數,直到後來。像「STRING」或「PRINT」這樣的某些命令可能是空白不可知的,其中STRING S =「HELLO WORLD」實際上與STRING S =「HELLOWORLD」在功能上不同。你不想「過度設計」這樣的事情 - 最好是做最簡單的工作,編寫一個或兩個命令類,然後弄清楚這些命令類的共同之處。

如果您以後發現所有(或大部分)命令都希望以某種方式將這些參數解析到列表中,則可以將該列表解析代碼重構爲靜態實用程序方法(或者可能是非易失性實用程序方法)如果你正在使用繼承,那麼父類Command類本身就有一個靜態實用方法。)如果你隨時隨地創建一套自動化測試,那麼這樣做的風險就小得多,但這種任務可能會超出範圍你的任務。

0

一個不錯的方法是使用enum。我不會避免使用split,但限制爲2項。

enum Command { 
    LET { 
     @Override 
     public void execute(Context context, String args) { 
     } 
    }, 
    INTEGER { ... }, 
    STRING { ... }, 
    PRINT { ... }, 
    END { ... }; 

    public abstract void execute(Context context, String args); 
} 

private void executeLine(String line) { 
    String[] commandAndArgs = line.split("\\s+", 2); 
    String command = ""; 
    String args = ""; 
    if (commandAndArgs.length > 0) 
     command = commandArgs[0].toUpperCase(); 
    if (commandAndArgs.length > 1) 
     args = commandArgs[1]; 
    Command cmd = Command.valueOf(command); 
    Context context = ...; 
    cmd.execute(context, args); 
} 
相關問題