GNU Bizonu - GNU Bison

GNU Bizonu
Heckert GNU white.svg
Orijinal yazar (lar)Robert Corbett
Geliştirici (ler) GNU Projesi
İlk sürümHaziran 1985; 35 yıl önce (1985-06)[1]
Kararlı sürüm
3.7.2 / 5 Eylül 2020; 3 ay önce (2020-09-05)[2]
Depo Bunu Vikiveri'de düzenleyin
YazılmışC ve m4
İşletim sistemiUnix benzeri
TürAyrıştırıcı oluşturucu
LisansGPL
İnternet sitesihttps://savannah.gnu.org/projects/bison/ www.gnu.org/yazılım/bizon/, https:// savannah.gnu.org/ projeler/bizon/ Bunu Vikiveri'de düzenleyin

GNU Bizonuyaygın olarak Bison olarak bilinen bir ayrıştırıcı oluşturucu bu parçası GNU Projesi. Bison, bir bağlamdan bağımsız dil, herhangi bir konuda uyarır ayrıştırma belirsizlikler oluşturur ve bir ayrıştırıcı oluşturur ( C, C ++ veya Java ) dizilerini okuyan jetonlar ve dizinin dilbilgisi tarafından belirtilen sözdizimine uygun olup olmadığına karar verir. Oluşturulan ayrıştırıcılar taşınabilirdir: herhangi bir özel derleyiciye ihtiyaç duymazlar. Varsayılan olarak Bison üretir LALR (1) ayrıştırıcıları ama aynı zamanda oluşturabilir kanonik LR, IELR (1) ve GLR ayrıştırıcılar.[3]

İçinde POSIX modu, Bison ile uyumludur Yacc, ancak bu önceki programa göre birkaç uzantıya sahiptir:

  • çatışmalar için karşı örneklerin oluşturulması,
  • konum izleme (ör. dosya, satır, sütun),
  • oluşturulan ayrıştırıcılarda zengin ve uluslararasılaştırılabilir sözdizimi hata mesajları,
  • özelleştirilebilir sözdizimi hatası oluşturma,
  • evresel ayrıştırıcılar,
  • otomatik tamamlama ile ayrıştırıcıları itin,
  • adlandırılmış referanslar için destek,
  • oluşturulan ayrıştırıcıda çeşitli rapor türleri (grafik, XML),
  • çeşitli programlama dilleri için destek,
  • vb.

Esnek otomatik sözcük çözümleyici, genellikle girdi verilerini belirtmek ve Bison'a belirteçler sağlamak için Bison ile birlikte kullanılır.[4]

Bison ilk olarak 1985 yılında Robert Corbett tarafından yazılmıştır.[1] Robert Corbett daha sonra 1989 yılında Berkeley Yacc. Bison, Yacc uyumlu hale getirildi. Richard Stallman.[5]

Bizon ücretsiz yazılım ve altında mevcuttur GNU Genel Kamu Lisansı, oluşturulan kodun tetiklenmeden kullanılmasına izin veren bir istisna (aşağıda tartışılmıştır) copyleft lisansın gereksinimleri.


Bazı Bison Özellikleri

Karşı Örnek Üretimi

LR ayrıştırıcı oluşturucularla ilgili hassas bir sorun, çakışmaların çözülmesidir (çakışmaları kaydır / azalt ve azalt / azalt). Çatışmaların çözülmesi genellikle raporlarda açıklandığı gibi ayrıştırıcı otomatının analizini ve kullanıcının biraz uzmanlığını gerektirir. Karşı örnekler, bazı çatışmaları hızlı bir şekilde anlamaya yardımcı olur ve hatta sorunun dilbilgisinin aslında belirsiz olduğunu kanıtlayabilir.

Örneğin, kötü şöhretli bir dilbilgisi hakkında sarkan başka sorun, Bison raporları

doc / if-then-else.y: uyarı: "else" simgesindeki çakışmayı değiştir / azalt [-Örnekler]  Misal: "eğer" ifade "ise" "if" ifade "sonra" deyim  "else" ifadesi  Vardiya türetme if_stmt    ↳ "eğer" ifade "ise" stmt                         if_stmt                           ↳ "eğer" ifade "ve ardından" ifade "  "else" ifadesi  Misal: "eğer" ifade "ise" "if" ifade "sonra" deyim  "else" ifadesi  Türetmeyi azaltın if_stmt    ↳ "eğer" ifade "ise" stmt                        "else" ifadesi                         if_stmt                           ↳ "eğer" ifade "ve ardından" ifade " 

