1

我的任务是为语言 c-- 实现词法分析器。我们必须将 c-- 代码翻译成一系列标记,这些标记将在内部表示为整数,因为它更容易操作。该语言的一些词汇约定是有关键字,如 double、else、if、int、return、void 和 while。还有特殊符号,如 + - * / < <= > >= == != = ; , . ( ) [ ] { } /* */ //. 标识符可以以任何字母或下划线开头,后跟字母、数字和下划线的任意组合。空格分隔标记并被忽略。数字可以是整数或小数,并且允许使用注释行和块。

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();


    }

}

这是我们的测试代码:

int fact(int x) {
// recursive factorial function 
   if (x>1) 
      return x * fact(x-1);
   else return 1;
}

void main(void) {
/* CS 311 project 2
A lexical analyzer */
   int x, y, z;
   double _funny;
   x = get_integer();
   _Funny = get_double();
   if (x>0) 
      print_line(fact(x));
   else if (_funny != 3.14) 
      print_line(x*_funny);
}

这应该是我们的输出

3 27 21 3 27 22 25 2 21 27 13 28 22 4 27 9 27 21 27 8 28 22 18 1 4 28 18 26 5 27 21 5 22 25 3 27 19 27 19 27 18 0 277 18 27 1817 27 17 27 21 22 18 2 21 27 13 28 22 27 21 27 21 27 22 22 18 1 2 21 27 12 28 22 27 21 27 9 27 22 18 26

INT id leftparen INT id rightparen leftbrace IF leftparen id 大于 num rightparen RETURN id 乘法 id leftparen id 减 num rightparen 分号 ELSE RETURN num 分号 rightparen VOID id leftparen VOID rightparen leftbrace INT id comma id comma id 分号 DOUBLE id 分号 id assignop id leftparen rightparen 分号id assignop id leftparen rightparen 分号 IF leftparen id 更大的 num rightparen id leftparen id leftparen id rightparen rightparen 分号 ELSE IF leftparen id notequal num rightparen id leftparen id 乘法 id rightparen 分号 rightbrace

好的,我根据用户 John 的建议编写了一些代码。我仍然对这将如何工作感到困惑。当我迭代第二个循环以查找空白或符号时,我如何知道符号的 ws 之前出现了什么类型的令牌。我试图将我跳过的字符放入字符串中并使用 case 语句来确定它,但我认为它会将整个文件写入字符串,因此我的标记永远不会匹配。另外,方法如何找到评论并安全地忽略它们?

4

2 回答 2

0

非常熟悉的味道,除了我正在编写 LLK 分析器的事实......在你的情况下,试着看看形式语法之类的方式 - 在这些语法执行分析之前,你的步骤几乎是必需的步骤。也许一些像 lex && flex 这样的工作解析器(开源)会有所帮助。

INHO,最简单的方法是将输入文件逐个字符读入某个字符串并检查,该字符串是否与您的正则表达式之一匹配...如果匹配,则将适当的代码写入输出并清除您用作缓冲区的字符串. 在这种情况下有两个问题:这在 O(n*m) 中有效,其中 n 是您的文本长度,m 是您拥有的正则表达式的数量(在有价值的情况下),其次 - 您不能使用前缀表达式...我的意思是,您不能有任何表达式以将另一个表达式作为前缀(开始),否则该表达式将无法访问。

于 2012-05-10T11:30:25.790 回答
0

有几种不同的方法可以处理这个程序。在不编写代码的情况下,我将尝试解释您需要做什么。

从您提交的示例中。

你的导师给了你这个项目的钥匙。他给了你输出,你可以构建一个状态表。

您可以通过输出并手动执行此操作以检查您的答案,或创建一个小程序为您执行此操作。

这是一张表格,左边是状态编号,右边是对应的单词。

         3  int,  
         27 ID,
         21 leftparen, 
         22 right paren,
         25 left brace s, 
         2  if,
         13  greater, 

等等。

您将需要创建一个输入缓冲区
2 个输出缓冲区
2 个循环 一个外部循环和一个内部循环
1 个对应于状态表的 case 语句。

当您通过输入缓冲区时,您初始化外循环初始化内循环比较第一个字符并确定它是否是有效字符?if not 递增循环,直到找到有效字符

一旦找到有效字符,它就是令牌的开始。然后通过查找空格或特殊符号来增加内部循环来查找令牌的结尾。然后使用case语句输出一个缓冲区中的数字和第二个缓冲区对应的单词。

然后打印出数字缓冲区。然后打印出单词缓冲区。

然后将外循环增加到内循环 + 1 使内循环等于外循环

继续,直到找到文件结尾。如果它们与您的老师的输出相匹配,您就完成了。如果不是,你有一个逻辑错误。然后检查哪个值无效,并查看程序的那部分。

伙计们已经 20 岁了。

于 2012-05-10T08:13:56.097 回答