在 JavaCC parser/lexer 代码中查找错误

Finding error in JavaCC parser/lexer code

我正在编写一个 JavaCC parser/lexer,它可以识别以下语言的所有输入字符串 L:

来自 L 的字符串由几个由 space 个字符分隔的块组成。
必须至少存在一个块(即,不允许只包含一定数量的白色 spaces 的输入)。

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;
  }
}

我遇到的问题如下:

我正在尝试编写代码以确保:

目前,当我输入字符串 "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");
}