Qu'est-ce qu'un "prédicat sémantique" dans ANTLR?

Qu'est-ce qu'un prédicat sémantique dans ANTLR?

94
demandé sur Bart Kiers 2010-06-16 23:16:48

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
156
répondu Bart Kiers 2017-05-23 10:30:50

j'ai toujours utilisé la référence terse à ANTLR prédit sur wincent.com comme guide.

11
répondu Kaleb Pederson 2010-06-16 19:40:36