Hangi süreçte sözdizimi hatası oluşuyor? (tokenizing veya ayrıştırma)


23

Derleme ve yorumlamayı anlamaya çalışıyorum, adım adım toplam bir görüntü bulmaya çalışıyorum. Bu yüzden http://www.cs.man.ac.uk/~pjj/farrell/comp3.html bu makaleyi okurken bir soru sordum.

Diyor ki :

Derleyicinin bir sonraki aşamasına Ayrıştırıcı denir. Derleyicinin bu kısmı dilin gramerini anlıyor. Sözdizimi hatalarının tanımlanmasından ve hatasız bir programın başka bir dilde yorumlanabilen veya yazılabilen iç veri yapılarına dönüştürülmesinden sorumludur.

Ancak, belirtecin sözdizimi hatası olan verilen akışı nasıl düzgün şekilde belirleyebildiğini bulamadım.

Orada sıkışmış olmalı veya ayrıştırıcıya bazı yanlış bilgiler vermelidir. Demek istediğim, belirteci bir tür tercüman değil mi?

Öyleyse, tokenize ederken sözcüksel bozuk kod satırlarının üstesinden nasıl geldi?

Tokenizer başlığında , yukarıdaki linkin içinde bir token örneği var .

Anladığım kadarıyla belirteci şeklinde görünüyor, kodunda yanlış bir şey varsa belirteci de bozuk olurdu.

Yanlış anlaşılmamı netleştirir misin?

Yanıtlar:


32

Bir belirteç, yalnızca bir ayrıştırıcı optimizasyonu. Bir belirteç olmadan bir ayrıştırıcı uygulamak tamamen mümkün.

Bir belirteç (veya lexer veya tarayıcı) girişi bir belirteç listesine kılar. Dizenin bazı bölümleri (yorumlar, boşluklar) genellikle dikkate alınmaz. Her belirtecin bir türü (dilde bu dizgenin anlamı) ve bir değeri (belirteci oluşturan dize) vardır. Örneğin, PHP kaynak snippet'i

$a + $b

belirteçleri tarafından temsil edilebilir

Variable('$a'),
Plus('+'),
Variable('$b')

Belirteç bu bağlamda bir belirtecin mümkün olup olmadığını düşünmez. Örneğin, giriş

$a $b + +

mutlulukla token akışını üretecekti

Variable('$a'),
Variable('$b'),
Plus('+'),
Plus('+')

Ayrıştırıcı daha sonra bu belirteçleri kullandığında, iki değişkenin birbirini takip edemediğini ve iki infix operatörünün de olmadığını fark edecektir. (Diğer dillerin, böyle bir belirteç akışının yasal olabileceği, ancak PHP'de bulunmadığı farklı sözdizimlerine sahip olduğunu unutmayın).

Bir ayrıştırıcı belirteç aşamasında hala başarısız olabilir. Örneğin, geçersiz bir karakter olabilir:

$a × ½ — 3

Bir PHP belirteç bu girişi kurallarıyla eşleştiremez ve ana ayrıştırma başlamadan önce bir hata oluşturur.

Daha resmi olarak belirteçler, her belirteç düzenli bir dil olarak tanımlanabildiği zaman kullanılır . Jetonlar daha sonra oldukça verimli bir şekilde eşleştirilebilir, muhtemelen bir DFA olarak uygulanabilir. Buna karşılık, ana dilbilgisi genellikle bağlamsızdır ve LALR gibi daha karmaşık, daha az performanslı bir ayrıştırma algoritması gerektirir.


Bu nedenle, ayrıştırıcının bir parçası olarak belirteci düşünebiliriz ve sözdizimi hatası, sözdizimi hatası formuna göre, belirtici adım veya ayrıştırma adımı oluşabilir. Açıklama için teşekkürler.
FZE

4
@FZE: Sen olabilir bu şekilde düşünmek, ancak yanıltıcı oluyor. Lexing "sadece bir ayrıştırıcı optimizasyonu" değildir. Aksine, lexing, fiziksel bir gösterimi (bazı karakter dizileri) mantıksal bir gösterime (bu karakterlerin temsil ettiği belirteçlere) eşler. Bu, ayrıştırıcıyı bir satırın sonunun nasıl temsil edileceği veya bir mantıksal ve and/ &&veya başka bir şeyi temsil etmeye karar verip vermediğiniz gibi Minutia'dan izole eder . Ayrılıktan ayrı (ayrı) ve farklı. Optimizasyon (eğer varsa) neredeyse tesadüfi bir yan etkidir.
Jerry Coffin

@JerryCoffin şimdi daha anlamlı hale getirdiği daha fazla açıklama için teşekkür ederiz.
FZE

2
@ JerryCoffin, amon doğrudur ki fark temel değildir. Hem "lexer" hem de "parser" bölümlerini kapsayan yapışkan bir BNF dilbilgisi oluşturabilirsiniz. Kuralları genellikle düşük seviyeye (örneğin, sayı, toplama operatörü) ve yüksek seviyeye (toplama) göre sınıflandırırız, ancak gramerin kendisi böyle bir ayrım yapmaz.
Paul Draper

1
@PaulDraper Düzenli bir dili ilk aşama olarak ayırmanın doğru seçenek olup olmadığından emin değilsiniz. Örneğin, eşleştirilmiş çiftler (normal değil) bazı dillerdeki dize değişmezlerini tanımlamak için gerekli olabilir, ancak yine de ilk aşamada bunları ele almak mantıklı. Geri izlemeyi önlemek / en aza indirgemek daha iyi bir rehber gibi görünmektedir.
CodesInChaos

16

Sen ediyorum genellikle çoğu sözdizimi hataları ayrıştırıcı değil lexer gelmesini bekleyebilirsiniz.

Sözcü, girdide belirtilemeyen bir şey varsa (ve çoğunlukla da) bir hata oluşturur. Bununla birlikte, birçok dilde, hemen hemen her karakter dizisi bir tür belirteçlere dönüştürülebilir, bu nedenle buradaki hatalar oldukça nadirdir.

Girdi geçerli belirteçler içeriyorsa ayrıştırıcı bir hata üretecektir, ancak bu belirteçler düzenlenmez, böylece hedef dilde geçerli ifadeler / ifadeler oluştururlar. Bu kural olarak çok daha yaygındır.


11

Tokenizer sadece karakter akışını belirteçlere böler. Tokenizer POV'dan bu tamamen geçerlidir:

1 * * 1

ve şöyle bir şeye çevirir: ["1", MULTIPLY, MULTIPLY, "1"] Yalnızca ayrıştırıcı bu tür ifadeleri reddedebilir - çarpma operatörünün başka bir çarpma operatörünü takip edemeyeceğini bilir. Örneğin, JavaScript’te bu:

Uncaught SyntaxError: Unexpected token *(…)

Tokenleyici tarafından algılanabilecek hatalar var. Örneğin bitmemiş dize hazır: "abcveya geçersiz numaraları: 0x0abcdefg. Yine de, sözdizimi hataları olarak rapor edilebilirler:

Uncaught SyntaxError: Unexpected token ILLEGAL

Ancak belirteç tanınmadı ve olarak bildirildi ILLEGAL.

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.