Antlr : 간단한 예가 있습니까?
문제
나는 Antlr을 시작하고 싶지만 몇 시간을 보낸 후에는 예제를 검토했습니다. antlr.org 사이트, 나는 여전히 문법에 대한 자바 과정에 대한 명확한 이해를 얻을 수 없습니다.
Parser 정의를 통해 ANTLR과 Java 소스 코드까지의 4 개 작동 계산기와 같은 간단한 예가 있습니까?
해결책
메모:이 대답은입니다 antlr3! 당신이 찾고 있다면 antlr4 예를 들어, 이것 Q & A 간단한 표현 파서를 만드는 방법을 보여주고 평가자를 사용하는 방법을 보여줍니다. antlr4.
먼저 문법을 만듭니다. 아래는 4 개의 기본 수학 연산자 인 +, -, * 및 /를 사용하여 구축 된 표현식을 평가하는 데 사용할 수있는 작은 문법입니다. 괄호를 사용하여 표현을 그룹화 할 수도 있습니다.
이 문법은 매우 기본적인 것입니다. 단지 연산자 (-1+9의 마이너스 : -1+9) 또는 .99 (주요 숫자가없는)와 같은 소수점을 처리하지 않으며 두 가지 단점을 지정합니다. 이것은 당신이 스스로 일할 수있는 예일뿐입니다.
문법 파일의 내용은 다음과 같습니다 exp.g:
grammar Exp;
/* This will be the entry point of our parser. */
eval
: additionExp
;
/* Addition and subtraction have the lowest precedence. */
additionExp
: multiplyExp
( '+' multiplyExp
| '-' multiplyExp
)*
;
/* Multiplication and division have a higher precedence. */
multiplyExp
: atomExp
( '*' atomExp
| '/' atomExp
)*
;
/* An expression atom is the smallest part of an expression: a number. Or
when we encounter parenthesis, we're making a recursive call back to the
rule 'additionExp'. As you can see, an 'atomExp' has the highest precedence. */
atomExp
: Number
| '(' additionExp ')'
;
/* A number: can be an integer value, or a decimal value */
Number
: ('0'..'9')+ ('.' ('0'..'9')+)?
;
/* We're going to ignore all white space characters */
WS
: (' ' | '\t' | '\r'| '\n') {$channel=HIDDEN;}
;
(파서 규칙은 소문자로 시작하고 Lexer 규칙은 대문자로 시작합니다)
문법을 만든 후에는 파서와 Lexer를 생성하고 싶을 것입니다. 다운로드 Antlr 항아리 문법 파일과 동일한 디렉토리에 저장하십시오.
쉘/명령 프롬프트에서 다음 명령을 실행하십시오.
java -cp antlr-3.2.jar org.antlr.Tool Exp.g
오류 메시지와 파일을 생성해서는 안됩니다. Explexer.java, Expparser.java 그리고 exp.tokens 이제 생성해야합니다.
모든 것이 올바르게 작동하는지 확인하려면이 테스트 클래스를 작성하십시오.
import org.antlr.runtime.*;
public class ANTLRDemo {
public static void main(String[] args) throws Exception {
ANTLRStringStream in = new ANTLRStringStream("12*(5-6)");
ExpLexer lexer = new ExpLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
ExpParser parser = new ExpParser(tokens);
parser.eval();
}
}
컴파일 :
// *nix/MacOS
javac -cp .:antlr-3.2.jar ANTLRDemo.java
// Windows
javac -cp .;antlr-3.2.jar ANTLRDemo.java
그런 다음 실행하십시오.
// *nix/MacOS
java -cp .:antlr-3.2.jar ANTLRDemo
// Windows
java -cp .;antlr-3.2.jar ANTLRDemo
모든 것이 잘되면 콘솔에 아무것도 인쇄되지 않습니다. 이것은 파서가 오류를 찾지 못했음을 의미합니다. 당신이 변할 때 "12*(5-6)"
~ 안으로 "12*(5-6"
그런 다음 다시 컴파일하고 실행하면 다음을 인쇄해야합니다.
line 0:-1 mismatched input '<EOF>' expecting ')'
좋아, 이제 우리는 파서가 실제로 유용한 일을하도록 문법에 약간의 Java 코드를 추가하고 싶습니다. 코드를 추가하면 배치하여 수행 할 수 있습니다 {
그리고 }
평범한 자바 코드가있는 문법 내부.
그러나 먼저 : 문법 파일의 모든 파서 규칙은 원시 이중 값을 반환해야합니다. 추가하여 할 수 있습니다 returns [double value]
각 규칙 후 :
grammar Exp;
eval returns [double value]
: additionExp
;
additionExp returns [double value]
: multiplyExp
( '+' multiplyExp
| '-' multiplyExp
)*
;
// ...
설명이 거의 필요합니다. 모든 규칙은 이중 값을 반환 할 것으로 예상됩니다. 이제 반환 값과 "상호 작용"합니다 double value
(일반 Java 코드 블록 내부에 있지 않습니다. {...}
) 코드 블록 내부에서 앞에 달러 표시를 추가해야합니다. value
:
grammar Exp;
/* This will be the entry point of our parser. */
eval returns [double value]
: additionExp { /* plain code block! */ System.out.println("value equals: "+$value); }
;
// ...
문법은 다음과 같습니다. 이제 Java 코드가 추가되었습니다.
grammar Exp;
eval returns [double value]
: exp=additionExp {$value = $exp.value;}
;
additionExp returns [double value]
: m1=multiplyExp {$value = $m1.value;}
( '+' m2=multiplyExp {$value += $m2.value;}
| '-' m2=multiplyExp {$value -= $m2.value;}
)*
;
multiplyExp returns [double value]
: a1=atomExp {$value = $a1.value;}
( '*' a2=atomExp {$value *= $a2.value;}
| '/' a2=atomExp {$value /= $a2.value;}
)*
;
atomExp returns [double value]
: n=Number {$value = Double.parseDouble($n.text);}
| '(' exp=additionExp ')' {$value = $exp.value;}
;
Number
: ('0'..'9')+ ('.' ('0'..'9')+)?
;
WS
: (' ' | '\t' | '\r'| '\n') {$channel=HIDDEN;}
;
그리고 우리 이후로 eval
규칙은 이제 두 배를 반환하고 antlrdemo.java를 이것으로 변경합니다.
import org.antlr.runtime.*;
public class ANTLRDemo {
public static void main(String[] args) throws Exception {
ANTLRStringStream in = new ANTLRStringStream("12*(5-6)");
ExpLexer lexer = new ExpLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
ExpParser parser = new ExpParser(tokens);
System.out.println(parser.eval()); // print the value
}
}
다시 (Re) 문법 (1)에서 신선한 Lexer와 Parser를 생성하고 모든 클래스 (2)를 컴파일하고 Antlrdemo (3)를 실행하십시오.
// *nix/MacOS
java -cp antlr-3.2.jar org.antlr.Tool Exp.g // 1
javac -cp .:antlr-3.2.jar ANTLRDemo.java // 2
java -cp .:antlr-3.2.jar ANTLRDemo // 3
// Windows
java -cp antlr-3.2.jar org.antlr.Tool Exp.g // 1
javac -cp .;antlr-3.2.jar ANTLRDemo.java // 2
java -cp .;antlr-3.2.jar ANTLRDemo // 3
그리고 이제 표현의 결과를 볼 수 있습니다 12*(5-6)
콘솔에 인쇄되었습니다!
다시 : 이것은 매우 간단한 설명입니다. 나는 당신이 찾아 보라고 권장합니다 Antlr Wiki 그리고 방금 게시 한 내용과 함께 튜토리얼을 읽거나 조금 재생하십시오.
행운을 빕니다!
편집하다:
이 게시물 위의 예를 확장하여 Map<String, Double>
제공된 표현식에서 변수를 보유하는 제공 될 수 있습니다.
이 코드가 현재 버전의 Antlr (2014 년 6 월)으로 작동하도록하려면 몇 가지 변경이 필요했습니다. ANTLRStringStream
필요합니다 ANTLRInputStream
, 변경하는 데 필요한 반환 된 값 parser.eval()
에게 parser.eval().value
, 그리고 나는 그것을 제거해야했다 WS
다음과 같은 속성 값 때문에 끝에있는 조항 $channel
더 이상 Lexer 행동에 나타나지 않습니다.
다른 팁
Antlr 메가 튜토리얼 Gabriele Tomassetti는 매우 도움이됩니다
문법 예제, 다른 언어 (Java, JavaScript, C# 및 Python)의 방문자의 예 및 기타 많은 것들이 있습니다. 추천.
편집 : Antlr의 Gabriele Tomassetti의 기타 유용한 기사
Antlr 4의 경우 Java 코드 생성 프로세스는 다음과 같습니다.
java -cp antlr-4.5.3-complete.jar org.antlr.v4.Tool Exp.g
그에 따라 ClassPath에서 항아리 이름을 업데이트하십시오.
~에 https://github.com/bitplan/com.bitplan.antlr 유용한 도우미 클래스와 몇 가지 완전한 예제가있는 Antlr Java 라이브러리가 있습니다. Maven과 함께 사용할 준비가되어 있으며 Eclipse와 Maven을 좋아한다면.
https://github.com/bitplan/com.bitplan.antlr/blob/master/src/main/antlr4/com/bitplan/exp/exp.g4
곱하고 작업을 추가 할 수있는 간단한 표현 언어입니다.https://github.com/bitplan/com.bitplan.antlr/blob/master/src/test/java/com/bitplan/antlr/testexpparser.java 해당 단위 테스트가 있습니다.
https://github.com/bitplan/com.bitplan.antlr/blob/master/src/main/antlr4/com/bitplan/iri/iriparser.g4 세 부분으로 분할 된 IRI 파서입니다.
- 파서 문법
- 렉서 문법
- 수입 된 렉스 바이스 문법
https://github.com/bitplan/com.bitplan.antlr/blob/master/src/test/java/com/bitplan/antlr/testiriparser.java단위 테스트가 있습니다.
개인적으로 나는 이것이 바로 올바른 부분을 찾았다는 것을 알았습니다. 보다 http://wiki.bitplan.com/index.php/antlr_maven_plugin
https://github.com/bitplan/com.bitplan.antlr/tree/master/src/main/antlr4/com/bitplan/expr
이전 버전에서 Antlr4의 성능 문제를 위해 만들어진 세 가지 예제가 포함되어 있습니다. 그 동안이 문제는 테스트 케이스로 수정되었습니다. https://github.com/bitplan/com.bitplan.antlr/blob/master/src/test/java/com/bitplan/antlr/testissue994.java 쇼.
버전 4.7.1은 약간 다릅니다. 가져 오기 :
import org.antlr.v4.runtime.*;
기본 세그먼트의 경우 - Charstreams를 참고하십시오.
CharStream in = CharStreams.fromString("12*(5-6)");
ExpLexer lexer = new ExpLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
ExpParser parser = new ExpParser(tokens);