ANTLR: y a-t-il un exemple simple?

j'aimerais commencer avec ANTLR, mais après avoir passé quelques heures à examiner les exemples au antlr.org site, je ne peux toujours pas obtenir une compréhension claire de la grammaire au processus Java.

y a-t-il un exemple simple, quelque chose comme une calculatrice à quatre opérations implémentée avec ANTLR passant par la définition de l'analyseur et jusqu'au code source Java?

204
demandé sur AlexP11223 2009-12-19 02:35:16

4 réponses

vous créez d'abord une grammaire. Ci-dessous une petite grammaire que vous pouvez utiliser pour évaluer les expressions qui sont construites en utilisant les 4 opérateurs mathématiques de base:+, -, * et /. Vous pouvez également grouper des expressions en utilisant la parenthèse.

notez que cette grammaire n'est qu'une grammaire de base: elle ne gère pas les opérateurs unaires (le moins en: -1+9) ou décimales comme .99 (sans numéro), pour ne citer que deux lacunes. C'est juste un exemple, vous pouvez travailler sur vous-même.

Voici le contenu du fichier de grammaire Exp.g :

grammar Exp;

/* This will be the entry point of our parser. */
eval
    :    additionExp
    ;

/* Addition and subtraction have the lowest precedence. */
additionExp
    :    multiplyExp 
         ( '+' multiplyExp 
         | '-' multiplyExp
         )* 
    ;

/* Multiplication and division have a higher precedence. */
multiplyExp
    :    atomExp
         ( '*' atomExp 
         | '/' atomExp
         )* 
    ;

/* An expression atom is the smallest part of an expression: a number. Or 
   when we encounter parenthesis, we're making a recursive call back to the
   rule 'additionExp'. As you can see, an 'atomExp' has the highest precedence. */
atomExp
    :    Number
    |    '(' additionExp ')'
    ;

/* A number: can be an integer value, or a decimal value */
Number
    :    ('0'..'9')+ ('.' ('0'..'9')+)?
    ;

/* We're going to ignore all white space characters */
WS  
    :   (' ' | '\t' | '\r'| '\n') {$channel=HIDDEN;}
    ;

après avoir créé la grammaire, vous voudrez générer un analyseur et lexer à partir de celui-ci. Téléchargez le ANTLR jar et stockez-le dans le même répertoire que votre fichier de grammaire.

exécutez la commande suivante sur votre invite shell / commande:

java -cp antlr-3.2.jar org.antlr.Tool Exp.g

il ne doit pas produire de message d'erreur, et les fichiers Expresser.java , ExpParser.java et Exp.les tokens devraient maintenant être générés.

pour voir si tout fonctionne correctement, créez cette classe d'essai:

import org.antlr.runtime.*;

public class ANTLRDemo {
    public static void main(String[] args) throws Exception {
        ANTLRStringStream in = new ANTLRStringStream("12*(5-6)");
        ExpLexer lexer = new ExpLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        ExpParser parser = new ExpParser(tokens);
        parser.eval();
    }
}

et le compiler:

// *nix/MacOS
javac -cp .:antlr-3.2.jar ANTLRDemo.java

// Windows
javac -cp .;antlr-3.2.jar ANTLRDemo.java

puis lancez-le:

// *nix/MacOS
java -cp .:antlr-3.2.jar ANTLRDemo

// Windows
java -cp .;antlr-3.2.jar ANTLRDemo

Si tout va bien, rien n'est imprimé sur la console. Cela signifie que l'analyseur n'a trouvé aucune erreur. Lorsque vous changez "12*(5-6)" en "12*(5-6" et que vous le recompilez et l'exécutez, il faut imprimer ce qui suit:

line 0:-1 mismatched input '<EOF>' expecting ')'

Ok, maintenant nous voulons ajouter un peu de code Java à la grammaire pour que l'analyseur fasse quelque chose d'utile. L'ajout de code peut être fait par placer { et } dans votre grammaire avec un code Java simple à l'intérieur.

mais d'abord: toutes les règles de l'analyseur dans le fichier grammatical doivent retourner une valeur primitive double. Vous pouvez le faire en ajoutant returns [double value] après chaque règle:

grammar Exp;

eval returns [double value]
    :    additionExp
    ;

additionExp returns [double value]
    :    multiplyExp 
         ( '+' multiplyExp 
         | '-' multiplyExp
         )* 
    ;

// ...

ce qui nécessite peu d'explications: chaque règle est censée rapporter une double valeur. Maintenant, pour "interagir" avec la valeur de retour double value (qui N'est pas à l'intérieur d'un bloc de code Java simple {...} ) de l'intérieur d'un bloc de code, vous devrez ajouter un signe dollar en face de value :

grammar Exp;

/* This will be the entry point of our parser. */
eval returns [double value]                                                  
    :    additionExp { /* plain code block! */ System.out.println("value equals: "+$value); }
    ;

// ...

voici la grammaire mais maintenant avec le code Java ajouté:

grammar Exp;

eval returns [double value]
    :    exp=additionExp {$value = $exp.value;}
    ;

