0

そのため、プロジェクトのために、ファイルから読み込まれる偽のプログラミング言語用の単純な語彙アナライザーを作成しようとしています。その週の初めに、そのようなプログラムを実装する方法を尋ねる質問をしたところ、入力バッファーと 2 つの出力バッファーを作成するようにという答えに安堵しました。2 つのループを初期化し、トークンの開始が見つかるまでインクリメントします。開始点を見つけたら、空白または記号が見つかるまで 2 番目のループをインクリメントし、case ステートメントを使用して 2 つの出力ファイルに出力し、外側のループを内側のループと等しくしてスキャンを続けます。私はいくつかの調査を行いましたが、この方法はループとスイッチの方法または「アドホック」方法に似ています。

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 ステートメントでトークンが一致しませんでした。また、この方法を使用して、コメントとコメント ブロックはトークン化されるべきではないため、安全に無視するにはどうすればよいでしょうか。

4

2 に答える 2

1

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

于 2012-05-13T02:04:29.863 に答える
0

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

「本物の」字句解析器は通常、有限オートマトンとして機能します。正規表現を認識できるオートマトンを構築する方法を知っている場合は、これらのいくつかを組み合わせて、O(1) の複雑さで複数の式を認識するより大きなオートマトンにすることができます。興味があれば、このテーマに関する一連の記事を書いています。複雑ですがやりがいのある仕事です。

于 2012-05-12T18:15:34.030 に答える