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