1

JavaCCを始めたばかりです。しかし、私はそれに対して奇妙な行動をとっています。記号 (+、-、​​/) で連結され、括弧を含めることができるトークン (文字と数字) の形式で入力を検証したいと考えています。それが理解できたことを願っています:)

メイン メソッドには文字列があり、開き括弧が 1 つと閉じ括弧が 2 つあるため、エラーが発生するはずですが、解析例外が発生しません --> なぜですか?

なぜ例外が発生しないのか、誰にも手がかりがありますか?

私は最初の試行で左再帰と選択の競合に苦しんでいましたが、なんとかそれらを乗り越えることができました. 多分私は問題を導入しましたか?

ああ、おそらく私の解決策はあまり良くありません-この事実を無視してください...または、より良いアドバイスをしてください;-)

ファイル: 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 コンパイラ コンパイラ バージョン 5.0 (パーサー ジェネレーター)
(ヘルプの引数なしで「javacc」と入力)
ファイル CodeParser.jj からの読み取り。. .
ファイル「TokenMgrError.java」は再構築中です。
ファイル「ParseException.java」は再構築中です。
ファイル「Token.java」は再構築中です。
ファイル「SimpleCharStream.java」は再構築中です。
パーサーが正常に生成されました。
呼び出し: 式
  呼び出し: operator_expression
    消費されたトークン: <<コード>: 行 1 列 1 の「A」>
    消費されたトークン: <<op>: "+" at line 1 column 2>
    呼び出し: 式
      呼び出し: operator_expression
        消費トークン: <<code>: 行 1 列 3 の「BC」>
        消費されたトークン: <<op>: "+" at line 1 column 5>
        呼び出し: 式
          呼び出し: negated_expression
            消費トークン: <"-" at line 1 column 6>
            呼び出し: parenthesis_expression
              消費されたトークン: <"(" at line 1 column 7>
              呼び出し: 式
                呼び出し: operator_expression
                  消費されたトークン: <<code>: 行 1 列 8 の「2XXL」>
                  消費されたトークン: <<op>: "+" at line 1 column column 12>
                  呼び出し: 式
                    呼び出し: operator_expression
                      消費トークン: <<code>: 行 1 列 13 の「A」>
                      消費されたトークン: <<op>: "/" at line 1 column column 14>
                      呼び出し: 式
                        消費トークン: <<code>: "-B" at line 1 column column 15>
                      戻り値: 式
                    戻り値: operator_expression
                  戻り値: 式
                戻り値: operator_expression
              戻り値: 式
              消費されたトークン: <")" 行 1 列 17>
            戻り値: 括弧式
          戻り値: negated_expression
        戻り値: 式
      戻り値: operator_expression
    戻り値: 式
  戻り値: operator_expression
戻り値: 式

わかりますか?最後に消費されたトークンは、最後から 2 番目の文字 (最後から 2 番目の右括弧) です。

例外が必要な場合は、kgregory が言ったように、「ファイル」または「データ」などと呼ばれる新しいトップレベルのプロダクションを追加し、トークンで終了することができます。そうすれば、このようなぶら下がっている括弧はエラーを引き起こします。これを行う文法は次のとおりです。

オプション {
  静的 = false;
}

PARSER_BEGIN(コードパーサー)
パッケージcom.testing;

java.io.StringReader をインポートします。
java.io.Reader をインポートします。

public class CodeParser {

    public CodeParser(String s)
    {
        this((Reader)(新しい StringReader(s)));

    }

    public static void main(String args[])
    {
        試す
        {
              /** 文字列には開き括弧が 1 つありますが、閉じ括弧が 2 つあります --> 解析エラーが発生するはずです */
              文字列 s = "A+BC+-(2XXL+A/-B))";
              CodeParser パーサー = 新しい CodeParser(s);
              パーサー.ファイル();
        }
        キャッチ(例外e)
        {
              e.printStackTrace();
        }
    }
}
PARSER_END(コードパーサー)

