SableCC + IntelliJ – krótka instrukcja obsługi

SableCC jest generatorem parserów dla Javy. Więcej informacji możecie znaleźć TUTAJ. W swoim artykule chciałam skupić się na konfiguracji IntelliJ, skompilowaniu prostej gramatyki napisanej właśnie w SableCC i przetestowaniu jej z wykorzystaniem własnego interpretera napisanego w Javie.

Zacznijmy od pobrania programu. TUTAJ znajdziecie najnowszą stabilną wersję sableCC, którą należy pobrać i rozpakować. Do poprawnego działania potrzebne będzie nam JDK w odpowiedniej wersji. Teraz przystąpmy do ustawień.

Otwórzmy okno Project Settings (CTRL+ALT+SHIFT+S) -> zakładka Modules -> karta Dependencies. Klikając na plusa (ATL+INSERT) dodajmy plik .JAR z folderu lib w lokalizacji, w której rozpakowaliśmy paczkę z sableCC.

 

Bez tytułu1

Teraz stwórzmy plik z gramatyką (*.sable) i dodajmy go do naszego projektu. Dla przykładu stworzyłam gramatykę (grammar.sable) bardzo prostego kalkulatora.

Package calculator ;

Helpers
    digit = ['0' .. '9'] ;
    add = '+';
    sub = '-';
    div = '/';
    multi = '*';

Tokens
    integer = digit+;
    operation = add | sub | div | multi;

Productions
    program = [left]:integer operation [right]:integer;

Co tak naprawdę znajduje się w naszej gramatyce:

  • package: nazwa pakietu, w którym mają nam się tworzyć parsery i leksery po skompilowaniu gramatyki,
  • helpers: pomocnicze znaki, które wykorzystujemy do tworzenia tokenów,
  • tokens: podstawowe jednostki leksykalne,
  • productions: reguły naszej gramatyki.

Następnie stworzymy narzędzie do kompilowania naszej gramatyki. Wejdźmy w ustawienia (CTRL+ALT+S) -> Tools -> External Tools. Klikając na plusa (ALT+INSERT) dodajmy nowe narzędzie.

Bez tytułu2

Teraz ustawmy wszystkie potrzebne pola:

  • Name: nazwa naszego narzędzia, np. “SableCC Compiler”,
  • Program: ścieżka do pliku javaw.exe z folderu JDK,
  • Parameters: -classpath <ścieżka do pliku sablecc.jar> org.sablecc.sablecc.SableCC <ścieżka do naszego pliku z gramatyką>

Bez tytułu3

Mamy już wszystko, co potrzebne do skompilowania gramatyki, więc do dzieła. Wyszukujemy nasz plik z gramatyką w strukturze projektu, a następnie prawym przyciskiem myszy wybieramy ExternalTool i nasze narzędzie (SableCC Compiler).

Bez tytułu5

Po skompilowaniu powinny nam się pojawić 4 nowe pakiety (analysis, lexer, parser, node) w pakiecie, który podaliśmy w pliku z gramatyką.

Bez tytułu7

Ostatnim krokiem zostało napisanie kompilatora, który odczyta naszą gramatykę i zwróci odpowiedni wynik. Dodajmy nową klasę Interpreter:

package calculator.interpreter;

import calculator.analysis.DepthFirstAdapter;
import calculator.node.AProgram;

/**
 * Created by CodeCouple
 */
public class Interpreter extends DepthFirstAdapter {
    public void caseAProgram(AProgram node) {
        String l = node.getLeft().getText().trim();
        String r = node.getRight().getText().trim();
        String sign = node.getOperation().getText().trim();

        double left = new Double(l).doubleValue();
        double right = new Double(r).doubleValue();
        double result = 0;

        switch(sign) {
            case ("+"):
                result = left + right; break;
            case ("-"):
                result = left - right; break;
            case ("*"):
                result = left * right; break;
            case ("/"):
                result = left / right; break;
        }
        System.out.println(left + " " + sign + " " + right + " = " + result);
    }
}

Oraz klasę startową Main:

package calculator.runner;

import calculator.interpreter.Interpreter;
import calculator.lexer.Lexer;
import calculator.node.Start;
import calculator.parser.Parser;

import java.io.* ;

/**
 * Created by CodeCouple
 */
public class Main {
    public static void main(String[] args) {
        if (args.length > 0) {
            try {
                Lexer lexer = new Lexer (new PushbackReader(new FileReader(args[0]), 1024));
                Parser parser = new Parser(lexer);
                Start ast = parser.parse() ;
                Interpreter interpreter = new Interpreter () ;
                ast.apply(interpreter) ;
            }
            catch (Exception e) {
                System.out.println (e) ;
            }
        } else {
            System.exit(1);
        }
    }
}

Teraz dodajmy do programu plik tekstowy expression.txt, w którym będziemy podawać wyrażenia do obliczenia:

2+2

Ustawmy parametry programu Run->Edit Configurations…->Program arguments: <ścieżka do naszego pliku z wyrażeniem>:

Bez tytułu8

Teraz wystarczy skompilować i uruchomić program. W konsoli powinniśmy otrzymać następujący wynik:

SableCCresult

 

  • Grzegorz

    Ciekawy artykuł, dzięki 🙂 Zastanawia mnie tylko ten wynik na końcu 🙂

    • Agnieszka Pieszczek

      Dzięki. Obraz był z fazy testów. Już poprawiłam. Cieszę się, że artykuł był tak uważnie czytany:)