2017-10-22 1 views
0

나는 this tutorial을 따르고 있으며 자습서에서 사용한 4.5 대신 Antlr 4.7을 사용한다는 것을 제외하고는 동작을 복제했습니다.요소에 ANTLR에 의해 생성 된 파서로 구문 분석 된 특성을 포함 할 수 있습니까? 그렇다면 어떻게?

비용 추적자 용 DSL을 구축하려고합니다.

각 요소에 속성이있을 수 있는지 궁금한가요?

예. 이것은 요소가 또한 양 등 2 개 속성을 가질 것이다라고 의미 https://github.com/simkimsia/learn-antlr-web-js/blob/master/todo.g4

grammar todo; 

elements 
    : (element|emptyLine)* EOF 
    ; 

element 
    : '*' (' ' | '\t')* CONTENT NL+ 
    ; 

emptyLine 
    : NL 
    ; 

NL 
    : '\r' | '\n' 
    ; 

CONTENT 
    : [a-zA-Z0-9_][a-zA-Z0-9_ \t]* 
    ;  

에서 볼 수 있듯이 이것은 todo.g4에 대한 코드가

enter image description here

지금 모습입니다 수취인. 간단하게하기 위해 동일한 구문을 사용하여 구문 분석을보다 쉽게 ​​수행 할 수 있습니다.

포맷은 예 pay Acme Corp 123,789.45

이다 pay [payee] [amount]

될 것이다하기 때문에 수취인은 파브 사이며 센트

다른 예의 교의 양을 나타 내기 위해 정수로 표현 된 양 12,378,945이고 pay Banana Inc 700

이므로 수취인은 Banana Inc이고 금액은 70000이며 금액으로 나타내는 단위는 천 단위입니다. 센트

나는 todo.g4를 변경하고 파서를 다시 생성해야한다고 생각한다.

요소에 다른 속성이 있습니까? 그렇다면 어떻게 시작해야합니까?

UPDATE

이 상단에 최신 업데이트를 위 내 최신 시도입니다 :

난 그냥 GRUN 및 testRig을 사용하는 방법을 알아 냈어. 그 팁에 @Raven 감사합니다.

최신 시도 : 내 최신 expense.g4

grammar expense; 

payments: (payment NL)* ; 
payment: PAY receiver amount=NUMBER ; 
receiver: surname=ID (lastname=ID)? ; 

PAY: 'pay' ; 
NUMBER: ([0-9]+(','[0-9]+)*)('.'[0-9]*)?; 
ID: [a-zA-Z0-9_]+ ; 
NL: '\n' | '\r\n' ; 
WS: [\t ]+ -> skip ; 

enter image description here

이전 시도 (이전 시도에서 유일한 차이는 지불을위한 정규식) : 이것은 내 비용입니다.G4

grammar expense; 

payments: (payment NL)* ; 
payment: PAY receiver amount=NUMBER ; 
receiver: surname=ID (lastname=ID)? ; 

PAY: 'pay' ; 
NUMBER: [0-9]+ (',' [0-9]+)+ ('.' [0-9]+)? ; 
ID: [a-zA-Z0-9_]+ ; 
NL: '\n' | '\r\n' ; 
WS: [\t ]+ -> skip ; 

enter image description here

enter image description here

이전 시도 : https://github.com/simkimsia/learn-antlr-web-js/commit/728813ac275a3f2ad16d7f51ce15fcc27d40045b#commitcomment-25127606

이전 시도 : https://github.com/simkimsia/learn-antlr-web-js/commit/0c32aec6ffb4b4275db86d54e9788058a2ce8759#commitcomment-25125695

+1

내가 모든 코드를 이해하지만, 오타에 독수리 눈을 가지고 있지 않습니다. 56 행 :'var 토큰 = 새로운 새로운 antlr4.CommonTokenStream (expenseLexer); -> 두 번, 새로운 오류의 원인. – BernardK

+0

@BernardK 감사합니다. 나는 새로운 것을 제거하고 Raven이 제안한 지불 기능을 사용했다. 나는 console.log에 시도했을 때 여전히 빈 배열을 보았습니다. –

답변

2

상황은 10 월 24 일에 2017 at 19:00 UTC + 1

문법은 완벽하게 작동합니다. Java로 전체 테스트를했습니다.

파일 Expense.g4 :

grammar Expense; 

