2012-05-12 15 views
0

プロジェクトでは、ファイルから読み込まれた偽のプログラミング言語用の単純な字句解析ツールを作成しようとしています。私はその週の早い段階で、このようなプログラムをどのように実装することができるかを尋ねました。 入力バッファと2つの出力バッファを作成します。 2つのループを初期化し、トークンの開始点を見つけるまでそれらを増分します。いったん開始点を見つけたら、空白または記号が見つかるまで2番目のループをインクリメントしてから、2つの出力ファイルに出力する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(); 


    } 

} 

私の質問は、空白または記号を見つけた後に単語を割り当てるトークンを決定する方法です。私は文字の前に各文字を置くことができ、それをそのように比較することができますか?私は似たようなことを試しましたが、入力ファイル全体を文字列に書き込んで、私のトークンが私のswitch文で一致しないようにしました。また、このメソッドを使用すると、トークン化されてはならないので、コメントブロックとコメントブロックを安全に無視できます。

答えて

0

あなたのレクサーがどれほど複雑であるかによって異なります。空白で分割している場合は、各語彙素を一連の正規表現と単純に比較し、一致するものを確認することができます。これは簡単な方法であり、それほど効率的ではありませんが、それはあなたの決定には関係しません。

"本当の"レクサーは通常、有限オートマトンとして機能します。正規表現を認識できるオートマトンを構築する方法がわかっている場合は、O(1)の複雑さの中でいくつかの式を認識するより大きなオートマトンにこれらのいくつかを組み合わせることができます。それが興味のあるものなら、私はこの件に関してseries of articlesと書いています。複雑ではあるが、やりがいのある仕事です。

+0

私はレクサーがそれほど複雑ではないと思っています。私が近づいているところです。私は識別子、特別なキーワード、sysmbol、または整数/小数点を取得するかどうかに基づいてトークンを区切ります。 – Thomas

+0

はい、あなたのアプローチはうまくいくでしょう。あなたのセパレータchechから受け取ったものを大量の正規表現と比較して一致するものがどれかを確認し、次に優先順位が最も高いもののトークンタイプを選んでください。 – Dervall

+0

java.util.regexを使用できますか? if文を使って各文字を調べることができます。例:if(scanner.chatAt(i)== a || == b)。 (文字が文字か_かどうかを私に知らせる方法があります)私は個々の文字に正規表現を使用する方法を見ていません。 – Thomas

1

レクサーを構築する古典的なアプローチは、ループ内のswitch文を使用する方法です。基本的な考え方は、各文字を再スキャンするのではなく、一度だけ処理することです。ケースA〜Zとa〜zは識別子を始めることができるので、そうでないケースにヒットして識別子トークンにアセンブルし、IDENTIFIERを呼び出し元に戻すまで、すべての可能な識別子文字を入力する必要があります。同様に、0から9の場合は数字を始めることができるので、数字を吸い込んでINTEGERまたはDOUBLEを返します。スペース、タブ、改行、改ページなどは空白なので、すべての空白を取り除き、まったく返さずに外側のループを続行します。他のすべては句読点なので、あなたはそれらを吸い取り、2文字の文字から1文字の文字を並べ替え、通常は1文字の文字の値そのものと、他の文字の特殊なトークンの値を返します。 EOFを正しく処理することを忘れないでください:-)分析する言語に合わせてケースとルールを調整してください。

+0

このメソッドでコメントを処理するにはどうすればよいですか?もし私が//スキャンすれば、私は読んでいる入力ファイルの次の行にスキップするだけですか?コメントブロックにも同じです。ちょうど私がヒットするまで文字を吸う* /? – Thomas

+0

これは正しいです。一度始めると、それはかなり明白です。lex/flexのようなDFAベースの字句解析ツールが登場するまで、これはコンパイラスキャナが常に実装された方法でした。複数の正規表現を使用するよりもはるかに効率的です。 – EJP

+0

また、私はこれを私の以前のコメントに入れて、文字を "吸って"ケースの中にループを作って、それからケースのループに外側のループを送ったトークンを返した後に、文字列ビルダーを使用してファイルを1行に保存すると、コメント行をどのように処理できますか?私は次の行にスキップすることができないので – Thomas