additionExp returns [double value]
    :    m1=multiplyExp       {$value =  $m1.value;} 
         ( '+' m2=multiplyExp {$value += $m2.value;} 
         | '-' m2=multiplyExp {$value -= $m2.value;}
         )* 
    ;

multiplyExp returns [double value]
    :    a1=atomExp       {$value =  $a1.value;}
         ( '*' a2=atomExp {$value *= $a2.value;} 
         | '/' a2=atomExp {$value /= $a2.value;}
         )* 
    ;

atomExp returns [double value]
    :    n=Number                {$value = Double.parseDouble($n.text);}
    |    '(' exp=additionExp ')' {$value = $exp.value;}
    ;

Number
    :    ('0'..'9')+ ('.' ('0'..'9')+)?
    ;

WS  
    :   (' ' | '\t' | '\r'| '\n') {$channel=HIDDEN;}
    ;

et puisque notre règle eval retourne maintenant un double, changez votre ANTLRDemo.java dans le présent:

import org.antlr.runtime.*;

public class ANTLRDemo {
    public static void main(String[] args) throws Exception {
        ANTLRStringStream in = new ANTLRStringStream("12*(5-6)");
        ExpLexer lexer = new ExpLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        ExpParser parser = new ExpParser(tokens);
        System.out.println(parser.eval()); // print the value
    }
}

encore une fois (re) générer une lexer et un analyseur à partir de votre grammaire( 1), compiler toutes les classes (2) et exécuter ANTLRDemo (3):

// *nix/MacOS
java -cp antlr-3.2.jar org.antlr.Tool Exp.g   // 1
javac -cp .:antlr-3.2.jar ANTLRDemo.java      // 2
java -cp .:antlr-3.2.jar ANTLRDemo            // 3

// Windows
java -cp antlr-3.2.jar org.antlr.Tool Exp.g   // 1
javac -cp .;antlr-3.2.jar ANTLRDemo.java      // 2
java -cp .;antlr-3.2.jar ANTLRDemo            // 3

et vous verrez maintenant le résultat de l'expression 12*(5-6) imprimé sur votre console!

Encore une fois: c'est une très brève explication. Je vous encourage à parcourir le ANTLR wiki et lire quelques tutoriels et/ou jouer un peu avec ce que je viens de poster.

bonne chance!

EDIT:

Ce post , montre comment étendre l'exemple ci-dessus pour qu'un Map<String, Double> puisse être fourni qui contient des variables dans l'expression fournie.

et ce Q&A montre comment créer un analyseur d'expression simple, et un évaluateur en utilisant ANTLR4 .

pour que ce code fonctionne avec une version actuelle D'Antlr (juin 2014) j'ai dû faire quelques changements. ANTLRStringStream devait devenir ANTLRInputStream , la valeur retournée nécessaire de passer de parser.eval() à parser.eval().value , et j'ai dû supprimer la clause WS à la fin, parce que les valeurs d'attribut telles que $channel ne sont plus autorisées à apparaître dans les actions de lexer.

416
répondu Bart Kiers 2017-05-23 12:10:41

pour moi ce tutoriel a été très utile: https://tomassetti.me/antlr-mega-tutorial

il a des exemples de grammaire, des exemples de visiteurs dans différentes langues (Java, JavaScript, C# et Python) et beaucoup d'autres choses. Fortement recommandé.

8
répondu solo 2017-11-09 08:18:24

pour Antlr 4 le processus de génération de code java est ci-dessous: -

java -cp antlr-4.5.3-complete.jar org.antlr.v4.Tool Exp.g

mettez à jour le nom de votre pot dans classpath en conséquence.

7
répondu Abhishek K 2016-04-16 06:48:13

à https://github.com/BITPlan/com.bitplan.antlr vous trouverez une bibliothèque java ANTLR avec quelques classes d'aide utiles et quelques exemples complets. Il est prêt à être utilisé avec maven et si vous aimez eclipse et maven.

https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/main/antlr4/com/bitplan/exp/Exp.g4

est un langage D'Expression simple qui peut faire multiplier et ajouter opérations. https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/test/java/com/bitplan/antlr/TestExpParser.java la rubrique comporte les épreuves unitaires correspondantes.

https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/main/antlr4/com/bitplan/iri/IRIParser.g4 est un analyseur IRI qui a été divisé en trois parties:

  1. analyseur de grammaire
  2. lexer grammaire
  3. grammaire Lexbasique importée

https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/test/java/com/bitplan/antlr/TestIRIParser.java il a les tests de l'unité.

personnellement, J'ai trouvé que c'était la partie la plus délicate à corriger. Voir http://wiki.bitplan.com/index.php/ANTLR_maven_plugin

https://github.com/BITPlan/com.bitplan.antlr/tree/master/src/main/antlr4/com/bitplan/expr

contient trois autres exemples qui ont été créés pour un problème de performance D'ANTLR4 dans une version antérieure. Dans l'intervalle, ces problèmes ont été résolus comme le cas d'essai https://github.com/BITPlan/com.bitplan.antlr/blob/master/src/test/java/com/bitplan/antlr/TestIssue994.java shows.

1
répondu Wolfgang Fahl 2017-10-23 05:49:10