JavaCC

JavaCC

JavaCC est un générateur d'analyseur syntaxique extrêmement populaire pour les applications Java.
Il permet d'écrire un parseur extrêmement facilement.

Il va lire la spécification de la grammaire puis la transforme en programme java.

Comment l'installer et l'utiliser

Installation

Pour l'installer dans Gradle, c'est simple comme bonjour.

Ajouter le plugin pour la génération des class Java

plugins {
    id "org.javacc.javacc" version "4.0.1"
}```
Puis ajouter la dépendance
```groovy
dependencies {
    implementation group: 'net.java.dev.javacc', name: 'javacc', version: '7.0.13'
}```
### Fonctionnement

Pour commencer, il faut creer un fichier dans src/main/javacc/nom_package avec le nom de la class, 
Puis écrire le parser de cette manière.


```javacc
PARSER_BEGIN(Example)
/** Simple brace matcher. */
public class Example {
  /** Main entry point. */
  public static void main(String args[]) throws ParseException {
    Example parser = new Example(System.in);
    parser.Input();
  }
}
PARSER_END(Example)
/** Root production. */
void Input() :
{}
{
  MatchedBraces() ("\n"|"\r")* <EOF>
}
/** Brace matching production. */
void MatchedBraces() :
{}
{
  "{" [ MatchedBraces() ] "}"
}```
On peut voir dans cet exemple, qu'il s'agit d'un parser d'accolade et qu'il verifie que toute nos accolade 
sont correctement fermée.

Pour finir, un petit coup de gradle build, et la class est généré dans build/generated.

Toute la documentation sur le fonctionnement et l'écriture d'un parser se trouve [ici](https://javacc.github.io/javacc/#an-example)
Il est possible de faire des choses un peu plus complexe en prenant des paramètre par exemple.

Dans l'exemple ci-dessous, je parse des expressions du style `>=5 && <8`
```javacc
options {
    JAVA_TEMPLATE_TYPE = "modern";
}
PARSER_BEGIN(RangePredicateParser)
package com.github.mehrunessky.engine;
import java.util.function.Predicate;
public class RangePredicateParser {
    public static Predicate<Double> parse(String input) throws ParseException {
        RangePredicateParser parser = new RangePredicateParser(input);
        return parser.expressions();
    }
}
PARSER_END(RangePredicateParser)
SKIP : {
    " " | "\t" | "\n" | "\r"
}
TOKEN : {
    < LBRACKET: "[" > |
    < RBRACKET: "]" > |
    < DOTDOT: ".." > |
    < COLON: ":" > |
    < GT: ">" > |
    < GTE: ">=" > |
    < LT: "<" > |
    < LTE: "<=" > |
    < OR: "||" > |
    < AND: "&&" > |
    < NUMBER: (["0"-"9"])+ > |
    < LPAREN: "(" > |
    < RPAREN: ")" >
}
Predicate<Double> expressions():
{
    Predicate<Double> from;
    Predicate<Double> or = new Predicate<Double>() {@Override public boolean test(Double aDouble) {
        return false;
    }};
    Predicate<Double> and = new Predicate<Double>() {@Override public boolean test(Double aDouble) {
            return true;
        }};
}
{
    (from=expression() ((<OR> or=expressions())|(<AND> and=expressions()))?)
    {return from.or(or).and(and);}
}
Predicate<Double> expression():
{
    Predicate<Double> from;
}
{
    (from=up() | from=down() | from = rangePredicate())
    {return from;}
}
Predicate<Double> up():
{
    Predicate<Double> p;
    Token number;
}
{
    ((<GTE> number=<NUMBER>){p = new Predicate<Double>() {@Override public boolean test(Double i) {return i >= Double.parseDouble(number.image);}};}
    |(<GT> number=<NUMBER>){p = new Predicate<Double>() {@Override public boolean test(Double i) {return i > Double.parseDouble(number.image);}};})
    {return p;}
}
Predicate<Double> down():
{
    Predicate<Double> p;
    Token number;
}
{
    ((<LTE> number=<NUMBER>){p = new Predicate<Double>() {@Override public boolean test(Double i) {return i <= Double.parseDouble(number.image);}};}
    |(<LT> number=<NUMBER>){p = new Predicate<Double>() {@Override public boolean test(Double i) {return i < Double.parseDouble(number.image);}};})
    {return p;}
}
Predicate<Double> rangePredicate() :
{
    Predicate<Double> from;
    Predicate<Double> to;
}
{
    from = from() (<DOTDOT> | <COLON>) to = to()
    {
        return from.and(to);
    }
}
Predicate<Double> from() :
{
    Token fromToken;
    Predicate<Double> p;
}
{
    (<LBRACKET> fromToken = <NUMBER>
    {
        double from = Double.parseDouble(fromToken.image);
        p = new Predicate<Double>() {
            @Override
            public boolean test(Double i) {
                return i >= from;
            }
        };
    }
    | <RBRACKET> fromToken = <NUMBER>
    {
      double from = Double.parseDouble(fromToken.image);
      p = new Predicate<Double>() {
          @Override
          public boolean test(Double i) {
              return i > from;
          }
      };
    })
    {return p;}
}
Predicate<Double> to() :
{
    Token toToken;
    Predicate<Double> p;
}
{
    (toToken = <NUMBER>
    (
        <RBRACKET>
        {
            double to = Double.parseDouble(toToken.image);
            p = new Predicate<Double>() {
                @Override
                public boolean test(Double i) {
                    return i <= to;
                }
            };
        }
        | <LBRACKET>
        {
          double to = Double.parseDouble(toToken.image);
          p = new Predicate<Double>() {
              @Override
              public boolean test(Double i) {
                  return i < to;
              }
          };
        }
        )
    )
    {return p;}
}

JavaCC

JavaCC est un générateur d'analyseur syntaxique extrêmement populaire pour les applications Java.
Il permet d'écrire un parseur extrêmement facilement.

Il va lire la spécification de la grammaire puis la transforme en programme java.

Comment l'installer et l'utiliser

Installation

Pour l'installer dans Gradle, c'est simple comme bonjour.

Ajouter le plugin pour la génération des class Java

plugins {
    id "org.javacc.javacc" version "4.0.1"
}

Puis ajouter la dépendance

dependencies {
    implementation group: 'net.java.dev.javacc', name: 'javacc', version: '7.0.13'
}

Read more