在JavaCC解析器/词法分析器代码中查找错误

时间:2016-04-02 17:41:41

标签: parsing compiler-construction javacc

我正在编写一个JavaCC解析器/词法分析器,用于识别以下语言 L 中的所有输入字符串:

L 中的字符串由多个以空格字符分隔的块组成 必须至少存在一个块(即,不允许仅包含一定数量的空格的输入)。

  • 一个块是一个奇数长度的小写字母序列(a-z)。
  • 在第一个区块之前或最后一个区块之后不允许有空格。
  • 块之间的空格数必须为奇数。

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 中(我使用回车符和EOF [CTRL + D]进行此操作) ),打印出文本NO Empty input。 我没想到会发生这种情况。

为了解决这个问题,我在我的作品中写了...TRUE...FALSE印刷语句(参见上面的代码)。 有趣的是,我发现当我输入相同的j字符串时,终端打印出...TRUE语句一次,紧接着出现两次...FALSE语句。
然后像以前一样打印出文本NO Empty input

我还使用Google尝试查看我是否错误地在制作|中使用了OR符号Input(),或者我是否正确使用了return关键字,无论是。但是,这没有帮助。

我是否可以提示来解决此问题?

2 个答案:

答案 0 :(得分:2)

当输入为jjj jjj jjj后跟换行符或回车符(但不是两者)时,您的main方法会调用Parser.Input三次。

  • 第一次,您的解析器会消耗所有输入并返回true
  • 第二次和第三次,所有输入都已被消耗,解析器返回false

输入消耗后,词法分析器将继续返回<EOF>个令牌。

答案 1 :(得分:2)

您正在调用Input方法三次。它第一次从stdin读取,直到它到达流的末尾。这将成功解析输入并返回true。另外两次,流将为空,因此它将失败并返回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");
}