source

ANTLR: 간단한 예가 있나요?

factcode 2022. 8. 30. 22:09
반응형

ANTLR: 간단한 예가 있나요?

ANTLR을 시작하고 싶은데, antlr.org 사이트에서 몇 시간 동안 예제를 검토해도 Java 프로세스에 대한 문법을 명확하게 이해할 수 없습니다.

ANTLR을 사용하여 구현된 4연산 계산기가 파서 정의를 거쳐 Java 소스 코드까지 이어지는 간단한 예가 있습니까?

참고: 이 답변은 ANTLR3에 대한 것입니다!ANTLR4의 예를 찾는 경우 이 Q&A에서는 ANTLR4를 사용하여 간단한 파서와 평가자를 작성하는 방법을 보여 줍니다.


먼저 문법을 만듭니다.다음은 +, -, * 및 /의 4가지 기본 연산자를 사용하여 작성된 식을 평가하는 데 사용할 수 있는 작은 문법입니다.괄호를 사용하여 식을 그룹화할 수도 있습니다.

이 문법은 단수 연산자(-1+9)나 .99와 같은 소수점(선행 번호 없음)을 처리하지 않고, 2개의 단점을 제시합니다.이것은 여러분이 스스로 할 수 있는 하나의 예에 불과합니다.

다음은 문법 파일 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;}
    ;

(파서 규칙은 소문자로 시작하고 렉서 규칙은 대문자로 시작합니다.)

문법을 만든 후에는 구문 분석기와 어휘기를 생성해야 합니다.ANTLR jar를 다운로드하여 문법 파일과 동일한 디렉토리에 저장합니다.

셸/명령 프롬프트에서 다음 명령을 수행합니다.

java -cp antlr-3.2.jar org.antlr.Tool Exp.g

에러 메세지는 표시되지 않습니다.ExpLexer.java, ExpParser.javaExp.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]: "Discription"

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이치노ANTLDemo.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)에서 새로운 렉서 및 파서를 생성하고 모든 클래스 (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월)는 Antlr (2014년 6월)입니다.ANTLRStringStream '''가 되기 위해'' ANTLRInputStream, 에서하기 위해 parser.eval()로로 합니다.parser.eval().value그리고 나는 제거할 필요가 있었다.WS절이 를 들어, 「」 때문입니다.$channel【플렉서

가브리엘레 Tomassetti에 의해 ANTLR메가 튜토리얼은 도움이 된다.

문법을 예, 방문자 다른 언어의 예(자바, 자바 스크립트, C#, Python)과 많은 다른 것들을 가지고 있다.고도로 추천된다.

편집:가브리엘레 Tomassetti ANTLR에 의해서 다른 유용한 용품들이다.

Antlr 4을 위해java 코드 생성 과정 이하- 있다.

java -cp antlr-4.5.3-complete.jar org.antlr.v4.Tool Exp.g

classpath에 그에 따라 교반 이름을 업데이트합니다.

버전 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);

https://github.com/BITPlan/com.bitplan.antlr에서 유용한 도우미 클래스와 몇 가지 완전한 예가 포함된 ANTLR Java 라이브러리를 찾을 수 있습니다.메이븐과 함께 사용할 수 있고 일식이나 메이븐을 좋아하시면 됩니다.

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은 3개의 파트로 분할된 IRI 파서입니다.

  1. 파서 문법
  2. 렉서 문법
  3. Import된 LexBasic 문법

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에 나타나 있듯이 수정되었습니다.

언급URL : https://stackoverflow.com/questions/1931307/antlr-is-there-a-simple-example

반응형