5

不完全な文法を使用する一般的な解決策はありますか? 私の場合、Delphi(Pascal)ファイルのメソッドを検出したいだけです。つまりproceduresfunctions. 次の最初の試みは機能しています

    methods
      : ( procedure | function | . )+
      ;

しかし、それはまったく解決策ですか?より良い解決策はありますか?アクションで解析を停止することは可能ですか (たとえば、検出後implementation)。プリプロセッサを使用する意味はありますか? はい、いつ - どのように?

4

2 に答える 2

4

あなたが尋ねていることは、島の文法と呼ばれています。その概念は、関心のある言語の部分 (「島」) にパーサーを定義し、その部分に必要なすべての古典的なトークン化を定義し、残りをスキップするために非常にずさんなパーサーを定義することです (「海」)島が埋め込まれている)。これを行うための一般的なトリックの 1 つは、対応するずさんなレクサーを定義することです。これは膨大な量のものを取得します (HTML を埋め込まれたコードにスキップするには、レクサーのスクリプト タグのように見えないものをすべてスキップすることができます。例)。

ANTLR サイトでは、いくつかの関連する問題についても説明していますが、特に ANTLR に含まれる例があると述べています。私は ANTLR の経験がないので、この特定の情報がどれほど役立つかわかりません。

パーサーを使用してコードを分析/変換する多くのツールを構築してきました (私のバイオを確認してください)。私は島の文法の一般的な有用性について少し悲観的です。あなたの目標が解析された島でかなり些細なことをすることでない限り、それが直接的または間接的に使用するすべての識別子の意味を収集する必要があります...そして残念ながらそれらのほとんどは海で定義されています。したがって、私見では、些細なタスクを乗り越えるためにも海を解析する必要があります。他の問題も発生し、島のことを本当にスキップしていることを確認してください。これは、海洋レクサーが空白、コメント、および文字列のすべてのうるさい構文 (これは現代の言語で見るよりも難しい) を認識しているため、これらが適切にスキップされることを意味します。YMMV。

于 2011-08-26T13:59:18.093 に答える
4

名前だけを探している場合は、次のように簡単です。

grammar PascalFuncProc;

parse
  :  (Procedure | Function)* EOF
  ;

Procedure
  :  'procedure' Spaces Identifier
  ;

Function
  :  'function' Spaces Identifier
  ;

Ignore
  :  (StrLiteral | Comment | .) {skip();}
  ;

fragment Spaces     : (' ' | '\t' | '\r' | '\n')+;
fragment Identifier : ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')*;
fragment StrLiteral : '\'' ~'\''* '\'';
fragment Comment    : '{' ~'}'* '}';

トリックを行います。私は Delhpi/Pascal にあまり詳しくないので、StrLiterals や s を間違いなく間違えていることに注意してくださいComment。しかし、それは簡単に修正できます。

上記の文法から生成されたレクサーは、2 種類のトークン ( Procedures とFunctions) のみを生成し、残りの入力 (文字列リテラル、コメント、または何も一致しない場合は単一の文字: the .) はレクサーからすぐに破棄されます (skip()メソッド)。

次のような入力の場合:

some valid source
{ 
  function NotAFunction ...
}

procedure Proc
Begin
  ...
End;

procedure Func
Begin
  s = 'function NotAFunction!!!'
End;

次の解析ツリーが作成されます。

ここに画像の説明を入力

于 2011-08-26T13:09:57.523 に答える