Java'da bir kod çevirmeni Antlr4 yardımıyla yazmaya çalışıyorum ve dilbilgisi bölümü ile bugüne kadar büyük başarılar kazandım. Ancak şimdi kafamı, girdim ayrıştırıldıktan sonra üzerinde çalışmam gereken ayrıştırıcı ağacı veri yapısının etrafına aklımı saran bir duvara çarpıyorum.Antlr4'teki içerik veri yapısını anlama
Ayrıştırma ağacım üzerinden gitmek için ziyaretçi şablonunu kullanmaya çalışıyorum. Kargaşamın noktalarını gösterecek bir örnek göstereceğim.
Benim dilbilgisi:
grammar pqlc;
// Lexer
//Schlüsselwörter
EXISTS: 'exists';
REDUCE: 'reduce';
QUERY: 'query';
INT: 'int';
DOUBLE: 'double';
CONST: 'const';
STDVECTOR: 'std::vector';
STDMAP: 'std::map';
STDSET: 'std::set';
C_EXPR: 'c_expr';
INTEGER_LITERAL : (DIGIT)+ ;
fragment DIGIT: '0'..'9';
DOUBLE_LITERAL : DIGIT '.' DIGIT+;
LPAREN : '(';
RPAREN : ')';
LBRACK : '[';
RBRACK : ']';
DOT : '.';
EQUAL : '==';
LE : '<=';
GE : '>=';
GT : '>';
LT : '<';
ADD : '+';
MUL : '*';
AND : '&&';
COLON : ':';
IDENTIFIER : JavaLetter JavaLetterOrDigit*;
fragment JavaLetter : [a-zA-Z$_]; // these are the "java letters" below 0xFF
fragment JavaLetterOrDigit : [a-zA-Z0-9$_]; // these are the "java letters or digits" below 0xFF
WS
: [ \t\r\n\u000C]+ -> skip
;
COMMENT
: '/*' .*? '*/' -> skip
;
LINE_COMMENT
: '//' ~[\r\n]* -> skip
;
// Parser
//start_rule: query;
query :
quant_expr
| qexpr+
| IDENTIFIER // order IDENTIFIER and qexpr+?
| numeral
| c_expr //TODO
;
c_type : INT | DOUBLE | CONST;
bin_op: AND | ADD | MUL | EQUAL | LT | GT | LE| GE;
qexpr:
LPAREN query RPAREN bin_op_query?
// query bin_op query
| IDENTIFIER bin_op_query? // copied from query to resolve left recursion problem
| numeral bin_op_query? //^
| quant_expr bin_op_query? //^
|c_expr bin_op_query?
// query.find(query)
| IDENTIFIER find_query? // copied from query to resolve left recursion problem
| numeral find_query? //^
| quant_expr find_query?
|c_expr find_query?
// query[query]
| IDENTIFIER array_query? // copied from query to resolve left recursion problem
| numeral array_query? //^
| quant_expr array_query?
|c_expr array_query?
// | qexpr bin_op_query // bad, resolved by quexpr+ in query
;
bin_op_query: bin_op query bin_op_query?; // resolve left recursion of query bin_op query
find_query: '.''find' LPAREN query RPAREN;
array_query: LBRACK query RBRACK;
quant_expr:
quant id ':' query
| QUERY LPAREN match RPAREN ':' query
| REDUCE LPAREN IDENTIFIER RPAREN id ':' query
;
match:
STDVECTOR LBRACK id RBRACK EQUAL cm
| STDMAP '.''find' LPAREN cm RPAREN EQUAL cm
| STDSET '.''find' LPAREN cm RPAREN
;
cm:
IDENTIFIER
| numeral
| c_expr //TODO
;
quant :
EXISTS;
id :
c_type IDENTIFIER
| IDENTIFIER // Nach Seite 2 aber nicht der Übersicht. Laut übersicht id -> aber dann wäre Regel 1 ohne +
;
numeral :
INTEGER_LITERAL
| DOUBLE_LITERAL
;
c_expr:
C_EXPR
;
Şimdi
en aşağıdaki dizeyi ayrıştırmak edelim:
benim ziyaretçi visitQexpr(@NotNull pqlcParser.QexprContext ctx)
olduğunu varsayalım:
double x: x >= c_expr
Görme bu ağacı alırsınız Qexpr (x bin_op_query) dalına ulaştığında rutin.
Soruma göre, soldaki çocukların ("x" ağacında) bir terminal düğümü veya daha özel olarak "IDENTIFIER" olduğunu nasıl söyleyebilirim? Kurallar olmadığından Terminal düğümleri için ziyaret kuralları yoktur. ctx.getChild(0)
'un RuleIndex'i yoktur. Terminalde olup olmadığımı kontrol etmek için kullanabilirim, fakat IDENTIFIER ya da başka tür terminal belirteçlerinde olduğumu söyleyemem. Farkı bir şekilde söyleyebilmem lazım.
Daha fazla sorularım vardı, ancak açıklamalarımı yazmam için gereken süreyi unuttum: < Şimdiden teşekkürler.
id :
c_type labelA = IDENTIFIER
| labelB = IDENTIFIER
;
Ayrıca farklı ziyaretleri yaratmak için bu yapabilirdi:
id :
c_type IDENTIFIER #idType1 //choose more appropriate names!
| IDENTIFIER #idType2
;
Bu yaratacak
Genel çözüm, ayrıştırma ağacını ziyaret etmek yerine [AST (soyut sözdizim ağacı)] (https://en.wikipedia.org/wiki/Abstract_syntax_tree) adresini ziyaret etmektir ... Ancak bu özellik [kaldırıldı beri antlr4] (http://stackoverflow.com/questions/15823333/how-can-i-build-an-ast-using-antlr4).Belki de x sembolü olan bir simge olup olmadığını öğrenmek için [sembol tablosu] (https://en.wikipedia.org/wiki/Symbol_table) kralı kullanabilirsiniz :) İyi şanslar! – NiziL
Çocuğun payLoad() öğesini alırsam, belirteç kimliği (diğer öğeler arasında) bulunur. Böylece bilgi veri yapısında saklanır, kolayca erişebilmek için uygun bir yol olmalıdır. ctx, ctx.IDENTIFIER() gibi farklı terminal düğümlerim için işlevleri var ancak tam olarak ne yaptığını anlatamam. Görünüşe göre ctx.IDENTIFIER() dönüş değeri, düğüm düğümleri ve diğer düğümlerin metni yoksa boştur. Yine de, birden çok çocuk varsa/hangisinin uçbirim düğümü olduğunu söylemez. Tüm veri yapısını böylesine kafa karıştırıcı buluyorum: \ – user2323596
Bazı Bağlamda bir alt ağ/terminal düğümünün ziyaret edilip edilmediğini öğrenmek istediğimde, genellikle bu subrule/terminalin boş olup olmadığını (ziyaret edilmiyor) veya boş olmadığını kontrol ediyorum. (ziyaret ediliyor). Ama aynı zamanda bu oldukça hacky'i de, istediğini elde etmek için güzel ve temiz bir yoldan daha iyi buluyorum ... – schauk11erd