Kendi içinde SLIC (Derleyicileri Uygulamak için Diller Sistemi) yazdım. Sonra el derleme içine derledi. Beş alt dilin tek bir derleyicisi olduğu için SLIC'de çok şey var:
- SYNTAX Ayrıştırıcı Programlama Dili PPL
- JENERATÖR LISP 2 tabanlı ağaç tarama PSEUDO kod oluşturma dili
- ISO Sırası, PSEUDO kodu, Optimizasyon dili
- PSEUDO Macro gibi Assembly kodu üreten dil.
- MACHOP Dili tanımlayan montaj makinesi talimatı.
SLIC, CWIC'den (Derleyiciler Yazma ve Uygulama Derleyicisi) esinlenmiştir. Çoğu derleyici geliştirme paketinin aksine, SLIC ve CWIC uzman, alana özgü dillerle kod oluşturma konusunu ele aldı. SLIC, hedef makine özelliklerini ağaç tarama üreteci dilinden ayıran ISO, PSEUDO ve MACHOP alt dillerini ekleyerek CWIC kod üretimini genişletir.
LISP 2 ağaçları ve listeleri
LISP 2 tabanlı jeneratör dilinin dinamik bellek yönetim sistemi önemli bir bileşendir. Listeler köşeli parantez içine alınmış dilde ifade edilir, bileşenleri virgülle ayrılır, yani üç elemanlı [a, b, c] liste.
Ağaçlar:
ADD
/ \
MPY 3
/ \
5 x
ilk girişi bir düğüm nesnesi olan listelerle temsil edilir:
[ADD,[MPY,5,x],3]
Ağaçlar genellikle dallardan önce gelen düğüm ayrı olarak görüntülenir:
ADD[MPY[5,x],3]
LISP 2 tabanlı jeneratör fonksiyonları ile ayıklama
Bir üreteç işlevi adlandırılmış (ayrıştır) => eylem> çiftler kümesidir ...
<NAME>(<unparse>)=><action>;
(<unparse>)=><action>;
...
(<unparse>)=><action>;
Unparse ifadeleri, ağaç desenlerini ve / veya nesne türlerini birbirinden ayıran ve bu parçaları yordamsal eylemiyle işlenmek üzere yerel değişkene atayan testlerdir. Farklı argüman türlerini alan aşırı yüklenmiş bir işlev gibi. () => ... hariç kodlar sırasıyla test edilir. Karşılık gelen eylemi gerçekleştiren ilk başarılı çözüm. Eşitsiz ifadeler testleri söküyor. ADD [x, y], dallarını x ve y yerel değişkenlerine atayan iki dallı ADD ağacıyla eşleşir. Eylem basit bir ifade veya bir .BEGIN ... .END sınırlı kod bloğu olabilir. Bugün c tarzı {...} blokları kullanardım. Ağaç eşleştirme, [], unparse kuralları, döndürülen sonuçları eyleme geçiren jeneratörleri çağırabilir:
expr_gen(ADD[expr_gen(x),expr_gen(y)])=> x+y;
Özellikle yukarıdaki expr_gen unparse, iki dallı bir ADD ağacıyla eşleşir. Test modeli içinde, bir ağaç dalına yerleştirilen tek bir argüman üreteci bu dal ile çağrılır. Ancak argüman listesi, döndürülen nesnelerle atanan yerel değişkenlerdir. Ayrıştırmanın üstünde, iki dalın ADD ağacının sökülmesini belirtir, her dalın expr_gen öğesine yinelemeli olarak bastırılması. Sol dal dönüşü yerel değişkenlere x yerleştirilir. Benzer şekilde sağ dal, dönüş nesnesiyle birlikte expr_gen öğesine geçti. Yukarıdakiler sayısal ifade değerlendiricisinin bir parçası olabilir. Düğüm dizesi yerine yukarıda vektörler olarak adlandırılan kısayol özellikleri vardı, karşılık gelen eylemlerin bir vektörü ile bir düğüm vektörü kullanılabilir:
expr_gen(#node[expr_gen(x),expr_gen(y)])=> #action;
node: ADD, SUB, MPY, DIV;
action: x+y, x-y, x*y, x/y;
(NUMBER(x))=> x;
(SYMBOL(x))=> val:(x);
Yukarıdaki daha eksiksiz ifade değerlendirici expr_gen sol daldan x'e ve sağ daldan y'ye dönüş atar. X ve y'de gerçekleştirilen ilgili hareket vektörü geri döndü. Son unparse => eylem çiftleri, sayısal ve sembol nesnelerle eşleşir.
Sembol ve sembol özellikleri
Semboller adlandırılmış niteliklere sahip olabilir. val: (x) x içinde bulunan sembol nesnesinin val özelliğine erişir. Genelleştirilmiş bir sembol tablosu yığını SLIC'in bir parçasıdır. SYMBOL tablosu, işlevler için yerel semboller sağlayarak itilebilir ve patlatılabilir. Yeni oluşturulan sembol üst sembol tablosunda kataloglanır. Sembol araması, üstteki tablodan ilk önce yığını geriye doğru sembol tablosu yığınını arar.
Makineden bağımsız kod oluşturma
SLIC'in jeneratör dili PSEUDO komut nesnelerini üretir ve bunları bir bölüm kod listesine ekler. Bir .FLUSH, PSEUDO kod listesinin çalışmasını ve her PSEUDO komutunu listeden kaldırmasını ve çağırmasını sağlar. Yürütmeden sonra bir PSEUDO nesnesi belleği serbest bırakılır. PSEUDO'ların ve JENERATÖR eylemlerinin prosedür organları, çıktıları dışında temel olarak aynı dildir. PSEUDO, makineden bağımsız kod sıralaması sağlayan montaj makroları olarak işlev görür. Belirli hedef makinenin ağaç tarama üreteci dilinden ayrılmasını sağlarlar. PSEUDO'lar makine kodunu çıkarmak için MACHOP işlevlerini çağırır. MACHOP'lar, montajlı sahte operasyonları (dc, sabit vb. Tanımlamak) ve makine talimatını veya vektörlü girişi kullanarak benzer formlu talimatlar ailesini tanımlamak için kullanılır. Parametreleri, talimatı oluşturan bir bit alan dizisine dönüştürürler. MACHOP çağrıları, montaj gibi görünmeli ve derleme listesinde montajın gösterileceği alanların yazdırma formatını sağlamalıdır. Örnek kodda kolayca eklenebilir, ancak orijinal dillerde olmayan c tarzı yorum kullanıyorum. MACHOP'lar, adreslenebilir bir bit belleğe kod üretmektedir. SLIC bağlayıcı derleyicinin çıktısını işler. Vektörlü girişi kullanan DEC-10 kullanıcı modu talimatları için bir MACHOP: MACHOP'lar, adreslenebilir bir bit belleğe kod üretmektedir. SLIC bağlayıcı derleyicinin çıktısını işler. Vektörlü girişi kullanan DEC-10 kullanıcı modu talimatları için bir MACHOP: MACHOP'lar, adreslenebilir bir bit belleğe kod üretmektedir. SLIC bağlayıcı derleyicinin çıktısını işler. Vektörlü girişi kullanan DEC-10 kullanıcı modu talimatları için bir MACHOP:
.MACHOP #opnm register,@indirect offset (index): // Instruction's parameters.
.MORG 36, O(18): $/36; // Align to 36 bit boundary print format: 18 bit octal $/36
O(9): #opcd; // Op code 9 bit octal print out
(4): register; // 4 bit register field appended print
(1): indirect; // 1 bit appended print
(4): index; // 4 bit index register appended print
O(18): if (#opcd&&3==1) offset // immediate mode use value else
else offset/36; // memory address divide by 36
// to get word address.
// Vectored entry opcode table:
#opnm := MOVE, MOVEI, MOVEM, MOVES, MOVS, MOVSI, MOVSM, MOVSS,
MOVN, MOVNI, MOVNM, MOVNS, MOVM, MOVMI, MOVMM, MOVMS,
IMUL, IMULI, IMULM, IMULB, MUL, MULI, MULM, MULB,
...
TDO, TSO, TDOE, TSOE, TDOA, TSOA, TDON, TSON;
// corresponding opcode value:
#opcd := 0O200, 0O201, 0O202, 0O203, 0O204, 0O205, 0O206, 0O207,
0O210, 0O211, 0O212, 0O213, 0O214, 0O215, 0O216, 0O217,
0O220, 0O221, 0O222, 0O223, 0O224, 0O225, 0O226, 0O227,
...
0O670, 0O671, 0O672, 0O673, 0O674, 0O675, 0O676, 0O677;
MORG 36, O (18): $ / 36; konumu sekiz bitlik 18 bitlik $ / 36 sözcük adresini yazdırarak 36 bitlik bir sınıra hizalar. 9 bit opcd, 4 bit yazmaç, dolaylı bit ve 4 bitlik dizin yazmaç birleştirilir ve tek bir 18 bitlik alan gibi yazdırılır. 18 bit adres / 36 veya anlık değer çıkarılır ve sekizlik olarak yazdırılır. MOVEI örneği r1 = 1 ve r2 = 2 ile yazdırılıyor:
400020 201082 000005 MOVEI r1,5(r2)
Derleyici montaj seçeneği ile oluşturulan derleme kodunu derleme listesine alırsınız.
Birlikte bağlayın
SLIC bağlayıcı, bağlantı ve sembol çözünürlüklerini işleyen bir kütüphane olarak sağlanır. Hedef çıktı çıktı dosya biçimlendirmesi hedef makineler için yazılmalı ve bağlayıcı kütüphane kitaplığına bağlanmalıdır.
Jeneratör dili, ağaçlara bir dosya yazabilir ve bunları okuyarak çok yollu bir derleyicinin uygulanmasına izin verir.
Kısa yazlık kod üretimi ve kökenleri
Ben SLIC gerçek bir derleyici derleyici olduğu anlaşılır olduğundan emin olmak için ilk kod üretimi üzerine gitti. SLIC, 1960'ların sonunda Systems Development Corporation'da geliştirilen CWIC'den (Derleyiciler Yazma ve Uygulama Derleyicisi) esinlenmiştir. CWIC, yalnızca JENERATÖR dilinden sayısal bayt kodu üreten SYNTAX ve GENERATOR dillerine sahipti. Bayt kodu, adlandırılmış bölümlerle ilişkili bellek tamponlarına yerleştirildi veya ekildi (CWICs belgelerinde kullanılan terim) .FLUSH ifadesi ile yazıldı. CWIC ile ilgili bir ACM belgesi ACM arşivlerinden edinilebilir.
Büyük bir programlama dilini başarıyla uygulamak
1970'lerin sonunda bir COBOL çapraz derleyicisi yazmak için SLIC kullanıldı. Yaklaşık 3 ay içinde çoğunlukla tek bir programcı tarafından tamamlandı. Gerektiğinde programcı ile biraz çalıştım. Başka bir programcı hedef TI-990 mini BİLGİSAYAR için çalışma zamanı kitaplığını ve MACHOP'ları yazdı. Bu COBOL derleyicisi, derlemede yazılan DEC-10 yerel COBOL derleyicisinden saniyede önemli ölçüde daha fazla satır derledi.
Derleyici hakkında daha fazla bilgi genellikle
Derleyiciyi sıfırdan yazmanın büyük bir kısmı çalışma zamanı kütüphanesidir. Bir sembol tablosuna ihtiyacınız var. Giriş ve çıkışa ihtiyacınız var. Dinamik bellek yönetimi vb. Bir derleyici için çalışma zamanı kitaplığını yazmaktan sonra derleyiciyi yazmak daha kolay olabilir. Ancak SLIC ile bu çalışma zamanı kütüphanesi, SLIC'de geliştirilen tüm derleyiciler için ortaktır. İki çalışma zamanı kitaplığı olduğunu unutmayın. Dilin (örneğin COBOL) hedef makinesi için bir tane. Diğeri de derleyici derleyicileri çalışma zamanı kütüphanesidir.
Sanırım bunların ayrıştırıcı jeneratörler olmadığını belirledim. Şimdi arka ucun biraz anlaşılmasıyla ayrıştırıcı programlama dilini açıklayabilirim.
Ayrıştırıcı programlama dili
Ayrıştırıcı basit denklemler şeklinde yazılmış formül kullanılarak yazılmıştır.
<name> <formula type operator> <expression> ;
En düşük seviyedeki dil elemanı karakterdir. Jetonlar, dilin karakterlerinin bir alt kümesinden oluşur. Karakter sınıfları, bu karakter alt kümelerini adlandırmak ve tanımlamak için kullanılır. İşleç tanımlayan karakter sınıfı iki nokta üst üste (:) karakteridir. Sınıfın üyesi olan karakterler tanımın sağ tarafında kodlanır. Yazdırılabilir karakterler, tekli 'dizeler içine alınır. Basılamayan ve özel karakterler sayısal sıralarıyla temsil edilebilir. Sınıf üyeleri bir alternatif ile ayrılır | Şebeke. Sınıf formülü noktalı virgülle biter. Karakter sınıfları daha önce tanımlanmış sınıfları içerebilir:
/* Character Class Formula class_mask */
bin: '0'|'1'; // 0b00000010
oct: bin|'2'|'3'|'4'|'5'|'6'|'7'; // 0b00000110
dgt: oct|'8'|'9'; // 0b00001110
hex: dgt|'A'|'B'|'C'|'D'|'E'|'F'|'a'|'b'|'c'|'d'|'e'|'f'; // 0b00011110
upr: 'A'|'B'|'C'|'D'|'E'|'F'|'G'|'H'|'I'|'J'|'K'|'L'|'M'|
'N'|'O'|'P'|'Q'|'R'|'S'|'T'|'U'|'V'|'W'|'X'|'Y'|'Z'; // 0b00100000
lwr: 'a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'i'|'j'|'k'|'l'|'m'|
'n'|'o'|'p'|'q'|'r'|'s'|'t'|'u'|'v'|'w'|'x'|'y'|'z'; // 0b01000000
alpha: upr|lwr; // 0b01100000
alphanum: alpha|dgt; // 0b01101110
Skip_class 0b00000001 önceden tanımlanmıştır ancak bir skip_class tanımlıyor olabilir.
Özetle: Bir karakter sınıfı, yalnızca bir karakter sabiti, bir karakterin sırası veya daha önce tanımlanmış bir karakter sınıfı olabilen bir alternatif listesidir. Karakter sınıflarını uygularken: Sınıf formülüne bir sınıf bit maskesi atanır. (Yukarıdaki yorumlarda gösterilmiştir) Herhangi bir gerçek veya sıralı karaktere sahip herhangi bir sınıf formülü, bir sınıf bitinin tahsis edilmesine neden olur. Bir maske, dahil edilen sınıf (lar) ın sınıf maskesini / maskelerini ayrılan bit (varsa) ile oring yaparak yapılır. Karakter sınıflarından bir sınıf tablosu oluşturulur. Bir karakterin sıralamasıyla dizine eklenen bir giriş, karakterin sınıf üyeliklerini gösteren bitler içerir. Sınıf testi yerinde yapılır. Karakter sıralamasında eax'ta bulunan bir IA-86 kod örneği sınıf testini gösterir:
test byte ptr [eax+_classmap],dgt
Ardından a:
jne <success>
veya
je <failure>
IA-86 talimat kodu örnekleri kullanılıyor çünkü bence IA-86 talimatları bugün daha yaygın olarak biliniyor. Sınıf maskesini değerlendiren sınıf adı, ordinal (eax cinsinden) karakterlerle dizinlenmiş sınıf tablosu ile tahribatsız AND'tir. Sıfırdan farklı bir sonuç sınıf üyeliğini gösterir. (EAX karakteri içeren al (EAX'in en düşük 8 biti) dışında sıfırlanır).
Jetonlar bu eski derleyicilerde biraz farklıydı. Anahtar kelimeler jeton olarak açıklanmadı. Bunlar, ayrıştırıcı dilinde alıntılanan dize sabitleri ile eşleştirildi. Alıntılanan dizeler normalde tutulmaz. Değiştiriciler kullanılabilir. A + dizeyi eşleştirir. (ie + '-' başarılı olduğunda karakteri koruyan bir - karakteriyle eşleşir), işlemi (yani 'E') dizgiyi jetona ekler. Beyaz boşluk, ilk eşleşme yapılana kadar önde gelen SKIP_CLASS karakterlerini atlayan jeton formülüyle işlenir. Açık bir skip_class karakter eşleşmesinin, jetonun skip_class karakteriyle başlamasına izin vererek atlamayı durduracağını unutmayın. Dize jetonu formülü, tek tırnaklı bir çift karakterle veya çift tırnaklı bir dize ile eşleşen skip_class karakterlerini atlar. İlgilenilen bir "dize içinde" karakteri eşleşen bir dizedir:
string .. (''' .ANY ''' | '"' $(-"""" .ANY | """""","""") '"') MAKSTR[];
İlk alternatif, alıntı yapılan herhangi bir tek karakterle eşleşir. Doğru alternatif, tek bir karakteri temsil etmek için iki "karakteri bir arada kullanan çift tırnak işareti karakterleri içerebilen çift tırnaklı bir alıntı dizesiyle eşleşir. Bu formül kendi tanımında kullanılan dizeleri tanımlar. Sağ iç alternatif '"' $ (-" "" ".ANY |" "" "" "", "" "") '"', çift tırnaklı bir dize ile eşleşir. Bir çift tırnak işareti karakteriyle eşleştirmek için tek bir tırnak karakteri kullanabiliriz. Ancak "tırnak işareti" kullanmak istiyorsak, bir "karakter kullanmak istiyorsak, iki karakter kullanmalıyız." Örneğin, iç sol alternatifte, tırnak işareti dışında herhangi bir karakterle eşleşen:
-"""" .ANY
Negatif bir göz atma - "" "" başarılı olduğunda (bir "karakteri eşleşmediğinde) .ANY karakteriyle eşleşir (" bir karakter olamaz çünkü - "" "" bu olasılığı ortadan kaldırır). Doğru alternatif - "" "" ile "karakteri eşleştirerek başarısız olmak doğru alternatifti:
"""""",""""
iki "karakteri tek bir çift ile değiştirmeyi dener," "" "thw single" karakterini eklemeye çalışır. Kapatma dizesi alıntı karakterini geçemeyen her iki iç seçenek de eşleştirilir ve MAKSTR [] bir dize nesnesi oluşturmaya çağırılır. dizi, döngü başarılı olduğunda, operatör bir diziyi eşleştirmek için kullanılır.Tozör formülü önde gelen atlama sınıfı karakterlerini atla (beyaz boşluk) İlk eşleme yapıldıktan sonra skip_class atlama devre dışı bırakılır. [] kullanarak diğer dillerde programlanmış işlevleri çağırabiliriz. [], MAKBIN [], MAKOCT [], MAKHEX [], MAKFLOAT [] ve MAKINT [], eşleşen bir belirteç dizesini yazılan bir nesneye dönüştüren kitaplık işlevidir: Aşağıdaki sayı formülü oldukça karmaşık bir belirteç tanımayı gösterir:
number .. "0B" bin $bin MAKBIN[] // binary integer
|"0O" oct $oct MAKOCT[] // octal integer
|("0H"|"0X") hex $hex MAKHEX[] // hexadecimal integer
// look for decimal number determining if integer or floating point.
| ('+'|+'-'|--) // only - matters
dgt $dgt // integer part
( +'.' $dgt // fractional part?
((+'E'|'e','E') // exponent part
('+'|+'-'|--) // Only negative matters
dgt(dgt(dgt|--)|--)|--) // 1 2 or 3 digit exponent
MAKFLOAT[] ) // floating point
MAKINT[]; // decimal integer
Yukarıdaki sayı belirteci formülü tamsayı ve kayan nokta sayılarını tanır. - alternatifleri her zaman başarılıdır. Hesaplamalarda sayısal nesneler kullanılabilir. Belirteç nesneleri, formülün başarısı üzerine ayrıştırma yığınına itilir. (+ 'E' | 'e', 'E') üssündeki kurşun ilginçtir. MAKEFLOAT [] için her zaman büyük E harfine sahip olmak istiyoruz. Ama biz küçük bir 'e' harfini 'E' kullanarak değiştirmeye izin veriyoruz.
Karakter sınıfı ve simge formülünün tutarlılıklarını fark etmiş olabilirsiniz. Ayrıştırma formülü, geri izleme alternatifleri ve ağaç inşaat operatörleri eklemeye devam ediyor. Geri izleme ve geri izleme olmayan alternatif işleçler, bir ifade düzeyi içinde karıştırılamaz. Geri izlemesiz karıştırma (a | b \ c) yapamayabilirsiniz | \ backtracking alternatifi ile. (a \ b \ c), (a | b | c) ve ((a | b) \ c) geçerlidir. \ Backtracking alternatifi, sol alternatifini denemeden önce ayrıştırma durumunu kaydeder ve hata durumunda doğru alternatifi denemeden önce ayrıştırma durumunu geri yükler. Bir dizi alternatifte ilk başarılı alternatif grubu tatmin eder. Başka alternatifler denenmez. Faktoring ve gruplama, sürekli ilerleyen bir ayrıştırma sağlar. Geri izleme alternatifi, sol alternatifini denemeden önce ayrıştırmanın kaydedilmiş bir durumunu oluşturur. Ayrıştırma kısmi bir eşleşme yapabilir ve sonra başarısız olursa geri izleme gereklidir:
(a b | c d)\ e
Yukarıda bir hata döndürürse alternatif cd denenir. Eğer o zaman c başarısızlık verirse, backtrack alternatifi denenecektir. Başarılı ve b başarısız olursa, ayrıştırma geri izlenir ve e denenir. Aynı şekilde başarısız bir c başarılı ve b başarısız olursa ayrıştırma geri izlenir ve alternatif e alınır. Geri izleme bir formül içinde sınırlı değildir. Herhangi bir ayrıştırma formülü herhangi bir zamanda kısmi bir eşleşme yapar ve başarısız olursa, ayrıştırma üst geri izlemeye sıfırlanır ve alternatifi alınır. Kod çıkarılırsa, derleme hatası oluştuğunda bir derleme hatası oluşabilir. Derlemeye başlamadan önce bir geri iz bırakılır. Geri dönüş hatası veya geri izleme derleyici hatasıdır. Geri izler istiflenir. Olumsuz ve pozitif kullanabilir miyiz? ayrıştırmayı ilerletmeden test etmek için operatörlere göz atın / bakın. dize testi olmak, yalnızca giriş durumunun kaydedilmesi ve sıfırlanması gereken bir adım öndedir. İleriye bakma, başarısız olmadan önce kısmi eşleşme yapan bir ayrıştırma ifadesi olacaktır. Geri izleme kullanılarak ileriye bir bakış uygulanır.
Ayrıştırıcı dili LL veya LR ayrıştırıcısı değildir. Ancak, ağaç yapısını programladığınız özyinelemeli düzgün bir ayrıştırıcı yazmak için bir programlama dili:
:<node name> creates a node object and pushes it onto the node stack.
.. Token formula create token objects and push them onto
the parse stack.
!<number> pops the top node object and top <number> of parstack
entries into a list representation of the tree. The
tree then pushed onto the parse stack.
+[ ... ]+ creates a list of the parse stack entries created
between them:
'(' +[argument $(',' argument]+ ')'
could parse an argument list. into a list.
Yaygın olarak kullanılan bir ayrıştırma örneği aritmetik bir ifadedir:
Exp = Term $(('+':ADD|'-':SUB) Term!2);
Term = Factor $(('*':MPY|'/':DIV) Factor!2);
Factor = ( number
| id ( '(' +[Exp $(',' Exp)]+ ')' :FUN!2
| --)
| '(' Exp ')" )
(^' Factor:XPO!2 |--);
Exp ve Term bir döngü kullanarak solak bir ağaç oluşturur. Sağ özyineleme kullanan faktör sağ elini kullanan bir ağaç oluşturur:
d^(x+5)^3-a+b*c => ADD[SUB[EXP[EXP[d,ADD[x,5]],3],a],MPY[b,c]]
ADD
/ \
SUB MPY
/ \ / \
EXP a b c
/ \
d EXP
/ \
ADD 3
/ \
x 5
İşte cc derleyicisinin bir kısmı, c stili yorumlarla SLIC'in güncellenmiş bir sürümü. İşlev türleri (dilbilgisi, belirteç, karakter sınıfı, jeneratör, PSEUDO veya MACHOP, kimliklerini izleyen ilk sözdizimleriyle belirlenir. Bu yukarıdan aşağıya ayrıştırıcılarla formül tanımlayan bir programla başlarsınız:
program = $((declaration // A program is a sequence of
// declarations terminated by
|.EOF .STOP) // End Of File finish & stop compile
\ // Backtrack: .EOF failed or
// declaration long-failed.
(ERRORX["?Error?"] // report unknown error
// flagging furthest parse point.
$(-';' (.ANY // find a ';'. skiping .ANY
| .STOP)) // character: .ANY fails on end of file
// so .STOP ends the compile.
// (-';') failing breaks loop.
';')); // Match ';' and continue
declaration = "#" directive // Compiler directive.
| comment // skips comment text
| global DECLAR[*1] // Global linkage
|(id // functions starting with an id:
( formula PARSER[*1] // Parsing formula
| sequencer GENERATOR[*1] // Code generator
| optimizer ISO[*1] // Optimizer
| pseudo_op PRODUCTION[*1] // Pseudo instruction
| emitor_op MACHOP[*1] // Machine instruction
) // All the above start with an identifier
\ (ERRORX["Syntax error."]
garbol); // skip over error.
// Ağacı oluştururken kimliğin nasıl kapatıldığını ve daha sonra nasıl birleştirildiğini not edin.
formula = ("==" syntax :BCKTRAK // backtrack grammar formula
|'=' syntax :SYNTAX // grammar formula.
|':' chclass :CLASS // character class define
|".." token :TOKEN // token formula
)';' !2 // Combine node name with id
// parsed in calling declaration
// formula and tree produced
// by the called syntax, token
// or character class formula.
$(-(.NL |"/*") (.ANY|.STOP)); Comment ; to line separator?
chclass = +[ letter $('|' letter) ]+;// a simple list of character codes
// except
letter = char | number | id; // when including another class
syntax = seq ('|' alt1|'\' alt2 |--);
alt1 = seq:ALT!2 ('|' alt1|--); Non-backtrack alternative sequence.
alt2 = seq:BKTK!2 ('\' alt2|--); backtrack alternative sequence
seq = +[oper $oper]+;
oper = test | action | '(' syntax ')' | comment;
test = string | id ('[' (arg_list| ,NILL) ']':GENCALL!2|.EMPTY);
action = ':' id:NODE!1
| '!' number:MAKTREE!1
| "+[" seq "]+" :MAKLST!1;
// C style comments
comment = "//" $(-.NL .ANY)
| "/*" $(-"*/" .ANY) "*/";
Ayrıştırıcı dilinin yorumlama ve hata gidermeyi nasıl ele aldığı dikkat çekicidir.
Sanırım soruyu cevapladım. SLIC'lerin halefinin büyük bir bölümünü burada yazmış olan cc dili. Henüz bunun için bir derleyici yok. Ama el montaj kodu, çıplak asm c veya c ++ fonksiyonları derlemek olabilir.