2012-05-12 117 views
0

因此,對於一個項目,我試圖爲從文件讀入的假編程語言創建一個簡單的詞法分析器。我在本週早些時候提出了一個問題,詢問我如何實現這樣一個程序,並鬆了一口氣告訴我: 創建一個輸入緩衝區和兩個輸出緩衝區。 初始化兩個循環並遞增它們直到找到標記的開始。一旦我找到了開始,增加第二個循環,直到找到一個空格或符號,然後使用case語句輸出到兩個輸出文件,然後使外部循環等於內部並繼續掃描。我做了一些研究,這種方法類似於循環和切換方法或「特設」方法。「Ad Hoc」詞法分析器

import java.io.*; 

public class Lex { 

    public static boolean contains(char[] a, char b){ 
     for (int i = 0; i < a.length; i++) { 
      if(b == a[i]) 
       return true; 
     } 
     return false; 
    } 
    public static void main(String args[]) throws FileNotFoundException, IOException{ 

     //Declaring token values as constant integers. 
     final int T_DOUBLE = 0; 
     final int T_ELSE = 1; 
     final int T_IF = 2; 
     final int T_INT = 3; 
     final int T_RETURN = 4; 
     final int T_VOID = 5; 
     final int T_WHILE = 6; 
     final int T_PLUS = 7; 
     final int T_MINUS = 8; 
     final int T_MULTIPLICATION = 9; 
     final int T_DIVISION = 10; 
     final int T_LESS = 11; 
     final int T_LESSEQUAL = 12; 
     final int T_GREATER = 13; 
     final int T_GREATEREQUAL = 14; 
     final int T_EQUAL = 16; 
     final int T_NOTEQUAL = 17; 
     final int T_ASSIGNOP = 18; 
     final int T_SMEICOLON = 19; 
     final int T_PERIOD = 20; 
     final int T_LEFTPAREN = 21; 
     final int T_RIGHTPAREN = 22; 
     final int T_LEFTBRACKET = 23; 
     final int T_RIGHTBRACKET = 24; 
     final int T_LEFTBRACE = 25; 
     final int T_RIGHTBRACE = 26; 
     final int T_ID = 27; 
     final int T_NUM = 28; 
     char[] letters_ = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D', 
      'E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','_'}; 
     char[] numbers = {'0','1','2','3','4','5','6','7','8','9'}; 
     char[] symbols = {'+','-','*','/','<','>','!','=',':',',','.','(',')','[',']','{','}'}; 
     FileInputStream fstream = new FileInputStream("src\\testCode.txt"); 
     DataInputStream in = new DataInputStream(fstream); 
     BufferedReader br = new BufferedReader(new InputStreamReader(in)); 
     BufferedWriter bw1 = new BufferedWriter(new FileWriter(new File("src\\output.txt"), true)); 
     BufferedWriter bw2 = new BufferedWriter(new FileWriter(new File("src\\output2.txt"), true)); 
     String scanner;String temp = ""; 
     int n = 0; 
     while((scanner = br.readLine()) != null){ 
      for (int i = 0; i < scanner.length(); i++) { 
       for (int j = 0; j < scanner.length(); j++) { 
        if(contains(letters_,scanner.charAt(i)) || contains(numbers,scanner.charAt(i)) || contains(symbols,scanner.charAt(i))){ 
         j++; 
         n++; 
         if(scanner.charAt(j) == ' ' || scanner.charAt(j) == '\n' || scanner.charAt(j) == '\t'){ 

         } 
        } 

       } 

      } 
     } 

     in.close(); 


    } 

} 

我的問題是如何確定在找到空格或符號後指定一個詞的標記。我可以把每個字符放在一個字符串中的ws和符號之前,然後像這樣比較嗎?我嘗試過類似的東西,但是它將整個輸入文件寫入字符串,所以我的令牌在我的switch語句中不匹配。同樣使用這種方法,我怎樣才能安全地忽略註釋和註釋塊,因爲它們不應該被標記。

回答

0

這取決於您需要使用詞法分析器的複雜程度。如果你現在正在分割空白,你可以簡單地將每個詞位與一系列正則表達式進行比較,看看哪一個與它匹配。這是一種簡單的做法,效率不高,但這可能不會影響您的決定。

「真正的」詞法分析器通常用作有限自動機。如果你知道如何構建一個能夠識別正則表達式的自動機,你可以將其中的幾個組合成一個更大的自動機,以識別O(1)複雜性中的幾個表達式。如果有興趣,我已經寫了一個關於這個主題的series of articles。這是一項複雜而有益的任務。

+0

我不認爲詞法分析器很複雜,只是我接近它的方式是。我只需要基於我是否得到標識符,特殊關鍵字,sysmbol或整數/小數來分開令牌。 – Thomas

+0

是的,你的方法將起作用。只需將你從分隔符中得到的任何內容與一堆正則表達式進行比較,看看哪些匹配,然後選擇最高優先級的令牌類型。 – Dervall

+0

我可以使用java.util.regex嗎?或者用if語句遍歷每個字符。例如:if(scanner.chatAt(i)== a || == b)。 (我有一個方法告訴我,如果字符是一個字母或_)我只是沒有看到如何使用正則表達式對個別字符。 – Thomas

1

構建詞法分析器的經典方法是通過循環內的switch語句。基本思想是每個字符處理一次,而不是重新掃描。案例A到Z和a到z可以開始一個標識符,因此這些案例必須吸收所有可能的標識符字符,直到您找到一個不是的標識符字符,將它們組裝成標識符標記並將IDENTIFIER返回給調用者。類似的情況下0到9可以開始一個數字,所以你吸入數字並返回INTEGER或DOUBLE或其它。例如空格,製表符,換行符,換頁符等等都是空格,所以將所有的空格都填滿並繼續外循環而不返回。所有其他的都是標點符號,所以你把它們吸引過來,從兩個字符的字符中挑出一個字符值,並且通常爲單字符字符值返回字符值,爲其他字符值賦予一個特殊的標記值。不要忘記正確處理EOF :-)調整案例和規則以適應您正在分析的語言。

+0

我如何處理這種方法的意見?如果我掃描/ /我只是跳到我正在閱讀的輸入文件的下一行?和相同的評論塊..只是吸字符,直到我打* /? – Thomas

+0

這是正確的。一旦你開始,你會發現它很明顯。在像lex/flex這樣的基於DFA的詞法分析器出現之前,這就是編譯器掃描器總是如何實現的。它比使用多個正則表達式更有效率。 – EJP

+0

另外,我應該在我之前的評論中包含這個,以便「吸取」我在一個案例中製作循環的字符,然後在我返回一個令牌後將外部循環發送到在該案例中製作的循環中?如果我使用字符串生成器將文件存儲在一行上,我如何處理註釋行?因爲我不能跳到下一行 – Thomas