payments 
@init {System.out.println("Expense last update 1853");} 
    : (payment NL)* 
    ; 

payment 
    : PAY receiver amount=NUMBER 
     {System.out.println("Payement found " + $amount.text + " to " + $receiver.text);} 
    ; 

receiver 
    : surname=ID (lastname=ID)? 
    ; 

PAY : 'pay' ; 
NUMBER : ([0-9]+(','[0-9]+)*)('.'[0-9]*)? ; 
ID  : [a-zA-Z0-9_]+ ; 
NL  : '\n' | '\r\n' ; 
WS  : [\t ]+ -> channel(HIDDEN) ; // keep the spaces (witout spaces ==> paydeltaco98) 

파일 ExpenseMyListener.java :

public class ExpenseMyListener extends ExpenseBaseListener { 
    ExpenseParser parser; 
    public ExpenseMyListener(ExpenseParser parser) { this.parser = parser; } 

    public void exitPayments(ExpenseParser.PaymentsContext ctx) { 
     System.out.println(">>> in ExpenseMyListener for paymentsss"); 
     System.out.println(">>> there are " + ctx.payment().size() + " elements in the list of payments"); 
     for (int i = 0; i < ctx.payment().size(); i++) { 
      System.out.println(ctx.payment(i).getText()); 
     } 
    } 

    public void exitPayment(ExpenseParser.PaymentContext ctx) { 
     System.out.println(">>> in ExpenseMyListener for payment"); 
     System.out.println(parser.getTokenStream().getText(ctx)); 
    } 
} 

파일 test_expense.java :

import org.antlr.v4.runtime.ANTLRFileStream; 
import org.antlr.v4.runtime.ANTLRInputStream; 
import org.antlr.v4.runtime.CommonTokenStream; 
import org.antlr.v4.runtime.ParserRuleContext; 
import org.antlr.v4.runtime.tree.*; 
import java.io.FileInputStream; 
import java.io.InputStream; 
import java.io.IOException; 

public class test_expense { 
    public static void main(String[] args) throws IOException { 
     ANTLRInputStream input = new ANTLRFileStream(args[0]); 
     ExpenseLexer lexer = new ExpenseLexer(input); 
     CommonTokenStream tokens = new CommonTokenStream(lexer); 
     ExpenseParser parser = new ExpenseParser(tokens); 
     ParseTree tree = parser.payments(); 
     System.out.println("---parsing ended"); 
     ParseTreeWalker walker = new ParseTreeWalker(); 
     ExpenseMyListener my_listener = new ExpenseMyListener(parser); 
     System.out.println(">>>> about to walk"); 
     walker.walk(my_listener, tree); 
    } 
} 

입력 파일 top.text :

pay Acme Corp 123,456 
pay Banana Inc 456789.00 
pay charlie pte 123,456.89 
pay delta co 98 

실행 :

$ export CLASSPATH=".:/usr/local/lib/antlr-4.6-complete.jar" 
$ alias 
alias a4='java -jar /usr/local/lib/antlr-4.6-complete.jar' 
alias grun='java org.antlr.v4.gui.TestRig' 
$ a4 Expense.g4 
$ javac Ex*.java 
$ javac test_expense.java 
$ grun Expense payments -tokens -diagnostics top.text 
[@0,0:2='pay',<'pay'>,1:0] 
[@1,3:3=' ',<WS>,channel=1,1:3] 
[@2,4:7='Acme',<ID>,1:4] 
[@3,8:8=' ',<WS>,channel=1,1:8] 
[@4,9:12='Corp',<ID>,1:9] 
... 
[@32,90:89='<EOF>',<EOF>,5:0] 
Expense last update 1853 
Payement found 123,456 to Acme Corp 
Payement found 456789.00 to Banana Inc 
Payement found 123,456.89 to charlie pte 
Payement found 98 to delta co 

$ java test_expense top.text 
Expense last update 1853 
Payement found 123,456 to Acme Corp 
Payement found 456789.00 to Banana Inc 
Payement found 123,456.89 to charlie pte 
Payement found 98 to delta co 
---parsing ended 
>>>> about to walk 
>>> in ExpenseMyListener for payment 
pay Acme Corp 123,456 
>>> in ExpenseMyListener for payment 
pay Banana Inc 456789.00 
>>> in ExpenseMyListener for payment 
pay charlie pte 123,456.89 
>>> in ExpenseMyListener for payment 
pay delta co 98 
>>> in ExpenseMyListener for paymentsss 
>>> there are 4 elements in the list of payments 
payAcmeCorp123,456 
payBananaInc456789.00 
paycharliepte123,456.89 
paydeltaco98 
+0

