1

コンパイラー、パーサー、パーサージェネレーターの作成に興味がありますが、よくわかりません。

この質問の答えを読んだ後、私は「非常に」単純なLaTeXパーサーを作成しようとしました。

これはコードです:

grammar Latex;

latex   :   ITEM*;
ITEM    :   CMD|LAWTEXT;
CMD :   CHEAD ARGS;
CHEAD   :   '\\' LETTER(LETTER|DIGIT)*;
LETTER  :   'A'..'Z'|'a'..'z';
DIGIT   :   '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9';
ARGS    :   '{' ITEM* '}';
LAWTEXT :   (LETTER|DIGIT|WHITESPACE|PUNC)*;
WHITESPACE
    :   ' '|'\t'|'\n'|'\r';
PUNC    :   '!'|'^';

(テスト目的で、PUNCには2文字しかありません)

そしてこれはエラーメッセージです:

[18:39:09] warning(200): C:\Users\***\Documents\Latex.g:9:12: Decision can match input such as "{'\t'..'\n', '\r', ' '..'!', '0'..'9', 'A'..'Z', '\\', '^', 'a'..'z', '}'}" using multiple alternatives: 1, 2
As a result, alternative(s) 2 were disabled for that input
[18:39:09] error(201): C:\Users\***\Documents\Latex.g:9:12: The following alternatives can never be matched: 2

[18:39:09] error(211): C:\Users\***\Documents\Latex.g:1:8: [fatal] rule Tokens has non-LL(*) decision due to recursive rule invocations reachable from alts 1,2.  Resolve by left-factoring or using syntactic predicates or using backtrack=true option.

このエラーはあいまいさが原因で発生することがわかりました。コードは2つ以上の方法で解釈できますが、このあいまいさがどのように生成されるのかわかりません。

そして、これは図であり、何かを解釈できる2つの方法です(多分)。

図。

...しかし、どのよう\に、そして}混乱する可能性がありますか?

4

1 に答える 1

5

JiminPは次のよ​​うに書いています。

コンパイラー、パーサー、パーサージェネレーターの作成に興味がありますが、よくわかりません。

ANTLRは、作成した文法に基づいてレクサーとパーサーを作成します。ANTLR自体がパーサージェネレーターであるため、パーサージェネレーター自体を作成する必要はありません(幸いなことに!)。コンパイラーは、パーサーが生成するツリーを取得し、入力を他の形式に変換するアプリケーションです。これは、自分で行う必要があるものです。したがって、強調しておきます。ANTLRは、言語のパーサーを作成するのに役立つだけで、残りはあなた次第です。

さて、問題。

文法には、ほとんどレクサールールのみが含まれています。レクサールールは大文字で始まり、入力ソースをトークン化するために使用されます。したがって、次のようなルール:

LETTER  :   'A'..'Z'|'a'..'z';
...
LAWTEXT :   (LETTER|DIGIT|WHITESPACE|PUNC)*;

レクサーがLETTER独自にトークンを作成する可能性があります。常に小文字または大文字のASCII文字をLAWTEXTトークンにしたい場合は、次LETTERのようなフラグメントルールを作成する必要があります。

fragment LETTER  :   'A'..'Z'|'a'..'z';
...
LAWTEXT :   (LETTER|DIGIT|WHITESPACE|PUNC)+;

ご覧のとおり、LAWTEXTルールを:の+代わりに終了しました*。何も含まない(空の文字列)トークンを作成したくない場合。

またargs、、itemおよびcmdはレクサールールの適切な候補ではありません。代わりにパーサールールにする必要があります。

エラーなしでレクサーとパーサーを生成する文法は次のとおりです。

grammar Latex;

latex
  :  item* EOF
  ;

item 
  :  cmd
  |  LAWTEXT
  ;

cmd
  :  CHEAD args
  ;

args
  :  '{' item* '}'
  ;

CHEAD 
  :  '\\' LETTER (LETTER | DIGIT)*
  ;  

LAWTEXT
  :  (LETTER | DIGIT | WHITESPACE | PUNC)+
  ;

fragment  
WHITESPACE 
  :  ' ' | '\t' | '\n' | '\r'
  ;

fragment  
PUNC       
  : '!' | '^'
  ;

fragment
LETTER
  :  'A'..'Z' | 'a'..'z'
  ;

fragment
DIGIT
  :  '0'..'9'
  ;

編集

すでに述べたように、レクサールールは大文字で始まり、パーサールールは小文字で始まります。トークナイザーまたはスキャナーと呼ばれることもあるレクサーは、入力ソースを切り刻む役割を果たします。入力ソースは、単なる文字のストリームとして始まります。これらの文字は、レクサーによってグループ化されます。したがって、次のレクサールールが与えられます。

Identifier
  :  (Letter | '_') (Letter | '_' | Digit)*
  ;

Assign
  :  '='
  ;

Number
  :  Digit+ ('.' Digit+)?
  ;

fragment Digit
  :  '0'..'9'
  ;

fragment Letter
  :  'a'..'z' | 'A'..'Z'
  ;

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

次のような入力ソースを取ることができます:

foo = 12.34

レクサーはこれを次のように認識します。

'f', 'o', 'o', ' ', '=', ' ', '1', '2', '.', '3', '4', EOF

次のトークンを作成します。

  • Identifier "foo"
  • Assign "="
  • Number "12.34"

(空白から作成されているトークンはないことに注意してください:これらをスキップしました!)

レクサーが入力ソースからトークンを作成した後、パーサーにこれらのトークンが渡されます。割り当てパーサールールは次のようになります。

assignment
  :  Identifier Assign Number
  ;

入力ソースは最初にレクサーによってトークン化され、そのプロセスの後でのみパーサールールが機能することを覚えておくことが重要です。

于 2011-05-23T11:48:46.427 に答える