Ayrıştırma ve lexing geçişleri ayrıştırıcı birleştiricilerle iyi bir uygulama mıdır?


18

Ayrıştırıcı birleştiricileri kullanmaya başladığımda ilk tepkim ayrıştırma ve lexing arasında yapay bir ayrım gibi hissettiren bir kurtuluş hissiydi. Birdenbire her şey sadece ayrışıyordu!

Ancak, yakın zamanda codereview.stackexchange adresinde bu gönderiyle karşılaştım ve birinin bu ayrımı eski haline getirdiğini gösterdim. İlk başta bunun çok aptalca olduğunu düşündüm, ancak daha sonra Parsec'te bu davranışı destekleyecek işlevlerin var olması beni sorgulamama neden oluyor.

Ayrıştırıcı birleştiricilerde zaten lexed edilmiş bir akış üzerinden ayrıştırmanın avantajları / dezavantajları nelerdir?


Lütfen birisi [ayrıştırıcı-birleştirici] etiketi ekleyebilir mi?
Eli Frey

Yanıtlar:


15

Ayrıştırma altında, çoğunlukla bağlamdan bağımsız dillerin analizini anlıyoruz. Bağlamdan bağımsız bir dil, normal bir dilden daha güçlüdür, bu nedenle ayrıştırıcı (çoğunlukla) sözlük çözümleyicisinin işini hemen yapabilir.

Ancak, bu a) oldukça doğal olmayan b) genellikle verimsizdir.

Düşünmem bile), nasıl bir örnek için ifIF ifade görünüyor, sanırım İfade SONRA İfade BAŞKA İfade ve 'i' 'f', belki bazı alanlarda, daha sonra herhangi bir karakter bir ifade ile başlayabilir, vb olsun fikir.

B) tanımlayıcılar, değişmez değerler, her türlü parantez, vb. Gibi sözcüksel varlıkları tanıyan mükemmel bir iş yapan güçlü araçlar vardır. Onlar neredeyse hiçbir zaman işlerini yapacaklar ve size güzel bir arayüz verecekler: jeton listesi. Ayrıştırıcıdaki boşlukları atlamaktan endişe etmeyin, ayrıştırıcı karakterlerle değil belirteçlerle uğraşırken çok daha soyut olacak.

Sonuçta, bir ayrıştırıcının düşük seviyeli şeylerle meşgul olması gerektiğini düşünüyorsanız, neden karakterleri işleyesiniz? Biri de bit düzeyinde yazabilir! Görüyorsunuz, bit düzeyinde çalışan böyle bir ayrıştırıcı neredeyse anlaşılmaz olacaktır. Karakterler ve jetonlarla aynıdır.

Sadece 2 sentim.


3
Sadece doğruluk uğruna: bir çözümleyici her zaman sözlüksel bir analizörün işini yapabilir.
Giorgio

Ayrıca, verimlilikle ilgili olarak: Bir ayrıştırıcının daha az verimli (yavaş) olacağından emin değilim. Ortaya çıkan dilbilgisinin normal bir dili tanımlayan bir alt dilbilgisi içermesini ve bu alt dilbilgisinin kodunun karşılık gelen bir sözcük analizcisi kadar hızlı olmasını beklerdim. IMO asıl mesele (a): daha basit, daha soyut bir ayrıştırıcı ile çalışmak ne kadar doğal, sezgisel.
Giorgio

@Giorgio - İlk yorumunuzla ilgili olarak: Haklısınız. Burada aklımda olan şey, lexerin pragmatik olarak dilbilgisini kolaylaştıran bazı çalışmaları yaptığı, böylece bir kişinin LALR (2) yerine LALR (1) kullanabileceği durumlardır.
Ingo

2
Daha fazla deney ve düşünmeden sonra cevabınızı kabul ettiğimi kaldırdım. İkinizin Antlr ve diğerlerinin yon dünyasından geldiğini gösterir. Ayrıştırıcı birleştiricilerinin birinci sınıf doğası göz önüne alındığında, genellikle belirteç ayrıştırıcılar için bir ayırıcı ayrıştırıcı tanımlamakla bitiriyorum. örneğin, if örneğiniz şöyle görünür if = string "if" >> expr >> string "then" >> expr >> string "else" >> expr.
Eli Frey

1
Performans hala açık bir soru, bazı kriterler yapacağım.
Eli Frey

8

Lexing ve ayrıştırma işlemlerini ayırmanın "iyi bir uygulama" olduğunu - herkes katılmıyorum - tek bir geçişte lexing ve ayrıştırma gerçekleştirmenin çok daha fazla güç verdiğini ve performans sonuçlarının sunulduğu kadar kötü olmadığını öne süren herkes diğer cevaplar (bakınız Packrat ).

