5

私はレクサーでこのようなものを解析したい:

( begin expression )

ここで、式も括弧で囲みます。(begin式に何が含まれているかは重要ではありません。と の一致の間にあるものをすべて)トークンとして取得したいだけです。例は次のとおりです。

(begin 
    (define x (+ 1 2)))

したがって、トークンのテキストは

(define x (+ 1 2)))

何かのようなもの

PROGRAM : LPAREN BEGIN .* RPAREN;

彼は「)」を見るとすぐにルールが終わったと思うので、(明らかに)機能しませんが、これには対応するブラケットが必要です。

どうやってやるの?

4

1 に答える 1

5

レクサールール内では、ルールを再帰的に呼び出すことができます。だから、それはこれを解決する一つの方法です。もう1つのアプローチは、開き括弧と閉じ括弧の数を追跡し、カウンターがゼロより大きい限り、ゲート付きセマンティック述語をループさせることです。

デモ:

Tg

grammar T;

parse
  :  BeginToken {System.out.println("parsed :: " + $BeginToken.text);} EOF
  ;

BeginToken 
@init{int open = 1;}
  :  '(' 'begin' ( {open > 0}?=>              // keep reapeating `( ... )*` as long as open > 0
                     ( ~('(' | ')')           // match anything other than parenthesis
                     | '('          {open++;} // match a '(' in increase the var `open`
                     | ')'          {open--;} // match a ')' in decrease the var `open`
                     )
                 )*
  ;

Main.java

import org.antlr.runtime.*;

public class Main {
  public static void main(String[] args) throws Exception {
    String input = "(begin (define x (+ (- 1 3) 2)))";
    TLexer lexer = new TLexer(new ANTLRStringStream(input));
    TParser parser = new TParser(new CommonTokenStream(lexer));
    parser.parse();
  }
}
java -cp antlr-3.3-complete.jar org.antlr.Tool T.g
javac -cp antlr-3.3-complete.jar *.java
java -cp .:antlr-3.3-complete.jar Main

parsed :: (begin (define x (+ (- 1 3) 2)))

ソース内の括弧を含む可能性のある文字列リテラルに注意する必要があることに注意してください。

BeginToken
@init{int open = 1;}
  :  '(' 'begin' ( {open > 0}?=>              // ...
                     ( ~('(' | ')' | '"')     // ...
                     | '('          {open++;} // ...
                     | ')'          {open--;} // ...
                     |  '"' ...               // TODO: define a string literal here
                     )
                 )*
  ;

または括弧を含む可能性のあるコメント。

述語を使用した提案では、言語固有のコード(この場合はJava)を使用します。レクサールールを再帰的に呼び出すことの利点は、レクサーにカスタムコードがないことです。

BeginToken 
  :  '(' Spaces? 'begin' Spaces? NestedParens Spaces? ')'
  ;

fragment NestedParens
  :  '(' ( ~('(' | ')') | NestedParens )* ')'
  ;

fragment Spaces
  :  (' ' | '\t')+
  ;
于 2011-08-03T05:01:57.787 に答える