2013-01-24 3 views
1

인용 된 식별자 (테이블 이름, 필드 이름 등) 및 인용 된 리터럴 문자열을 허용하는 ANTLR의 SQL 문법 작업 중입니다.ANTLR 리터럴 및 인용 된 ID 구문 분석

이 문법은 따옴표로 묶인 입력을 항상 "QUOTED_LITERAL"로 간주하고 ID는 따옴표로 묶지 않는 것으로 보입니다.

  • 입력 : 'blahblah'결과, 예상대로 string_literal 여기

    내 결과입니다.
  • 입력 : 필드 1 restul : table.field1 결과 :
  • 입력 예상대로 COLUMN_NAME 결과 '필드 1' '테이블':.
  • 입력을 예상대로 column_spec string_literal, MissingTokenException는
  • 아래

은 내 누가 SQL 문법의 표현 부분에 대해 간단한 문법을 ​​사용하는지, 인용 된 리터럴 이외의 인용 된 규칙과 일치하는 데 필요한 것이 무엇인지 식별하는 데 도움이 될 수 있다면 감사합니다.

grammar test; 

expression 
    : 
    simpleExpression EOF! 
    ; 

simpleExpression 
    : 
    column_spec 
    | literal_value 
; 
column_spec 
    : 
    (table_name '.')? column_name 
    | ('\''table_name '\'''.')? '\'' column_name '\'' 
    | ('\"'table_name '\"' '.')? '\"' column_name '\"' 
    ; 

string_literal:  QUOTED_LITERAL ; 
boolean_literal: 'TRUE' | 'FALSE' ; 
literal_value : 
    ( 
    string_literal 
    | boolean_literal 
    ) 
     ; 

table_name :ID; 
column_name :ID; 

QUOTED_LITERAL: 
    ( '\'' 
     (('\\' '\\') | ('\'' '\'') | ('\\' '\'') | ~('\''))* 
    '\'' ) 
    | 
    ( '\"' 
     (('\\' '\\') | ('\"' '\"') | ('\\' '\"') | ~('\"'))* 
    '\"' ) 
; 

ID 
    : 
    ('A'..'Z' | 'a'..'z') ('A'..'Z' | 'a'..'z' | '_' | '0'..'9'| '::')* 
    ; 


WHITE_SPACE : (' '|'\r'|'\t'|'\n') {$channel=HIDDEN;} ; 

답변

0

아무나 관심이있는 경우 따옴표 붙은 리터럴 문자열에서 약간의 유연성을 제거했습니다. 리터럴 문자열은 작은 따옴표로만 인용 할 수 있으며 식별자는 큰 따옴표로 선택적으로 인용 할 수 있습니다. 문자 그대로의 따옴표와 식별자 따옴표가 잘 정의되어 있고 겹치지 않는 한, 문법은 사소하다.

이 정책은 문법을 훨씬 깔끔하게 해주 며 식별자를 인용 할 수있는 기능을 제거하지 않습니다. 필자는 JDBC 메소드 getIdentifierQuote를 사용하여 식별자를 래핑하는 데 사용할 수있는 견적을보고합니다.

+0

답을 수락하면 "대답이없는"풀에서 질문을 제거합니다. 나는 그것을 upvote 수도 있습니다 ... –

0

이것은 고전적인 시프트/감소 충돌입니다. (즉, ANTLR은 이동 또는 감소하지 않습니다를 제외하고, 그것은 스택 자동 장치 아니기 때문에.)

하면 다음과 같은 문제가있다 : 당신이 simpleExpression 상태에있을 때

는 당신이 를 취할 지점을 결정해야합니다을 하나의 토큰 시크릿 헤드. ANTLR의 경우, 렉서와 파서간에 차이가 없으므로 하나의 토큰은 단일 문자입니다. (ANTLR로부터 충돌에 관한 경고가 표시되어야합니다.) "Bob Dillan"과 "table1"의 차이점은 무엇입니까? 파서의 관점에서 볼 때 아무도 없습니다. 그래서 당신은 차이 만들 기대 방법 :

('\"'table_name '\"' '.')? '\"' column_name '\"' 

( '\"' 
    (('\\' '\\') | ('\"' '\"') | ('\\' '\"') | ~('\"'))* 
'\"' ) 

난 강력하게 제안이에 simpleExpression 규칙을 재 작성 :

