我是一名学生程序员,我正在尝试为我的一个计算机科学课程构建一个HTML代码的词法分析器,其输出应该是HTML代码的单个标记和词汇。但是当我编译并运行我的分析器时,输出似乎有问题。
根据HTML代码:
<table>
<tr><td>temp</td><td>temp2</td></tr>
</table>
输出应为:
TOKEN LEXEME
------------------
TAGIDENT <table
GTHAN >
TAGIDENT <tr
GTHAN >
TAGIDENT <td
GTHAN >
IDENT temp
ENDTAGHEAD </
IDENT td
GTHAN >
TAGIDENT <td
GTHAN >
IDENT temp2
ENDTAGHEAD </
IDENT td
GTHAN >
ENDTAGHEAD </
IDENT tr
GTHAN >
目前,这是我的代码:
import java.io.*;
import java.util.*;
public class LexAnalyzer {
public static void main(String[] args) {
try {
String input = "" , s = "";
Token t;
BufferedReader in = new BufferedReader(new FileReader(new File("Sample.html")));
while((s = in.readLine()) != null) {
input += s;
}
System.out.println(input);
System.out.println("TOKEN LEXEME");
System.out.println("------------------");
ArrayList<Token> a = getToken(input);
for(int i = 0; i < a.size(); i++) {
System.out.println(a.get(i).getId() + " " + a.get(i).getLexeme());
}
}
catch(Exception e) {
e.printStackTrace();
}
}
public static ArrayList<Token> getToken(String input) {
String lexeme = ""; //lexeme = TOKEN = ie. TAGIDENT
Token t = null;
ArrayList<Token> a = new ArrayList<Token>();
for(int i = 0; i < input.length(); i++) {
if(input.charAt(i) == '<') {
lexeme += input.charAt(i);
i++;
//case 1: if followed by ! < = COMMENT
if(input.charAt(i) == '!') {
lexeme += input.charAt(i);
i++;
while(input.charAt(i) != '>') {
lexeme += input.charAt(i);
i++;
}
input = input.substring(lexeme.length(), input.length());
}
//case 2: if followed by letter < = TAGIDENT
else if(isALetter(input.charAt(i))) {
lexeme += input.charAt(i);
i++;
while(input.charAt(i) != '>' && input.charAt(i) != ' ') {
lexeme += input.charAt(i);
i++;
}
t = new Token("TAGIDENT", lexeme);
input = input.substring(lexeme.length(), input.length());
a.add(t);
}
//case 3: if followed by number or space < = LTHAN
else if((isANumber(input.charAt(i)))) {
lexeme += input.charAt(i);
i++;
while(input.charAt(i) != '<' || input.charAt(i) == ' ') {
lexeme += input.charAt(i);
i++;
}
t = new Token("LTHAN", lexeme);
input = input.substring(lexeme.length(), input.length());
a.add(t);
}
//case 4: if followed by / < = ENDTAGHEAD
else if(input.charAt(i) == '/') {
lexeme += input.charAt(i);
i++;
//case 5: after ENDTAGHEAD -> IDENT
if(isALetter(input.charAt(i))) {
lexeme += input.charAt(i);
i++;
while(input.charAt(i) != '>') {
lexeme += input.charAt(i);
i++;
}
t = new Token("IDENT", lexeme);
input = input.substring(lexeme.length(), input.length());
a.add(t);
}
t = new Token("ENDTAGHEAD", lexeme);
input = input.substring(lexeme.length(), input.length());
a.add(t);
}
}
else if(input.charAt(i) == '>') {
lexeme += input.charAt(i);
i++;
t = new Token("GTHAN", lexeme);
input = input.substring(lexeme.length(), input.length());
}
}
return a;
}
public static boolean isALetter(char inputChar) {
Boolean itIsALetter = false;
if("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM".indexOf(inputChar) != -1) {
itIsALetter = true;
}
return itIsALetter;
}
public static boolean isANumber(char inputChar) {
Boolean itIsANumber = false;
if("1234567890".indexOf(inputChar) != -1) {
itIsANumber = true;
}
return itIsANumber;
}
}
令牌类:
public class Token {
String id, lexeme;
public Token(String id, String lexeme) {
this.id = id;
this.lexeme = lexeme;
}
public String getId() {
return id;
}
public String getLexeme() {
return lexeme;
}
}
我的代码输出:
TOKEN LEXEME
------------------
TAGIDENT <table
IDENT <table>></td
ENDTAGHEAD <table>></td
有关如何修复代码的任何建议?非常感谢!
答案 0 :(得分:1)
每当您阅读令牌时:
while(input.charAt(i) != '>' && input.charAt(i) != ' ') {
lexeme += input.charAt(i);
i++;
}
你应该在while循环之后再添加一行:
lexeme += input.charAt(i);
以便读取最后一个结束字符>
。一旦你修复了代码中的所有这些位置(或者更好的是,重构你的代码并将其提取到外部辅助方法) - 你将获得完整的令牌。
答案 1 :(得分:1)
您没有完全迭代input String
的内容,因为您正在使用substrings
,递增计数器i
并检查您的input length
。
实际上,根据您的代码,lexeme
负责获取所需内容,您根本不必使用子字符串。但是,lexeme
还会向自身添加数据,并且根据您的打印语句,您希望将各个元素显示为lexeme
的一部分。
删除此内容:
input = input.substring(lexeme.length(), input.length());
在每个父条件开始时,不是递增lexeme
,而是从头开始
lexeme = "" + input.charAt(i);
但是,在内部循环和条件中,您可能仍希望增加它。
另一方面是您没有编写代码来处理text
内容(temp
)。
修改强>
根据上述建议,我尝试使用更改后的XML代码,这里是更改后的getToken()
:
public static ArrayList<Token> getToken(String input) {
String lexeme = ""; // lexeme = TOKEN = ie. TAGIDENT
Token t = null;
ArrayList<Token> a = new ArrayList<Token>();
for (int i = 0; i < input.length(); i++) {
if (input.charAt(i) == '<') {
lexeme = "" + input.charAt(i);
i++;
// case 1: if followed by ! < = COMMENT
if (input.charAt(i) == '!') {
lexeme += input.charAt(i);
i++;
while (input.charAt(i) != '>') {
lexeme += input.charAt(i);
i++;
}
}
// case 2: if followed by letter < = TAGIDENT
if (isALetter(input.charAt(i))) {
lexeme += input.charAt(i);
i++;
while (input.charAt(i) != '>' && input.charAt(i) != ' ') {
lexeme += input.charAt(i);
i++;
}
t = new Token("TAGIDENT", lexeme);
a.add(t);
}
// case 3: if followed by number or space < = LTHAN
if ((isANumber(input.charAt(i)))) {
lexeme = "" + input.charAt(i);
i++;
while (input.charAt(i) != '<' || input.charAt(i) == ' ') {
lexeme += input.charAt(i);
i++;
}
t = new Token("LTHAN", lexeme);
a.add(t);
}
// case 4: if followed by / < = ENDTAGHEAD
if (input.charAt(i) == '/') {
lexeme = "" + input.charAt(i);
i++;
// case 5: after ENDTAGHEAD -> IDENT
if (isALetter(input.charAt(i))) {
lexeme += input.charAt(i);
i++;
while (input.charAt(i) != '>') {
lexeme += input.charAt(i);
i++;
}
t = new Token("IDENT", lexeme);
a.add(t);
}
t = new Token("ENDTAGHEAD", lexeme);
a.add(t);
}
if (input.charAt(i) == '>') {
lexeme = "" + input.charAt(i);
// i++;
t = new Token("GTHAN", lexeme);
a.add(t);
}
}
else if (input.charAt(i) == '>') {
lexeme = "" + input.charAt(i);
i++;
t = new Token("GTHAN", lexeme);
a.add(t);
}
// System.out.println(temp);
}
return a;
}
输出我得到的是:
TOKEN LEXEME
------------------
TAGIDENT <table
GTHAN >
TAGIDENT ><tr
GTHAN >
TAGIDENT ><td
GTHAN >
IDENT /td
ENDTAGHEAD /td
GTHAN >
TAGIDENT ><td
GTHAN >
IDENT /td
ENDTAGHEAD /td
GTHAN >
IDENT /tr
ENDTAGHEAD /tr
GTHAN >
IDENT /table
ENDTAGHEAD /table
GTHAN >
不是确切的输出,但仍然可以获得所有元素,并且应该让你去。