1

刚开始使用 JavaCC。但我有一个奇怪的行为。我想以标记(字母和数字)的形式验证输入,这些标记与符号(+、-、/)连接,并且可以包含括号。我希望这是可以理解的:)

在 main 方法中是一个字符串,它应该会产生错误,因为它有一个左括号和两个右括号,但是我没有得到解析异常 --> 为什么?

有人知道为什么我没有得到例外吗?

我在最初的尝试中遇到了左递归和选择冲突,但设法克服了它们。也许那里是我介绍的问题?!

哦 - 也许我的解决方案不是很好 - 忽略这个事实......或者更好,给一些建议;-)

文件:CodeParser.jj

 options {
   STATIC=false;
 }

 PARSER_BEGIN(CodeParser)

 package com.testing;

 import java.io.StringReader;
 import java.io.Reader;

 public class CodeParser {

     public CodeParser(String s) 
     {
         this((Reader)(new StringReader(s))); 

     }

     public static void main(String args[])
     {
         try
         {
               /** String has one open, but two closing parenthesis --> should produce parse error */
               String s = "A+BC+-(2XXL+A/-B))";
               CodeParser parser = new CodeParser(s);
               parser.expression();
         }
         catch(Exception e)
         {
               e.printStackTrace();
         }
     }
 }
 PARSER_END(CodeParser)

 TOKEN:
 {
  <code : ("-")?(["A"-"Z", "0"-"9"])+ >
  | <op : ("+"|"/") >
  | <not : ("-") >
  | <lparenthesis : ("(") >
  | <rparenthesis : (")") >
 }

 void expression() :
 {
 }
 {
  negated_expression() | parenthesis_expression() | LOOKAHEAD(2) operator_expression() | <code>
 }

 void negated_expression() :
 {
 }
 {
       <not>parenthesis_expression()
 }

 void parenthesis_expression() :
 {
 }
 {
        <lparenthesis>expression()<rparenthesis>
 }

 void operator_expression() :
 {
 }
 {
       <code><op>expression()
 }

编辑 - 2009 年 11 月 16 日

现在我尝试了ANTLR。

我更改了一些术语以更好地匹配我的问题域。我想出了以下代码(使用本网站上的答案),现在似乎可以完成工作:

grammar Code;

CODE    :   ('A'..'Z'|'0'..'9')+;
OP  :   '+'|'/';

start   :   terms EOF;
terms   :   term (OP term)*;
term    :   '-'? CODE
    |   '-'? '(' terms ')';

顺便说一句... ANTLRWORKS 是一个很好的调试/可视化工具!帮了我很多。

附加信息
上面的代码匹配如下内容:

(-Z19+-Z07+((FV+((M005+(M272/M276))/((M278/M273/M642)+-M005)))/(FW+(M005+(M273/M278/M642)))))+(-Z19+-Z07+((FV+((M005+(M272/M276))/((M278/M273/M642/M651)+-M005)))/(FW+(M0))))
4

3 回答 3

3

kgregory 说的是正确的答案。如果您使用 DEBUG_PARSER 选项构建语法然后运行它,您可以看到这一点:

$ javacc -debug_parser -output_directory=com/testing/ CodeParser.jj && javac com/testing/*.java && java -cp 。com.testing.CodeParser
Java Compiler 编译器版本 5.0(解析器生成器)
(键入“javacc”,不带参数寻求帮助)
从文件 CodeParser.jj 中读取。. .
正在重建文件“TokenMgrError.java”。
正在重建文件“ParseException.java”。
正在重建文件“Token.java”。
正在重建文件“SimpleCharStream.java”。
解析器生成成功。
调用:表达式
  调用:operator_expression
    使用的令牌:<<code>: "A" at line 1 column 1>
    使用的令牌:<<op>: "+" at line 1 column 2>
    调用:表达式
      调用:operator_expression
        使用的令牌:<<code>: "BC" at line 1 column 3>
        使用的令牌:<<op>: "+" at line 1 column 5>
        调用:表达式
          调用:否定表达式
            使用的令牌:<"-" at line 1 column 6>
            调用:括号表达式
              使用的令牌:<"(" at line 1 column 7>
              调用:表达式
                调用:operator_expression
                  使用的令牌:<<code>: "2XXL" at line 1 column 8>
                  使用的令牌:<<op>: "+" at line 1 column 12>
                  调用:表达式
                    调用:operator_expression
                      使用的令牌:<<code>: "A" at line 1 column 13>
                      使用的令牌:<<op>: "/" at line 1 column 14>
                      调用:表达式
                        使用的令牌:<<code>: "-B" at line 1 column 15>
                      返回:表达式
                    返回:operator_expression
                  返回:表达式
                返回:operator_expression
              返回:表达式
              使用的令牌:<")" 在第 1 行第 17 列>
            返回:括号表达式
          返回:否定表达式
        返回:表达式
      返回:operator_expression
    返回:表达式
  返回:operator_expression
返回:表达式

看到了吗?最后消耗的令牌是倒数第二个字符 - 倒数第二个右括号。

如果你想要例外,就像 kgregory 所说的那样,你可以添加一个名为“file”或“data”或其他东西的新顶级产品,并以令牌结束。这样任何像这样的悬空括号都会导致错误。这是一个这样做的语法:

选项 {
  静态=假;
}

PARSER_BEGIN(代码解析器)
包 com.testing;

导入 java.io.StringReader;
导入java.io.Reader;

公共类 CodeParser {

    公共代码解析器(字符串)
    {
        this((Reader)(new StringReader(s)));

    }

    公共静态无效主(字符串参数 [])
    {
        尝试
        {
              /** 字符串有一个左括号,但有两个右括号 --> 应该会产生解析错误 */
              字符串 s = "A+BC+-(2XXL+A/-B))";
              CodeParser 解析器 = 新的 CodeParser(s);
              解析器.file();
        }
        捕获(异常 e)
        {
              e.printStackTrace();
        }
    }
}
PARSER_END(代码解析器)

