LR, SLR ve LALR ayrıştırıcıları arasındaki fark nedir?


103

LR, SLR ve LALR ayrıştırıcıları arasındaki gerçek fark nedir? SLR ve LALR'nin LR ayrıştırıcı türleri olduğunu biliyorum, ancak ayrıştırma tabloları söz konusu olduğunda gerçek fark nedir?

Ve bir dilbilgisinin LR, SLR veya LALR olup olmadığı nasıl gösterilir? Bir LL dilbilgisi için, ayrıştırma tablosunun herhangi bir hücresinin birden fazla üretim kuralı içermemesi gerektiğini göstermemiz yeterlidir. LALR, SLR ve LR için benzer kurallar var mı?

Örneğin, dilbilgisinin

S --> Aa | bAc | dc | bda
A --> d

LALR (1), SLR (1) değil mi?


DÜZENLE (ybungalobill) : LALR ve LR arasındaki farkın ne olduğuna dair tatmin edici bir yanıt alamadım. Dolayısıyla, LALR tablolarının boyutu daha küçüktür ancak yalnızca LR gramerlerinin bir alt kümesini tanıyabilir. Birisi LALR ve LR arasındaki fark hakkında daha fazla bilgi verebilir mi lütfen? LALR (1) ve LR (1) bir cevap için yeterli olacaktır. Her ikisi de 1 jeton ön izleme kullanıyor ve her ikisi de masaya dayanıyor! Nasıl farklılar?


bu konuda doğru bir cevap arıyor olsam bile, LALR (1), bellek kullanımını en aza indirebilmemiz için masa boyutunun küçültüldüğü LR (1) 'in küçük bir modifikasyonudur ...
vikkyhacks

Yanıtlar:


64

SLR, LALR ve LR ayrıştırıcılarının tümü, tamamen aynı masa tabanlı makine kullanılarak uygulanabilir.

