it-swarm.dev

Bir ayrıştırıcı oluşturucu kullanmalı mıyım yoksa kendi özel lexer ve ayrıştırıcı kodumu mı döndürmeliyim?

Ne spesifik Bir programlama dili dilbilgisi üzerinde çalışmanın her yolunun avantajları ve dezavantajları nelerdir?

Neden/Ne zaman kendi başıma dönmeliyim? Jeneratörü neden/ne zaman kullanmalıyım?

83
Maniero

Gerçekten üç seçenek var, üçü de farklı durumlarda tercih edilebilir.

Seçenek 1: Ayrıştırıcılar veya 'bazı dilleri ayrıştırmanız gerekiyor ve sadece onu çalıştırmak istiyorsunuz, kahretsin'

Diyelim ki ŞİMDİ bazı eski veri formatları için ayrıştırıcı oluşturmanız isteniyor. Veya hızlı olması için ayrıştırıcıya ihtiyacınız var. Ya da çözümleyicinizin kolayca bakımı için ihtiyacınız vardır.

Bu durumlarda, muhtemelen en iyi şekilde bir ayrıştırıcı üreteci kullanamazsınız. Detaylar ile uğraşmak zorunda değilsiniz, düzgün çalışmak için çok sayıda karmaşık kod almak zorunda değilsiniz, sadece girişin yapışacağı dilbilgisini yazın, bazı taşıma kodu ve presto: anında ayrıştırıcı yazın.

Avantajları açıktır:

  • Özellikle giriş formatı çok garip değilse (genellikle 2 seçeneği daha iyi olurdu) bir spesifikasyon yazmak genellikle (genellikle) kolaydır.
  • Sonunda, kolayca anlaşılabilen, kolayca anlaşılabilir bir iş parçasıyla sonuçlanırsınız: dilbilgisi tanımı genellikle koddan çok daha doğal akar.
  • İyi ayrıştırıcı jeneratörleri tarafından üretilen ayrıştırıcılar genellikle elle yazılmış koddan çok daha hızlıdır. Elle yazılmış kod can daha hızlı olun, ancak yalnızca öğelerinizi biliyorsanız - bu yüzden en çok kullanılan derleyiciler elle yazılmış özyinelemeli bir ayrıştırıcı kullanır.

Ayrıştırıcı üreteçlerinde dikkatli olmanız gereken bir şey vardır: bazen gramerlerinizi reddedebilir. Farklı ayrıştırıcı türlerine ve bunların sizi nasıl ısırdıklarına genel bir bakış için başlamak isteyebilirsiniz here . Burada birçok uygulamaya ve kabul ettikleri gramer türlerine genel bir bakış bulabilirsiniz.

2. Seçenek: elle yazılmış ayrıştırıcılar veya 'kendi ayrıştırıcınızı oluşturmak istiyorsunuz ve kullanıcı dostu olmayı önemsiyorsunuz'

Ayrıştırıcı jeneratörleri Nice, ancak çok kullanıcı dostu değiller (son kullanıcı, siz değil). Genellikle iyi hata iletileri veremez veya hata giderme sağlayamazsınız. Belki de diliniz çok garip ve ayrıştırıcılar dilbilginizi reddediyor veya jeneratörün size verdiğinden daha fazla kontrole ihtiyacınız var.

