2017-09-11 24 views
0

私はANTLR4を使ってパーサーを生成しています。私はパーサーの文法には新しいです。私は非常に役に立ちましたANTLR Mega Tutorialを読んだことがありますが、私はまだレクサーとパーサーの規則を正しく(そして/または書く)方法に固執しています。私は、パーサはこのようなものを扱うことができるようにしたいANTLR4を使用して文法でレクサールールを注文する

こんにちは< <名>>、お元気ですか?

実行時に「< < >>」をユーザーの名前に置き換えます。

私はレクサールールで "func"と呼ぶ "< < something"というタグを除いて、ほとんどがテキストワード(と句読点、記号など)を解析しています。ここで

は私の文法である:

doc: item* EOF ; 
item: (func | WORD) PUNCT? ; 
func: '<<' ID '>>' ; 

WS : [ \t\n\r] -> skip ; 
fragment LETTER : [a-zA-Z] ; 
fragment DIGIT : [0-9] ; 
fragment CHAR : (LETTER | DIGIT | SYMB) ; 
WORD : CHAR+ ; 
ID: LETTER (LETTER | DIGIT)* ; 
PUNCT : [.,?!] ; 
fragment SYMB : ~[a-zA-Z0-9.,?! |{}<>] ; 

サイドノート:私は "PUNCTの?" 追加しました上記の例の文章のように、 "func"の直後にコンマを置くことができるので、 "item"ルールの最後に。しかし、 "WORD"の後にコンマを置くこともできるので、 "func"と "WORD"の両方でなく、 "item"に句読点を入れることにしました。

私は上記の文で、このパーサを実行する場合、私はこのようになります解析木を取得:赤で強調表示 Parse tree 1

ものはパースエラーです。

したがって、「ID」として二重山括弧内の「ID」は認識されません。おそらくこれは、 "WORD"が私のレクサールールのリストの中で最初に来るからです。しかし、私は "< < WORD >>"というルールはありません。 "< < >>"というルールしかないので、なぜそれが起こっているのかは分かりません。

私は今、彼らはこの順序である、私の文法で「ID」の順と「WORD」を交換する場合: :

ID: LETTER (LETTER | DIGIT)* ; 
WORD : CHAR+ ; 

パーサーを実行し、私はこのような構文解析ツリーを取得Parse tree 2

"func"ルールと "ID"ルールは適切に処理されていますが、 "WORD"は認識されません。

どうすればこの問題を回避できますか?

「func」ルールを「< < WORD >>」に変更し、すべてを単語として扱い、「ID」で取り除くことが1つの選択肢と考えられます。しかし、私はテキストワードを可変識別子と区別したいと考えました(たとえば、可変識別子に特殊文字は使用できません)。

ありがとうございました!

+1

私はANTLRユーザーではありませんが、ANTLRは私が使った他のパーサジェネレータと同じように動作します:トークンは上から下への文法に関係なく認識されます。したがって、もし何かが 'WORD'と' ID'の両方にマッチすれば、それは常に文法の定義で最初に定義されたトークンとして認識されます。ですから、両方の場所で共通のトークン定義が必要になるでしょう。構文解析後、使用する文字が制作の要件と一致しているかどうかを確認できます。 –

答えて

1

The Definitive ANTLR 4 Referenceより:

ANTLRは文法で最初の指定されたルールへの入力文字列と一致 によって字句曖昧さを解決します。

あなたの文法で

(Question.g4中)と

Hello <<name>>, how are you at nine o'clock? 

を含むt.textファイル

$ grun Question doc -tokens -diagnostics t.text 

の実行が

[@0,0:4='Hello',<WORD>,1:0] 
[@1,6:7='<<',<'<<'>,1:6] 
[@2,9:12='name',<WORD>,1:9] 
[@3,14:15='>>',<'>>'>,1:14] 
[@4,16:16=',',<PUNCT>,1:16] 
[@5,18:20='how',<WORD>,1:18] 
[@6,22:24='are',<WORD>,1:22] 
[@7,26:28='you',<WORD>,1:26] 
[@8,30:31='at',<WORD>,1:30] 
[@9,33:36='nine',<WORD>,1:33] 
[@10,38:44='o'clock',<WORD>,1:38] 
[@11,45:45='?',<PUNCT>,1:45] 
[@12,47:46='<EOF>',<EOF>,2:0] 
line 1:9 mismatched input 'name' expecting ID 
line 1:14 extraneous input '>>' expecting {<EOF>, '<<', WORD, PUNCT} 

今すぐWORDを変更できますのwordにルール、およびwordルールを追加します

item: (func | word) PUNCT? ; 
word: WORD | ID ; 

をし、WORD前にIDを入れて:

ID: LETTER (LETTER | DIGIT)* ; 
WORD : CHAR+ ; 

トークンは今

[@0,0:4='Hello',<ID>,1:0] 
[@1,6:7='<<',<'<<'>,1:6] 
[@2,9:12='name',<ID>,1:9] 
[@3,14:15='>>',<'>>'>,1:14] 
[@4,16:16=',',<PUNCT>,1:16] 
[@5,18:20='how',<ID>,1:18] 
[@6,22:24='are',<ID>,1:22] 
[@7,26:28='you',<ID>,1:26] 
[@8,30:31='at',<ID>,1:30] 
[@9,33:36='nine',<ID>,1:33] 
[@10,38:44='o'clock',<WORD>,1:38] 
[@11,45:45='?',<PUNCT>,1:45] 
[@12,47:46='<EOF>',<EOF>,2:0] 

であり、これ以上のエラーはありません。 -guiのグラフィックが示すように、今度はwordまたはfuncと表示されています。

1

「500 - Internal Server Error」は既に彼のコメントで言及されているように、ANTLRは文法で定義された順序でレクサールールに一致します(一番上のルールが最初にマッチします)それを違うものにしようとしないでください。WORDが最初に宣言されているとして、あなたの場合は

WORDIDルールがabcは、両方の試合abcのような入力が、常にWORDとして一致さと決してIDようになることができます。実際にIDは、WORDと一致できないIDとして有効な入力がないため、決してマッチしません。

ただし、唯一の目標が<<>>の間にあるものを置き換えるのであれば、正規表現を使用する方がよいでしょう。しかし、まだANTLRを使用したい場合は、文法を減らして本質を気にする必要があります。これは、<<>>の間の入力と入力を区別するためです。

start: (INTERESTING | UNINTERESTING) ; 
INTERESTING: '<<' .*? '>>' ; 
UNINTERESTING: (~[<])+ | '<' ; 

それとも、完全にUNINTERESTINGをスキップすることもできますので、あなたの文法は次のようになります。

関連する問題