Sarkan başka - Dangling else

Başka sarkan bir sorundur bilgisayar programlama bir isteğe bağlı bir başka şartı olan şart-(-else) iç içe Koşullamalar ifadesi sonuçları belirsiz olma. Biçimsel olarak, dilin referans bağlamdan bağımsız dilbilgisi belirsizdir , yani birden fazla doğru ayrıştırma ağacı vardır .

Birçok programlama dilinde koşullu olarak yürütülen kod iki biçimde yazılabilir: if-then formu ve if-then-else formu – else yan tümcesi isteğe bağlıdır:

if a then s
if b then s1 else s2

Bu, iç içe geçmiş ifadeler olduğunda, özellikle if-then formunun s1if-then-else formunda göründüğü zaman, yorumlamada bir belirsizliğe yol açar :

if a then if b then s else s2

Bu örnekte, doğru ve doğru solduğunda açık bir şekilde yürütülür , ancak yanlış olduğunda (böylece else'i ilk if'ye ekleyerek) veya doğru olduğunda ve yanlış olduğunda (böylece else'i ikinci if'ye bağlayarak ) yürütülüyor olarak yorumlanabilir . ). Başka bir deyişle, önceki ifade aşağıdaki ifadelerden biri olarak görülebilir: abs2aab

if a then (if b then s) else s2
if a then (if b then s else s2)

Sarkan başka sorunu ALGOL 60'a kadar uzanır ve sonraki dillerde çeşitli şekillerde çözülmüştür. In LR ayrıştırıcıları , başka sarkan bir arketip örneğidir vardiya-azaltmak çatışma .

Sözdizimini korurken belirsizlikten kaçınmak

Bu , özellikle tarayıcısız ayrıştırma olmak üzere , derleyici yapımında sıklıkla karşılaşılan bir sorundur . Sarkan başka ile uğraşırken, kural, özellikle, açık bir bağlamdan bağımsız gramerlere izin vererek, diğerini yakındaki if ifadesine eklemektir. Pascal, C ve Java gibi programlama dilleri bu kuralı takip eder, bu nedenle dilin semantiğinde herhangi bir belirsizlik yoktur , ancak ayrıştırıcı üreteci kullanımı belirsiz gramerlere yol açabilir . Bu durumlarda alternatif gruplama, Pascal ve C'deki gibi açık bloklarla gerçekleştirilir . begin...end{...}

Derleyici oluşturma yaklaşımına bağlı olarak, belirsizliği önlemek için farklı düzeltici önlemler alınabilir:

  • Ayrıştırıcı bir SLR, LR(1) veya LALR LR ayrıştırıcı üreteci tarafından üretiliyorsa , programcı genellikle bir çakışma olduğunda azaltma yerine kaydırmayı tercih eden oluşturulan ayrıştırıcı özelliğine güvenecektir. Alternatif olarak, dilbilgisi boyutunda bir artış pahasına dilbilgisi çatışmayı ortadan kaldırmak için yeniden yazılabilir (aşağıya bakın ).
  • Ayrıştırıcı elle yazılmışsa, programcı belirsiz olmayan bağlamdan bağımsız bir dilbilgisi kullanabilir. Alternatif olarak, bağlamdan bağımsız bir dilbilgisine veya ayrıştırıcı bir ifade dilbilgisine güvenilebilir .

Sözdizimini değiştirerek belirsizliği önleme

Sorun, sözdizimi içinde bir else ve onun if arasındaki bağlantıyı açık hale getirerek de çözülebilir. Bu genellikle insan hatalarından kaçınmaya yardımcı olur.