감사합니다. 나는 당신이 100의 현상금으로 보상하고 싶었 기 때문에 당신이 ur 대답을 업데이트하는 것을 선호합니다. 그건 그렇고, 나는 antlr과 DSL에 일반적으로 정말 새로운 것입니다. 내 목표는 내 자신의 DSL을 사용하여 내 자신의 비용 추적기를 구축하는 것입니다. 구문 분석을 수행 한 후에는 어떻게해야합니까? DSL 언어를 그대로 데이터베이스에 저장해야합니까? 아니면 개별 토큰을 데이터베이스의 개별 필드에 저장해야합니까? –

+1

DSL에 대한 경험이 없으므로 곧 Tomassetti의 책을 읽으겠습니다. 어딘가에 응용 프로그램을 작성해야합니다. 'exitPayment' 청취자 규칙에서,'receiver'와'amount'를 토큰이 아닌 데이터베이스에 저장할 수 있습니다.이 토큰은 주로 파서가 사용합니다. – BernardK

+0

감사합니다. 나는 토마 세티와 직접 접촉하고 그의 책을 가지고있다. 건배 –

1
내가 정확하게 당신이 완전히 확실하지 원하는 무슨을

하지만 제공된 예제이 문법이 그 일을해야합니다 :

나는 다음 todo.g4을 변경해야하고 추측하고
payments: (payment NL)* ; 
payment: PAY receiver amount=NUMBER ; 
receiver: surname=ID (lastname=ID)? ; 

PAY: 'pay' ; 
NUMBER: [0-9]+ (',' [0-9]+)+ ('.' [0-9]+)? ; 
ID: [a-zA-Z0-9_]+ ; 
NL: '\n' | '\r\n' ; 
WS: [\t ]+ -> skip ; 

필요한 경우 좀 더 설명을 추가 할 것이 당신이 요구 한 어떤 경우...

+0

어떻게 대답을 테스트합니까? 그냥 todo.g4 안에있는 모든 것을 이걸로 바꿔 줘? –

+0

옙 ... 'grammar todo' 헤더 제외 – Raven

+0

내가 제안한대로 했어. 구문 분석이 성공적이라는 것을 어떻게 알 수 있습니까? 현재이 결과가 있습니다 https://github.com/simkimsialean-antlr-web-js/commit/728813ac275a3f2ad16d7f51ce15fcc27d40045b#commitcomment-25127606 –

1

는 파서를 생성 다시.

물론 변경 될 때마다 재생성하십시오. 나에게는는 다음과 같습니다

$ alias 
alias a4='java -jar /usr/local/lib/antlr-4.6-complete.jar' 
alias grun='java org.antlr.v4.gui.TestRig' 

이 더 많이 구체적인 내용을 설명

$ a4 Question.g4 
$ javac Q*.java 
$ grun Question elements -tokens -diagnostics t.text 

이, 더 당신이 모호성 문제에 직면 할 수있다.

payment : 'pay' [payee] [amount] 
free_text : ... any character ... 

다음과 같은 내용을 고려하십시오 : 때문에,

* pay Federico Tomassetti 10 € for the tutorial 

* pay Federico Tomassetti 10이 모호하고,이 규칙에 의해 일치 할 수 있지만, 마침내 무료 텍스트를 구문 분석 할 것입니다 예를 들어, 두 개의 규칙이 € for the tutorial의 값은 payment을 만족하지 않습니다.

나중에는 시간이 지나면 더 많은 정보를 받아들이도록 payment 규칙을 변경하는 경우 :

payment : 'pay' [payee] [amount] payment_info 

위의 내용이 payment 일치한다 (모호성 ANTLR의 경우 첫 번째 규칙을 선택합니다). 반가운 소식은 ANTLR 4가 모호성을 제거하는 데 매우 강하며 필요한 경우 전체 파일을 읽는 것입니다.

모호한 토큰 및 선행 규칙의 경우 지난 3 주간의 게시물을 읽으십시오.

파일 Question.g4

grammar Question; 

elements 
@init {System.out.println("Question last update 1432");} 
    : (element | emptyLine)* EOF 
    ; 

