我目前正在用Java创建一个简单的Lexer生成器。我差不多完成了,在这里和那里熨了几个虫子,但是遇到了一个问题。
我希望能够在Lexer中包含评论检测,并希望以特定方式包含评论:
single = "//"
,multi_beg = "/*"
和multi_end = "*/"
包括这样的东西在技术上很简单,只需要几个布尔和字符串替换。但是,Lexer还包含可定义的String和Character常量。由于注释字符可以在这些常量中定义,因此当前没有定义字符串或字符时,注释只能是“可执行的”。
此逻辑可能如下所示:
我的想法完全标记在脑海中,但不知道如何在Java中实现它。
注意:我正在处理一个String数组,并且正在考虑通过增强的for循环来实现这一点,在Scanner中一次处理每一行,在标记堆栈之前处理注释。
for (String s : data) {
// ???
}
有关如何在Java中实现的任何想法?
更新:这就是我想要进/出的样子:
答案 0 :(得分:2)
这是一个未经测试的实现。测试是最难的部分,要非常小心。
public class CommentStripper {
private enum State {
CODE,
LINE_COMMENT,
COMMENT,
STRING
}
public static String strip(String input) {
return strip(input.toCharArray());
}
public static String strip(char[] input) {
State currentState = State.CODE;
StringBuilder rv = new StringBuilder();
char[] lineSeparator = System.lineSeparator().toCharArray();
for (int i = 0; i < input.length; i++) {
STATE_SWITCH: switch (currentState) {
case CODE:
if (input[i] == '"') {
currentState = State.STRING;
rv.append(input[i]);
break;
}
if (input[i] == '/') {
if (i + 1 >= input.length) {
rv.append(input[i]);
break;
}
if (input[i+1] == '*') {
i++;
currentState = State.COMMENT;
break;
} else if (input[i+1] == '/') {
i++;
currentState = State.LINE_COMMENT;
break;
}
}
rv.append(input[i]);
break;
case STRING:
if (input[i] == '"') {
currentState = State.CODE;
rv.append(input[i]);
break;
}
rv.append(input[i]);
break;
case COMMENT:
if (input[i] == '*') {
if (i + 1 >= input.length) {
break;
}
if (input[i + 1] == '/') {
i++;
currentState = State.CODE;
break;
}
}
break;
case LINE_COMMENT:
for (int sepIndex = 0; sepIndex < lineSeparator.length; sepIndex++) {
if (input[i+sepIndex] != lineSeparator[sepIndex]) {
break STATE_SWITCH;
}
}
i+=lineSeparator.length-1;
rv.append(lineSeparator);
currentState = State.CODE;
break;
}
}
return rv.toString();
}
}
初步测试:
import static commentStrip.CommentStripper.strip;
import static org.junit.Assert.*;
import org.junit.Test;
public class CommentStripperTest {
@Test
public void test() {
assertEquals("\"test\"", strip("\"test\"//hello\"test\""));
assertEquals("\"test\"\"test\"", strip("\"test\"/*hello*/\"test\""));
assertEquals("test"+System.lineSeparator()+"test", strip("test//linecomment"+System.lineSeparator()+"test"));
assertEquals("test", strip("test/*test"));
assertEquals("\"test//hellotest\"", strip("\"test//hellotest\""));
assertEquals("\"test/*hello*/test\"", strip("\"test/*hello*/test\""));
}
}
选择基于阵列的简单方法来提高效率。流式API使其膨胀或无效。您必须连接字符串才能使用它。
请注意,无法在字符串文字中放置转义引号。您的问题未指明这一点,因此我省略了对此的处理。
考虑使用像ANTLR这样的解析库,而不是自己编写解析器。
答案 1 :(得分:0)
通常的方法是将此作业留给tokenizer并使注释成为一种空白令牌。