Qu'est-ce qu'un "prédicat sémantique" dans ANTLR?
2 réponses
ANTLR 4
Pour les prédicats de ANTLR 4, checkout ces pile dépassement Q&A:
ANTLR 3
Un prédicat sémantique est un moyen d'appliquer des règles extra (sémantiques) sur la grammaire actions utilisant du code simple.
il y a 3 types de prédicats sémantiques:
- validation prédicats sémantiques;
- dépendants sémantique des prédicats;
- disambiguating sémantique des prédicats.
exemple de grammaire
disons que vous avez un bloc de texte composé uniquement de Nombres séparés par
virgule, sans tenir compte des espaces blancs. Vous souhaitez analyser cette contribution à faire
assurez-vous que les numéros sont au plus 3 chiffres "long" (au plus 999). La suite
grammaire ( Numbers.g
) ferait une telle chose:
grammar Numbers;
// entry point of this parser: it parses an input string consisting of at least
// one number, optionally followed by zero or more comma's and numbers
parse
: number (',' number)* EOF
;
// matches a number that is between 1 and 3 digits long
number
: Digit Digit Digit
| Digit Digit
| Digit
;
// matches a single digit
Digit
: '0'..'9'
;
// ignore spaces
WhiteSpace
: (' ' | '\t' | '\r' | '\n') {skip();}
;
Test
la grammaire peut être vérifiée avec la classe suivante:
import org.antlr.runtime.*;
public class Main {
public static void main(String[] args) throws Exception {
ANTLRStringStream in = new ANTLRStringStream("123, 456, 7 , 89");
NumbersLexer lexer = new NumbersLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
NumbersParser parser = new NumbersParser(tokens);
parser.parse();
}
}
le tester en générant le lexer et l'analyseur, en compilant tous les fichiers .java
et
exécution de la classe Main
:
java -cp antlr-3.2.jar org.antlr.Tool Numbers.g javac -cp antlr-3.2.jar *.java java -cp .:antlr-3.2.jar Main
pour ce faire, rien n'est imprimé sur la console, ce qui indique que rien s'est mal passé. Essayez de changer:
ANTLRStringStream in = new ANTLRStringStream("123, 456, 7 , 89");
en:
ANTLRStringStream in = new ANTLRStringStream("123, 456, 7777 , 89");
et refaire le test: vous verrez une erreur apparaître sur la console juste après la chaîne de caractères 777
.
Prédicats Sémantiques
cela nous amène aux prédicats sémantiques. Disons que vous voulez discuter les nombres entre 1 et 10 chiffres. Une règle comme:
number
: Digit Digit Digit Digit Digit Digit Digit Digit Digit Digit
| Digit Digit Digit Digit Digit Digit Digit Digit Digit
/* ... */
| Digit Digit Digit
| Digit Digit
| Digit
;
deviendrait encombrant. Les prédicats sémantiques peuvent aider à simplifier ce type de règle.
1. La Validation De La Sémantique Des Prédicats
Un la validation de prédicat sémantique n'est rien d' plus qu'un bloc de code, suivi par un point d'interrogation:
RULE { /* a boolean expression in here */ }?
pour résoudre le problème ci-dessus en utilisant un valider
prédicat sémantique, changer la règle number
dans la grammaire en:
number
@init { int N = 0; }
: (Digit { N++; } )+ { N <= 10 }?
;
Les parties { int N = 0; }
et { N++; }
sont de simples rapports de Java dont
la première est initialisée lorsque l'analyseur "entre" la règle number
. Réel
prédicat est: { N <= 10 }?
, ce qui provoque l'analyseur de jeter un
FailedPredicateException
chaque fois qu'un numéro est supérieur à 10 chiffres.
tester en utilisant le ANTLRStringStream
suivant:
// all equal or less than 10 digits
ANTLRStringStream in = new ANTLRStringStream("1,23,1234567890");
qui ne produit pas d'exception, alors que le
// '12345678901' is more than 10 digits
ANTLRStringStream in = new ANTLRStringStream("1,23,12345678901");
2. Dépendants De La Sémantique Des Prédicats
Un gated prédicat sémantique est similaire à un la validation de prédicat sémantique ,
seule la version fermée produit une erreur de syntaxe au lieu d'une FailedPredicateException
.
La syntaxe d'un gated prédicat sémantique est:
{ /* a boolean expression in here */ }?=> RULE
à la place de résoudre le problème ci-dessus en utilisant gated prédit des nombres jusqu'à 10 chiffres de long vous écririez:
number
@init { int N = 1; }
: ( { N <= 10 }?=> Digit { N++; } )+
;
tester à nouveau avec les deux:
// all equal or less than 10 digits
ANTLRStringStream in = new ANTLRStringStream("1,23,1234567890");
et:
// '12345678901' is more than 10 digits
ANTLRStringStream in = new ANTLRStringStream("1,23,12345678901");
et vous verrez le dernier sur lèvera une erreur.
3. Discambuating Semantic Predicates
le dernier type de prédicat est un prédicat sémantique désambiguant , qui ressemble un peu à un prédicat validant ( {boolean-expression}?
), mais agit plus comme un prédicat sémantique à guillotine (aucune exception n'est lancée lorsque l'expression booléenne évalue à false
). Vous pouvez l'utiliser au début d'une règle pour vérifier une propriété d'une règle et laisser l'analyseur correspondre ladite règle ou non.
Supposons que la grammaire de l'exemple crée des tokens Number
(une règle lexer au lieu d'une règle parser) qui correspondront à des nombres dans l'intervalle de 0..999. Maintenant, dans l'analyseur, vous souhaitez faire une distinction entre basse et haute numéros (faible: 0..500, hauteur: 501..999). Cela pourrait être fait en utilisant un désambiguant prédicat sémantique où vous inspectez le jeton suivant dans le flux ( input.LT(1)
) pour vérifier s'il est faible ou élevé.
une démo:
grammar Numbers;
parse
: atom (',' atom)* EOF
;
atom
: low {System.out.println("low = " + $low.text);}
| high {System.out.println("high = " + $high.text);}
;
low
: {Integer.valueOf(input.LT(1).getText()) <= 500}? Number
;
high
: Number
;
Number
: Digit Digit Digit
| Digit Digit
| Digit
;
fragment Digit
: '0'..'9'
;
WhiteSpace
: (' ' | '\t' | '\r' | '\n') {skip();}
;
si vous analysez maintenant la chaîne de caractères "123, 999, 456, 700, 89, 0"
,vous verrez la sortie suivante:
low = 123
high = 999
low = 456
high = 700
low = 89
low = 0
j'ai toujours utilisé la référence terse à ANTLR prédit sur wincent.com comme guide.