2012-03-15 6 views
1

私はこの方法でXMLリテラルを組み込む予定そこに少し言葉を書いている:レクサーとパーサー間でANTLRの動的スコープを共有できますか?

X ?= <element attr='blah'>text<another attr='blah /> more text</element>; 

私はテレンスパーで貢献XML grammarsで働いています。私の問題は、PCDATAの定義が(~'<')+のようなものなので、の外にある私のモジュールの他のソースのすべてを取ります。

私がしたいのは、TEXTトークンにガードを入れて、XMLが必要なときだけアクティブにすることです。

PCDATA : {isInXmlFragment}?=> (~'<')+; 

問題は、スコープ変数をパーサーから設定する必要がありますが、レクサーで使用することです。私は、一般的に見えるクラスでは静的変数を介して何かを手配することができますが、複数のモジュールを並列に解析したいのであれば手間がかかります。 Parrのソリューションにはこのようなガードがありますが、レクサーのコンテキスト内でのみ動作し、他の種類のコンテンツがない純粋なXMLファイルでのみ動作します。

ソースコードファイルの中にそのXMLを埋め込んでいるので、XMLレシピのXML部分の範囲外にある他のテキストがスキャンされますが、XML PCDATAルールピースはすべてのソース、それはとても一般的ですから。

パーサーとレクサーの間でこのような通信を可能にする安全な組み込みの方法がありますか?スコープのようなもので、パーサ内からレクサーの動的スコープを参照する方法はありますか?

答えて

2

...パーザとレクサー間の通信を許可する方法はありますか?

いいえ、カスタムレクサーを作成しないでください。 ANTLRのデフォルトのlexer/parserには厳密な分離があります。つまり、lexerはパーサーとは別に動作します。

しかし、私が見る限り、これは必要ありません。あなたは再帰的にレクサールールを呼び出すことができます。だから、あなたがタグの始まりである<elementを見つけたときは、先読みして/>または>と一致するかのいずれかになります。 >が一致する場合は、<以外の文字を一致させるか、このレクサールール全体を再帰的に呼び出してください。その最後にはもちろん、</element>があるはずです。

迅速なデモ(属性なしには、簡単な文法を維持する):

grammar Test; 

parse 
: (t=. {System.out.printf("type=\%-15s text='\%s'\n", tokenNames[$t.type], $t.text);})* EOF 
; 

XML 
: '<' Identifier ('/>' 
        | '>' (~'<' | XML)* '</' Identifier '>' 
       ) 
; 

Identifier 
: ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')* 
; 

QAssign 
: '?=' 
; 

SCol 
: ';' 
; 

Spaces 
: (' ' | '\t' | '\r' | '\n')+ {skip();} 
; 

あなたが今入力パーサ場合:

X ?= <element>text<another/>more<i><b>text</b></i></element>; 

はあなたがコンソールに出力されている以下の表示されます。

type=Identifier  text='X' 
type=QAssign   text='?=' 
type=XML    text='<element>text<another/>more<i><b>text</b></i></element>' 
type=SCol   text=';' 

ご覧のとおり、XMLブロックは単一のトークンとして扱われています。それらの間にPCDATAトークンを持つopeneingとclosingタグトークンを使用する場合は、 "opening tags"の数を数え、その数が0より大きい場合は、~'<'+のようにPCDATAトークンと一致させる必要があります。このアプローチでは、レクサーとパーサーの間で通信する必要もありません。オープニングタグを保持するカウンタは、レクサーで定義されます。

デモ:

grammar Test; 

@lexer::members { 
    private int openTags = 0; 
} 

parse 
: any* EOF 
; 

any 
: Identifier 
| QAssign 
| SCol 
| xml 
; 

xml 
: OTag (PCData | xml)* CTag 
| Tag 
; 

PCData 
: {openTags > 0}?=> ~'<'+ 
; 

OTag 
: '<' Identifier ('>' {openTags++;} | '/>' {$type=Tag;}) 
; 

CTag 
: '</' Identifier '>' {openTags--;} 
; 

Identifier 
: ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')* 
; 

QAssign 
: '?=' 
; 

SCol 
: ';' 
; 

Spaces 
: (' ' | '\t' | '\r' | '\n')+ {skip();} 
; 

fragment Tag : ; 

が今のように入力をパース:

enter image description here

+0

おかげバート:

X ?= <x>text<y/>more<i><b>text</b></i></x>; 

すると、次のパースになります。私が探していたソリューションより優れた優れた答えです! –

+0

ようこそ@AndrewMatthews。 –

関連する問題