Bu yaklaşım, tek bir giriş akışında birkaç farklı dili karıştırmak gerektiğinde parlar. Bu sadece Katahdin ve benzerleri gibi garip meta programlamaya yönelik diller için değil, okuryazar programlama (lateks karıştırma ve örneğin C ++), yorumlarda HTML kullanma, Javascript'i HTML'ye doldurma ve yakında.


Cevabımda bunun "bazı bağlamlarda iyi bir uygulama" olduğunu ve "tüm bağlamlarda daha iyi bir uygulama" olduğunu söylemedim.
Giorgio

5

Sözlüksel analizör normal bir dili ve ayrıştırıcı bağlamsız bir dili tanır. Her normal dil aynı zamanda bağlamdan bağımsız olduğu için ( sağ doğrusal bir dilbilgisi ile tanımlanabilir ), bir ayrıştırıcı da normal bir dili tanıyabilir ve ayrıştırıcı ve sözcük analizörü arasındaki ayrım bazı gereksiz karmaşıklıklar ekler gibi görünür: tek bir bağlam -ücretsiz dilbilgisi (ayrıştırıcı) bir ayrıştırıcı ve sözlük çözümleyicisinin işini yapabilir.

Öte yandan, bağlamsız bir dilin bazı öğelerini normal bir dil (ve dolayısıyla sözlüksel bir analizör) aracılığıyla yakalamak yararlı olabilir.

  1. Genellikle bu öğeler, standart bir şekilde ele alınabilecek kadar sık ​​görülür: sayı ve dizi değişmezlerini, anahtar kelimeleri, tanımlayıcıları, beyaz alanı atlamak vb.
  2. Normal bir jeton dili tanımlamak, sonuçtaki bağlamsız dilbilgisini daha basit hale getirir, örneğin, tek tek karakterler açısından değil, tanımlayıcılar açısından bir neden olabilir veya kişi, belirli bir dil için ilgili değilse beyaz alanı tamamen yok sayabilir.

Dolayısıyla ayrışmayı sözcüksel çözümlemeden ayırmanın avantajı, daha basit bir bağlamsız dilbilgisi ile çalışabilmeniz ve sözcüksel analizörde (divide et impera) bazı temel (genellikle rutin) görevleri özetleyebilmenizdir.

DÜZENLE

Ayrıştırıcı birleştiricilere aşina değilim, bu yüzden yukarıdaki hususların bu bağlamda nasıl uygulandığından emin değilim. Benim izlenimim, ayrıştırıcı birleştiricilerde, yalnızca bir bağlamsız dilbilgisi olsa bile, iki düzey arasında ayrım yapmak (sözcüksel analiz / ayrıştırma) bu dilbilgisini daha modüler hale getirmeye yardımcı olabilir. Daha önce belirtildiği gibi, alt sözlük analizi katmanı, tanımlayıcılar, değişmez değerler, vb. İçin temel yeniden kullanılabilir ayrıştırıcılar içerebilir.


2
Lexemes doğal olarak değil, kural olarak düzenli gramerlere düşer, çünkü tüm lexers düzenli ifade motorları üzerine inşa edilmiştir. Tasarlayabileceğiniz dillerin ifade gücünü sınırlar.
SK-logic

1
Normal dil olarak tanımlanamayan sözcükleri tanımlamanın uygun olacağı bir dil örneği verebilir misiniz?
Giorgio

1
örneğin, oluşturduğum alana özgü birkaç dilde, tanımlayıcılar TeX ifadeleri olabilir, bu da kodun güzel yazdırılmasını basitleştirmiştir, örneğin \alpha'_1 (K_0, \vec{T})\ alpha'_1, K_0 ve \ vec {T} gibi bir ifade tanımlayıcılardır.
SK-logic

1
Bağlamdan bağımsız bir dilbilgisi göz önüne alındığında, her zaman terminal olmayan bir N alabilir ve türetebileceği kelimeleri, kendileri için yararlı bir anlama sahip birimler (örneğin bir ifade, bir terim, bir sayı, bir ifade) olarak ele alabilirsiniz. Bu, birimi nasıl ayrıştırdığınızdan bağımsız olarak yapılabilir (ayrıştırıcı, ayrıştırıcı + sözlük, vb.). IMO bir ayrıştırıcı + lexer seçimi semantik olandan (ayrıştırdığınız kaynak kodu bloklarının anlamı nedir) daha teknik bir çözümdür (ayrıştırma nasıl uygulanır). Belki bir şeye bakmıyorum ama iki yönü bana dik görünüyor.
Giorgio

