2015-02-13 8 views
6

Używam następującej gramatyki ANTLR do zdefiniowania funkcji.ANTLR przetwarza łapczywie, nawet jeśli pasuje do reguły wysokiego priorytetu

definition_function 
    : DEFINE FUNCTION function_name '[' language_name ']' 
     RETURN attribute_type '{' function_body '}' 
    ; 

function_name 
    : id 
    ; 

language_name 
    : id 
    ; 

function_body 
    : SCRIPT 
    ; 

SCRIPT 
    : '{' ('\u0020'..'\u007e' | ~('{' | '}'))* '}' 
     { setText(getText().substring(1, getText().length()-1)); } 
    ; 

Ale gdy próbuję analizować dwie funkcje, takie jak poniżej,

define function concat[Scala] return string { 
    var concatenatedString = "" 
    for(i <- 0 until data.length) { 
    concatenatedString += data(i).toString 
    } 
    concatenatedString 
}; 
define function concat[JavaScript] return string { 
    var str1 = data[0]; 
    var str2 = data[1]; 
    var str3 = data[2]; 
    var res = str1.concat(str2,str3); 
    return res; 
}; 

Następnie ANTLR nie analizuje to jak dwie definicje funkcji, ale jak jeden z następującą funkcją ciała,

var concatenatedString = "" 
    for(i <- 0 until data.length) { 
    concatenatedString += data(i).toString 
    } 
    concatenatedString 
}; 
define function concat[JavaScript] return string { 
    var str1 = data[0]; 
    var str2 = data[1]; 
    var str3 = data[2]; 
    var res = str1.concat(str2,str3); 
    return res; 

Czy możesz wyjaśnić to zachowanie? Ciało funkcji może mieć w sobie wszystko. Jak poprawnie zdefiniować gramatykę?

Odpowiedz

0

Chyba że absolutnie trzeba SCRIPT być token (rozpoznawana przez Lexer reguły), można użyć parsera regułę, która rozpoznaje zagnieżdżonych bloków (blok z przepis poniżej). Gramatyka zawarta w tym miejscu powinna przeanalizować twój przykład jako dwie odrębne definicje funkcji.

DEFINE : 'define'; 
FUNCTION : 'function'; 
RETURN : 'return'; 
ID : [A-Za-z]+; 
ANY : . ; 
WS : [ \r\t\n]+ -> skip ; 

test : definition_function* ; 

definition_function 
    : DEFINE FUNCTION function_name '[' language_name ']' 
     RETURN attribute_type block ';' 
    ; 

function_name : id ; 
language_name : id ; 
attribute_type : 'string' ; 
id : ID; 

block 
    : '{' ((~('{'|'}'))+ | block)* '}' 
    ; 
+1

Należy zauważyć, że przepisy lexer mogą zawierać również rekurencyjne (lexer) zasady. Zauważ, że wewnątrz reguły parsera '~ ('{' | '}')' nie * nie * pasuje ** dowolny znak ** inny niż '{' i '}', ale raczej ** dowolny token ** inny niż tokeny pasujące do '{' i '}'. –

3

Twoja reguła pasuje, że dużo, bo '\u0020'..'\u007e' od reguły '{' ('\u0020'..'\u007e' | ~('{' | '}'))* '}' meczów zarówno { i }.

Reguła powinna działać, jeśli można zdefiniować tak:

SCRIPT 
    : '{' (SCRIPT | ~('{' | '}'))* '}' 
    ; 

Jednak to zawiedzie, gdy blok zawiera skrypt, mówi, smyczki i komentarze zawierające { lub }. Oto sposób, aby dopasować SCRIPT tokena, w tym komentarze i napisowych, które mogą zawierać { i „}”:

SCRIPT 
: '{' SCRIPT_ATOM* '}' 
; 

fragment SCRIPT_ATOM 
: ~[{}] 
| '"' ~["]* '"' 
| '//' ~[\r\n]* 
| SCRIPT 
; 

Kompletny gramatyka, że ​​właściwie analizuje swoje wejście będzie wtedy wyglądać tak:

grammar T; 

parse 
: definition_function* EOF 
; 

definition_function 
: DEFINE FUNCTION function_name '[' language_name ']' RETURN attribute_type SCRIPT ';' 
; 

function_name 
: ID 
; 

language_name 
: ID 
; 

attribute_type 
: ID 
; 

DEFINE 
: 'define' 
; 

FUNCTION 
: 'function' 
; 

RETURN 
: 'return' 
; 

ID 
: [a-zA-Z_] [a-zA-Z_0-9]* 
; 

SCRIPT 
: '{' SCRIPT_ATOM* '}' 
; 

SPACES 
: [ \t\r\n]+ -> skip 
; 

fragment SCRIPT_ATOM 
: ~[{}] 
| '"' ~["]* '"' 
| '//' ~[\r\n]* 
| SCRIPT 
; 

który analizuje również wkład odpowiednio:

define function concat[JavaScript] return string { 
    for (;;) { 
    while (true) { } 
    } 
    var s = "}" 
    // } 
    return s 
}; 
+0

Dzięki, to zadziałało :) – Ayash

Powiązane problemy