Yeniden giriş

Yeniden giriş, Bison'a eklenen ve Yacc'de bulunmayan bir özelliktir.

Normalde, Bison bir ayrıştırıcı üretir. giriş. Yeniden giriş yapmak için beyanname api.pure% tanımla kullanılmalıdır. Bison yeniden girişiyle ilgili daha fazla ayrıntı, Bison kılavuzunda bulunabilir.[6]

Çeşitli Çıkış Dilleri

Bison için kod üretebilir C, C ++ ve Java.[7] İçin deneysel bir arka uç D da mevcuttur.[8]

Diğer dillerden Bison tarafından oluşturulan ayrıştırıcıyı kullanmak için dil bağlama gibi araç SWIG kullanılabilir.

Üretilen kodun lisansı ve dağıtımı

Bison, diğer yazılım projelerinin kaynak koduna eklenen kaynak kodu ürettiğinden, bazı basit ama ilginç telif hakkı sorularını gündeme getiriyor.

GPL uyumlu bir lisans gerekli değildir

Bison tarafından üretilen kod, Bison projesinin kendisinden önemli miktarda kod içerir. Bison paketi şu şartlar altında dağıtılır: GNU Genel Kamu Lisansı (GPL), ancak GPL'nin çıktı için geçerli olmaması için bir istisna eklendi.[9][10]

Bison'un önceki sürümleri, çıktıya orijinal kaynak kodundan yyparse () işlevinin eklenmesi nedeniyle, çıktısının bir kısmının da GPL kapsamında lisanslandığını şart koşuyordu.

Bison kullanarak paket dağıtımı

Bison kullanan özgür yazılım projeleri, projelerinin Bison'a beslediği kaynak kodunu veya Bison tarafından üretilen sonuç C kodunu dağıtma seçeneğine sahip olabilir. Her ikisi de bir alıcının proje kaynak kodunu derleyebilmesi için yeterlidir. Ancak, yalnızca girdinin dağıtılması, alıcıların projeyi derlerken gerekli C kodunu oluşturabilmeleri için uyumlu bir Bison kopyasına sahip olmaları gerektiği gibi küçük bir rahatsızlık verir. Ve çıktıda sadece C kodunu dağıtmak, alıcıların ayrıştırıcıyı değiştirmesini çok zorlaştırma sorununu yaratır çünkü bu kod da yazılmamıştır. tarafından bir insan ne de için insanlar - amacı doğrudan bir C derleyicisine beslenmektir.

Bu sorunlar, hem girdi dosyalarını hem de üretilen kodu dağıtarak önlenebilir. Çoğu kişi, oluşturulan kodu kullanarak derler, diğer herhangi bir yazılım paketinden farklı değildir, ancak ayrıştırıcı bileşenini değiştirmek isteyen herkes önce girdi dosyalarını değiştirebilir ve oluşturulan dosyaları derlemeden önce yeniden oluşturabilir. Her ikisini de dağıtan projeler, oluşturulan dosyalara genellikle gözden geçirme sistemleri. Dosyalar yalnızca bir sürüm oluşturulurken oluşturulur.

Gibi bazı lisanslar GPL, kaynak kodunun "üzerinde değişiklik yapmak için çalışmanın tercih edilen şekli". Bu nedenle, Bison kullanan GPL'li projeler, Bison için girdi olan dosyaları dağıtmalıdır. Elbette, oluşturulan dosyaları da içerebilirler.

Kullanım

Bison, Yacc'ın yerini alacak şekilde yazıldığı ve büyük ölçüde uyumlu olduğu için, Bison kullanan birçok projeden gelen kod, Yacc'e eşit şekilde beslenebilir. Bu, bir projenin Bison'a özgü kaynak kodunu "kullanıp kullanmadığını" belirlemeyi zorlaştırır. Çoğu durumda, Bison'un "kullanımı", Yacc veya diğer türevlerinden birinin eşdeğer kullanımı ile önemsiz bir şekilde değiştirilebilir.

Bison, Yacc'de bulunmayan özelliklere sahiptir, bu nedenle, Yacc yeterli olmayacağından bazı projelerin Bison'u "kullandığı" söylenebilir.