3
Bu yüzden size katılıyorum: bazı keyfi temel yapı taşları ( lexemes ) tanımlarsanız ve bunları tanımak için sözlüksel bir analizör kullanmak isterseniz, bu her zaman mümkün değildir. Sadece bunun bir lexer hedefi olup olmadığını merak ediyorum. Anladığım kadarıyla, sözlüksel bir analizcinin amacı daha teknik bir sorundur: ayrıştırıcıdan bazı düşük seviyeli, sıkıcı uygulama ayrıntılarını almak.
Giorgio

3

Basitçe, lexing ve ayrıştırma birbirinden ayrılmalıdır çünkü bunlar farklı karmaşıklıklardır. Lexing bir DFA'dır (deterministik sonlu otomat) ve ayrıştırıcı bir PDA'dır (aşağı itilen otomat). Bu, ayrıştırmanın doğal olarak lexing'den daha fazla kaynak tükettiği ve yalnızca DFA'lar için belirli optimizasyon teknikleri olduğu anlamına gelir. Ayrıca, sonlu durumlu bir makine yazmak çok daha az karmaşıktır ve otomatikleştirilmesi daha kolaydır.

Lex'e bir ayrıştırma algoritması kullanarak israf edersiniz.


Sözcük analizi yapmak için bir ayrıştırıcı kullanırsanız, PDA yığını asla kullanmaz, temelde bir DFA olarak çalışır: sadece girdi tüketmek ve durumlar arasında atlamak. % 100 emin değilim, ama bir DFA uygulanabilecek optimizasyon teknikleri (devlet sayısını azaltmak) da bir PDA uygulanabilir bence. Ancak evet: daha güçlü bir araç kullanmadan sözcüksel analizörü yazmak ve daha sonra üzerine daha basit bir ayrıştırıcı yazmak daha kolaydır.
Giorgio

Ayrıca, her şeyi daha esnek ve bakım yapılabilir hale getirir. Örneğin, düzen kuralı olmadan (yani noktalı virgül ve kaşlı ayraçlar) Haskell dili için bir ayrıştırıcımız olduğunu varsayalım. Ayrı bir lexer'ımız varsa, artık jetonları başka bir geçiş yaparak, gerektiğinde parantez ve noktalı virgül ekleyerek düzen kurallarını ekleyebiliriz. Veya daha kolay bir örnek için: yalnızca tanımlayıcılarda ASCII karakterlerini destekleyen bir dille başladığımızı ve şimdi tanımlayıcılarda unicode harfleri desteklemek istediğimizi varsayalım.
Ingo

1
@Ingo, neden ayrı bir lexer ile yapman gerekiyor? Sadece bu terminalleri hesaba katın.
SK-logic

1
@ SK-logic: Sorunuzu anladığımdan emin değilim. Neden ayrı bir lexer iyi bir seçim olabilir benim yazımda doğrulamaya çalıştım.
Ingo

Giorgio, hayır. Yığın, normal LALR tarzı ayrıştırıcının önemli bir bileşenidir. Bir ayrıştırıcı ile lexing yapmak korkunç bir bellek kaybıdır (hem statik depolama hem de dinamik olarak tahsis edilir) ve çok daha yavaş olacaktır. Lexer / Parser modeli verimli - kullanın :)
riwalk

1

Ayrı ayrıştırma / lex'un ana avantajlarından biri ara gösterimdir - belirteç akışı. Bu, birleşik bir lex / ayrıştırma ile mümkün olmayacak çeşitli şekillerde işlenebilir.

Bununla birlikte, iyi 'özyinelemeli terbiyenin daha az karmaşık ve bazı ayrıştırıcı jeneratörünü öğrenmeye karşı çalışmanın daha kolay olabileceğini ve ayrıştırıcı jeneratörünün kuralları içinde dilbilgisinin zayıflığının nasıl ifade edileceğini bulmam gerektiğini buldum.


Ayrıştırma zamanında gerçekleştirilen, önceden hazırlanmış bir akışta daha kolay ifade edilen dilbilgileri hakkında daha fazla bilgi verebilir misiniz? Sadece oyuncak dilleri ve çok az veri formatı uygulama deneyimim var, bu yüzden belki bir şey kaçırdım. Elle haddelenmiş RD ayrıştırıcı / lex kombinasyonlarınızla BNF beslemeli (varsayıyorum) jeneratörler arasında herhangi bir performans özelliği fark ettiniz mi?
Eli Frey
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.