在 JavaCC parser/lexer 代码中查找错误
Finding error in JavaCC parser/lexer code
我正在编写一个 JavaCC parser/lexer,它可以识别以下语言的所有输入字符串 L:
来自 L 的字符串由几个由 space 个字符分隔的块组成。
必须至少存在一个块(即,不允许只包含一定数量的白色 spaces 的输入)。
- 块是小写字母 (a-z) 的奇数长度序列。
- 第一个块之前或最后一个块之后不允许有 space。
- 块之间的space个数必须是奇数。
I/O规格包括以下规格:
如果输入确实表示来自 L 的字符串,那么单词 YES
必须打印到 System.out,以 EOL 字符结尾。
如果输入不在L,那么只需要一行NO字
打印到 System.out,也以 EOL 字符结尾。
此外,应在 System.err 上打印一条简短的错误消息,解释输入不在 L.
中的原因
问题:
这是我当前的代码:
PARSER_BEGIN(Assignment)
/** A parser which determines if user's input belongs to the langauge L. */
public class Assignment {
public static void main(String[] args) {
try {
Assignment parser = new Assignment(System.in);
parser.Input();
if(parser.Input()) {
System.out.println("YES"); // If the user's input belongs to L, print YES.
} else if(!(parser.Input())) {
System.out.println("NO");
System.out.println("Empty input");
}
} catch (ParseException e) {
System.out.println("NO"); // If the user's input does not belong to L, print NO.
}
}
}
PARSER_END(Assignment)
//** A token which matches any lowercase letter from the English alphabet. */
TOKEN :
{
< ID: (["a"-"z"]) >
}
//* A token which matches a single white space. */
TOKEN :
{
<WHITESPACE: " ">
}
/** This production is the basis for the construction of strings which belong to language L. */
boolean Input() :
{}
{
<ID>(<ID><ID>)* ((<WHITESPACE>(<WHITESPACE><WHITESPACE>)*)<ID>(<ID><ID>)*)* ("\n"|"\r") <EOF>
{
System.out.println("ABOUT TO RETURN TRUE");
return true;
}
|
{
System.out.println("ABOUT TO RETURN FALSE");
return false;
}
}
我遇到的问题如下:
我正在尝试编写代码以确保:
- 如果用户输入为空,则打印出文本
NO Empty input
。
- 如果因为输入不符合上面L的描述而出现解析错误,那么只会打印出文字
NO
。
目前,当我输入字符串 "jjj jjj jjj"
时,根据定义,它在 L 中(我在后面加上回车符 return 和 EOF [CTRL + D]),打印出文本 NO Empty input
。
我没想到会这样。
为了解决这个问题,我在我的作品中写了 ...TRUE
和 ...FALSE
打印语句(见上面的代码)。
有趣的是,我发现当我输入相同的字符串 j
时,终端打印了一次 ...TRUE
语句,紧接着是两次出现的 ...FALSE
语句。
然后文本 NO Empty input
像以前一样被打印出来。
我还使用 Google 来尝试找出我是否在我的作品 Input()
中错误地使用了 OR 符号 |
,或者我是否没有使用 return
关键字正确,要么。然而,这并没有帮助。
我可以提示解决这个问题吗?
当输入 jjj jjj jjj
后跟换行符或回车符 return(但不是两者)时,您的 main
方法调用 Parser.Input
三次。
- 第一次,您的解析器消耗所有输入和 returns
true
。
- 第二次和第三次,所有输入已经被消耗,解析器returns
false
.
一旦输入被消耗,词法分析器将只保留 returning <EOF>
个标记。
您正在调用 Input
方法三次。第一次它将从 stdin 读取直到它到达流的末尾。这将成功解析输入和 return true。另外两次,流将是空的,所以它会失败并且 return false.
您不应该多次调用一个规则,除非您确实希望它被应用多次(这只有在规则只消耗部分输入而不是直到流结束时才有意义)。相反,当您在多个地方需要结果时,只需调用一次该方法并将结果存储在一个变量中。
或者在您的情况下,您可以在 if
中调用一次,甚至不需要变量:
Assignment parser = new Assignment(System.in);
if(parser.Input()) {
System.out.println("YES"); // If the user's input belongs to L, print YES.
} else {
System.out.println("NO");
System.out.println("Empty input");
}
我正在编写一个 JavaCC parser/lexer,它可以识别以下语言的所有输入字符串 L:
来自 L 的字符串由几个由 space 个字符分隔的块组成。
必须至少存在一个块(即,不允许只包含一定数量的白色 spaces 的输入)。
- 块是小写字母 (a-z) 的奇数长度序列。
- 第一个块之前或最后一个块之后不允许有 space。
- 块之间的space个数必须是奇数。
I/O规格包括以下规格:
如果输入确实表示来自 L 的字符串,那么单词 YES
必须打印到 System.out,以 EOL 字符结尾。
如果输入不在L,那么只需要一行NO字
打印到 System.out,也以 EOL 字符结尾。
此外,应在 System.err 上打印一条简短的错误消息,解释输入不在 L.
问题:
这是我当前的代码:
PARSER_BEGIN(Assignment)
/** A parser which determines if user's input belongs to the langauge L. */
public class Assignment {
public static void main(String[] args) {
try {
Assignment parser = new Assignment(System.in);
parser.Input();
if(parser.Input()) {
System.out.println("YES"); // If the user's input belongs to L, print YES.
} else if(!(parser.Input())) {
System.out.println("NO");
System.out.println("Empty input");
}
} catch (ParseException e) {
System.out.println("NO"); // If the user's input does not belong to L, print NO.
}
}
}
PARSER_END(Assignment)
//** A token which matches any lowercase letter from the English alphabet. */
TOKEN :
{
< ID: (["a"-"z"]) >
}
//* A token which matches a single white space. */
TOKEN :
{
<WHITESPACE: " ">
}
/** This production is the basis for the construction of strings which belong to language L. */
boolean Input() :
{}
{
<ID>(<ID><ID>)* ((<WHITESPACE>(<WHITESPACE><WHITESPACE>)*)<ID>(<ID><ID>)*)* ("\n"|"\r") <EOF>
{
System.out.println("ABOUT TO RETURN TRUE");
return true;
}
|
{
System.out.println("ABOUT TO RETURN FALSE");
return false;
}
}
我遇到的问题如下:
我正在尝试编写代码以确保:
- 如果用户输入为空,则打印出文本
NO Empty input
。 - 如果因为输入不符合上面L的描述而出现解析错误,那么只会打印出文字
NO
。
目前,当我输入字符串 "jjj jjj jjj"
时,根据定义,它在 L 中(我在后面加上回车符 return 和 EOF [CTRL + D]),打印出文本 NO Empty input
。
我没想到会这样。
为了解决这个问题,我在我的作品中写了 ...TRUE
和 ...FALSE
打印语句(见上面的代码)。
有趣的是,我发现当我输入相同的字符串 j
时,终端打印了一次 ...TRUE
语句,紧接着是两次出现的 ...FALSE
语句。
然后文本 NO Empty input
像以前一样被打印出来。
我还使用 Google 来尝试找出我是否在我的作品 Input()
中错误地使用了 OR 符号 |
,或者我是否没有使用 return
关键字正确,要么。然而,这并没有帮助。
我可以提示解决这个问题吗?
当输入 jjj jjj jjj
后跟换行符或回车符 return(但不是两者)时,您的 main
方法调用 Parser.Input
三次。
- 第一次,您的解析器消耗所有输入和 returns
true
。 - 第二次和第三次,所有输入已经被消耗,解析器returns
false
.
一旦输入被消耗,词法分析器将只保留 returning <EOF>
个标记。
您正在调用 Input
方法三次。第一次它将从 stdin 读取直到它到达流的末尾。这将成功解析输入和 return true。另外两次,流将是空的,所以它会失败并且 return false.
您不应该多次调用一个规则,除非您确实希望它被应用多次(这只有在规则只消耗部分输入而不是直到流结束时才有意义)。相反,当您在多个地方需要结果时,只需调用一次该方法并将结果存储在一个变量中。
或者在您的情况下,您可以在 if
中调用一次,甚至不需要变量:
Assignment parser = new Assignment(System.in);
if(parser.Input()) {
System.out.println("YES"); // If the user's input belongs to L, print YES.
} else {
System.out.println("NO");
System.out.println("Empty input");
}