Aşağıdaki liste, Bison'u daha gevşek anlamda "kullandığı", özgür yazılım geliştirme araçlarını kullandıkları ve Bison'a veya Bison uyumlu bir pakete beslenmesi amaçlanan kodu dağıttığı bilinen projelerden oluşmaktadır.

  • Bison'ın kendi dilbilgisi ayrıştırıcısı Bison tarafından oluşturulmuştur.[11]
  • Yakut programlama dili (YARV)
  • PHP programlama dili (Zend Parser)
  • GCC Bison kullanarak başladı, ancak elle yazılmış bir özyinelemeli iniş ayrıştırıcı 2004'te C ++ için (sürüm 3.4),[12] ve 2006'da C ve Objective-C için (sürüm 4.1)[13]
  • Git programlama dili (GC) Bison kullandı, ancak 1.5 sürümünde elle yazılmış bir tarayıcıya ve ayrıştırıcıya geçti.[14]
  • Bash kabuk, komut girdisini ayrıştırmak için bir yacc dilbilgisi kullanır.
  • Zambak gölet
  • PostgreSQL[15]
  • MySQL[16]
  • GNU Oktav Bison tarafından üretilen bir ayrıştırıcı kullanır.[17]
  • Perl 5 5.10'da başlayan Bison tarafından oluşturulmuş bir ayrıştırıcı kullanır.[18]

Tam bir evresel ayrıştırıcı örneği

Aşağıdaki örnek, basit bir hesap makinesi programı (yalnızca toplama ve çarpma) ve bir hesap makinesi oluşturmak için bir program yazmak için Bison ve flex'in nasıl kullanılacağını gösterir. soyut sözdizimi ağacı. Sonraki iki dosya sözdizimi ağacı işlevlerinin tanımını ve uygulanmasını sağlar.

/* * Expression.h * Sözdizimi ağacını oluşturmak için kullanılan yapının tanımı. */#ifndef __EXPRESSION_H__#define __EXPRESSION_H__/** * @brief İşlem türü */typedef Sıralama tagEOperationType{    eVALUE,    ÇOKLU,    eADD} EOperationType;/** * @brief İfade yapısı */typedef yapı tagSExpression{    EOperationType tip; / * /     int değer; / * /     yapı tagSExpression *ayrıldı; / * /     yapı tagSExpression *sağ; / * / } SExpression;/** * @brief Bir tanımlayıcı oluşturur * @param değeri Sayı değeri * @return Hafıza olmaması durumunda ifade veya NULL */SExpression *createNumber(int değer);/** * @brief Bir operasyon yaratır * @param türü İşlem türü * @param ayrıldı Sol işlenen * @param right Doğru işlenen * @return Hafıza olmaması durumunda ifade veya NULL */SExpression *createOperation(EOperationType tip, SExpression *ayrıldı, SExpression *sağ);/** * @brief Bir ifadeyi siler * @param b İfade */geçersiz deleteExpression(SExpression *b);#endif / * __EXPRESSION_H__ * /
/* * İfade.c * Sözdizimi ağacını oluşturmak için kullanılan işlevlerin uygulanması. */#Dahil etmek "Expression.h"#Dahil etmek <stdlib.h>/** * @brief İfade için alan ayırır * @return İfade veya yeterli hafıza yoksa NULL */statik SExpression *assignateExpression(){    SExpression *b = (SExpression *)Malloc(boyutu(SExpression));    Eğer (b == BOŞ)        dönüş BOŞ;    b->tip = eVALUE;    b->değer = 0;    b->ayrıldı = BOŞ;    b->sağ = BOŞ;    dönüş b;}SExpression *createNumber(int değer){    SExpression *b = assignateExpression();    Eğer (b == BOŞ)        dönüş BOŞ;    b->tip = eVALUE;    b->değer = değer;    dönüş b;}SExpression *createOperation(EOperationType tip, SExpression *ayrıldı, SExpression *sağ){    SExpression *b = assignateExpression();    Eğer (b == BOŞ)        dönüş BOŞ;    b->tip = tip;    b->ayrıldı = ayrıldı;    b->sağ = sağ;    dönüş b;}geçersiz deleteExpression(SExpression *b){    Eğer (b == BOŞ)        dönüş;    deleteExpression(b->ayrıldı);    deleteExpression(b->sağ);    Bedava(b);}

Bison ayrıştırıcısının ihtiyaç duyduğu belirteçler, flex kullanılarak üretilecektir.