Olası çözümler şunlardır:

  • Bir "if sonu" ifadesine sahip olmak. Bu tür dillere örnek olarak ALGOL 68 , Ada , Eiffel , PL/SQL , Visual Basic ve AppleScript verilebilir .
  • Bir "then"den sonra gelen ifadenin "if" olmasına izin verilmemesi (ancak bu, yalnızca bir if-then-yan tümcesi içeren bir çift ifade parantezleri olabilir). Bu yaklaşımı ALGOL 60 takip etmektedir .
  • Bir "if"in ardından "else" geçtiğinde parantez (parantez) gerektirmesi.
  • Her "if" öğesinin bir "else" ile eşleştirilmesini gerektirir. Semantiğini ziyade sözdizimi hakkında benzer bir sorunu önlemek için, Raket sapan Planı bir dikkate alınarak ifetkin bir şartlı ayırt bir hata olması için bir geri dönüş koşulu olmadan ifadeleri (yani ifşartlı itibaren) ifadeleri (yani whenve unlessyedek maddelerini bizde olmayan).
  • Tek alternatifli ve iki alternatifli "if" ifadeleri için farklı anahtar kelimeler kullanmak. S-Algol kullanımları if e do stek alternatif durum için ve if e1 then e2 else e3genel durumu için.
  • Swift ve Modula-2 gibi koşulsuz olarak parantez gerektirmesi . Girinti kuralları yalnızca "if" ifadelerindekileri değil, her bloğu sınırladığı için Python'da bu gerçekten doğrudur . Ortaya çıkan dağınıklığı azaltmak için Modula-2 , fonksiyon dışı seviyelerde blok açıcıyı ortadan kaldırır .

Örnekler

Somut örnekler aşağıdadır.

C

In C , dilbilgisi bölümünde şunlar yazıyor:

 statement = ...
    | selection-statement

 selection-statement = ...
    | IF ( expression ) statement
    | IF ( expression ) statement ELSE statement

Böylece, başka bir kural olmaksızın, ifade

if (a) if (b) s; else s2;

belirsiz bir şekilde şundan biriymiş gibi ayrıştırılabilir:

if (a)
{
  if (b)
    s;
  else
    s2;
}

veya:

if (a)
{
  if (b)
    s;
}
else
  s2;

Uygulamada C'de ilk ağaç, elseen yakın ile ilişkilendirilerek seçilir if.

LR ayrıştırıcılarında çakışmayı önleme

Belirsizliği gidermek için yukarıdaki örnek aşağıdaki şekilde yeniden yazılabilir:

statement: open_statement
         | closed_statement
         ;

open_statement: IF '(' expression ')' statement
              | IF '(' expression ')' closed_statement ELSE open_statement
              ;

closed_statement: non_if_statement
                | IF '(' expression ')' closed_statement ELSE closed_statement
                ;

non_if_statement: ...
                ;

Doğrudan veya dolaylı olarak bir terminal ile statementveya selection-statementterminal dışı ile bitebileceklerse, deyimle ilgili diğer dilbilgisi kurallarının da bu şekilde çoğaltılması gerekebilir .

Ancak, hem if hem de while ifadelerini içeren dilbilgisi veriyoruz.

statement: open_statement
         | closed_statement
         ;

open_statement: IF '(' expression ')' statement
              | IF '(' expression ')' closed_statement ELSE open_statement
              | WHILE '(' expression ')' open_statement
              ;

closed_statement: simple_statement
                | IF '(' expression ')' closed_statement ELSE closed_statement
                | WHILE '(' expression ')' closed_statement
                ;

simple_statement: ...
                ;

Son olarak, belirsiz IF ifadelerini yasaklayan dilbilgisini veriyoruz.

statement: open_statement
         | closed_statement
         ;

open_statement: IF '(' expression ')' simple_statement
              | IF '(' expression ')' open_statement
              | IF '(' expression ')' closed_statement ELSE open_statement
              | WHILE '(' expression ')' open_statement
              ;

closed_statement: simple_statement
                | IF '(' expression ')' closed_statement ELSE closed_statement
                | WHILE '(' expression ')' closed_statement
                ;

simple_statement: ...
                ;

Bu dilbilgisi ile "if (a) if (b) c else d" ayrıştırması başarısız olur:

statement
open_statement
IF '(' expression ')' closed_statement ELSE open_statement
'if' '(' 'a' ')' closed_statement 'else' 'd'

ve ardından ayrıştırma closed_statement"if (b) c" ile eşleşmeye çalışırken başarısız oluyor . İle bir deneme closed_statementaynı şekilde başarısız olur.

Ayrıca bakınız

Referanslar