simpleExpression: 
    IDENTIFIER | 
    IDENTIFIER . IDENTIFIER | 
    QUOTED_LITERAL | 
    QUOTED_LITERAL . QUOTED_LITERAL | 
    boolean_literal; 

그리고 액션 코드에서 결정 simpleExpression을 어떻게 할 것인가? 특히 인용 된 이름을 가진 테이블을 참조 할 수 있다고 확신하기 때문에 특히 그렇습니다. 절대로 "사용자"와 "Bod Dillan"이 구문 적으로 동일하지 않습니다.

강사 문법에 따라 다르지만 더 높은 수준의 우호 성을 해결할 수도 있습니다.

+0

감사합니다 @rioki,이 하위 문법에서 "table1"은 리터럴 문자열로 간주되어야합니다 (정규화 된 열에 대해서만 테이블에 대한 참조가 없음). 그러나 더 높은 수준의 문법에서는 따옴표 붙은 테이블도 지원해야합니다. 어쨌든, 다음과 같이 할 것입니다 : simpleExpression : \t string_values ​​ \t | \t 부울 _litereral ; string_values ​​ \t : \t \t ID \t | \t table_name '.' column_name \t | \t QUOTED_LITERAL \t | \t QUOTED_LITERAL '.' QUOTED_LITERAL \t; –

+0

그런 다음 결과 string_type –

0

antlr 렉서는 욕심이 있습니다. 가능한 두 개의 토큰이 일치 할 때 가능한 가장 긴 토큰과 일치합니다.

렉서가 'some_id'를 볼 때 첫 번째 따옴표를 따옴표 또는 따옴표로 묶은 리터럴과 일치시킬 수 있습니다. 리터럴은 더 길기 때문에 일치합니다.

부수적으로 일반적으로 아무 것도 (ID와 일치 할 수도있는) 렉서 규칙이나 파서 규칙의 문자열 상수를 사용하지만 참조 토큰 이름 만 사용하는 것은 원하지 않습니다.

원하는 작업은 다음과 같습니다. 렉서는 인용 ID처럼 보이는 뭔가를 보는 경우

QUOTE: '\''; 
ID: ('a'..'z' | 'A'..'Z')+; // Must have at least one character 
QUOTED_LITERAL: QUOTE ((ID QUOTE) => { $type=QUOTE; }) | .* QUOTE; 

id: ID | QUOTE ID QUOTE; 
quoted_literal: QUOTED_LITERAL | QUOTE ID QUOTE; 

, 그것은 사용할 말할 수 없다, 그래서 작은 토큰으로 그것을 파괴. 파서에서는 인용 부호가있는 ID가 필요한 곳에서 id를 사용하고 QUOTED_LITERAL이 필요한 곳에서는 quoted_literal을 사용합니다.

QUOTED_LITERAL의 구문 술어는 입력이 모호 할 때 전체 인용과 일치하지 못하게합니다.

이, 그것은 '텍스트'는 QUOTED_LITERAL으로 해석 될 것이다 제대로

'tag' text 'second' 

같은 라인을 구문 분석하는 데 실패 할 찾고 있습니다. 즉 유효한 입력되면, 당신은 같은 것을 필요

fragment QUOTED_ID; 
QUOTED_LITERAL: QUOTE (ID {$type=QUOTED_ID} | .*) QUOTE; 
id: ID | QUOTED_ID; 
quoted_literal: QUOTED_LITERAL | QUOTED_ID; 

(귀하의 의견에 모든 경우를 다루지는 않지만을 연장 명백해야한다. 또한 아마 중 하나를 생성하기 위해 몇 가지 조치를 필요로 내 예 AST에서 올바른 토큰을 사용하거나 구문 분석 후에 수행하는 작업에 따라 텍스트에서 따옴표를 추가/제거하십시오.

+0

에 대해 감사드립니다. @Troy Daniels, 나는 귀하의 제안을 시도했으며, 원래의 질문에서 케이스 2,3 & 4에 대해 작동합니다. 하지만 문자열 리터럴을 일치시킬 수있는 능력이 없어졌습니다. 아마도 모든 column_name 노드는 동작 코드에서 식별자로 확인되어야합니다 ... –

+0

Btw, 원래 질문과 관련이 없지만 ID에 대한 의견으로 혼동을 ... 원래 서면으로 대소 문자를 구분하지 않는 문자가 필요합니다. 비어서는 안됩니다. –