2016-08-13 37 views
0

我想學習一點ANTLR4並定義一些4GL語言的語法。ParserRule匹配錯誤的標記

這是我有:

compileUnit 
: 
    typedeclaration EOF 
; 

typedeclaration 
: 
    ID LPAREN DATATYPE INT RPAREN 
; 

DATATYPE 
: 
    DATATYPE_ALPHANUMERIC 
    | DATATYPE_NUMERIC 
; 

DATATYPE_ALPHANUMERIC 
: 
    'A' 
; 

DATATYPE_NUMERIC 
: 
    'N' 
; 

fragment 
DIGIT 
: 
    [0-9] 
; 

fragment 
LETTER 
: 
    [a-zA-Z] 
; 

INT 
: 
    DIGIT+ 
; 

ID 
: 
    LETTER 
    (
     LETTER 
     | DIGIT 
    )* 
; 

LPAREN 
: 
    '(' 
; 

RPAREN 
: 
    ')' 
; 

WS 
: 
    [ \t\f]+ -> skip 
; 

我希望能夠解析什麼:

TEST(A10)

我得到什麼:

typedeclaration:1:6:不匹配輸入'A10'期待DATATYPE

不過,我能寫:

測試(10)

爲什麼我需要把空白會在這裏? LPAREN DATATYPE本身正在工作,所以不需要在兩者之間留出空間。 INT RPAREN也在工作。 爲什麼DATATYPE和INT之間需要一個空間?我對這個有點困惑。 我想它是匹配ID,因爲它是「最長」的匹配,但是必須有某種方法來強迫這裏變得更懶,對嗎?

+0

因爲'A10'是ID的有效標記。你想匹配第一個變體還是兩個? ANTLR總是儘可能匹配令牌(在解析之前創建令牌)。 – CoronA

+0

@CoronA我想匹配第一個變體,沒有空間。 –

+0

我可以想到以下解決方案:明確地包含空白(而不是跳過),使ID不以「A」或「N」開頭或接受括號內的任何ID,並在語義分析中過濾掉錯誤的ID。有偏好嗎? – CoronA

回答

1

您應該在ID的第一個位置忽略'A'和'N'聊天。由於@CoronA注意到ANTLR儘可能長地匹配令牌(ID'A10'的長度超過DATATYPE_ALPHANUMERIC'A'的長度)。另請閱讀:Priority rules。嘗試使用以下語法:

grammar expr; 

compileUnit 
    : typedeclaration EOF 
    ; 

typedeclaration 
    : ID LPAREN datatype INT RPAREN 
    ; 

datatype 
    : DATATYPE_ALPHANUMERIC 
    | DATATYPE_NUMERIC 
    ; 

DATATYPE_ALPHANUMERIC 
    : 'A' 
    ; 

DATATYPE_NUMERIC 
    : 'N' 
    ; 

INT 
    : DIGIT+ 
    ; 

ID 
    : [b-mo-zB-MO-Z] (LETTER | DIGIT)* 
; 

LPAREN 
    : '(' 
    ; 

RPAREN 
    : ')' 
    ; 

WS 
    : [ \t\f]+ -> skip 
    ; 

fragment 
DIGIT 
    : [0-9] 
    ; 

fragment 
LETTER 
    : [a-zA-Z] 
    ; 

此外,您可以使用以下不帶ID限制的語法。數據類型將比字母更早識別。它也不清楚:

grammar expr; 

compileUnit 
    : typedeclaration EOF 
    ; 

typedeclaration 
    : id LPAREN datatype DIGIT+ RPAREN 
    ; 

id 
    : (datatype | LETTER) (datatype | LETTER | DIGIT)* 
    ; 

datatype 
    : DATATYPE_ALPHANUMERIC 
    | DATATYPE_NUMERIC 
    ; 

DATATYPE_ALPHANUMERIC: 'A'; 
DATATYPE_NUMERIC:  'N'; 
// List with another Data types. 
LETTER:    [a-zA-Z]; 

LPAREN 
    : '(' 
    ; 

RPAREN 
    : ')' 
    ; 

WS 
    : [ \t\f]+ -> skip 
    ; 

DIGIT 
    : [0-9] 
    ; 
+0

感謝你的例子@KvanTTT,我有點看到這是怎麼回事。但是現在我的標識符不能以A或N開始,這不是一個理想的行爲。有11個數據類型只用一個字母表示,爲了便於閱讀,我省略了所有的2個數據類型 –

+0

我可以讓類型聲明期望一個ID而不是數據類型,並在偵聽器/訪問者中提取它,但這不是一個「語法聞」? :-) –

+0

@MarkusA。我刪除了ID限制。如果這個語法不適合你,那麼應該使用聽衆/訪客方法。 –