因此,对于一个项目,我试图为从文件中读入的伪编程语言创建一个简单的词法分析器。本周早些时候我问了一个问题,询问我如何实施这样一个程序并解除了答案告诉我: 创建一个输入缓冲区和两个输出缓冲区。 初始化两个循环并递增它们,直到找到令牌的开头。一旦我找到了开始,增加第二个循环,直到我找到一个空格或符号,然后使用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 :(得分:1)
构建词法分析器的经典方法是通过循环内的switch语句。基本思想是将每个char只处理一次而不是重新扫描它。情况A到Z和a到z可以开始一个标识符,因此这些情况必须吸入所有可能的标识符字符,直到你找到一个不是,将它们组装成标识符标记,并将IDENTIFIER返回给调用者。类似情况0到9可以开始一个数字,所以你吮吸数字并返回INTEGER或DOUBLE或其他任何东西。案例空格,制表符,换行符,换页符等都是空格,所以填充所有空格并继续外循环而不返回。所有其他都是标点符号,所以你把它们搞砸了,从两个字符串中挑出一个char字符串,并且通常返回字符值本身为one-char,以及其他的特殊标记值。不要忘记正确处理EOF :-)调整案例和规则以适合您正在分析的语言。
答案 1 :(得分:0)
这取决于你的词法分析器需要多大的复杂程度。如果你像现在一样,分裂空格,你可以简单地将每个词汇与一系列正则表达式进行比较,看看哪一个匹配它。这是一种简单的方法,而且效率不高,但这可能不会影响您的决定。
“真正的”词法分析器通常用作有限自动机。如果您知道如何构建可以识别正则表达式的自动机,您可以将其中的几个组合成一个更大的自动机,它可以识别O(1)复杂度中的几个表达式。如果感兴趣的话,我已就这个问题写过series of articles。这是一项复杂但有益的任务。