Garip Lexical Syntax yapıları
(justine.lol)- llamafile için yeni bir sözdizimi vurgulayıcı oluşturmak üzere 42 dili ele alınca, basit leksing işlemlerinde bile dillere özgü istisnalar ve eski gramerlerin sıkça gizlendiği ortaya çıktı
- Gerçekleme, anahtar sözcük aramasını hızlandırmak için C++ ve GNU gperf kullanıyor; string, yorum ve anahtar sözcük odaklı işleme ise
fordöngüsü veswitchtabanlı sonlu durum makinesiyle çözülüyor - C'nin trigraph'ları, JavaScript'in
u2028veu2029satır sonlandırıcıları, Shell·Perl·Ruby'nin heredoc'u, Kotlin·Scala·TypeScript·Swift'in string interpolasyonu, yalnızca leksingle ele alınması zor örnekler olarak tekrar tekrar öne çıkıyor - Kod satırı sayısına göre FORTH 125 satır, Ruby ise 1042 satıra kadar çıkıyor; Ruby'de
<<operatörü, heredoc ve backquote çakıştığı için parse etmeden vurgulama özellikle zor - llamafile'ın yeni vurgulayıcısı Windows 10'da Meta LLaMA 3.2 3B Instruct ile gösterildi; macOS, Linux, FreeBSD ve NetBSD'de de çalışabiliyor, bu da onu sözdizimi vurgulaması olmayan ollama'dan ayırıyor
llamafile vurgulayıcısını yapma motivasyonu
- llamafile için yeni bir sözdizimi vurgulayıcı oluşturmak amacıyla bir ay boyunca 42 programlama dili incelendi
- Desteklenenler: Ada, Assembly, BASIC, C, C#, C++, COBOL, CSS, D, FORTH, FORTRAN, Go, Haskell, HTML, Java, JavaScript, Julia, JSON, Kotlin, ld, LISP, Lua, m4, Make, Markdown, MATLAB, Pascal, Perl, PHP, Python, R, Ruby, Rust, Scala, Shell, SQL, Swift, Tcl, TeX, TXT, TypeScript, Zig
- Bu liste TIOBE Index'in büyük kısmını kapsıyor; ancak Scratch metin yerine blok kullandığı için vurgulama kapsamına alınmadı
Gerçekleme yöntemi: gperf ve sonlu durum makinesi
- Temel bir sözdizimi vurgulayıcıda en büyük darboğaz, bir token'ın anahtar sözcük olup olmadığını belirlerken yinelenen string karşılaştırmalarının artması
- C++ ve GNU gperf kullanılarak mükemmel bir hash tablosu üretildi
- Örnek
gperfgirdisi,true,false,nullgibi Java sabitlerini anahtar sözcük olarak tanımlıyor gperftarafından üretilen C dosyası, çakışmasız arama için yalnızca tek bir karakteri dikkate alan bir hash fonksiyonu oluşturabiliyor
- Örnek
- C vurgulaması, yaklaşık 4.000 anahtar sözcük tanımlansa bile gperf sayesinde 35 MB/s hızında çalışabiliyor
- Kalan işlemlerin çoğu için sonlu durum makinesi yeterli oluyor
flex,bison,ragelolmadan, yalnızcafordöngüsü veswitchile temel bir vurgulayıcı yapılabiliyor- String'lere, yorumlara ve anahtar sözcüklere odaklanınca işin çoğu leksing düzeyinde çözülebiliyor
- C fonksiyon adları gibi öğeleri de vurgulamak istenirse gerçek parse gerekebilir
- highlight_ada.cpp örnek gerçekleme olarak kullanılıyor
llamafile demosu ve çalışma ortamı
- Yeni vurgulayıcı ve chatbot arayüzü, llamafile'ın kullanılabilirliğini artırdı; ollama'da olmayan sözdizimi vurgulaması ayırt edici bir özellik oldu
- Demo, Windows 10'da Meta LLaMA 3.2 3B Instruct modeliyle çalıştırıldı
- Bu llamafile, macOS, Linux, FreeBSD ve NetBSD'de de çalışabiliyor
- gemma 27b it gibi açık ağırlıklı modellerin kalitesi arttıkça Claude kullanma motivasyonu azalıyor
C: Basit bir dil izleniminden farklı leksing istisnaları
- C, basit olduğu yönündeki izlenime rağmen leksik öğeler açısından oldukça sıra dışı
- trigraph,
#,[,\\,^,{,|,},~gibi karakterleri??=,??(,??/,??),??',??<,??!,??>,??-ile değiştirebiliyor- C23 standardından çıkarıldı, ancak eski yazılımlar nedeniyle derleyiciler bunu desteklemeyi sürdürecek gibi görünüyor
- İyi bir sözdizimi vurgulayıcı bu grameri de işlemeli
- C'nin universal character yapısı,
int \\uFEB2 = 1;örneğinde olduğu gibi ASCII kaynak kod içinde Unicode tanımlayıcılar yazılmasına izin veriyor- GCC, standart komitesinin izin verdiği belirli Unicode plane'ler dışında hata veriyor
- C'de tek satırlık yorumlar, satır sonundaki ters eğik çizgi kullanılırsa birden fazla satıra yayılabiliyor
- Perl, Ruby, Shell gibi kaynak kodda backslash escape destekleyen diller bile bu C tarzı davranışı desteklemiyor
- Tcl ve GNU Make'in bu davranışı desteklediği anlaşılıyor
- Emacs ve Pygments bunu zaman zaman yanlış işlerken, Vim'in backslash işlemesini sürekli doğru yaptığı görülüyor
- C'de bir de null preprocessor directive var
- İlk dönem v6 kaynak kodundaki
.cdosyaları sık sık tek satırlık#ile başlıyor - Bu bugün de geçerli bir kod ve
cc -C -Eile yorumların korunması istense bile önişlemcinin belirli yorumları kaldırmasını sağlamak için kullanılabiliyor
- İlk dönem v6 kaynak kodundaki
Yorum sözdizimi: Haskell ve D
- C'de çok satırlı yorumların içine yeniden çok satırlı yorum yerleştirilemez
- Haskell,
{- ... {- ... -} ... -}biçiminde iç içe yorumları destekliyor - D, C'nin
//,/* ... */yorumlarını aynen alırken ek olarak/+ ... +/biçiminde özyinelemeli yorum sözdizimi getiriyor - D'nin leksik gramer dokümanı biçimsel ve ayrıntılı; gerçekleme için gerekli bilgileri iyi sağlıyor
- D lexical syntax document, hex string ve heredoc string gibi ayrıntıları ele alıyor
- D'de
"...", backtick string,r"...",q"...",x"..."gibi çeşitli string biçimleri var
Tcl ve JavaScript: tırnak işaretleri ve görünmez satır sonlandırıcılar
- Tcl'de tanımlayıcıların içinde tırnak işareti bulunabiliyor
puts a"b,a"bçıktısını verir- Değişken adlarına da tırnak konabilir, ancak başvururken
$a"byerine${a"b}yazımı kullanılmalı
- JavaScript, regular expression için yerleşik bir leksik gramer içeriyor
/[/]/görneğinde karakter kümesi köşeli parantezleri içindeki/için escape gerekmiyor- Sadece kapanış slash'ını tarayan yaklaşım, minified kodda yanlış sonuç verebilir
- ECMAScript,
u2028LINE SEPARATOR veu2029PARAGRAPH SEPARATOR karakterlerini satır sonlandırıcı olarak tanımlıyor- Bu karakterler fiilen
\ngibi davranıyor - Trojan Source karakterleri oldukları için Emacs'te sırasıyla
↵,¶olarak görünecek şekilde ayarlanmış - Birçok yazılım bu karakterleri tanımıyor ve soru işareti olarak render edebiliyor
- D dışında bunu yapan başka bir dil bilinmediği belirtiliyor
- Bu karakterler fiilen
- Bu özellik sayesinde SectorLISP içinde C ve JavaScript polyglot oluşturmak mümkün oldu
- lisp.js tarayıcıda çalışıyor, GCC ile derlenip yerelde de çalıştırılabiliyor
- llamafile bu tür kodları doğru vurguluyor; diğer vurgulayıcılarda ise aynı davranışın bulunamadığı söyleniyor
Shell ve heredoc'un köşe durumları
- Shell'de heredoc,
cat <<EOF ... EOFbiçiminde çok satırlı string yazmak için kullanılıyor - Tırnaklı heredoc sözdizimi
cat <<'END', değişken ikamesini devre dışı bırakıyor - heredoc işaretleyicisi boş string yapılırsa heredoc bir sonraki boş satırda biter
- Örnek program,
helloveworldçıktısını iki satır halinde veriyor
- Örnek program,
- Shell, Ruby ve Perl gibi heredoc destekleyen dillerde aynı satırda birden fazla heredoc bulunabiliyor
- Shell'de Tcl'deki gibi
#her zaman yorum başlatmıyor${x#hi-}içinde#, öneki kaldırmak için kullanılıyor; örnekthereçıktısını veriyor
String interpolasyonu: durum yığını gerektiren diller
- Kotlin string'leri
"ile başlasa bile string interpolasyonu nedeniyle{noktasında başka bir duruma geçebiliyor - TypeScript, Swift, Kotlin ve Scala; string içinde gerçek kod gömmeyi hedefleyen güçlü string interpolasyonu desteği sunuyor
- Kotlin, Scala ve TypeScript'i vurgulamak için süslü parantezlerin sayılması ve bir parser durum yığını tutulması gerekiyor
- TypeScript nispeten daha basit; sonlu durum makinesine birkaç ek durum eklemek yetiyor
- Kotlin ve Scala, hem çift tırnak hem de üçlü tırnak sözdiziminde interpolasyonu desteklediğinden yalnızca string leksingi için yaklaşık 13 bağımsız durum gerekti
- Swift,
"\\(var)"interpolasyon sözdizimini ve üçlü tırnağı destekliyor; gerçekleme ise 10 durum gerektirdi
Swift, C#, FORTH: string'i çevreleme biçimlerindeki farklar
- Swift,
"...","""...""",/regex/string'lerini istenen sayıda#ile sarmalama sözdizimini destekliyor- İki taraftaki
#sayısı eşleşmeli - Bu yöntem, string içinde tırnak ya da regex sınırı bulundurma sorununu çözüyor
- İki taraftaki
- C#, Python'un üçlü tırnaklı çok satırlı string'ine benziyor, ancak başlangıç ve bitişte daha fazla sayıda tırnağın eşleştirilmesine izin veriyor
- Soldaki tırnak sayısı sağdaki kapanış koşulunu belirliyor
- Rastgele sayıda tırnak kabul etmenin, klasik Python üçlü tırnağına göre geçerlilik kurallarını azaltıp sonlu durum makinesiyle daha basit çözümleme sağladığı düşünülüyor
- FORTH, her şeyi boşluk sınırlarına göre token'laştırıyor
- String başlatma sözdizimi
c"de tek bir token c" hello world", diğer dillerdeki"hello world"ile aynı anlama geliyor
- String başlatma sözdizimi
FORTRAN ve COBOL: sabit sütun kuralları
- llamafile, FORTRAN ve COBOL programcıları emekli olduktan sonra bile banka sistemlerinin bakımına yardımcı olabilecek bir kullanım senaryosu olarak sunuluyor
- Air-gapped ortamlarda kontrol edilebilir bir yapay zeka olan Gemma 27b'den COBOL ve FORTRAN kodu istenebileceği belirtiliyor
- FORTRAN'ın sabit sütun kuralları şöyle
-
- sütunda
*,c,Cvarsa satır yorum sayılıyor
- sütunda
-
- sütunda boşluk dışı bir karakter varsa 80 karakteri aşan satır devam ettirilebiliyor
- 1–5. sütunlarda sayı varsa bu bir etiket oluyor
-
- COBOL kuralları ise şöyle
-
- sütunda
*varsa yorum
- sütunda
-
- sütunda
-varsa 80 karakteri aşan satırın devamı
- sütunda
- 1–6. sütunlar satır numarasını içeriyor
-
Zig ve Lua: çok satırlı string'e farklı çözümler
- Zig, iki ters eğik çizgiyle başlayan bir çok satırlı string sözdizimine sahip
- Bu sözdizimi, Python üçlü tırnaklı string'lerde
textwrap.dedent()çağırma ihtiyacını ortadan kaldırıyor - Dezavantaj olarak noktalı virgülün hoş görünmediği düşünülüyor
- Go, Scala, Python gibi noktalı virgül gerektirmeyen diller için değerlendirilebilecek bir string sözdizimi önerisi olarak sunuluyor
- Bu sözdizimi, Python üçlü tırnaklı string'lerde
- Lua'nın çok satırlı string'i
[[...]]tabanlı ve köşeli parantezler arasına istenen sayıda=konabiliyor[==[ ... ]==]biçiminde başlangıç ve bitişteki=sayısı eşleştiriliyor- Aynı yöntem yorumlar için de kullanılabiliyor
- Hem
--[[ ... ]]hem de--[==[ ... ]==]biçimleri mümkün
Assembly: lehçeler ve önişlemcilerin birleşimi
- Assembly, çok sayıda lehçeye ayrıldığı için vurgulaması zor dillerden biri
- llamafile, AT&T, nasm ve benzeri çeşitli sözdizimlerini makul biçimde işlemeyi hedefliyor
- Anahtar sözcüklerin, satırdaki ilk tanımlayıcı olup iki nokta üst üste sonrasında gelmeyen öğeler olarak ele alınması çoğu assembly kodunu yeterince düzgün gösteriyor
- Yorum sözdizimi de basit değil
- Orijinal UNIX yorumları için yalnızca tek bir
/yeterliydi - GNU as bunu hâlâ yalnızca satır başı konumunda destekliyor
- Clang fixed comment'i desteklemediği için açık kaynak kodda pratik kullanımı zor deniyor
- Orijinal UNIX yorumları için yalnızca tek bir
- Orijinal UNIX assembler, karakter sabitlerinde kapanış tırnağı kullanmıyordu
'x,xkarakterinin0x78değerini ifade ediyor- GNU as bunu hâlâ destekliyor, LLVM ise desteklemiyor
- Eski kodlarda bu sözdizimi bulunduğundan iyi bir vurgulayıcı bunu da desteklemeli
- GNU assembler, alıntılanmış tanımlayıcılara izin verdiği için sembollerde neredeyse her karakter kullanılabiliyor
- Assembly sıklıkla C önişlemcisi ya da m4 ile birlikte kullanılıyor
dnl,m4_dnl,Cile başlayan satırların da yorum olarak ele alınması gerekiyor
Ada ve BASIC: küçük gramer farklarının leksingi sarsması
- Ada'nın leksingi oldukça basit, ancak tek tırnak kullanımı sıra dışı
- C'deki gibi
'x'karakter sabitleri bulunabiliyor Foo'Sizeörneğinde olduğu gibi özellik başvurularında da tek tırnak kullanılıyorCharacter'(')')'Image, bir karakter tanımlayıp ardındanImagefonksiyonuyla string gösterimine dönüştürüyor
- C'deki gibi
- Commodore BASIC örneği, sözdizimi vurgulamasına dair birçok varsayımı bozuyor
- String'lerde satır sonunda kapanış tırnağı atlanabiliyor
- Değişken adlarında
$gibi sigil'ler bulunuyor gotogibi anahtar sözcükler tanımlayıcıların içinde bile agresif biçimde leksing ediliyor
- Visual BASIC'te
#1/1/2024#gibi bir tarih sabiti sözdizimi var - Visual BASIC'te ayrıca
#If DEBUG Then,#Else,#End Ifgibi önişlemci yönergeleri de bulunduğundan leksing zorlaşıyor
Perl: Shell ile programlama dili arasındaki karmaşıklık
- Perl, Shell ile programlama dili arasında konumlandığı için iki tarafın karmaşıklığını da miras alıyor
- Regular expression'ı dilin birinci sınıf unsuru haline getirdi ve bunun etkisi Python gibi diğer dillere de yayıldı
- Perl'in değiştirme sözdizimi
s/hello/Perl/i, sed'e benziyor/yerine herhangi bir noktalama işareti ayraç olarak kullanılabiliyors!hello!Perl!i, slash regex içinde yer aldığında kullanışlıs{hello}{Perl}igibi eşleşen karakterler kullanıldığında ek karakter gerekebiliyor
- Perl'de string gibi vurgulanması gereken çok sayıda sihirli önek bulunuyor
m,s,y,qr,qw,qq,qxçeşitli ayraçlarla birlikte kullanılıyor
y/x/y/ifadesini yanlışlıkla bölme işlemi saymamak için bağlamı görmek gerekiyor- Perl değişkenleri skaler
$, dizi@, hash%gibi sigil'ler taşıdığı için tüm gramer parse edilmeden de ayrım yapmaya yardımcı oluyor
- Perl değişkenleri skaler
- Perl'de kaynak kod içine man page için POD belgeleri gömme geleneği var
- Satır başındaki
=wordPOD belgesini başlatıyor,=cutise bitiriyor
- Satır başındaki
Ruby: en zor leksing hedefi
- Ruby, önceki dillerin birleşimi gibi görünüyor ve gramerinin biçimsel olarak yeterince belgelenmediği düşünülüyor
- Ruby kılavuzundaki syntax document, ayrıntı bakımından hafif bulunuyor
- Ruby, backquote sözdizimini desteklerken aynı zamanda backquote'u yöntem adı gibi kullanabildiğinden, vurgulayıcının bunun string olup olmadığını ayırt etmesi zorlaşıyor
- Ruby'de hem
<<operatörü hem de heredoc var- Gerçek kodda
options[:includes] <<arg; truegibi biçimler bulunuyor - Bu, heredoc gibi görünebilir ve Emacs de bunu yanlış işliyor
- Gerçek kodda
puts "This is #{<<HERE.strip} evil"gibi string interpolasyonu içinde heredoc barındıran kodlar da geçerli- 42 dil arasında Ruby en büyük şok olarak anılıyor; Ruby'nin parse etmeden leksinginin mümkün olmayabileceği, parse edilse bile yorumlanabilirliğinden emin olunamayacağı düşünülüyor
Gerçekleme kod satırı sayısına göre karmaşıklık
- Her dil vurgulayıcısının gerçekleme kod satırı sayısı baz alındığında en basit dil FORTH, en karmaşığı Ruby
- En kısa gerçekleme highlight_forth.cpp ile 125 satır
- Görece kısa gerçeklemeler arasında m4 132 satır, Ada 149 satır, LISP 160 satır, MATLAB 166 satır, COBOL 186 satır, BASIC 199 satır, FORTRAN 200 satır yer alıyor
- Orta ölçekli gerçeklemeler arasında JavaScript 337 satır, TypeScript 371 satır, Kotlin 387 satır, Scala 387 satır, Assembly 447 satır, C 449 satır, Swift 455 satır, D 521 satır bulunuyor
- En uzun gerçeklemeler Shell 570 satır, Perl 583 satır ve highlight_ruby.cpp 1042 satır
1 yorum
Hacker News görüşleri
C üçlü karakter dizileri (trigraph) içinde en sevdiğim şey,
do_action() ??!??! handle_error()gibi bir biçimÖzel bir hata işleme söz dizimi gibi görünüyor ama aslında
??!??!,||mantıksal OR'a dönüşüyor ve kısa devre değerlendirme kuralı sayesindedo_action()sıfır olmayan bir değer döndürdüğündehandle_error()çalıştırılıyor; bu da hoşuma gidiyor??!,|karakterine dönüştüğü için??!??!de||, yani “or” oluyor||yerine eski tip C üçlü karakter dizileri mi seçilmiş?Keyifle okudum ama bu beni daha çok Lisp bakış açısına yaklaştırdı
Anladığım kadarıyla burada söylenen, söz diziminin bir dilde o kadar da önemli olmadığı, yardımcı olmaktan çok engel olmaya yatkın olduğu ve bu yüzden başka şeylere odaklanabilmek için olabildiğince basit ve tekdüze olması gerektiği
Yine de Lisp'te yapısal düzenlemeyi öğrenmek şu ana kadar yardım olmaktan çok engel gibi geldi; belki bir gün karşılığını verir
Lisp'teki gibi fazla basitleştirince söz dizimi tartışması sadece anlambilim meselesine ötelenmiş oluyor; yani sadece katman değişiyor
Karmaşık söz diziminin, karmaşık anlambilime sahip basit söz diziminden çok daha okunur ve yazılır olduğunu düşünüyorum. Söz dizimi hataları hızlı geri bildirim verirken anlambilim hataları çalıştırma anına kadar gizli kalabiliyor
Mesela https://pyret.org/ gibi örnekler var. Bu yüzden Lisp'in gerçekten basit ya da zorunlu olarak tekdüze olduğunu söylemek zor
parinferkullanmak ve sadeceslurp,barf,raiseadlı üç komutun tuş kısayollarını öğrenmekYalnızca bu dördüyle bile paredit'in avantajlarının yaklaşık %95'inden, karmaşıklık olmadan yararlanabilirsiniz; geri kalan incelikleri ise alıştıktan sonra öğrenebilirsiniz
Yazıda “kim C'yi saniyede 35MB hızla sözdizimi vurgulamak ister bilmiyorum ama artık mümkün” deniyordu; hızlı olduğu doğru ama
tcc, çok eski bilgisayarlarda bile C'yi saniyede 29MB ikili koda derliyor: https://bellard.org/tcc/#speedDaha da hızlı yapılabilir belki ama muhtemelen gerek yok
Yazarın gözden kaçırdığı birkaç nokta var
Yalnızca TypeScript, Swift, Kotlin ve Scala, string interpolation içine gerçek kod koyma uç noktasına gitmiş değil; C#, Python, JavaScript, Ruby, Shell ve Make de benzer destek sunuyor
Tcl'de kod ile veri arasındaki ayrım belirsiz olduğu için
{ }aslında alışılmadık bir string sınırlayıcısı gibi davranıyor vexyzzy {#hello world}içindeki#hello worldifadesinin yorum mu yoksa string mi olduğu, değerlendirme anından önce bilinemezPostgreSQL'de kullanışlı bir dollar-quoted string yapısı var; https://www.postgresql.org/docs/current/sql-syntax-lexical.h... örneğinde olduğu gibi
'Dianne''s horse',$$Dianne's horse$$,$SomeTag$Dianne's horse$SomeTag$aynı anlama geliyor"I have $foo $bar's: @{[$bar x $foo]}"gibi bir string,I have 5 x's: xxxxxçıktısını üretebilir@{[...]}söz dizimi, Perl'in yalnızca skaler değil dizi interpolasyonu da yapabilmesinden yararlanıyor; içteki[...]bir dizi referansı oluşturuyor, dıştaki@{...}ise bunun referansını çözüyor. Perl yorumlayıcısı, iç taraftaki ifadede keyfi koda izin veriyorBöyle düşününce
"foo { toUpper("bar { x + y } bar") } foo"gibi iç içe kullanım mümkün oluyor ve+string birleştirme ise bu, özünde"foo " + toUpper("bar " + (x + y) + " bar") + " foo"ile aynı şey oluyorGerçekte böyle çalışan bir dil var mı bilmiyorum
Ruby'yi seviyorum ama string interpolation ile heredoc'u karıştıran
puts "This is #{<gibi geçerli Ruby kodlarını savunmak zorAyrıca Ruby'de boşluk da bir alıntılama karakteri olabilir. Sol işlenenin olmadığı bağlamlarda
%bir quoted string başlatır ve sonraki karakter alıntılama türünü belirler; bu yüzden% hello,helloiçeren bir string olur.%(this is a string)ya da%{this is a string}güzel ama boşluk kullanımıyla vahşi doğada hiç karşılaşmadım,irbbile bunu düzgün işleyemiyor, kaldırılsa iyi olurduval s"${a} + ${b}" = "1 + 2"yazarsanıza,1;bise2olurEskiden sıcak döngüler içinde
log.trace($"Entering iteration {i} for customer {c.ID} [{c.ShortName}]");gibi kodlar, logger gerçekten çıkış vermese bile her seferindestring.Concatçağırdığı için pek çok logger kendi interpolation mekanizmasını uyguluyorduC#'ta
DefaultInterpolatedStringHandlerya da özel handler desenini alan overload'lar tanımlanabiliyor; bu overload'lar öncelikli seçiliyor, böylece gerçekten log yazılması gerekip gerekmediği önce kontrol edilip string oluşturma geciktirilebiliyorBurada değinilmeyen, çoğu sözdizimi vurgulayıcıyı bozan bir başka dilbilgisi tuhaflığı daha var
Java'da Unicode escape dizileri yalnızca string içinde değil, her yerde gelebilir
Örneğin
class Foo\u007b}geçerli bir sınıftır ve//yorumunun içindeki\u000Agerçek bir satır sonu olarak işlenebildiği içinassertörneği de beklendiği gibi çalışmazUnicode escape kullanarak blok yorumu kapatabildiğiniz için, Java kaynak dosyasındaki yorumların içine kötü amaçlı kod saklamak istiyorsanız yorum içinde Unicode escape bloğu bulunması için sadece makul bir bahane üretmeniz yeterli olur
Bu özelliği bilmeyen geliştiriciler bunun yorum satırı olduğunu düşünüp kolayca gözden kaçırabilir
“Ruby, sözdizimini anlama girişimlerinin hepsinden kaçan bir dil” deniyor ama rastgele yeniden programlanabilen bir lexere sahip TeX açısından bakınca bu sevimli kalıyor
“Her C programcısı çok satırlı yorumların içine çok satırlı yorum konulamayacağını bilir” deniyor ama Standard ML programcıları için bu beklenmedik bir kısıt olabilir
(* (* Nested (**) *) comment *)gibi iç içe yorumlar geçerlidir ve ardından gelenval _ = print "hello, world\n"da normal şekilde çalışırC'nin ortaya çıktığında ifade gücü yüksek bir dil sayıldığını düşününce, iç içe yorumların dile dahil edilmemiş olması ilginç
ML'de tek satırlık yorum da yoktu; bu da benzer ölçüde şaşırtıcı bir kısıt. C'yi “ifade gücü yüksek” diye anmaksa ilk kez duyduğum bir şey ama 1972'de assembly ile karşılaştırılınca öyle görünmüş olabilir
Bir de yorum sözdiziminin dilin ifade gücüyle ne ilgisi var bilmiyorum; tanım gereği hiçbir ilgisi olmadığını düşünürüm
Geleneksel olarak sözcüksel analiz, regex benzeri sonlu durum otomatlarının kullanıldığı bir alan sayıldığı için, böyle bir özellik lexing kapsamının dışında görülüyordu
#if 0kullanarak yorumları iç içe geçirmenin bir yolu var#if 0 ... #if 0 ... #endif ... #endifşeklinde sarabilirsinizjoe'nun sözdizimi vurgulama uygulamasını yeniden kullanılabilir bir biçimde görmek isterdim
https://joe-editor.sf.net/ biçimi, Python f-string'lerini düzgün vurgulayabilecek kadar güçlü
İlgili belgeler ve örnekler https://github.com/cmur2/joe-syntax/blob/joe-4.4/misc/HowItW..., https://gist.github.com/irdc/6188f11b1e699d615ce2520f03f1d0d... adreslerinde bulunuyor
Durumlar ve geçiş dilbilgisi, standart araçlara göre çok daha anlaşılırdı
Dezavantajı kural kümesinin uzayıp gitmesi ve ideal biçimde yapılandırmanın biraz zor olması; ama koddan tüm üretim kurallarını çıkarsamayı kolaylaştırdığı için bunu bir avantaj olarak da görüyorum
Yazar belli ki TeX sözdizimi vurgulamayı denememiş
Bu ruh sağlığı açısından iyi bir şey olabilir, çünkü TeX'te yorumlamadan tam sözdizimi vurgulama yapmak genelde imkansızdır
Sadece parse etmek de yetmez; çünkü her karakterin ne işe yaradığını yeniden tanımlayabilirsiniz, hatta “artık K
{, C ise}” gibi şeyler yapmak bile mümkündürGerçekten de arXiv makaleleri arasında bu lanetli özelliği kullananlar var
.texdosyalarında bozulmadan oldukça iyi vurgulama yapıyorHedef, gerçek dünya kullanımının %99,9 kadarını kapsamak. Bu durumda bir LLM'in üretebileceği şeylerin de büyük kısmını kapsaması muhtemel
Acayip sözdizimleri de string ya da yorumların dosya sonuna kadar sürüp kaynak kodun geri kalanını kaplamadığı sürece genelde büyük sorun çıkarmıyor
\makeatletterifadesinin “bir şeyi at işaretine dönüştürmek” değil, parse sırasında@karakterini harf gibi ele almak anlamına geldiğini öğrenince inanmak zor olmuştuVim gibi iyi bir sözdizimi renklendirme motoru yazmanın kolay olmadığını düşünüyorum
Sözdizimi renklendirme, belirli biçimlerde iç içe geçmiş içeriklere farklı kurallar uygulayan bir bağlam işleme gerektirir
Vim sözdizimi vurgulayıcısı,
matchveregionolmak üzere iki tür öğe tanımlamaya izin verir;matchbasit bir sözcüksel kuraldır,regionise başlangıç, bitiş ve ara kısımları ayrı ayrı eşleyen ifadelere sahiptirÖğeler, yalnızca belirli bir alanın içinde olduklarında etkin olacak şekilde tanımlanabilir ve kapsama ilişkileri de birbirleri arasında belirtilebilir
Bu temel anlamsal yapının üzerine, çeşitli özel durumlar için ek özellikler bindirilmiştir. Justine için bile bunu mülakatta anında yapmak zor olurdu; en azından bir gecelik ödevlik iş gibi görünüyor
mansayfasının HTML dönüşüm çıktısını alıp bunu TXR kılavuzunun HTML'ine dönüştürengenmanbetiği burada: https://www.kylheku.com/cgit/txr/tree/genman.txrBeyaz görünen kısımlar literal şablonlardır; Lisp kodu ise
@(do ...)gibi yönergelerin içine girer. TXR anahtar sözcükleri mor, TXR Lisp anahtar sözcükleri yeşil görünür; aynı sözcük bile bağlama göre değişirQuasi-string'ler de iç içe geçmiş dilbilgileri barındırabilir; bunların içinde yeniden gömülü kod ya da quasi-string'ler bulunabilir.
txr.vimvetl.vimsözdizimi tanım dosyalarının ikisi de https://www.kylheku.com/cgit/txr/tree/genvim.txr üzerinden üretilirEğer böyle yapılmıyorsa muhtemelen verimlilik nedeniyledir. Örneğin, ekranda görünen kısmı vurgulamak yerine tüm dosyayı parse etmek gerekebilir ve bu da maliyeti artırabilir