2015-02-13 19 views
6

Sto usando la seguente grammatica ANTLR per definire una funzione.ANTLR analizza avidamente anche se può corrispondere alla regola ad alta priorità

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)); } 
    ; 

Ma quando si tenta di analizzare due funzioni come di seguito,

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; 
}; 

Poi ANTLR non analizza questi come due definizioni di funzione, ma come una singola funzione con il seguente,

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; 

Puoi spiegare questo comportamento? Il corpo della funzione può avere qualsiasi cosa in esso. Come posso definire correttamente questa grammatica?

risposta

0

A meno che non è assolutamente necessario script da un token (riconosciuto da un lexer regola), è possibile utilizzare una regolaparser che riconosce blocchi annidati (la blocco regola di seguito). La grammatica inclusa qui dovrebbe analizzare il tuo esempio come due definizioni di funzioni distinte.

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

Nota che le regole lexer possono anche contenere regole (lexer) ricorsive. Nota che all'interno di una regola parser '~ ('{' | '}')' fa * non * corrisponde a ** qualsiasi char ** altro che '{' e '}', ma piuttosto, ** qualsiasi token ** diverso da i token che corrispondono a '{' e '}'. –

3

La regola soddisfa più di tanto perché '\u0020'..'\u007e' dalla regola '{' ('\u0020'..'\u007e' | ~('{' | '}'))* '}' partite sia { e }.

La regola dovrebbe funzionare se si definisce in questo modo:

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

Tuttavia, questo non riuscirà quando il blocco script contiene, dice, stringhe o commenti che contengono { o }. Ecco un modo per abbinare un gettone SCRIPT, compresi i commenti e le stringhe letterali che potrebbero contenere { e '}':

SCRIPT 
: '{' SCRIPT_ATOM* '}' 
; 

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

Una grammatica completa che analizza correttamente l'input sarebbe quindi simile a questa:

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 
; 

che analizza anche il seguente testo corretto:

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

Grazie, ha funzionato :) – Ayash

Problemi correlati