ANTLRのセマンティック述語とは何ですか?
2 に答える
アントラー4
ANTLR 4 の述語については、これらのスタックオーバーフローの Q&A を確認してください。
アントラー3
セマンティック述語は、単純なコードを使用して文法アクションに追加の (セマンティック) ルールを適用する方法です。
セマンティック述語には次の 3 種類があります。
- セマンティック述語の検証。
- ゲートされたセマンティック述語;
- セマンティック述語の曖昧さの解消。
文法例
空白を無視して、カンマで区切られた数字のみで構成されるテキスト ブロックがあるとします。この入力を解析して、数値が「長い」最大 3 桁 (最大 999) であることを確認します。次の文法 ( Numbers.g
) は、そのようなことを行います。
grammar Numbers;
// entry point of this parser: it parses an input string consisting of at least
// one number, optionally followed by zero or more comma's and numbers
parse
: number (',' number)* EOF
;
// matches a number that is between 1 and 3 digits long
number
: Digit Digit Digit
| Digit Digit
| Digit
;
// matches a single digit
Digit
: '0'..'9'
;
// ignore spaces
WhiteSpace
: (' ' | '\t' | '\r' | '\n') {skip();}
;
テスト
文法は、次のクラスでテストできます。
import org.antlr.runtime.*;
public class Main {
public static void main(String[] args) throws Exception {
ANTLRStringStream in = new ANTLRStringStream("123, 456, 7 , 89");
NumbersLexer lexer = new NumbersLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
NumbersParser parser = new NumbersParser(tokens);
parser.parse();
}
}
レクサーとパーサーを生成し、すべての.java
ファイルをコンパイルし、Main
クラスを実行してテストします。
java -cp antlr-3.2.jar org.antlr.Tool Numbers.g javac -cp antlr-3.2.jar *.java java -cp .:antlr-3.2.jar メイン
その場合、コンソールには何も出力されません。これは、何も問題がなかったことを示しています。変更してみてください:
ANTLRStringStream in = new ANTLRStringStream("123, 456, 7 , 89");
の中へ:
ANTLRStringStream in = new ANTLRStringStream("123, 456, 7777 , 89");
もう一度テストを行います。コンソールの文字列の直後にエラーが表示されます777
。
セマンティック述語
これにより、セマンティック述語が表示されます。1 桁から 10 桁までの数字を解析したいとしましょう。次のようなルール:
number
: Digit Digit Digit Digit Digit Digit Digit Digit Digit Digit
| Digit Digit Digit Digit Digit Digit Digit Digit Digit
/* ... */
| Digit Digit Digit
| Digit Digit
| Digit
;
面倒になるでしょう。セマンティック述語は、このタイプのルールを簡素化するのに役立ちます。
1. セマンティック述語の検証
検証用セマンティック述語は、疑問符が後に続くコード ブロックにすぎません。
RULE { /* a boolean expression in here */ }?
検証
セマンティック述語を使用して上記の問題を解決するnumber
には、文法のルールを次のように変更します。
number
@init { int N = 0; }
: (Digit { N++; } )+ { N <= 10 }?
;
部分{ int N = 0; }
とは、パーサーがルール{ N++; }
に「入る」ときに最初の部分が初期化される単純な Java ステートメントです。number
実際の述語は: です。これにより、
数値が 10 桁を超える場合は常に{ N <= 10 }?
パーサーが をスローし
ます。FailedPredicateException
次を使用してテストしますANTLRStringStream
。
// all equal or less than 10 digits
ANTLRStringStream in = new ANTLRStringStream("1,23,1234567890");
これは例外を生成しませんが、次の例では例外が発生します。
// '12345678901' is more than 10 digits
ANTLRStringStream in = new ANTLRStringStream("1,23,12345678901");
2. ゲーテッドセマンティック述語
ゲート付きセマンティック述語は検証セマンティック述語に似ていますが、ゲート付きバージョンのみが.の代わりに構文エラーを生成しますFailedPredicateException
。
ゲーテッド セマンティック述語の構文は次のとおりです。
{ /* a boolean expression in here */ }?=> RULE
代わりに、ゲーテッド述語を使用して最大 10 桁の数字に一致する上記の問題を解決するには、次のように記述します。
number
@init { int N = 1; }
: ( { N <= 10 }?=> Digit { N++; } )+
;
両方で再度テストします。
// all equal or less than 10 digits
ANTLRStringStream in = new ANTLRStringStream("1,23,1234567890");
と:
// '12345678901' is more than 10 digits
ANTLRStringStream in = new ANTLRStringStream("1,23,12345678901");
最後の on がエラーをスローすることがわかります。
3. セマンティック述語の曖昧さの解消
述語の最後のタイプは、あいまいさを解消するセマンティック述語です。これは、検証述語 ( ) に少し似ていますが、{boolean-expression}?
よりゲートされたセマンティック述語のように機能します (ブール式が に評価される場合、例外はスローされませんfalse
)。ルールの開始時にこれを使用して、ルールの一部のプロパティをチェックし、パーサーがそのルールに一致するかどうかを確認できます。
例の文法がNumber
、0..999 の範囲の数値に一致するトークン (パーサー規則ではなくレクサー規則) を作成するとします。ここで、パーサーで、低い数値と高い数値 (低い: 0..500、高い: 501..999) を区別したいと考えています。これは、明確化セマンティック述語を使用して行うことができます。この場合、ストリーム内の次のトークンを調べて ( input.LT(1)
)、トークンが低いか高いかを確認します。
デモ:
grammar Numbers;
parse
: atom (',' atom)* EOF
;
atom
: low {System.out.println("low = " + $low.text);}
| high {System.out.println("high = " + $high.text);}
;
low
: {Integer.valueOf(input.LT(1).getText()) <= 500}? Number
;
high
: Number
;
Number
: Digit Digit Digit
| Digit Digit
| Digit
;
fragment Digit
: '0'..'9'
;
WhiteSpace
: (' ' | '\t' | '\r' | '\n') {skip();}
;
string を解析する"123, 999, 456, 700, 89, 0"
と、次の出力が表示されます。
low = 123
high = 999
low = 456
high = 700
low = 89
low = 0
私は常にwincent.com のANTLR 述語への簡潔な参照をガイドとして使用してきました。