2017-05-03 7 views
0

antlr4를 사용하여 표현 엔진을 작성하고 싶습니다.

다음은 문법입니다.antlr4를 사용하는 방법 특성 액세스 식, 메서드 호출 식, 배열 액세스 식을 구별 할 수있는 더 나은 파서를 작성 하시겠습니까?

expression 
: primary 
| expression '.' Identifier 
| expression '(' expressionList? ')' 
| expression '[' expression ']' 
| expression ('++' | '--') 
| ('+'|'-'|'++'|'--') expression 
| ('~'|'!') expression 
| expression ('*'|'/'|'%') expression 
| expression ('+'|'-') expression 
| expression ('<' '<' | '>' '>' '>' | '>' '>') expression 
| expression ('<=' | '>=' | '>' | '<') expression 
| expression ('==' | '!=') expression 
| expression '&' expression 
| expression '^' expression 
| expression '|' expression 
| expression '&&' expression 
| expression '||' expression 
| expression '?' expression ':' expression 
| <assoc=right> expression 
    ( '=' 
    | '+=' 
    | '-=' 
    | '*=' 
    | '/=' 
    | '&=' 
    | '|=' 
    | '^=' 
    | '>>=' 
    | '>>>=' 
    | '<<=' 
    | '%=' 
    ) 
    expression 
; 

이 문법은 올바르지 만 액세스 속성 expr, 메소드 호출 expr, 배열 액세스 expr을 구분할 수 없습니다. 그래서 내가

attributeAccessMethod:  
     expression '.' Identifier; 

    expression 
     : primary 
     | attributeAccessMethod 
     | expression '(' expressionList? ')' 
     | expression '[' expression ']' 
     | expression ('++' | '--') 
     | ('+'|'-'|'++'|'--') expression 
     | ('~'|'!') expression 

에 문법을 변경하지만,이 문법은 [attributeAccessMethod 표현]왼쪽 재귀, 그래서 어떻게 더 나은 문법이 왼쪽 재귀를 제거하고 이러한 조건을 구별 할 수 쓰기?

+0

이 대답에서 직접 왼쪽 재귀를 제거하는 규칙을 설명했습니다 : [ANTLR4 상호 왼쪽 재귀 문법] (http://stackoverflow.com/questions/41788100/antlr4-mutual-left-recursion-grammar/41789097#41789097) –

답변

1

예를 들어, 서로 다른 규칙 대안에 태그를 추가

expression 
: primary         # RulePrimary 
| expression '.' Identifier    # RuleAttribute 
| expression '(' expressionList? ')'  # RuleExpression 
| expression '[' expression ']'   # RuleArray 
... etc. 

당신이 이 규칙의 모든 당신의 대안이 작업을 수행 할 때, 당신의 BaseVisitor 또는 BaseListener는이 특별한 경우에 대한 공공 재정으로 생성됩니다 , 당신은 당신이 적합하다고 생각하는대로 각각을 치료할 수 있습니다.

0

이렇게 문법을 정의하는 것은 좋지 않습니다. @ JLH의 답변 외에도 문법은 이러한 표현의 연관성을 엉망으로 만들 가능성이 있습니다.

제가 말씀 드리고자하는 것은 당신은 어순 순서로 문법을 "하향식"해야한다는 것입니다.

예를 들어, 문법에서 모든 리터럴, 메서드 호출 등을 원자로 처리 할 수 ​​있습니다 (항상 리터럴 또는 식별자로 시작하기 때문에). 이러한 원자를 연관 연산자와 연결합니다. 처럼 보일 수

expression: binary_expr; 

// Binary_Expr 

// Logic_Expr 

// Add_expr 

// Mult_expr 

// Pow_expr 

// Unary_expr 

associate_expr 
: index_expr       # ToIndexExpr 
| lhs=index_expr '.' rhs=associate_expr # AssociateExpr 
; 

index_expr 
: index_expr '[' (expression (COMMA expression)*) ']' # IndexExpr 
| atom #ToAtom 
; 

atom 
: literals_1 #wwLiteral 
| ...  #xxLiteral 
| ...  #yyLiteral 
| literals_n #zzLiteral 
| function_call # FunctionCall 
; 


function_call 
: ID '(' (expression (',' expression)*)? ')'; 

// Define Literals 
// Literals Block 

그리고 당신의 산술 식의 일부 :

은 그럼 당신은 같은 문법을 쓸 수 있습니다 당신은 현재 EXPR 같은 왼쪽을

add_expr 
: mul_expr     # ToMulExpr 
| lhs=add_expr PLUS rhs=mul_expr #AddExpr 
| lhs=add_expr MINUS rhs=mul_expr #SubtractExpr 
; 

mul_expr 
: pow_expr       # ToPowExpr 
| lhs=mul_expr '+' rhs=pow_expr # MultiplyExpr 
| lhs=mul_expr '/' rhs=pow_expr # DivideExpr 
| lhs=mul_expr '%' rhs=pow_expr # ModExpr 
; 

및 오른쪽 다른 레벨이 expr과 연관되어 있기 때문에 연관성의 순서를 유지하면서 재귀를 남겨 둘 수 있습니다.