%{/* * Lexer.l dosyası * Sözcük analizörü çalıştırmak için: "flex Lexer.l" */#Dahil etmek "Expression.h"#Dahil etmek "Ayrıştırıcı.h"#Dahil etmek <stdio.h>%}%seçenek dosya="Lexer.c" başlık-dosya="Lexer.h"%seçenek uyarmak standart değil%seçenek giriş noyywrap asla-etkileşimli isim%seçenek bizon-köprü%%[ \r\n\t]*   { devam et; / * Boşlukları atla. * / }[0-9]+       { sscanf(yytext, "% d", &yylval->değer); dönüş TOKEN_NUMBER; }"*"          { dönüş TOKEN_STAR; }"+"          { dönüş TOKEN_PLUS; }"("          { dönüş TOKEN_LPAREN; }")"          { dönüş TOKEN_RPAREN; }.            { devam et; / * Beklenmedik karakterleri yoksay. * /}%%int yyerror(sabit kömür *msg) {    fprintf(Stderr, "Hatalar n", msg);    dönüş 0;}

Jetonların isimleri tipik olarak nötrdür: "TOKEN_PLUS" ve "TOKEN_STAR", "TOKEN_ADD" ve "TOKEN_MULTIPLY" değil. Örneğin, tekli "+" 'yı destekleyecek olsaydık ("+1"' de olduğu gibi), bunu "+" "TOKEN_ADD" olarak adlandırmak yanlış olur. C gibi bir dilde, "int * ptr" bir göstericinin tanımını belirtir, bir ürünü değil: bunu "*" "TOKEN_MULTIPLY" olarak adlandırmak yanlış olur.

Jetonlar esnek tarafından sağlandığından, bunlar arasında iletişim kurmak için araçlar sağlamalıyız. ayrıştırıcı ve lexer.[19] İletişim için kullanılan veri türü, YYSTYPE, Bison kullanılarak ayarlanır %Birlik beyanname.

Bu örnekte hem flex hem de yacc'nin reentrant versiyonunu kullandığımız için, yylex işlev, çağrıldığında yyparse.[19] Bu, Bison aracılığıyla yapılır % lex-param ve % parse-param beyannameler.[20]