Bu durumlarda, elle yazılmış özyinelemeli bir ayrıştırıcı kullanmak muhtemelen en iyisidir. Doğru yapmak karmaşık olsa da, ayrıştırıcı üzerinde tam kontrole sahip olursunuz, böylece hata mesajları ve hatta hata kurtarma gibi ayrıştırıcı jeneratörlerle yapamayacağınız her türlü Nice şeyler yapabilirsiniz (bir C # dosyasından tüm noktalı virgülleri kaldırmayı deneyin : C # derleyicisi şikayet edecek, ancak noktalı virgüllerin varlığına bakılmaksızın diğer hataların çoğunu yine de algılayacaktır).

Elle yazılan ayrıştırıcılar, ayrıştırıcının kalitesinin yeterince yüksek olduğu varsayılarak genellikle üretilenlerden daha iyi performans gösterir. Öte yandan, genellikle deneyim, bilgi veya tasarım eksikliğinden (bir kombinasyon) dolayı iyi bir ayrıştırıcı yazmayı başaramazsanız, performans genellikle daha yavaştır. Lexers için ise tam tersi doğrudur: genellikle oluşturulan lexers tablo aramalarını kullanır ve bunları (en çok) elle yazılmış olanlardan daha hızlı yapar.

Eğitim açısından, kendi ayrıştırıcınızı yazmak size bir jeneratör kullanmaktan daha fazlasını öğretecektir. Sonuçta gittikçe daha karmaşık bir kod yazmalısınız, ayrıca bir dili tam olarak nasıl ayrıştırdığınızı da anlamalısınız. Öte yandan, kendi dilinizi nasıl oluşturacağınızı öğrenmek istiyorsanız (bu nedenle, dil tasarımında deneyim kazanın), seçenek 1 veya seçenek 3 tercih edilir: eğer bir dil geliştiriyorsanız, muhtemelen çok değişecektir, ve seçenek 1 ve 3 size bununla ilgili daha kolay bir zaman sağlar.

Seçenek 3: elle yazılmış ayrıştırıcı jeneratörler, veya 'bu projeden çok şey öğrenmeye çalışıyorsunuz ve çok fazla yeniden kullanabileceğiniz şık bir kod parçası ile bitirmeyi düşünmezsiniz'

Şu anda yürüdüğüm yol budur: kendi ayrıştırıcı üretecini yazıyorsunuz. Son derece önemsiz olsa da, bunu yapmak size en çok öğretecek.

Size böyle bir proje yapmanın ne demek olduğu hakkında bir fikir vermek için size kendi gelişimimi anlatacağım.

Lexer üreticisi

Önce kendi lexer jeneratörümü oluşturdum. Genellikle kodun nasıl kullanılacağından başlayarak yazılım tasarlıyorum, bu yüzden kodumu kullanmak istedim ve bu kod parçasını yazdım (C # 'da):

Lexer<CalculatorToken> calculatorLexer = new Lexer<CalculatorToken>(
    new List<StringTokenPair>()
    { // This is just like a Lex specification:
      //                    regex   token
        new StringTokenPair("\\+",  CalculatorToken.Plus),
        new StringTokenPair("\\*",  CalculatorToken.Times),
        new StringTokenPair("(",    CalculatorToken.LeftParenthesis),
        new StringTokenPair(")",    CalculatorToken.RightParenthesis),
        new StringTokenPair("\\d+", CalculatorToken.Number),
    });

foreach (CalculatorToken token in
             calculatorLexer.GetLexer(new StringReader("15+4*10")))
{ // This will iterate over all tokens in the string.
    Console.WriteLine(token.Value);
}

// Prints:
// 15
// +
// 4
// *
// 10

Giriş dizesi belirteci çiftleri, aritmetik bir yığının fikirlerini kullanarak temsil ettikleri normal ifadeleri açıklayan karşılık gelen bir özyinelemeli yapıya dönüştürülür. Bu daha sonra bir NFA'ya (belirleyici olmayan sonlu otomat) dönüştürülür ve bu da bir DFA'ya (deterministik sonlu otomat) dönüştürülür. Daha sonra dizeleri DFA ile eşleştirebilirsiniz.

Bu şekilde, sözlüklerin tam olarak nasıl çalıştığı hakkında iyi bir fikir edinirsiniz. Buna ek olarak, doğru şekilde yaparsanız, lexer jeneratörünüzün sonuçları kabaca profesyonel uygulamalar kadar hızlı olabilir. Ayrıca, seçenek 2 ile karşılaştırıldığında herhangi bir ifade kaybetmezsiniz ve seçenek 1 ile karşılaştırıldığında çok fazla ifade olmazsınız.

Lexer jeneratörümü 1600'ün üzerinde kod satırında uyguladım. Bu kod yukarıdaki işi yapar, ancak programı her başlattığınızda hala lexer anında oluşturur: Ben bir noktada diske yazmak için kod ekleyeceğim.

Kendi lexer'ınızı nasıl yazacağınızı bilmek istiyorsanız, this başlamak için iyi bir yerdir.

Ayrıştırıcı oluşturucu

Daha sonra ayrıştırıcı jeneratörünüzü yazarsınız. Farklı ayrıştırıcı türlerine genel bir bakış için burada 'a tekrar bakın - genel bir kural olarak, daha fazla ayrıştırabilirler, daha yavaşlar.

Hız benim için bir sorun değil, ben bir Earley ayrıştırıcı uygulamayı seçtim. Bir Earley ayrıştırıcısının gelişmiş uygulamaları gösterilmiştir diğer ayrıştırıcı türlerinin yaklaşık iki katı kadar yavaş olmalıdır.

Bu hız vuruşuna karşılık olarak, (belirsiz) herhangi bir biraz dilbilgisi, hatta belirsiz olanları ayrıştırabilirsiniz. Bu, ayrıştırıcıda herhangi bir sol özyineleme olup olmadığı veya vardiya azaltma çakışmasının ne olduğu konusunda endişelenmenize gerek olmadığı anlamına gelir. 1 + 2 + 3'ü (1 + 2) +3 veya 1 olarak ayrıştırmanızın önemi olmaması gibi, hangi ayrıştırma ağacının sonucu olduğu önemli değilse, belirsiz gramerleri kullanarak dilbilgisini daha kolay tanımlayabilirsiniz. (+ 2 + 3).

Bu ayrıştırıcı jeneratör kullanarak kod parçası gibi görünebilir:

Lexer<CalculatorToken> calculatorLexer = new Lexer<CalculatorToken>(
    new List<StringTokenPair>()
    {
        new StringTokenPair("\\+",  CalculatorToken.Plus),
        new StringTokenPair("\\*",  CalculatorToken.Times),
        new StringTokenPair("(",    CalculatorToken.LeftParenthesis),
        new StringTokenPair(")",    CalculatorToken.RightParenthesis),
        new StringTokenPair("\\d+", CalculatorToken.Number),
    });

Grammar<IntWrapper, CalculatorToken> calculator
    = new Grammar<IntWrapper, CalculatorToken>(calculatorLexer);

// Declaring the nonterminals.
INonTerminal<IntWrapper> expr = calculator.AddNonTerminal<IntWrapper>();
INonTerminal<IntWrapper> term = calculator.AddNonTerminal<IntWrapper>();
INonTerminal<IntWrapper> factor = calculator.AddNonTerminal<IntWrapper>();

// expr will be our head nonterminal.
calculator.SetAsMainNonTerminal(expr);

// expr: term | expr Plus term;
calculator.AddProduction(expr, term.GetDefault());
calculator.AddProduction(expr,
                         expr.GetDefault(),
                         CalculatorToken.Plus.GetDefault(),
                         term.AddCode(
                         (x, r) => { x.Result.Value += r.Value; return x; }
                         ));

// term: factor | term Times factor;
calculator.AddProduction(term, factor.GetDefault());
calculator.AddProduction(term,
                         term.GetDefault(),
                         CalculatorToken.Times.GetDefault(),
                         factor.AddCode
                         (
                         (x, r) => { x.Result.Value *= r.Value; return x; }
                         ));

// factor: LeftParenthesis expr RightParenthesis
//         | Number;
calculator.AddProduction(factor,
                         CalculatorToken.LeftParenthesis.GetDefault(),
                         expr.GetDefault(),
                         CalculatorToken.RightParenthesis.GetDefault());
calculator.AddProduction(factor,
                         CalculatorToken.Number.AddCode
                         (
                         (x, s) => { x.Result = new IntWrapper(int.Parse(s));
                                     return x; }
                         ));

IntWrapper result = calculator.Parse("15+4*10");
// result == 55

(IntWrapper sadece bir Int32 olduğunu unutmayın, ancak C # bir sınıf olmasını gerektirir, bu nedenle bir sarıcı sınıf tanıtmak zorunda kaldı)

Umarım yukarıdaki kod çok güçlüdür: karşılaşabileceğiniz herhangi bir dilbilgisi ayrıştırılabilir. Çok sayıda görevi gerçekleştirebilen dilbilgisine rasgele kod parçaları ekleyebilirsiniz. Tüm bunları çalıştırmayı başarırsanız, ortaya çıkan kodu çok fazla görev yapmak için yeniden kullanabilirsiniz: bu kodu kullanarak bir komut satırı yorumlayıcısı oluşturmayı hayal edin.

78
Alex ten Brink

Asla, hiç ayrıştırıcı yazdıysanız bunu tavsiye ederim. Eğlenceli ve işlerin nasıl çalıştığını öğreniyorsunuz ve ayrıştırıcı ve lexer jeneratörlerinin sizi bir sonraki ihtiyacınız olan zamandan kurtarmaya çalıştığını takdir etmeyi öğreniyorsunuz. ayrıştırıcı.

Ayrıca nasıl yapılacağına dair çok gerçekçi bir tutum sergilediği için http://compilers.iecc.com/crenshaw/ okumaya çalışmanızı öneririm.

22
user1249

Kendi özyinelemeli iniş ayrıştırıcısını yazmanın avantajı, sözdizimi hatalarında yüksek kaliteli hata iletileri oluşturabilmenizdir. Ayrıştırıcı üreteçlerini kullanarak hata üretimleri yapabilir ve belirli noktalara özel hata mesajları ekleyebilirsiniz, ancak ayrıştırıcı üreteçleri ayrıştırma üzerinde tam kontrole sahip olma gücüyle eşleşmez.

Kendinizinkini yazmanın bir başka avantajı, dilbilginizle birebir yazışmaları olmayan daha basit bir temsili ayrıştırmanın daha kolay olmasıdır.

Dilbilginiz düzeltildiyse ve hata iletileri önemliyse, kendinizinkini yuvarlamayı veya en azından size ihtiyacınız olan hata iletilerini veren bir ayrıştırıcı oluşturucuyu kullanmayı düşünün. Dilbilginiz sürekli değişiyorsa, bunun yerine ayrıştırıcı jeneratörleri kullanmayı düşünmelisiniz.

Bjarne Stroustrup, C++ 'ın ilk uygulaması için YACC'yi nasıl kullandığını anlatıyor (bkz. C++ Tasarım ve Gelişimi ). Bu ilk durumda, kendi özyinelemeli iniş ayrıştırıcısını yazmasını diledi!

14
Macneil

Seçenek 3: Hiçbiri (Kendi ayrıştırıcı üretecinizi yuvarlayın)

Kullanmamanın bir nedeni olduğu için ANTLR , bizon , Coco/R , Grammatica , JavaCC , Limon , Kaynatılmış , SableCC , Quex , vb - bu, kendi ayrıştırıcıyı + lexer'ınızı anında döndürmeniz gerektiği anlamına gelmez.

neden tüm bu araçlar yeterince iyi değil - neden hedefinize ulaşmanıza izin vermiyorlar?

Karşılaştığınız gramerdeki tuhaflıkların benzersiz olduğundan emin olmadığınız sürece, bunun için tek bir özel ayrıştırıcı + lexer oluşturmamalısınız. Bunun yerine, istediğinizi yaratacak bir araç oluşturun, ancak gelecekteki ihtiyaçları karşılamak için de kullanılabilir, daha sonra diğer kişilerin sizinle aynı sorunu yaşamasını önlemek için Özgür Yazılım olarak serbest bırakın.

10
Peter Boughton

Kendi ayrıştırıcıyı yuvarlamak, sizi doğrudan dilinizin karmaşıklığı hakkında düşünmeye zorlar. Dilin ayrıştırılması zorsa, muhtemelen anlaşılması zor olacaktır.

İlk günlerde ayrıştırıcı jeneratörlere, oldukça karmaşık (bazıları "işkence" derdi) dil sözdizimi ile motive olmuştu. JOVIAL özellikle kötü bir örnekti: diğer her şeyin en fazla bir sembol gerektirdiği bir zamanda iki sembol ileriye ihtiyaç duyuyordu. Bu, JOVIAL derleyicisinin ayrıştırıcısını beklenenden daha zor hale getirdi (General Dynamics/Fort Worth Bölümü, F-16 programı için JOVIAL derleyicilerini tedarik ettiklerinde zor yolu öğrendikçe).

Bugün, özyinelemeli iniş evrensel olarak tercih edilen yöntemdir, çünkü derleyici yazarları için daha kolaydır. Özyinelemeli iniş derleyicileri basit, temiz bir dil tasarımını güçlü bir şekilde ödüllendirir, çünkü kıvrımlı, dağınık bir dilden daha basit, temiz bir dil için özyinelemeli bir ayrıştırıcı yazmak çok daha kolaydır.

Son olarak: Dilinizi LISP'ye katmayı ve bir LISP yorumlayıcısının sizin için ağır kaldırma yapmasına izin vermeyi düşündünüz mü? AutoCAD bunu yaptı ve hayatlarını çok daha kolay hale getirdi. Bazıları gömülebilir olmak üzere oldukça az sayıda hafif LISP tercümanı var.

8
John R. Strohm

Bir kez ticari uygulama için ayrıştırıcı yazdım ve yacc kullandım. Bir geliştiricinin her şeyi C++ 'da elle yazdığı ve yaklaşık beş kat daha yavaş çalıştığı rakip bir prototip vardı.

Bu ayrıştırıcı için lexer gelince, tamamen elle yazdım. Üzgünüm, neredeyse 10 yıl önceydi, bu yüzden tam olarak hatırlamıyorum - yaklaşık 1000 satır C .

Lexer'ı elle yazmamın nedeni, ayrıştırıcının giriş grameriydi. Ayrıştırıcı uygulamamın tasarladığım bir şeyin aksine uyması gereken bir gereklilikti. (Tabii ki bunu farklı şekilde tasarlardım. Ve daha iyisi!) Dilbilgisi ciddi ölçüde bağlama bağlıydı ve hatta lexing bazı yerlerde anlambilime bağlıydı. Örneğin, noktalı virgül, bir yerde bir simgenin parçası olabilir, ancak daha önce ayrıştırılan bazı öğelerin anlamsal yorumuna dayanan farklı bir yerde bir ayırıcı olabilir. Yani, elle yazılmış sözlükte bu tür anlamsal bağımlılıkları "gömdüm" ve bu beni oldukça açık bir şekilde bıraktı [~ # ~] bnf [~ # ~] bu yacc'de uygulanması kolaydı.

EKLEDI yanıt olarak Macneil: yacc, programcının terminaller, terminal olmayanlar, yapımları ve bunun gibi şeyler. Ayrıca, yylex() işlevini uygularken, geçerli simgeyi döndürmeye odaklanmama ve ondan önce veya sonra ne olduğu konusunda endişelenmeme yardımcı oldu. C++ programcısı, böyle bir soyutlamanın yararı olmadan karakter düzeyinde çalıştı ve daha karmaşık ve daha az verimli bir algoritma yarattı. Yavaş hızın C++ 'ın kendisi veya herhangi bir kütüphaneyle ilgisi olmadığı sonucuna vardık. Bellekte yüklü dosyalar ile saf ayrıştırma hızını ölçtük; bir dosya arabelleğe alma sorunumuz olsaydı, yacc bunu çözmek için tercih ettiğimiz araç olmazdı.

AYRICA EKLEMEK İSTİYORUM: Bu genel olarak ayrıştırıcılar yazmak için bir reçete değil, sadece belirli bir durumda nasıl çalıştığının bir örneğidir.

6
azheglov

Hedefinizin ne olduğuna bağlıdır.

Ayrıştırıcıların/derleyicilerin nasıl çalıştığını öğrenmeye mi çalışıyorsunuz? Sonra sıfırdan kendiniz yazın. Bu, yaptıklarının tüm giriş ve çıkışlarını takdir etmeyi öğrenmenin tek yolu. Son birkaç aydır bir tane yazıyorum ve ilginç ve değerli bir deneyim oldu, özellikle de 'ah, bu yüzden X dili bunu yapıyor ...' anları.

Son başvuru tarihine kadar bir başvuru için hızlıca bir şeyler bir araya getirmeniz mi gerekiyor? Sonra belki bir ayrıştırıcı aracı kullanın.

Önümüzdeki 10, 20, hatta 30 yıl boyunca genişletmek isteyeceğiniz bir şeye mi ihtiyacınız var? Kendiniz yazın ve acele etmeyin. Buna değer.

3
GrandmasterB

Bu tamamen neyi ayrıştırmanız gerektiğine bağlıdır. Bir lexer'ın öğrenme eğrisine vurabileceğinizden daha hızlı kendiniz dönebilir misiniz? Ayrıştırılacak olan şeyler karardan sonra pişman olmayacak kadar statik mi? Mevcut uygulamaları aşırı derecede karmaşık buluyor musunuz? Eğer öyleyse, kendi eğlencenizi yuvarlayın, ancak sadece bir öğrenme eğrisini kullanmıyorsanız.

Son zamanlarda, limon ayrıştırıcı gibi gerçekten geldim, ki bu şimdiye kadar kullandığım en basit ve en kolay olanı. İşlerin bakımını kolaylaştırmak adına, bunu çoğu ihtiyaç için kullanıyorum. SQLite, diğer bazı önemli projelerin yanı sıra bunu kullanır.

Ancak, lexers'la hiç ilgilenmiyorum, ötesinde bir tane kullanmam gerektiğinde (dolayısıyla limon) yoluma çıkmıyorlar. Siz olabilirsiniz, eğer öyleyse neden bir tane yapmıyorsunuz? Var olanı kullanmaya geri döneceğinizi hissediyorum, ancak gerekirse kaşıntıyı çizin :)

3
Tim Post

Martin Fowlers dil tezgahı yaklaşımını düşündünüz mü? Makaleden alıntı

Bir dil tezgahının denklemde yaptığı en belirgin değişiklik, harici DSL'ler oluşturma kolaylığıdır. Artık bir ayrıştırıcı yazmak zorunda değilsiniz. Soyut sözdizimini tanımlamanız gerekir - ancak bu aslında oldukça basit bir veri modelleme adımıdır. Buna ek olarak, DSL'iniz güçlü bir IDE - bu editörü tanımlamak için biraz zaman harcamanıza rağmen, jeneratör hala yapmanız gereken bir şey ve benim düşüncem çok fazla değil Ancak daha sonra iyi ve basit bir DSL için bir jeneratör oluşturmak egzersizin en kolay kısımlarından biridir.

Bunu okurken, kendi ayrıştırıcısını yazmanın günlerinin bittiğini söyleyebilirim ve mevcut kütüphanelerden birini kullanmak daha iyidir. Kütüphaneye hakim olduktan sonra, gelecekte oluşturacağınız tüm DSL'ler bu bilgiden yararlanır. Ayrıca, diğerleri ayrıştırma yaklaşımınızı öğrenmek zorunda değildir.

Yorumu (ve düzeltilmiş soruyu) kapsayacak şekilde düzenleyin

Kendinizi yuvarlamanın avantajları

  1. Ayrıştırıcıya sahip olacaksınız ve karmaşık bir dizi sorunla tüm bu güzel düşünme deneyimini kazanacaksınız.
  2. Kimsenin düşünmediği özel bir şey bulabilirsin (olası değil ama zeki bir adam gibi görünüyorsun)
  3. Sizi ilginç bir problemle meşgul edecek

Kısacası, gerçekten ustalaşmak için motive olduğunuzu ciddi olarak zor bir problemin bağırsaklarına derinlemesine kesmek istediğinizde kendi başınıza dönmelisiniz.

Başka birinin kütüphanesini kullanmanın avantajları

  1. Tekerleği yeniden icat etmekten kaçınacaksınız (kabul edeceğiniz programlamada yaygın bir sorun)
  2. Son sonuca (parlak yeni dil) odaklanabilirsiniz ve nasıl ayrıştırıldığı hakkında çok fazla endişelenmeyin vb.
  3. Dilini eylemde çok daha hızlı göreceksin (ama ödülün daha az olacak çünkü çünkü sen değilsin)

Bu nedenle, hızlı bir sonuç istiyorsanız, başka birinin kitaplığını kullanın.

Genel olarak, bu sorunun ne kadarına ve dolayısıyla çözümüne sahip olmak istediğinize karar verir. Eğer hepsini istiyorsanız o zaman kendi rulo.

3
Gary Rowe

Kendinizinkini yazmanın en büyük avantajı, kendinizinkini nasıl yazacağınızı bilmenizdir. Yacc gibi bir aracı kullanmanın en büyük avantajı, aracı nasıl kullanacağınızı bilmenizdir. Ben ilk keşif için treetop hayranıyım.

2
philosodad

Neden açık kaynaklı bir ayrıştırıcı jeneratörünü çatallaştırıp kendiniz yapmıyorsunuz? Ayrıştırıcı üreteçleri kullanmazsanız, kodunuzun bakımı çok zor olacaktır, büyük değişiklikler yaptıysanız dilinizin sözdizimi.

Ayrıştırıcılarımda, tokenize etmek için düzenli ifadeler (yani Perl tarzı) kullandım ve kod okunabilirliğini artırmak için bazı kolaylık işlevleri kullandım. Ancak, ayrıştırıcı tarafından oluşturulan bir kod durum tabloları ve uzun switch-cases yaparak daha hızlı olabilir, bu da .gitignore onları.

Özel olarak yazılmış ayrıştırıcılarıma iki örnek:

https://github.com/SHiNKiROU/DesignScript - TEMEL bir lehçe, çünkü dizi gösterimlerinde lookaheads yazmak için çok tembel olduğum için hata mesajı kalitesini feda ettim https: // github. com.tr/SHiNKiROU/ExprParser - Formül hesaplayıcısı. Garip metaprogram hilelerine dikkat edin

1
Ming-Tang

"Bu denenmiş ve test edilmiş" tekerleği "kullanmalı mıyım yoksa yeniden mi keşfetmeliyim?"

0
JBRWilkinson