ANTLR에서 의미 론적 술어 는 무엇입니까 ?
ANTLR에서 의미 론적 술어 는 무엇입니까 ?
답변:
ANTLR 4의 조건 자의 경우 다음 스택 오버플로 Q & A를 확인하십시오.
의미 술어 일반 코드를 사용하여 문법 조치에 따라 별도의 (의미) 규칙을 적용하는 방법입니다.
의미 론적 술어에는 세 가지 유형이 있습니다.
공백을 무시하고 쉼표로 구분 된 숫자로만 구성된 텍스트 블록이 있다고 가정 해 보겠습니다. 이 입력을 구문 분석하여 숫자가 최대 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
;
번거로울 것입니다. 시맨틱 술어는 이러한 유형의 규칙을 단순화하는 데 도움이 될 수 있습니다.
확인하는 의미 술어는 뒤에 물음표가 코드 블록에 지나지 않는다 :
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 }?
구문 분석기가 a를 던지도록
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");
게이트 의미 술어는 A와 비슷합니다 확인하는 의미 술어 만 문이 버전은 대신 구문 오류가 발생합니다 FailedPredicateException
.
게이트 시맨틱 술어 의 구문 은 다음과 같습니다.
{ /* a boolean expression in here */ }?=> RULE
대신 gated 술어를 사용하여 최대 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");
마지막에 오류가 발생하는 것을 볼 수 있습니다.
최종 유형의 술어는 명확화 의미 술어 이며, 이는 유효성 검사 술어 ( {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();}
;
이제 문자열을 파싱 "123, 999, 456, 700, 89, 0"
하면 다음 출력이 표시됩니다.
low = 123
high = 999
low = 456
high = 700
low = 89
low = 0
input.LT(1)
이다 getCurrentToken()
지금 :-)
나는 항상 wincent.com의 ANTLR 술어 에 대한 간결한 참조를 가이드로 사용했습니다.