%{/* * Parser.y dosyası * Ayrıştırıcı çalıştırmak için: "bison Parser.y" */#Dahil etmek "Expression.h"#Dahil etmek "Ayrıştırıcı.h"#Dahil etmek "Lexer.h"int yyerror(SExpression **ifade, yyscan_t tarayıcı, sabit kömür *msg) {    / * Gerektiği gibi hata işleme rutini ekleyin * /}%}%kodu gerektirir {  typedef geçersiz* yyscan_t;}%çıktı  "Ayrıştırıcı.c"%tanımlar "Ayrıştırıcı.h"%tanımlamak api.saf%lex-param   { yyscan_t tarayıcı }%ayrıştırmak-param { SExpression **ifade }%ayrıştırmak-param { yyscan_t tarayıcı }%Birlik {    int değer;    SExpression *ifade;}%jeton TOKEN_LPAREN   "("%jeton TOKEN_RPAREN   ")"%jeton TOKEN_PLUS     "+"%jeton TOKEN_STAR     "*"%jeton <değer> TOKEN_NUMBER "numara"%tip <ifade> ifade/ * Öncelik (artan) ve ilişkilendirilebilirlik:   a + b + c (a + b) + c: sol ilişkilendirilebilirlik   a + b * c a + (b * c) 'dir: "*" önceliği "+" dan daha yüksektir. * /%ayrıldı "+"%ayrıldı "*"%%giriş    : ifade { *ifade = $1; }    ;ifade    : ifade[L] "+" ifade[R] { $$ = createOperation( eADD, $ L, $ R ); }    | ifade[L] "*" ifade[R] { $$ = createOperation( ÇOKLU, $ L, $ R ); }    | "(" ifade[E] ")"     { $$ = $ E; }    | "numara"            { $$ = createNumber($1); }    ;%%

Bison tarafından oluşturulan ayrıştırıcıyı ve flex tarafından oluşturulan tarayıcıyı kullanarak sözdizimi ağacını elde etmek için gereken kod aşağıdaki gibidir.

/* * main.c dosyası */#Dahil etmek "Expression.h"#Dahil etmek "Ayrıştırıcı.h"#Dahil etmek "Lexer.h"#Dahil etmek <stdio.h>int yyparse(SExpression **ifade, yyscan_t tarayıcı);SExpression *getAST(sabit kömür *ifade){    SExpression *ifade;    yyscan_t tarayıcı;    YY_BUFFER_STATE durum;    Eğer (yylex_init(&tarayıcı)) {        / * başlatılamadı * /        dönüş BOŞ;    }    durum = yy_scan_string(ifade, tarayıcı);    Eğer (yyparse(&ifade, tarayıcı)) {        / * ayrıştırma hatası * /        dönüş BOŞ;    }    yy_delete_buffer(durum, tarayıcı);    yylex_destroy(tarayıcı);    dönüş ifade;}int değerlendirmek(SExpression *e){    değiştirmek (e->tip) {        durum eVALUE:            dönüş e->değer;        durum ÇOKLU:            dönüş değerlendirmek(e->ayrıldı) * değerlendirmek(e->sağ);        durum eADD:            dönüş değerlendirmek(e->ayrıldı) + değerlendirmek(e->sağ);        varsayılan:            / * burada olmamalı * /            dönüş 0;    }}int ana(geçersiz){    kömür Ölçek[] = " 4 + 2*10 + 3*( 5 + 1 )";    SExpression *e = getAST(Ölçek);    int sonuç = değerlendirmek(e);    printf("% S" sonucu% d n", Ölçek, sonuç);    deleteExpression(e);    dönüş 0;}

Projeyi oluşturmak için basit bir makefile aşağıdaki gibidir.

# MakefileDOSYALAR = Lexer.c Parser.c Expression.c main.cCC = g ++CFLAGS = -g -ansiÖlçek: $(DOSYALAR)	$(CC) $(CFLAGS) $(DOSYALAR)ÖlçekLexer.c: Lexer.lflex Lexer.lAyrıştırıcı.c: Ayrıştırıcı.y Lexer.cbizon Parser.ytemiz:rm -f * .o * ~ Lexer.c Lexer.h Parser.c Parser.h Ölçek

Ayrıca bakınız

  • Berkeley Yacc (byacc) - GNU Bison ile aynı yazarı paylaşan başka bir ücretsiz Yacc değiştirme yazılımı

Referanslar

  1. ^ a b Corbett, Robert Paul (Haziran 1985). Statik Semantik ve Derleyici Hata Kurtarma (Doktora). California Üniversitesi, Berkeley. DTIC ADA611756.
  2. ^ "Bison 3.7.2 [kararlı] yayınlandı".
  3. ^ Bison Kılavuzu: Giriş.
  4. ^ Levine, John (Ağustos 2009). esnek ve bizon. O'Reilly Media. ISBN  978-0-596-15597-1.
  5. ^ "YAZARLAR". bison.git. GNU Savana. Alındı 2017-08-26.
  6. ^ Bison Kılavuzu: Saf (Yeniden Giren) Ayrıştırıcı
  7. ^ Bizon Kılavuzu: Bizon Beyanı Özeti
  8. ^ https://savannah.gnu.org/forum/forum.php?forum_id=9639 Bison 3.5 çıktı
  9. ^ Bison Kılavuzu: Bison Kullanım Koşulları
  10. ^ İstisnayı içeren bir kaynak kodu dosyası, parse-gram.c
  11. ^ "parse-gram.y". bison.git. GNU Savana. Alındı 2020-07-29.
  12. ^ GCC 3.4 Sürüm Serisi Değişiklikleri, Yeni Özellikler ve Düzeltmeler
  13. ^ GCC 4.1 Sürüm Serisi Değişiklikleri, Yeni Özellikler ve Düzeltmeler
  14. ^ Golang gramer tanımı
  15. ^ http://www.postgresql.org/docs/9.0/static/parser-stage.html
  16. ^ https://www.safaribooksonline.com/library/view/flex-bison/9780596805418/ch04.html
  17. ^ http://octave.org/doxygen/4.0/d5/d60/oct-parse_8cc_source.html
  18. ^ http://perldoc.perl.org/perl5100delta.html
  19. ^ a b Flex Manual: Bison Ayrıştırıcılı C Tarayıcılar Arşivlendi 2010-12-17'de Wayback Makinesi
  20. ^ Bison Kılavuzu: Saf Ayrıştırıcılar için Çağrı Kuralları

daha fazla okuma

Dış bağlantılar