2013-10-15 29 views
14

Bir ayrıştırma ağacını genel olarak çaprazlarken ANTLR4'te alternatif etiketlere nasıl erişebilirim? Veya alternatif olarak, hile yapacağı gibi, ANTLR3'ün ^ operatörünün işlevselliğini çoğaltma yolu vardır.Alternatif olarak bir ayrıştırma ağacını çapraz olarak geçerken ANTLR4'teki alternatif etiketlere nasıl erişebilirim?

Basit bir metodolojiye (alternatif etiketlerle adlandırmalar ekleme gibi) yapışan ANTLR4 dilbilgisi için AST güzel yazıcısı yazmaya çalışıyorum. Çünkü, ben etkili plus ve minus yapımları için isim vermek alamıyorum

int_expression 
    : int_expression '+' int_expression # plus 
    | int_expression '-' int_expression # minus 
    | raw_int       # int_literal 
    ; 
raw_int 
    : Int 
    ; 
Int : [0-9]+ ; 

: Ben aşağıdaki gibi bir gramer verilen oldukça (int_expression (plus (int_literal 3) (int_literal 5))) veya benzer bir şey olarak 3 + 5 gibi bir terim yazdırmak mümkün olmak istiyorum Bunları kendi üretimlerine çekerek, aracın kuralların karşılıklı olarak sol-özyinelemesinden şikayet etmesine neden olur. Onları çıkaramazsam, bu yapım isimlerini nasıl verebilirim?

Not 1: metodolojik (örneğin yukarıda Int) özel yapımları (üretim raw_ gibi, özel bir önek ile başlayarak) "iyi" terminalleri koyarak + değişken kurtulmak başardı. Daha sonra sadece ana prodüksiyonları "raw_ ..." olarak adlandırılan ve diğerlerinin hepsine de sahip olan terminalleri yazdırabilirim. Bu, 3 ve 5 çıkışında tutulurken +'dan kurtulmak için çok çalıştı. Bu ANTLR3'te ! ile yapılabilir.

Not 2: Özel bir güzel yazıcı yazabileceğimi veya belirli bir dilin her bir üretimi için eylemleri kullanabileceğimi anlıyorum, ancak ANTLR4'ü çeşitli diller için AST'leri ayrıştırmak ve üretmek için kullanmak istiyorum. Böyle basit bir yazıcıyı genel olarak yazabilmem gerekir. Başka bir şekilde, sadece AST'leri almayı umuyorum, ve her bir grameri AST'yi elde etmek için uyarlanmış güzel bir yazıcıyla saklamak zorunda kalmamayı tercih ederim. Belki de ANTLR3'e geri dönmeliyim?

cevap

1

Çeşitli içerik nesnelerini almak için güzel yazıcıyı yuvalanmış bir ziyaretçi sınıfıyla bir dinleyici uygulaması olarak uygulamanızı öneririm.

private MyParser parser; // you'll have to assign this field 
private StringBuilder builder = new StringBuilder(); 

@Override 
public void enterEveryRule(@NotNull ParserRuleContext ctx) { 
    if (!builder.isEmpty()) { 
     builder.append(' '); 
    } 

    builder.append('('); 
} 

@Override 
public void visitTerminalNode(@NotNull TerminalNode node) { 
    // TODO: print node text to builder 
} 

@Override 
public void visitErrorNode(@NotNull TerminalNode node) { 
    // TODO: print node text to builder 
} 

@Override 
public void exitEveryRule(@NotNull ParserRuleContext ctx) { 
    builder.append(')'); 
} 

protected String getContextName(@NotNull ParserRuleContext ctx) { 
    return new ContextNameVisitor().visit(ctx); 
} 

protected class ContextNameVisitor extends MyParserBaseVisitor<String> { 
    @Override 
    public String visitChildren() { 
     return parser.getRuleNames()[ctx.getRuleIndex()]; 
    } 

    @Override 
    public String visitPlus(@NotNull PlusContext ctx) { 
     return "plus"; 
    } 

    @Override 
    public String visitMinus(@NotNull MinusContext ctx) { 
     return "minus"; 
    } 

    @Override 
    public String visitInt_literal(@NotNull MinusContext ctx) { 
     return "int_literal"; 
    } 
} 
+0

Ben her dil için bir uzman oldukça yazıcıyı yazmadan bunu yapmanın genel bir yol arıyorum. Bunu yapmanın bir yolu yok mu? Bir kullanıcının bakış açısından, neden var olmadığını anlamıyorum, çünkü alternatif etiketler orada. –