2017-03-25 6 views
1

ATN状態番号を何らかの形で文法に挿入できますか?文法に状態番号を入れようとする

私は、すべての不可避のリテラル値をドキュメントに自動的に追加するツールを作ろうとしています。ユーザーは、私が;を追加したいか、ユーザーがifを入力した場合、私は括弧()を追加したいassert書き込むと

statement 
    : block 
    | 'assert' expression (':' expression)? ';' 
    | 'if' '(' expression ')' statement ('else' statement)? 
    ; 

:たとえば、次のルールを与えられました。

私は状態番号を持っていれば、文法を解析してリテラル値を見つけて適切な状態番号で保存することができるので、ユーザーが特定の状態に入るときにパーサーはユーザーに自動的に挿入できるテキストがあるかどうかを確認します。

答えて

0

まあ、私はAPIで遊んだし、それほど難しいことでもありませんでした。状態が入力されたときに認識された文法の領域の前後に、すべての状態番号を文法ファイルのコピーに挿入するコードを次に示します。正直なところ、間隔がnullのときの意味がわからない。これは、およそ3分の1の州の場合のようです。

ファイルに挿入するコードは、xor_eq's answerからそのまま引き継がれています。答えるために時間を割いて

enter image description here

private static String GRAMMAR_FILE_NAME = "JavaSimple.g4"; 
private static String EDITED_GRAMMAR_FILE_NAME = "JavaSimple_edited.g4"; 

private static void insertStateNumbersIntoGrammar() throws IOException, RecognitionException { 
    copyGrammarFile(); 

    // Load tokens 
    ANTLRInputStream input = new ANTLRFileStream(GRAMMAR_FILE_NAME); 
    ANTLRv4Lexer lexer = new ANTLRv4Lexer(input); 
    CommonTokenStream tokens = new CommonTokenStream(lexer); 
    tokens.fill(); 

    // Load Grammar 
    String contents = new String(Files.readAllBytes(Paths.get(GRAMMAR_FILE_NAME))); 
    Grammar g = new Grammar(contents); 

    List<Insert> inserts = new ArrayList<Insert>(); 
    boolean before = false; 
    for (ATNState state : g.atn.states) { 
     int stateNr = state.stateNumber; 
     Interval interval = g.getStateToGrammarRegion(stateNr); 
     if (interval != null) { 
      Token token = before ? tokens.get(interval.a) : tokens.get(interval.b); 
      int i = before ? token.getStartIndex() : token.getStopIndex() + 1; 

      String stateStr = "[" + stateNr + "]"; 
      long insertSize = calcInsertLengthBefore(inserts, i); 
      insert(EDITED_GRAMMAR_FILE_NAME, i + insertSize, stateStr.getBytes()); 
      inserts.add(new Insert(i, stateStr)); 
     } 
    } 
} 

private static int calcInsertLengthBefore(List<Insert> inserts, int index) { 
    return inserts.stream() 
      .filter(insert -> insert.index < index) 
      .flatMapToInt(insert -> IntStream.of(insert.state.length())) 
      .sum(); 
} 

private static void insert(String filename, long offset, byte[] content) throws IOException { 
    RandomAccessFile r = new RandomAccessFile(new File(filename), "rw"); 
    RandomAccessFile rtemp = new RandomAccessFile(new File(filename + "~"), "rw"); 
    long fileSize = r.length(); 
    FileChannel sourceChannel = r.getChannel(); 
    FileChannel targetChannel = rtemp.getChannel(); 
    sourceChannel.transferTo(offset, (fileSize - offset), targetChannel); 
    sourceChannel.truncate(offset); 
    r.seek(offset); 
    r.write(content); 
    long newOffset = r.getFilePointer(); 
    targetChannel.position(0L); 
    sourceChannel.transferFrom(targetChannel, newOffset, (fileSize - offset)); 
    sourceChannel.close(); 
    targetChannel.close(); 
} 

private static void copyGrammarFile() { 
    File source = new File(GRAMMAR_FILE_NAME); 
    File target = new File(EDITED_GRAMMAR_FILE_NAME); 
    try { 
     Files.copy(source.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

private static class Insert { 
    final Integer index; 
    final String state; 

    Insert(int index, String state) { 
     this.index = index; 
     this.state = state; 
    } 
} 
0

文法には常に有効な入力が記述されているため、指定された文法ではこれを行うことはできません。
したがって、ユーザーが文をまだ完了していない入力(たとえば、assertと入力した)を解析しようとすると、エラーが発生します。もちろん、ANTLRのエラーリカバリシステムを利用して処理することもできますが、それはかなり"汚れた"ソリューションと考えています。

(私のopninionで)あなたが持っている選択肢が

  1. ているあなたは、それぞれの不完全な文に一致する文法を書いて、あなたが挿入プロセスを扱う特定の文字
  2. を挿入するかどうかをそのパーサに基づいて決めますそれは構文解析とは何の関係もないので、完全に分離しています(私が推奨する)。あなたが文法を変更しているときに補完を自動的に更新したいのであれば、文法のそれぞれの情報をファイルに書き込むプログラムを書く必要があると言いたいと思います。入れ子
+0

ありがとう:

このコードの結果は次のようになります。 2番目の方法は、挿入するテキストの保存方法です。問題は、挿入するときに**を選択することです。私はあなたが間違っているのは、有効な入力だけを解析すると言っていると思います。 Antlr4はHoney Badgerと呼ばれ、あなたが与えるものは何でもかまいません)。そして、私は文法のその位置に一致する州の番号を得るためにユーザーが入力したところまで解析する必要があります。 – MyiEye

+0

ええ、もしそれが唯一の必要ならば、ANTLRは実際にはあなたがそれをフィードしているが、適切であると思う方法でエラーノードを生成するので、それは動作する可能性があります。 – Raven

+0

どのようにして国家番号を取得し、文法のどの部分を参照できるのか分かりますか? – MyiEye

関連する問題