Проблема JavaCC - сгенерированный код не находит все ошибки разбора - PullRequest
1 голос
/ 12 ноября 2009

Только что начал с 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()
 }

Редактировать - 11/16/2009

Теперь я попробовал 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))))

Ответы [ 3 ]

3 голосов
/ 13 ноября 2009

То, что говорит Крегори, - правильный ответ. Это можно увидеть, если вы построите грамматику с параметром DEBUG_PARSER, а затем запустите ее:

$ javacc -debug_parser -output_directory=com/testing/ CodeParser.jj && javac com/testing/*.java && java -cp . com.testing.CodeParser
Java Compiler Compiler Version 5.0 (Parser Generator)
(type "javacc" with no arguments for help)
Reading from file CodeParser.jj . . .
File "TokenMgrError.java" is being rebuilt.
File "ParseException.java" is being rebuilt.
File "Token.java" is being rebuilt.
File "SimpleCharStream.java" is being rebuilt.
Parser generated successfully.
Call:   expression
  Call:   operator_expression
    Consumed token: <<code>: "A" at line 1 column 1>
    Consumed token: <<op>: "+" at line 1 column 2>
    Call:   expression
      Call:   operator_expression
        Consumed token: <<code>: "BC" at line 1 column 3>
        Consumed token: <<op>: "+" at line 1 column 5>
        Call:   expression
          Call:   negated_expression
            Consumed token: <"-" at line 1 column 6>
            Call:   parenthesis_expression
              Consumed token: <"(" at line 1 column 7>
              Call:   expression
                Call:   operator_expression
                  Consumed token: <<code>: "2XXL" at line 1 column 8>
                  Consumed token: <<op>: "+" at line 1 column 12>
                  Call:   expression
                    Call:   operator_expression
                      Consumed token: <<code>: "A" at line 1 column 13>
                      Consumed token: <<op>: "/" at line 1 column 14>
                      Call:   expression
                        Consumed token: <<code>: "-B" at line 1 column 15>
                      Return: expression
                    Return: operator_expression
                  Return: expression
                Return: operator_expression
              Return: expression
              Consumed token: <")" at line 1 column 17>
            Return: parenthesis_expression
          Return: negated_expression
        Return: expression
      Return: operator_expression
    Return: expression
  Return: operator_expression
Return: expression

Видишь это? Последний использованный токен - от второго до последнего символа - от второй до последней правой скобки.

Если вы хотите исключение, опять же, как сказал kgregory, вы можете добавить новый продукт верхнего уровня под названием «file» или «data» или что-то еще и завершить его токеном. Таким образом, любой подобный парандж может привести к ошибке. Вот грамматика, которая делает это:

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.file();
        }
        catch(Exception e)
        {
              e.printStackTrace();
        }
    }
}
PARSER_END(CodeParser)

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

void file() : {} {
  expression() <EOF>
}
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()
}

И примерный прогон:

$ javacc -debug_parser -output_directory=com/testing/ CodeParser.jj && javac com/testing/*.java && java -cp . com.testing.CodeParser
Java Compiler Compiler Version 5.0 (Parser Generator)
(type "javacc" with no arguments for help)
Reading from file CodeParser.jj . . .
File "TokenMgrError.java" is being rebuilt.
File "ParseException.java" is being rebuilt.
File "Token.java" is being rebuilt.
File "SimpleCharStream.java" is being rebuilt.
Parser generated successfully.
Call:   file
  Call:   expression
    Call:   operator_expression
      Consumed token: <<code>: "A" at line 1 column 1>
      Consumed token: <<op>: "+" at line 1 column 2>
      Call:   expression
        Call:   operator_expression
          Consumed token: <<code>: "BC" at line 1 column 3>
          Consumed token: <<op>: "+" at line 1 column 5>
          Call:   expression
            Call:   negated_expression
              Consumed token: <"-" at line 1 column 6>
              Call:   parenthesis_expression
                Consumed token: <"(" at line 1 column 7>
                Call:   expression
                  Call:   operator_expression
                    Consumed token: <<code>: "2XXL" at line 1 column 8>
                    Consumed token: <<op>: "+" at line 1 column 12>
                    Call:   expression
                      Call:   operator_expression
                        Consumed token: <<code>: "A" at line 1 column 13>
                        Consumed token: <<op>: "/" at line 1 column 14>
                        Call:   expression
                          Consumed token: <<code>: "-B" at line 1 column 15>
                        Return: expression
                      Return: operator_expression
                    Return: expression
                  Return: operator_expression
                Return: expression
                Consumed token: <")" at line 1 column 17>
              Return: parenthesis_expression
            Return: negated_expression
          Return: expression
        Return: operator_expression
      Return: expression
    Return: operator_expression
  Return: expression
Return: file
com.testing.ParseException: Encountered " ")" ") "" at line 1, column 18.
Was expecting:
    <EOF> 

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

Вуаля! Исключение.

1 голос
/ 13 ноября 2009

Проблема в том, что вы не получаете ошибку при использовании парсера, правильно? Не то чтобы генератор синтаксического анализатора утверждал, что грамматика неверна (что, кажется, обсуждается в другом ответе).

Если это так, то я подозреваю, что вы видите проблему, потому что синтаксический анализатор правильно соответствует продукции expression , а затем игнорирует последующий ввод. Я не использовал JavaCC в течение долгого времени, но в iirc он не выдавал ошибку за то, что не достиг конца потока.

Большинство грамматик имеют явную продукцию верхнего уровня, которая соответствует всему файлу, выглядит примерно так (я уверен, что синтаксис неправильный, как я уже сказал, это было давно):

input : ( expression ) *

Или, возможно, вы можете использовать токен EOF, если хотите обработать только одно выражение.

0 голосов
/ 12 ноября 2009

Из FAQ по Java CC :

4.7 Я добавил спецификацию LOOKAHEAD, и предупреждение исчезло; это значит, что я решил проблему?

Нет. JavaCC не будет сообщать о предупреждениях о конфликте выбора, если вы используете спецификацию LOOKAHEAD. отсутствие предупреждения не означает, что вы правильно решили проблему, это просто означает, что вы добавили спецификацию LOOKAHEAD .

Я бы начал с того, что попытался бы избавиться от конфликта, не используя вначале предвкушение.

...