element 
    : '*' content NL 
    ; 

content 
    : payment //{System.out.println("Payement found " + $payment.text);} 
    | free_text {System.out.println("Free text found " + $free_text.text);} 
    ; 

payment 
    : PAY receiver amount=NUMBER 
     {System.out.println("Payement found " + $amount.text + " to " + $receiver.text);} 
    ; 

receiver 
    : surname=WORD (lastname=WORD)? 
    ; 

free_text 
    : (WORD | PAY | NUMBER)+ 
    ; 

emptyLine 
    : NL 
    ; 

PAY : 'pay' ; 
WORD : LETTER (LETTER | DIGIT | '_')* ; 
NUMBER : DIGIT+ (',' DIGIT+)? ('.' DIGIT+)? ; 

NL : [\r\n] 
    | '\r\n' 
    ; 
//WS : [ \t]+ -> skip ; // $payment.text => payAcmeCorp123,789.45 
WS : [ \t]+ -> channel(HIDDEN) ; // spaces are needed to nicely display $payment.text 

fragment DIGIT : [0-9] ; 
fragment LETTER : [a-zA-Z] ; 

파일 t.text

* play with ANTLR 4 
* write a tutorial 
* pay Acme Corp 123,789.45 
* pay Banana Inc 700 
* pay Federico Tomassetti 10 € for the tutorial 

실행 :

$ grun Question elements -tokens -diagnostics t.text 
line 5:29 token recognition error at: '€' 
[@0,0:0='*',<'*'>,1:0] 
[@1,1:1=' ',<WS>,channel=1,1:1] 
[@2,2:5='play',<WORD>,1:2] 
[@3,6:6=' ',<WS>,channel=1,1:6] 
[@4,7:10='with',<WORD>,1:7] 
[@5,11:11=' ',<WS>,channel=1,1:11] 
[@6,12:16='ANTLR',<WORD>,1:12] 
[@7,17:17=' ',<WS>,channel=1,1:17] 
[@8,18:18='4',<NUMBER>,1:18] 
[@9,19:19='\n',<NL>,1:19] 
[@10,20:20='*',<'*'>,2:0] 
[@11,21:21=' ',<WS>,channel=1,2:1] 
[@12,22:26='write',<WORD>,2:2] 
[@13,27:27=' ',<WS>,channel=1,2:7] 
[@14,28:28='a',<WORD>,2:8] 
[@15,29:29=' ',<WS>,channel=1,2:9] 
[@16,30:37='tutorial',<WORD>,2:10] 
[@17,38:38='\n',<NL>,2:18] 
... 
[@56,136:135='<EOF>',<EOF>,7:0] 
Question last update 1432 
Free text found play with ANTLR 4 
Free text found write a tutorial 
line 3:26 reportAttemptingFullContext d=2 (content), input='pay Acme Corp 123,789.45 
' 
... 
Payement found 700 to Banana Inc 
Free text found pay Federico Tomassetti 10 for the tutorial 
,536,913,632 당신과 ​​까마귀의 문법을 혼합

, 이것은 하나 개의 가능한 솔루션입니다 10

보시다시피, € 기호는 인식되지 않습니다.

페데리코의 Mega tutorial 좋은 시작이다 ... 당신은 FIELDTEXThere 유사한 CONTENT 규칙을해야 할 수도 있습니다, 그리고 당신은 곤경에 얻을. 자세한 내용은 The Definitive ANTLR 4 Reference 또는 온라인 설명서 from www.antlr.org을 참조하십시오.

+0

antlr 4.7의 javascript 런타임을 사용하고 있으며 Tomassetti의 튜토리얼을 매우 엄격하게 따라갔습니다. 그래서 Parse 버튼을 사용하여 파싱을 시작합니다. 귀하의 답변은 자바 런타임을 사용하는 것으로 보입니까? 대신에 자바 스크립트 런타임을 사용할 수있는 방법이 있습니까? –

+0

죄송합니다. Java 이외의 다른 타겟을 사용한 적이 없습니다. '{System.out.println ... '을 제거/대체해야합니다. 여러 다른 대상 언어를 사용하는 Tomassetti의 Mega Tutorial 링크를 추가했습니다. – BernardK

+0

나는 당신이 당신의 대답의 시작에서 무엇을하려고했는지 훨씬 더 분명하게 깨닫는다. –

관련 문제