代币:
{
        <code : ("-")?(["A"-"Z", "0"-"9"])+ >
        | <操作:(“+”|“/”)>
        | <不是:(“-”)>
        | <l括号:(“(”)>
        | <r括号:(“)”)>
}

无效文件():{} {
  表达式() <EOF>
}
无效表达式():
{
}
{
        否定表达式() | 括号表达式() | LOOKAHEAD(2) 运算符_表达式() | <代码>
}

无效否定表达式():
{
}
{
      <not>括号表达式()
}

无效括号表达式():
{
}
{
       <lparenthesis>表达式()<rparenthesis>
}

无效操作员表达式():
{
}
{
      <code><op>表达式()
}

和一个示例运行:

$ javacc -debug_parser -output_directory=com/testing/ CodeParser.jj && javac com/testing/*.java && java -cp 。com.testing.CodeParser
Java Compiler 编译器版本 5.0(解析器生成器)
(键入“javacc”,不带参数寻求帮助)
从文件 CodeParser.jj 中读取。. .
正在重建文件“TokenMgrError.java”。
正在重建文件“ParseException.java”。
正在重建文件“Token.java”。
正在重建文件“SimpleCharStream.java”。
解析器生成成功。
调用:文件
  调用:表达式
    调用:operator_expression
      使用的令牌:<<code>: "A" at line 1 column 1>
      使用的令牌:<<op>: "+" at line 1 column 2>
      调用:表达式
        调用:operator_expression
          使用的令牌:<<code>: "BC" at line 1 column 3>
          使用的令牌:<<op>: "+" at line 1 column 5>
          调用:表达式
            调用:否定表达式
              使用的令牌:<"-" at line 1 column 6>
              调用:括号表达式
                使用的令牌:<"(" at line 1 column 7>
                调用:表达式
                  调用:operator_expression
                    使用的令牌:<<code>: "2XXL" at line 1 column 8>
                    使用的令牌:<<op>: "+" at line 1 column 12>
                    调用:表达式
                      调用:operator_expression
                        使用的令牌:<<code>: "A" at line 1 column 13>
                        使用的令牌:<<op>: "/" at line 1 column 14>
                        调用:表达式
                          使用的令牌:<<code>: "-B" at line 1 column 15>
                        返回:表达式
                      返回:operator_expression
                    返回:表达式
                  返回:operator_expression
                返回:表达式
                使用的令牌:<")" 在第 1 行第 17 列>
              返回:括号表达式
            返回:否定表达式
          返回:表达式
        返回:operator_expression
      返回:表达式
    返回:operator_expression
  返回:表达式
返回:文件
com.testing.ParseException:在第 1 行第 18 列遇到“”)“”)“”。
期待:
    <EOF>

  在 com.testing.CodeParser.generateParseException(CodeParser.java:354)
  在 com.testing.CodeParser.jj_consume_token(CodeParser.java:238)
  在 com.testing.CodeParser.file(CodeParser.java:34)
  在 com.testing.CodeParser.main(CodeParser.java:22)

瞧!一个例外。

于 2009-11-13T15:02:26.547 回答
1

来自Java CC 常见问题解答

4.7 我添加了一个 LOOKAHEAD 规范,警告消失了;这是否意味着我解决了问题?

不会。如果您使用 LOOKAHEAD 规范,JavaCC 将不会报告选择冲突警告。没有警告并不意味着你已经正确解决了问题,它只是意味着你添加了一个 LOOKAHEAD 规范

我会首先尝试在不使用前瞻的情况下摆脱冲突。

于 2009-11-12T11:58:29.560 回答
1

问题是您在使用解析器时没有收到错误,对吗?并不是解析器生成器声称语法不正确(这似乎是另一个答案中的讨论)。

如果是这种情况,那么我怀疑您看到了问题,因为解析器正确匹配表达式产生,然后忽略后续输入。我已经很久没有使用 JavaCC 了,但是 iirc 并没有因为没有达到流尾而引发错误。

大多数语法都有一个明确的顶级生产来匹配整个文件,看起来像这样(我确定语法是错误的,正如我所说,已经很长时间了):

input : ( expression ) *

或者,如果您只想处理一个表达式,则可能有一个 EOF 令牌可供您使用。

于 2009-11-13T13:08:51.817 回答