Sadece sorunu belirtmek için, Sarkan Else Sorunu, kod sözdizimi belirtiminde, belirsiz olabilen ifex ve els durumlarında belirsiz olabileceği bir belirsizliktir.
En basit ve klasik örnek:
if(conditionA)
if(conditionB)
doFoo();
else
doBar();
Bu ezbere dil şartname, özelliklerini bilmiyorum olanlara, belli değil if
alır else
(ve bu özel kod parçacığı yarım düzine dilde geçerlidir, ancak her farklı performans gösterebilir).
Sarkan Else yapısı, tarayıcısız ayrıştırıcı uygulamaları için potansiyel bir sorun oluşturur, çünkü strateji, ayrıştırıcı tokenleştirmeye (derleme veya ara dilde derleme veya ara dilde özetleme) sahip olduğunu görene kadar her seferinde dosya akışını birer birer artırmaktır. . Bu, ayrıştırıcının minimum durumu korumasını sağlar; dosyaya ayrıştırıldığı jetonları yazmak için yeterli bilgiye sahip olduğunu düşündüğü anda bunu yapar. Bu, tarayıcısız bir ayrıştırıcının son hedefi; hızlı, basit, hafif derleme.
Noktalama işaretlerinden önce veya sonra yeni satırların ve boşlukların anlamsız olduğu varsayılarak (çoğu C stili dilinde olduğu gibi), bu ifade derleyiciye şu şekilde görünür:
if(conditionA)if(conditionB)doFoo();else doBar;
Bir bilgisayara mükemmel şekilde ayrıştırılabilir, bu yüzden görelim. Ben sahip olana kadar bir kerede bir karakter alıyorum:
if(conditionA)
Oh, bunun ne anlama geldiğini biliyorum (C # 'da), " push
eval yığını üzerine conditionA anlamına gelir ve daha brfalse
sonra doğru değilse sonraki noktalı virgülden sonra ifadeye atlamaya çağırın ". Şu anda noktalı virgül görmüyorum, bu yüzden şimdilik bu talimattan sonra atlama uzaklığımı bir sonraki boşluğa ayarlayacağım ve noktalı virgül görene kadar daha fazla talimat ekledikçe bu ofseti artıracağım. Ayrıştırma devam ediyor ...
if(conditionB)
Tamam, bu benzer bir çift IL operasyonuna ayrılır ve az önce ayrıştırdığım talimattan hemen sonra gider. Noktalı virgül görmüyorum, bu yüzden önceki komutumun atlama ofsetini iki komutumun uzunluğuna (itme için ve diğeri mola için) kadar artıracağım ve aramaya devam edeceğim.
doFoo();
Tamam, bu kolay. Bu " call
doFoo". Ve bu gördüğüm noktalı virgül mü? Bu harika, çizginin sonu. Her iki bloğumun atlama ofsetlerini bu iki komutun uzunluğuna göre artıracağım ve umursadığımı unutacağım. Tamam, devam ediyorum ...
else
... Ah-oh. Göründüğü kadar basit değil. Tamam, sadece ne yaptığımı unuttum, ama bir else
şey zaten gördüğüm bir yerde koşullu bir mola ifadesi var, bu yüzden geri bakmama izin ver ... evet, işte, brfalse
bazı "conditionB" yığın, her neyse. Tamam, şimdi bir break
sonraki ifade olarak koşulsuz ihtiyacım var . Bundan sonra gelecek olan ifade şimdi kesinlikle şartlı molamın hedefi, bu yüzden doğru yaptığımdan emin olacağım ve koyduğum koşulsuz molayı artıracağım. Devam ediyorum ...
doBar();
Bu kolay. " call
doBar". Noktalı virgül var ve hiç diş teli görmedim. Yani, koşulsuz break
ne olursa olsun bir sonraki ifadeye atlamalı ve umursadığımı unutabilirim.
Peki, elimizde ne var ... (not: 10:00 PM ve bit ofsetlerini onaltılık biçime dönüştürmek veya bir fonksiyonun tüm IL kabuğunu bu komutlarla doldurmak gibi hissetmiyorum, bu yüzden bu sadece sahte IL normalde bayt uzaklığı olabilecek satır numaralarını kullanarak):
ldarg.1 //conditionA
brfalse <line 6> //jumps to "break"
ldarg.2 //conditionB
brfalse <line 7> //jumps to "call doBar"
call doFoo
break <line 8> //jumps beyond statement in scope
call doBar
<line 8 is here>
Aslında, bu doğru bir şekilde çalışır, EĞER kural (çoğu C tarzı dilde olduğu gibi) else
en yakın olan gider if
. Yürütme iç içe geçmesini izlemeye yöneliktir, conditionA yanlışsa snippet'in geri kalanının tamamı atlanır:
if(conditionA)
if(conditionB)
doFoo();
else
doBar();
Dış bağlantılı mola çünkü ... ama, Serendipity tarafından yapar if
ifadesine atlar break
sonunda deyimi iç if
tüm deyimi ötesinde yürütme işaretçi alır. Bu, gereksiz bir atlamadır ve bu örnek daha karmaşık olsaydı, bu şekilde ayrıştırılır ve belirtilirse artık çalışmayabilir.
Ayrıca, dil belirtimi sallantýdabir bu ne dese else
ilk aittir if
ve rahatsızlığı sonra yanlışsa rahatsızlığı doğrudur ancak conditionB sonra hiçbir şey aynen böyle olur iken Dobar, yürütülür?
if(conditionA)
if(conditionB)
doFoo();
else
doBar();
Ayrıştırıcı, ilk if
var olanı unutmuştu ve bu nedenle bu basit ayrıştırıcı algoritması, verimli kodun hiçbir şeyi söylemek için doğru kodu üretmeyecekti.
Şimdi, ayrıştırıcı daha uzun bir süre boyunca sahip olduğu if
s ve else
s'leri hatırlayacak kadar akıllı olabilir , ancak dil özelliği else
iki if
s'nin birinciyle eşleşmesinden sonra bir tane söylerse if
, bu if
s ile eşleşen else
s ile ilgili bir soruna neden olur :
if(conditionA)
if(conditionB)
doFoo();
else
doBar();
else
doBaz();
Ayrıştırıcı birinciyi, birinciyle else
eşleşir if
, sonra ikincisini görür ve "tekrar ne yapıyordum" kipine girer. Bu noktada, ayrıştırıcının değişken bir durumda oldukça fazla kod var ve zaten zaten çıkış filestreamine itmeyi tercih ediyordu.
Tüm bu sorunlara ve ne olur? Ancak, akıllı olması için ayrıştırıcı algoritmasının karmaşıklığını arttırması için gereken kod veya ayrıştırıcının bu aptal olmasına izin veren dil spesifikasyonu, gibi sonlandırma ifadeleri gerektirerek, dil kaynağı kodunun ayrıntı düzeyini artırır end if
veya iç içe gösteren parantezler if
ifadenin else
(her ikisi de diğer dil stillerinde yaygın olarak görülen) olup olmadığını engeller .
Bu, birkaç if
ifadenin sadece basit bir örneğidir ve derleyicinin vermesi gereken tüm kararlara ve nerede kolayca dağılabileceğine bakın. Sorunuzdaki Wikipedia'dan gelen bu zararsız ifadenin arkasındaki ayrıntı budur.