トークン:
{
        <コード : ("-")?(["A"-"Z", "0"-"9"])+ >
        | | <op : ("+"|"/") >
        | | <not : ("-") >
        | | <括弧: ("(") >
        | | <r括弧: (")") >
}

空ファイル(): {} {
  式() <EOF>
}
ボイド式() :
{
}
{
        negated_expression() | 括弧式() | LOOKAHEAD(2) operator_expression() | <コード>
}

void negated_expression() :
{
}
{
      <not>括弧式()
}

無効括弧_式() :
{
}
{
       <l括弧>expression()<r括弧>
}

void operator_expression() :
{
}
{
      <コード><op>式()
}

そしてサンプル実行:

$ javacc -debug_parser -output_directory=com/testing/ CodeParser.jj && javac com/testing/*.java && java -cp . com.testing.CodeParser
Java コンパイラ コンパイラ バージョン 5.0 (パーサー ジェネレーター)
(ヘルプの引数なしで「javacc」と入力)
ファイル CodeParser.jj からの読み取り。. .
ファイル「TokenMgrError.java」は再構築中です。
ファイル「ParseException.java」は再構築中です。
ファイル「Token.java」は再構築中です。
ファイル「SimpleCharStream.java」は再構築中です。
パーサーが正常に生成されました。
呼び出し: ファイル
  呼び出し: 式
    呼び出し: operator_expression
      消費されたトークン: <<コード>: 行 1 列 1 の「A」>
      消費されたトークン: <<op>: "+" at line 1 column 2>
      呼び出し: 式
        呼び出し: operator_expression
          消費トークン: <<code>: 行 1 列 3 の「BC」>
          消費されたトークン: <<op>: "+" at line 1 column 5>
          呼び出し: 式
            呼び出し: negated_expression
              消費トークン: <"-" at line 1 column 6>
              呼び出し: parenthesis_expression
                消費されたトークン: <"(" at line 1 column 7>
                呼び出し: 式
                  呼び出し: operator_expression
                    消費されたトークン: <<code>: 行 1 列 8 の「2XXL」>
                    消費されたトークン: <<op>: "+" at line 1 column column 12>
                    呼び出し: 式
                      呼び出し: operator_expression
                        消費トークン: <<code>: 行 1 列 13 の「A」>
                        消費されたトークン: <<op>: "/" at line 1 column column 14>
                        呼び出し: 式
                          消費トークン: <<code>: "-B" at line 1 column column 15>
                        戻り値: 式
                      戻り値: operator_expression
                    戻り値: 式
                  戻り値: operator_expression
                戻り値: 式
                消費されたトークン: <")" 行 1 列 17>
              戻り値: 括弧式
            戻り値: negated_expression
          戻り値: 式
        戻り値: 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 FAQから:

4.7 LOOKAHEAD 仕様を追加したところ、警告が消えました。それは私が問題を解決したということですか?

いいえ。LOOKAHEAD 仕様を使用する場合、JavaCC は選択肢の競合の警告を報告しません。警告がないことは、問題が正しく解決されたことを意味するのではなく、LOOKAHEAD 仕様を追加したことを意味するだけです

最初に先読みを使用せずに競合を取り除こうとすることから始めます。

于 2009-11-12T11:58:29.560 に答える
1

問題は、パーサーを使用するときにエラーが発生しないことですよね? パーサージェネレーターが文法が正しくないと主張しているわけではありません(これは他の回答の議論のようです)。

その場合は、パーサーがの生成を適切に照合し、後続の入力を無視するため、問題が発生していると思われます。私は長い間 JavaCC を使用していませんが、iirc はストリームの終わりに達していないというエラーをスローしませんでした。

ほとんどの文法には、ファイル全体に一致する明示的なトップレベルのプロダクションがあり、次のようになります (私が言ったように、構文が間違っていると確信しています。それは長い間です):

input : ( expression ) *

または、単一の式だけを処理する場合は、使用できる EOF トークンがおそらくあります。

于 2009-11-13T13:08:51.817 に答える