Temel olarak, ayrıştırma algoritması bir sonraki giriş belirteci T'yi toplar ve ne yapılacağına karar vermek için mevcut durum S'ye (ve ilişkili önden, GOTO ve azaltma tablolarına) danışır:

  • SHIFT: Mevcut tablo T belirteci üzerinde SHIFT diyorsa, çift (S, T) ayrıştırma yığınına itilir, durum GOTO tablosunun geçerli simge için söylediğine göre değiştirilir (örneğin, GOTO (T) ), başka bir giriş belirteci T 'getirilir ve işlem tekrar eder
  • AZALT: Her eyalette 0, 1 veya eyalette meydana gelebilecek birçok olası azaltma vardır. Ayrıştırıcı LR veya LALR ise, belirteç, durum için tüm geçerli azaltmalar için önden okuma kümelerine göre kontrol edilir. Belirteç, dilbilgisi kuralı G = R1 R2 .. Rn için bir azaltma için önden okuma kümesiyle eşleşirse, bir yığın azaltma ve kaydırma gerçekleşir: G için anlamsal eylem çağrılır, yığın n (Rn'den) kez atılır, çift ( S, G) yığın üzerine itilir, yeni S 'durumu GOTO (G)' ye ayarlanır ve döngü aynı token T ile tekrarlanır. Ayrıştırıcı bir SLR ayrıştırıcısı ise, için en fazla bir azaltma kuralı vardır. durum ve böylece indirgeme eylemi, hangi indirimin geçerli olduğunu görmek için arama yapmadan körü körüne yapılabilir. Orada olmadığını bilmek bir SLR ayrıştırıcı için yararlıdır olduğunubir azalma ya da değil; bu, her devletin kendisiyle ilişkili azaltma sayısını açıkça kaydettiğini ve pratikte L (AL) R versiyonları için bu sayının gerekli olup olmadığını anlamak kolaydır.
  • HATA: SHIFT veya REDUCE mümkün değilse, sözdizimi hatası bildirilir.

Öyleyse, hepsi aynı makineyi kullanıyorlarsa, ne anlamı var?

SLR'de sözde değer, uygulamadaki basitliğidir; Önden okuma setlerini kontrol ederek olası azaltmaları taramanıza gerek yoktur çünkü en fazla bir tane vardır ve bu durumdan SHIFT çıkışı yoksa tek uygulanabilir eylemdir. Hangi indirgemenin geçerli olduğu duruma özel olarak bağlanabilir, bu nedenle SLR ayrıştırma makinesinin bunun peşine düşmesi gerekmez. Uygulamada, L (AL) R ayrıştırıcıları, yararlı bir şekilde daha büyük bir dil kümesini idare eder ve uygulamak için çok az fazladan iştir ki, akademik bir alıştırma dışında hiç kimse SLR'yi uygulamaz.

LALR ve LR arasındaki fark tablosu ile ilgisi var jeneratör. LR ayrıştırıcı üreteçleri, belirli durumlardan olası tüm azaltmaları ve bunların hassas önden okuma setini takip eder; her indirgemenin, sol bağlamından yola çıkarak tam önden ayarlıyla ilişkili olduğu durumlar elde edersiniz. Bu, oldukça büyük devlet kümeleri oluşturma eğilimindedir. LALR ayrıştırıcı üreteçleri, GOTO tabloları ve indirgeme için bakma kafası kümeleri uyumluysa ve çakışmıyorsa durumları birleştirmeye isteklidir; bu, LR'nin ayırt edebileceği belirli sembol dizilerini ayırt edememe pahasına, önemli ölçüde daha az sayıda durum üretir. Bu nedenle, LR ayrıştırıcıları, LALR ayrıştırıcılarından daha büyük bir dil kümesini ayrıştırabilir, ancak çok daha büyük ayrıştırıcı tablolarına sahiptir. Uygulamada, durum makinesinin boyutunun optimize edilmeye değer olduğu hedef dillere yeterince yakın olan LALR gramerleri bulunabilir;

Yani: Üçü de aynı makineyi kullanıyor. SLR, makinenin küçük bir parçasını görmezden gelebileceğiniz anlamında "kolay" dır, ancak bu zahmete değmez. LR daha geniş bir dil kümesini ayrıştırır, ancak durum tabloları oldukça büyük olma eğilimindedir. Bu, LALR'ı pratik bir seçim olarak bırakır.

Tüm bunları söyledikten sonra, GLR ayrıştırıcılarının herhangi bir bağlamdan bağımsız dili, daha karmaşık makineler kullanarak, ancak tam olarak aynı tabloları (LALR tarafından kullanılan daha küçük sürüm dahil) ayrıştırabileceğini bilmeye değer . Bu, GLR'nin LR, LALR ve SLR'den kesinlikle daha güçlü olduğu anlamına gelir; hemen hemen standart bir BNF dilbilgisi yazabilirseniz, GLR buna göre ayrıştırır. Mekanizmadaki fark, GLR'nin GOTO tablosu ve / veya önden okuma setleri arasında çelişkiler olduğunda birden fazla ayrıştırmayı denemeye istekli olmasıdır. (GLR'nin bunu nasıl verimli bir şekilde yaptığı, katıksız bir dahidir [benim değil] ama bu SO gönderisine uymuyor).

Bu benim için son derece yararlı bir gerçek. Program çözümleyicileri oluşturuyorum ve kod dönüştürücüleri ve ayrıştırıcılar gerekli ama "ilginç değil"; ilginç çalışma, ayrıştırılmış sonuçla yaptığınız şeydir ve bu nedenle odak, ayrıştırma sonrası çalışmayı yapmaktır. GLR kullanmak, LALR kullanılabilir forma girmek için bir grameri hacklemeye kıyasla nispeten daha kolay çalışan gramerler oluşturabileceğim anlamına geliyor. Bu, C ++ veya Fortran gibi akademik olmayan dillerle uğraşmaya çalışırken çok önemlidir; burada kelimenin tam anlamıyla tüm dili iyi idare etmek için binlerce kurala ihtiyaç duyarsınız ve hayatınızı dilbilgisi kurallarını kırmaya çalışmakla geçirmek istemezsiniz. LALR (veya hatta LR) sınırlamalarını karşılar.

