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 语句中不匹配。同样使用这种方法,我怎样才能安全地忽略评论和评论块,因为它们不应该被标记化。

4

2 回答 2

1

构建词法分析器的经典方法是通过循环内的 switch 语句。基本思想是只处理每个字符一次,而不是重新扫描它。案例 A 到 Z 和 a 到 z 可以开始一个标识符,因此这些案例必须吸收所有可能的标识符字符,直到你找到一个不是的,将它们组装成一个标识符标记,并将 IDENTIFIER 返回给调用者。类似的情况 0 到 9 可以开始一个数字,所以你输入数字并返回 INTEGER 或 DOUBLE 或任何它。空格、制表符、换行符、换页符等都是空格,因此请吸收所有空格并继续外循环而不返回。所有其他的都是标点符号,所以你把它们吸起来,从两个字符的字符中挑选出一个字符的字符,通常返回字符值本身来返回一个字符的字符值,以及其他人的特殊令牌值。不要忘记正确处理 EOF :-) 调整案例和规则以适合您正在分析的语言。

于 2012-05-13T02:04:29.863 回答
0

这取决于您需要词法分析器有多复杂。如果您像现在一样在空格上拆分,您可以简单地将每个词位与一系列正则表达式进行比较,看看哪个匹配它。这是一种简单的方法,效率不高,但这可能不会影响您的决定。

“真正的”词法分析器通常用作有限自动机。如果您知道如何构建一个可以识别正则表达式的自动机,您可以将其中的几个组合成一个更大的自动机,该自动机可以识别 O(1) 复杂度的多个表达式。如果感兴趣的话,我已经写了一系列关于这个主题的文章。这是一项复杂但有益的任务。

于 2012-05-12T18:15:34.030 回答