SORU
18 Aralık 2009, Cuma


antlr: basit bir örnek var mı?

Antlr ile başlamak istiyorum, ama antlr.org yerinde birkaç saat örnekleri gözden geçirdikten sonra, ben hala cant işlem java dilbilgisi net bir anlayış olsun.

biraz basit bir örnek var mı? dört işlem hesap makinesi ile uygulanan antlr ayrıştırıcı tanımı ve java kaynak kodu tüm yol boyunca gitmek gibi bir şey mi?

CEVAP
19 Aralık 2009, CUMARTESİ


İlk önce bir dilbilgisi oluşturmak. Aşağıda oluşturulan ifadeler değerlendirmek için kullanabileceğiniz küçük bir dilbilgisi 4 temel matematik işlemleri: , -, * ve /. Ayrıca ifadeler parantez kullanarak gruplayabilirsiniz.

Not: bu dilbilgisi bir çok temel: yok kolu tekli işleçler (eksi: -1 9) ya da ondalıklar gibi .99 (olmadan bir lider sayısı), adı sadece iki kısa geliş. Bu sadece kendiniz üzerinde çalışabilirsiniz bir örnektir.

Burada dilbilgisi dosyasının içeriğiniExp.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;}
    ;

(Ayrıştırıcı kurallar, bir küçük harf ile başlar, ve lexer kuralları büyük harfle başlar)

Dilbilgisi oluşturduktan sonra, ayrıştırıcı ve lexer oluşturmak istiyorum. ANTLR jar indirmek ve saklamak dilbilgisi dosyası ile aynı dizinde.

Shell/komut istemi üzerinde aşağıdaki komutu yürütün

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

Herhangi bir hata mesajı ve dosyaları oluşturmak gerekirExpLexer.java,ExpParser.javaveExp.belirteçlerişimdi oluşturulan olmalıdır.

Eğer düzgün çalışırsa bu test sınıf oluşturun:

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();
    }
}

ve derleme:

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

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

ve çalıştırın:

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

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

Eğer her şey yolunda giderse, hiçbir şey konsola yazdırılıyor. Bu ayrıştırıcı herhangi bir hata buldunuz demektir. "12*(5-6" "12*(5-6)" değiştirin ve sonra yeniden derleyin ve çalıştırın, aşağıdaki basılı olmalıdır

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

Tamam, şimdi çözümleyici aslında yararlı bir şey yapabilmesi için dilbilgisi Java kod biraz eklemek istiyoruz. Kod ekleme içindeki bazı düz Java kodu ile dilbilgisi içine yerleştirerek { } ile yapılabilir.

Dilbilgisi dosyası ayrıştırıcı kurallar ilkel çift bir değer döndürmesi gerekir. ama önce: Her kural sonra returns [double value] ekleyerek bunu yapabilirsiniz:

grammar Exp;

eval returns [double value]
    :    additionExp
    ;

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

// ...

ihtiyacı olan küçük bir açıklama: her çift sayı bir değer döndürmesi beklenir. Şimdi "etkileşim" ile dönüş değeri double value (içinde DEĞİL sade bir Java kod bloğu {...}) içindeki bir kod bloğu ihtiyacınız olacak eklemek dolar işareti önünde 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); }
    ;

// ...

İşte ama şimdi Java ile kod eklendi: dilbilgisi

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;}
    ;

ve o zamandan beri eval kuralımızı şimdi bu içine antlrdemo.java : çift, bir değişiklik verir

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
    }
}

Yine (re) dilbilgisi (1) taze lexer ve ayrıştırıcı oluşturmak, tüm sınıflar, (2) derleme ve ANTLRDemo (3) çalıştırın:

// *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

ve şimdi 12*(5-6) yazdırılan ifadenin sonucu konsol göreceksiniz!

Tekrar: bu çok kısa bir açıklama. ANTLR wiki bulun ve okuyun bazı dersler ve ya ben sadece yayınlanmıştır ne ile biraz/oynamak için teşvik ediyoruz.

İyi şanslar!

DÜZENLEME:

This post yukarıdaki örnekte uzatmak için nasıl bu kadar Map<String, Double> verilen ifadede değişkenler tutan sağlanan gösterir.

Q&A bu basit bir ifade ayrıştırıcı oluşturmak ve kullanarak değerlendiricisi gösterilmiştirANTLR4.

Bu kod Antlr güncel bir sürüm (Haziran 2014) ile çalışma almak için birkaç değişiklik yapmak istedim. ANTLRStringStream olmak için gerekli ANTLRInputStream, döndürülen değer gerekli değişikliği parser.eval() parser.eval().value ve ihtiyacım kaldırmak WS fıkra sonunda, çünkü öznitelik değerleri gibi $channel artık izin görünmesini lexer eylemler.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Noam Erez

    Noam Erez

    3 NİSAN 2012
  • schmittastic

    schmittastic

    9 EYLÜL 2009
  • xdadevelopers

    xdadeveloper

    25 Aralık 2009