Ünlü bir örnek olarak, LALR ayrıştırması yapan adamlar tarafından C ++ 'nın ayrıştırılması son derece zor kabul edilir. C ++, C ++ referans kılavuzunun arkasında sağlanan kuralları hemen hemen kullanarak GLR makinelerini kullanarak ayrıştırmak için basittir. (Kesinlikle böyle bir ayrıştırıcım var ve sadece vanilya C ++ 'yı değil aynı zamanda çeşitli satıcı lehçelerini de işliyor. Bu sadece pratikte mümkün çünkü bir GLR ayrıştırıcı, IMHO kullanıyoruz).

[DÜZENLEME Kasım 2011: Ayrıştırıcımızı tüm C ++ 11'i işleyecek şekilde genişlettik. GLR bunu çok daha kolay hale getirdi. Ağustos 2014'ü DÜZENLE: Artık tüm C ++ 17'yi işliyor. Hiçbir şey kırılmadı ya da kötüleşmedi, GLR hala kedinin miyavı.]


AFAIK C ++, sonsuz ileriye bakılması gerektiğinden LR ile ayrıştırılamaz. Bu yüzden onu LR ile ayrıştırmayı mümkün kılacak herhangi bir hile düşünemiyorum. Ayrıca LRE ayrıştırıcıları umut verici görünüyor.
Yakov Galka

5
GCC, Bison == LALR kullanarak C ++ 'yı ayrıştırmak için kullanılır. Size gönül yarası veren durumları (ileriye dönük, is-this-a-typename) ele almak için her zaman ayrıştırıcınızı ekstra yapışkan ile artırabilirsiniz. Soru "Bilgisayar korsanlığı ne kadar acı verici?" GCC için oldukça acı vericiydi ama işe yaradı. Bu, bunun tavsiye edildiği anlamına gelmez, bu da GLR'yi kullanmakla ilgili noktam.
Ira Baxter

GLR kullanmanın C ++ konusunda size nasıl yardımcı olduğunu anlamıyorum. Bir şeyin tür adı olup olmadığını bilmiyorsanız, o zaman nasıl ayrıştıracağınızı bilmiyorsunuz x * y;- GLR kullanmak buna nasıl yardımcı olur?
user541686

2
Buradaki nokta, GLR ayrıştırıcısının her iki ayrıştırmayı da üreteceğidir (entegre bir ayrıştırma "ağacı" içinde (gerçekten DAG) "belirsiz alt ağaç (lar)" olarak. Tutmak istediğiniz alt ağaçlardan hangisini daha sonra diğerlerini getirerek çözebilirsiniz. C ++ çözümleyicimiz bu konuyla ilgili oldukça basittir: problemi çözmeye çalışmaz . Bu, sembol tablosu yapısını ayrıştırmayla karıştırmamıza gerek olmadığı anlamına gelir, yani hem ayrıştırıcımız hem de C ++ için sembol tablosu yapısı bireysel temiz ve sonuç çok her inşa etmek ve korumak.
Ira Baxter

18

LALR ayrıştırıcıları, genellikle saf LR ayrıştırma tablolarından daha küçük bir büyüklük sırası olan eşdeğer SLR dilbilgisi ile tam olarak aynı boyutta ayrıştırıcı durum tabloları oluşturmak için bir LR dilbilgisi içinde benzer durumları birleştirir. Bununla birlikte, LALR olamayacak kadar karmaşık olan LR gramerleri için, bu birleştirilmiş durumlar ayrıştırıcı çakışmalarına neden olur veya orijinal LR dilbilgisini tam olarak tanımayan bir ayrıştırıcı üretir.

BTW, benim MLR (k) ayrıştırma tablo algoritmasında bu konuda birkaç şey söz burada .

Ek

Kısa cevap, LALR ayrıştırma tablolarının daha küçük olması, ancak ayrıştırıcı mekanizmasının aynı olmasıdır. Verilen bir LALR dilbilgisi, tüm LR durumları çok sayıda fazlalık (neredeyse özdeş) durumla üretilirse çok daha büyük ayrıştırma tabloları üretir.

LALR tabloları daha küçüktür çünkü benzer (fazlalık) durumlar bir araya getirilir ve ayrı durumların kodladığı bağlam / önden okuma bilgisini etkili bir şekilde atar. Bunun avantajı, aynı dilbilgisi için çok daha küçük ayrıştırma tabloları almanızdır.

Bunun dezavantajı, tüm LR gramerlerinin LALR tabloları olarak kodlanamamasıdır, çünkü daha karmaşık gramerler daha karmaşık bakış açılarına sahiptir, bu da tek bir birleştirilmiş durum yerine iki veya daha fazla durumla sonuçlanır.

Temel fark, LR tablolarını üreten algoritmanın, durumdan duruma geçişler arasında daha fazla bilgi taşıması, ancak LALR algoritmasının taşımamasıdır. Bu nedenle, LALR algoritması, belirli bir birleştirilmiş durumun gerçekten iki veya daha fazla ayrı durum olarak bırakılması gerektiğini söyleyemez.


3
+1 Honalee fikrini beğendim. G / L (AL) R ayrıştırıcı oluşturucumda buna benzer bir şeyin tohumları vardı; minimal LALR makinesini üretir ve sonra çatışmaların olduğu eyaletleri bölecektim, ama asla üstesinden gelmedim. Bu, ayrıştırma tabloları kümesi gibi minimum boyutlu "LR" oluşturmanın güzel bir yolu gibi görünüyor. Ne ayrıştırabildiği açısından GLR'ye yardımcı olmayacak olsa da, GLR'nin taşıması gereken paralel çözümleme sayısını azaltabilir ve bu yararlı olabilir.
Ira Baxter

12

Yine başka bir cevap (YAA).

SLR (1), LALR (1) ve LR (1) için ayrıştırma algoritmaları Ira Baxter'ın dediği gibi aynıdır,
ancak ayrıştırıcı tabloları ayrıştırıcı oluşturma algoritması nedeniyle farklı olabilir.

Bir SLR ayrıştırıcı oluşturucu, bir LR (0) durum makinesi oluşturur ve dilbilgisinden (İLK ve İZLEME kümeleri) ileri bakışları hesaplar. Bu basitleştirilmiş bir yaklaşımdır ve LR (0) durum makinesinde gerçekten var olmayan çakışmaları rapor edebilir.

Bir LALR ayrıştırıcı üreteci, bir LR (0) durum makinesi oluşturur ve LR (0) durum makinesinden (terminal geçişleri aracılığıyla) önden bakmaları hesaplar. Bu doğru bir yaklaşımdır, ancak bazen bir LR (1) durum makinesinde bulunmayan çakışmaları bildirir.

Kanonik bir LR ayrıştırıcı oluşturucu, bir LR (1) durum makinesini hesaplar ve önden görünen başlıklar zaten LR (1) durum makinesinin bir parçasıdır. Bu ayrıştırıcı tabloları çok büyük olabilir.

Bir Minimal LR ayrıştırıcı üreteci, bir LR (1) durum makinesini hesaplar, ancak işlem sırasında uyumlu durumları birleştirir ve ardından, minimal LR (1) durum makinesinden önden bakma işlemlerini hesaplar. Bu ayrıştırıcı tabloları, en iyi çözümü veren LALR ayrıştırıcı tablolarıyla aynı boyutta veya biraz daha büyüktür.

LRSTAR 10.0 , dilbilginiz için ne gerekiyorsa, C ++ 'da LALR (1), LR (1), CLR (1) veya LR (*) ayrıştırıcıları oluşturabilir. LR ayrıştırıcıları arasındaki farkı gösteren bu şemaya bakın.

[Tam açıklama: LRSTAR benim ürünüm]


5

Önden bakmayan bir ayrıştırıcının dilbilginiz için dizeleri mutlu bir şekilde ayrıştırdığını varsayalım.

Verdiğiniz örneği kullanarak bir dizgeyle karşılaşır dc, ne yapar? O düşürün mu S, çünkü dcbu dilbilgisi tarafından üretilen geçerli bir dizedir? VEYA belki de bdcbu kabul edilebilir bir dize olduğu için ayrıştırmaya çalışıyorduk ?

İnsanlar, cevabın basit olduğunu bildiğimiz için, sadece ayrıştırıp ayrıştırmadığımızı hatırlamamız gerekiyor b. Ama bilgisayarlar aptaldır :)

Bir SLR (1) ayrıştırıcısı, bir önden okuma gerçekleştirmek için LR (0) üzerinde ek güce sahip olduğundan, herhangi bir miktarda önden okumanın bize bu durumda ne yapacağımızı söyleyemeyeceğini biliyoruz; bunun yerine geçmişimize bakmalıyız. Böylece kanonik LR ayrıştırıcısı kurtarmaya gelir. Geçmiş bağlamı hatırlar.

Bu bağlamı hatırlama şekli, kendisini disipline etmesidir, ne zaman bir a ile karşılaşsa , tek olasılık olarak bokumaya giden yolda yürümeye başlar bdc. Yani bir gördüğünde d, zaten bir yolda yürüdüğünü bilir. Böylece, bir CLR (1) ayrıştırıcısı, bir SLR (1) ayrıştırıcısının yapamayacağı şeyleri yapabilir!

Ama şimdi, çok fazla yol tanımlamak zorunda olduğumuz için, makinenin durumları çok büyüyor!

Böylece aynı görünümlü yolları birleştiriyoruz, ancak beklendiği gibi kafa karışıklığı sorunlarına yol açabilir. Bununla birlikte, boyutu küçültme pahasına risk almaya hazırız.

Bu sizin LALR (1) ayrıştırıcınızdır.


Şimdi algoritmik olarak nasıl yapılacağı.

Yukarıdaki dil için yapılandırma setlerini çizdiğinizde, iki durumda bir kaydırma-azaltma çakışması göreceksiniz. Bunları kaldırmak için, bir takipçiye bakarak kararlar alan bir SLR (1) düşünebilirsiniz, ancak yine de bunu yapamayacağını göreceksiniz. Bu nedenle, konfigürasyon setlerini yeniden çizersiniz, ancak bu sefer bir kısıtlama ile, kapanışı her hesapladığınızda, eklenen ek yapımların sıkı takip (ler) i olması gerekir. Bunların ne olması gerektiği konusunda herhangi bir ders kitabına bakın.


Bu doğru değil

4

SLR ile LR ile oluşturulan ayrıştırıcı tabloları arasındaki temel fark, azaltma eylemlerinin SLR tabloları için İzleme setine dayanmasıdır. Bu aşırı derecede kısıtlayıcı olabilir ve sonuçta vardiya-azalt çatışmasına neden olabilir.

Öte yandan, bir LR ayrıştırıcısı, yalnızca indirgenmekte olan terminal olmayanları gerçekten takip edebilen terminaller kümesindeki kararları azaltır. Bu uçbirim kümesi, genellikle böyle bir uçbirim olmayanın Takipler kümesinin uygun bir alt kümesidir ve bu nedenle vardiya eylemleriyle daha az çelişme şansı vardır.

LR ayrıştırıcıları bu nedenle daha güçlüdür. Bununla birlikte, LR ayrıştırma tabloları çok büyük olabilir.

Bir LALR ayrıştırıcısı, bir LR ayrıştırma tablosu oluşturma fikri ile başlar, ancak oluşturulan durumları önemli ölçüde daha az tablo boyutu sağlayacak şekilde birleştirir. Dezavantajı, bazı gramerler için bir LR tablosunun aksi takdirde kaçınacağı küçük bir çatışma şansı ortaya çıkacak olmasıdır.

LALR ayrıştırıcıları, LR ayrıştırıcılarından biraz daha az güçlüdür, ancak yine de SLR ayrıştırıcılarından daha güçlüdür. YACC ve diğer bu tür ayrıştırıcı oluşturucular, bu nedenle LALR kullanma eğilimindedir.

PS Kısalık açısından, yukarıdaki SLR, LALR ve LR gerçekten SLR (1), LALR (1) ve LR (1) anlamına gelir, bu nedenle bir jeton önden okuma ima edilir.


4

SLR ayrıştırıcıları, LALR (1) ayrıştırıcıları tarafından tanınabilen uygun bir gramer alt kümesini tanır ve bu da LR (1) ayrıştırıcıları tarafından tanınabilen uygun bir gramer alt kümesini tanır.

Bunların her biri bir durum makinesi olarak inşa edilmiştir, her durum girdiyi ayrıştırırken gramer üretim kurallarının (ve her birinin içindeki konumu) bazılarını temsil eder.

Ejderha Kitap SLR olmayan bir LALR (1) gramer örneği şudur:

S → L = R | R
L → * R | id
R → L

İşte bu dilbilgisinin durumlarından biri:

S → L•= R
R → L•

Olası üretim her ayrıştırıcı konumunu göstermektedir. Sonuna gelene kadar aslında hangi yapımların içinde olduğunu bilmez ve azaltmaya çalışır.

Burada, ayrıştırıcı ya kaydırabilir =ya da azaltabilir R → L.

Bir SLR (aka LR (0)) çözümleyici sonraki girdi sembolü ise o denetleyerek azaltıp azaltmadığını belirlemek olacaktır takip setinin içinde R(yani takip edebilir dilbilgisi tüm terminallerin kümesi R). =Bu kümede de olduğu için, SLR ayrıştırıcısı bir kaydırma-azaltma çakışmasıyla karşılaşır.

Bununla birlikte, bir LALR (1) ayrıştırıcısı, bu belirli R üretimini takip edebilen tüm terminaller kümesini kullanır ki bu sadece $(yani, girişin sonu). Böylece çatışma yok.

Önceki yorumcuların belirttiği gibi, LALR (1) ayrıştırıcıları SLR ayrıştırıcıları ile aynı sayıda duruma sahiptir. Önden okuma yayılım algoritması, karşılık gelen LR (1) durumlarından SLR durumu üretimlerine önden giden aramaları takip etmek için kullanılır. Sonuçta ortaya çıkan LALR (1) ayrıştırıcısı, LR (1) ayrıştırıcısında bulunmayan azalt-azalt çakışmalarını ortaya çıkarabilir, ancak kaydırma-azaltma çakışmalarını ortaya koyamaz.

Örnekte , aşağıdaki LALR (1) devlet SLR uygulanmasında bir kayma-azaltmak çakışmaya neden:

S → b d•a / $
A → d• / c

Sonraki sembol /, LALR (1) ayrıştırıcısındaki her üretim için aşağıdaki kümedir. SLR'de, aynı zamanda kaydırılabilen follow ( A) içerir a.


2

Yukarıdaki yanıtlara ek olarak, bu şema farklı ayrıştırıcıların birbiriyle nasıl ilişkili olduğunu gösterir:

görüntü açıklamasını buraya girin


-2

Basit bir cevap, tüm LR (1) gramerlerinin LALR (1) gramerleri olduğudur. LALR (1) ile karşılaştırıldığında, LR (1) ilişkili sonlu durum makinesinde daha fazla duruma sahiptir (durumların iki katından fazla). LALR (1) gramerlerinin sözdizimi hatalarını tespit etmek için LR (1) gramerlerinden daha fazla koda ihtiyaç duymasının ana nedeni budur. Ve bu iki gramerle ilgili bilinmesi gereken bir diğer önemli şey, LR (1) gramerlerinde çatışmaları daha az azaltabilir / azaltabiliriz. Ancak LALR'de (1) çatışmaları azaltma / azaltma olasılığı daha yüksektir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.