मैंने अपने आप में एसएलआईसी (सिस्टम के कार्यान्वयन के लिए भाषाओं की प्रणाली) लिखा। फिर हाथ ने इसे विधानसभा में संकलित किया। SLIC के लिए बहुत कुछ है क्योंकि यह पाँच उप-भाषाओं का एकल संकलक था:
- SYNTAX पार्सर प्रोग्रामिंग भाषा PPL
- जनरेटर LISP 2 आधारित पेड़ रेंगने PSEUDO कोड पीढ़ी भाषा
- आईएसओ इन सीक्वेंस, PSEUDO कोड, अनुकूलन भाषा
- PSEUDO मैक्रो असेंबली कोड प्रोड्यूसिंग लैंग्वेज की तरह।
- MACHOP विधानसभा-मशीन अनुदेश भाषा को परिभाषित करना।
एसएलआईसी सीडब्ल्यूआईसी (कंपाइलर फॉर राइटिंग एंड इंप्लीमेंटिंग कंपाइलर्स) से प्रेरित था। अधिकांश संकलक विकास पैकेजों के विपरीत, SLIC और CWIC ने विशेषज्ञ, डोमेन विशिष्ट, भाषाओं के साथ कोड पीढ़ी को संबोधित किया। SLIC ने ISO, PSEUDO और MACHOP सब-लैंग्वेज को जोड़ने वाली CWIC कोड कोड फैली हुई है, जो टारगेट-क्रॉलिंग जेनरेटर लैंग्वेज से अलग टारगेट मशीन बारीकियों को अलग करती है।
LISP 2 पेड़ और सूची
LISP 2 आधारित जनरेटर भाषा की गतिशील मेमोरी प्रबंधन प्रणाली एक प्रमुख घटक है। वर्गाकार कोष्ठक में दर्शाई गई भाषा में सूचियाँ व्यक्त की जाती हैं, इसके अवयव अल्पविराम से अलग हो जाते हैं अर्थात एक तीन तत्व [a, b, c] सूची।
पेड़:
ADD
/ \
MPY 3
/ \
5 x
उन सूचियों का प्रतिनिधित्व करते हैं जिनकी पहली प्रविष्टि एक नोड ऑब्जेक्ट है:
[ADD,[MPY,5,x],3]
पेड़ों को आमतौर पर शाखाओं से पहले अलग नोड के साथ प्रदर्शित किया जाता है:
ADD[MPY[5,x],3]
LISP 2 आधारित जनरेटर कार्यों के साथ अनपर्सिंग
एक जनरेटर फ़ंक्शन (अनपेक्षित) => क्रिया> जोड़े का एक नामित सेट है ...
<NAME>(<unparse>)=><action>;
(<unparse>)=><action>;
...
(<unparse>)=><action>;
विषम अभिव्यक्तियाँ ऐसे परीक्षण हैं जो पेड़ के पैटर्न और / या वस्तु प्रकारों से मेल खाती हैं और उन्हें अलग करती हैं और उन भागों को स्थानीय चर को संसाधित करने के लिए इसकी प्रक्रियात्मक कार्रवाई द्वारा निर्दिष्ट करती हैं। विभिन्न तर्क प्रकारों को लेते हुए एक अतिभारित फ़ंक्शन की तरह। सिवाय () => ... परीक्षणों के क्रम में कोड किए गए हैं। पहली सफल अनपेक्षित अपनी इसी क्रिया को अंजाम देती है। अनपेक्षित अभिव्यक्तियाँ परीक्षण विहीन हैं। ADD [x, y] दो शाखाओं से मेल खाता है ADD ट्री अपनी शाखाओं को स्थानीय चर x और y को सौंपता है। कार्रवाई एक साधारण अभिव्यक्ति हो सकती है या एक .BEGIN ...। बाउंड कोड ब्लॉक। मैं आज सी शैली {...} ब्लॉकों का उपयोग करूंगा। पेड़ मिलान, [], अनुचित नियम कार्रवाई के लिए लौटे परिणाम (ओं) को पारित करने वाले जनरेटर को बुला सकते हैं:
expr_gen(ADD[expr_gen(x),expr_gen(y)])=> x+y;
विशेष रूप से उपरोक्त expr_gen अनपेक्षित दो शाखा ADD ट्री से मेल खाता है। परीक्षण पैटर्न के भीतर एक पेड़ शाखा में रखा गया एक भी तर्क जनरेटर उस शाखा के साथ बुलाया जाएगा। इसकी तर्क सूची हालांकि स्थानीय चर निर्दिष्ट वस्तुएं हैं। अनपेक्षित के ऊपर एक दो शाखा निर्दिष्ट होती है ADD ट्री डिस्सैम्प, प्रत्येक शाखा को expr_gen को दबाने वाली पुनरावर्ती। बाईं शाखा वापसी को स्थानीय चर x में रखा गया। इसी तरह वापसी शाखा को yr रिटर्न ऑब्जेक्ट के साथ expr_gen को दिया गया। ऊपर एक संख्यात्मक अभिव्यक्ति मूल्यांकनकर्ता का हिस्सा हो सकता है। वैक्टर नाम के शॉर्टकट फीचर्स थे जो नोड स्ट्रिंग के बजाय ऊपर थे, एक वेक्टर के नोड्स को इसी क्रिया के वेक्टर के साथ इस्तेमाल किया जा सकता था:
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);
उपरोक्त अधिक पूर्ण अभिव्यक्ति मूल्यांकक expr_gen की बाईं शाखा से x पर लौटाता है और दाईं शाखा से y तक। एक्स और वाई पर किए गए संबंधित एक्शन वेक्टर वापस आ गए। अंतिम अनपेक्षित => एक्शन जोड़े संख्यात्मक और प्रतीक वस्तुओं से मेल खाते हैं।
प्रतीक और प्रतीक गुण
प्रतीकों का नाम विशेषता हो सकता है। वैल: (x) x में निहित प्रतीक ऑब्जेक्ट की वैल विशेषता तक पहुँचता है। एक सामान्यीकृत प्रतीक तालिका स्टैक SLIC का हिस्सा है। SYMBOL तालिका को धक्का दिया जा सकता है और कार्यों के लिए स्थानीय प्रतीक प्रदान किया जा सकता है। नव निर्मित प्रतीक को शीर्ष प्रतीक तालिका में सूचीबद्ध किया गया है। सिंबल लुकअप शीर्ष तालिका से पहले स्टैक के नीचे प्रतीक तालिका स्टैक को खोजता है।
मशीन स्वतंत्र कोड जनरेट करना
SLIC की जनरेटर भाषा PSEUDO निर्देश ऑब्जेक्ट का उत्पादन करती है, जो उन्हें एक कोड कोड सूची में जोड़ देती है। A .FLUSH अपनी PSEUDO कोड सूची को प्रत्येक PSEUDO निर्देश को सूची से हटाने और इसे कॉल करने के लिए चलाने का कारण बनता है। निष्पादन के बाद एक PSEUDO ऑब्जेक्ट्स मेमोरी जारी की जाती है। PSEUDO और जनरेटर कार्यों की प्रक्रियात्मक निकाय मूल रूप से अपने आउटपुट को छोड़कर एक ही भाषा है। PSEUDO को असेंबली मैक्रोज़ के रूप में कार्य करने के लिए कहा जाता है जो मशीन को स्वतंत्र कोड अनुक्रमिकता प्रदान करता है। वे पेड़ रेंगने वाले जनरेटर भाषा से बाहर विशिष्ट लक्ष्य मशीन का एक पृथक्करण प्रदान करते हैं। PSEUDO MACHOP फ़ंक्शन को आउटपुट मशीन कोड में कहते हैं। MACHOPs का उपयोग असेंबली छद्म ऑप्स को परिभाषित करने के लिए किया जाता है (जैसे dc, कॉन्स्टेंट आदि को परिभाषित करना) और मशीन इंस्ट्रक्शन या एक परिवार जैसे कि वॉन्टेड एंट्री का उपयोग करके निर्देश दिया जाता है। वे बस निर्देश बनाने के लिए अपने मापदंडों को बिट क्षेत्रों के अनुक्रम में बदल देते हैं। MACHOP कॉल असेंबली की तरह दिखती हैं और जब कंपाइल लिस्टिंग में असेंबली दिखाई जाती है तो उसके लिए खेतों की प्रिंट फॉर्मेटिंग प्रदान करती है। उदाहरण कोड में मैं c शैली टिप्पणी का उपयोग कर रहा हूं जिसे आसानी से जोड़ा जा सकता है लेकिन मूल भाषाओं में नहीं था। MACHOPs एक बिट एड्रेसेबल मेमोरी में कोड तैयार कर रहे हैं। SLIC लिंकर कंपाइलर का आउटपुट हैंडल करता है। डीईसी -10 उपयोगकर्ता मोड निर्देश के लिए एक MACHOP vectored प्रविष्टि का उपयोग कर: MACHOPs एक बिट एड्रेसेबल मेमोरी में कोड तैयार कर रहे हैं। SLIC लिंकर कंपाइलर का आउटपुट हैंडल करता है। डीईसी -10 उपयोगकर्ता मोड निर्देश के लिए एक MACHOP vectored प्रविष्टि का उपयोग कर: MACHOPs एक बिट एड्रेसेबल मेमोरी में कोड तैयार कर रहे हैं। SLIC लिंकर कंपाइलर का आउटपुट हैंडल करता है। डीईसी -10 उपयोगकर्ता मोड निर्देश के लिए एक MACHOP vectored प्रविष्टि का उपयोग कर:
.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; ऑक्टल में 18 बिट्स के $ 36 / शब्द शब्द पते के स्थान को 36 बिट सीमा पर स्थान संरेखित करता है। 9 बिट opcd, 4 बिट रजिस्टर, अप्रत्यक्ष बिट और 4 बिट इंडेक्स रजिस्टर संयुक्त हैं और मुद्रित हैं जैसे कि एक एकल 18 बिट फ़ील्ड। 18 बिट पता / 36 या तत्काल मूल्य आउटपुट है और ऑक्टल में मुद्रित होता है। एक MOVEI उदाहरण r1 = 1 और r2 = 2 के साथ प्रिंट आउट:
400020 201082 000005 MOVEI r1,5(r2)
कंपाइलर असेंबली ऑप्शन के साथ आपको कंपाइल लिस्टिंग में जनरेट असेंबली कोड मिलता है।
इसे एक साथ लिंक करें
एसएलआईसी लिंकर को एक पुस्तकालय के रूप में आपूर्ति की जाती है जो लिंकिंग और प्रतीक प्रस्तावों को संभालती है। लक्ष्य विशेष आउटपुट लोड फ़ाइल स्वरूपण हालांकि लक्ष्य मशीनों के लिए लिखा जाना चाहिए और लिंकर लाइब्रेरी लाइब्रेरी के साथ जोड़ा जाना चाहिए।
जनरेटर की भाषा एक फ़ाइल में पेड़ों को लिखने और उन्हें पढ़ने के लिए एक मल्टीपास कंपाइलर को लागू करने की अनुमति देने में सक्षम है।
कोड पीढ़ी और उत्पत्ति की लघु गर्मी
मैं यह सुनिश्चित करने के लिए कोड पीढ़ी से पहले चला गया हूं कि यह समझा जाता है कि SLIC एक वास्तविक संकलक था। एसएलआईसी 1960 के दशक के अंत में सीडब्ल्यूआईसी (कंपाइलर फॉर राइटिंग एंड इंप्लीमेंटिंग कंपाइलर) द्वारा विकसित किया गया था। CWIC में केवल SYNTAX और GENERATOR भाषाएँ थीं, जो GENERATOR की भाषा में सांख्यिक बाइट कोड का उत्पादन करती थीं। बाइट कोड रखा गया था या नामांकित वर्गों के साथ जुड़े मेमोरी बफ़र्स में (CWIC प्रलेखन में प्रयुक्त शब्द) को एक .FLUSH स्टेटमेंट द्वारा लिखा गया था। सीडब्ल्यूआईसी पर एक एसीएम पेपर एसीएम अभिलेखागार से उपलब्ध है।
एक प्रमुख प्रोग्रामिंग भाषा को सफलतापूर्वक लागू करना
1970 के दशक के अंत में SLIC का उपयोग COBOL क्रॉस कंपाइलर लिखने के लिए किया गया था। लगभग 3 महीने में पूरा हो गया ज्यादातर एक प्रोग्रामर द्वारा। मैंने आवश्यकतानुसार प्रोग्रामर के साथ थोड़ा काम किया। एक अन्य प्रोग्रामर ने लक्ष्य TI-990 मिनी-कंप्यूटर के लिए रनटाइम लाइब्रेरी और MACHOPs लिखा। उस COBOL कंपाइलर ने असेंबली में काफी अधिक लाइनें संकलित कीं, फिर DEC-10 देशी COBOL कंपाइलर को असेंबली में लिखा गया।
एक संकलक के लिए अधिक तो आमतौर पर के बारे में बात की
खरोंच से एक कंपाइलर लिखने का एक बड़ा हिस्सा रन टाइम लाइब्रेरी है। आपको एक प्रतीक तालिका की आवश्यकता है। आपको इनपुट और आउटपुट चाहिए। डायनेमिक मेमोरी मैनेजमेंट आदि यह आसानी से एक कंपाइलर के लिए रनटाइम लाइब्रेरी लिखने और फिर कंपाइलर लिखने के काम आ सकता है। लेकिन एसएलआईसी के साथ कि रनटाइम लाइब्रेरी एसएलआईसी में विकसित सभी कंपाइलरों के लिए आम है। ध्यान दें कि दो रनटाइम लाइब्रेरी हैं। भाषा की एक (उदाहरण के लिए COBOL) लक्ष्य मशीन। अन्य संकलक रनटाइम लाइब्रेरी है।
मुझे लगता है कि मैंने स्थापित किया है कि ये पार्सर जनरेटर नहीं थे। इसलिए अब बैक एंड की थोड़ी समझ के साथ मैं पार्सर प्रोग्रामिंग लैंग्वेज समझा सकता हूं।
पार्सर प्रोग्रामिंग भाषा
पार्सर को सरल समीकरणों के रूप में लिखे गए सूत्र का उपयोग करके लिखा जाता है।
<name> <formula type operator> <expression> ;
सबसे निचले स्तर पर भाषा का तत्व चरित्र है। टोकन भाषा के पात्रों के एक सबसेट से बनते हैं। चरित्र वर्णों का उपयोग उन वर्णों के नाम को परिभाषित और परिभाषित करने के लिए किया जाता है। वर्ण को परिभाषित करने वाला वर्ण बृहदान्त्र (:) वर्ण है। वर्ण जो वर्ग के सदस्य हैं, को परिभाषा के दाईं ओर कोडित किया गया है। मुद्रण योग्य वर्णों को 'एकल' स्ट्रिंग्स में संलग्न किया गया है। Nonprinting और विशेष वर्णों को उनके संख्यात्मक अध्यादेश द्वारा दर्शाया जा सकता है। क्लास के सदस्यों को एक विकल्प द्वारा अलग किया जाता है | ऑपरेटर। एक वर्ग सूत्र अर्धविराम के साथ समाप्त होता है। वर्ण वर्ग में पहले से परिभाषित वर्ग शामिल हो सकते हैं:
/* 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 पूर्वनिर्धारित है, लेकिन एक स्किप_क्लास को परिभाषित करने में ओवरराइड हो सकता है।
संक्षेप में: एक वर्ण वर्ग विकल्प की एक सूची है जो केवल एक चरित्र स्थिरांक, एक वर्ण का क्रम या पहले से परिभाषित वर्ण वर्ग हो सकता है। जैसा कि मैंने चरित्र वर्गों को लागू किया है: वर्ग सूत्र को एक वर्ग बिट मुखौटा सौंपा गया है। (ऊपर टिप्पणियों में दिखाया गया है) किसी भी अक्षर के शाब्दिक या क्रमिक होने वाले किसी भी वर्ग सूत्र को एक वर्ग बिट आवंटित किया जाता है। एक मुखौटा सम्मिलित वर्ग (एस) के क्लास मास्क (ओं) को एक साथ आवंटित बिट (यदि कोई हो) के साथ जोड़कर बनाया गया है। वर्ण वर्गों से एक वर्ग तालिका बनाई जाती है। एक चरित्र के अध्यादेश द्वारा अनुक्रमणित प्रविष्टि में बिट्स होते हैं जो चरित्र के वर्ग की सदस्यता का संकेत देते हैं। कक्षा परीक्षण इनलाइन किया जाता है। ईएक्स में चरित्र के क्रम के साथ एक IA-86 कोड उदाहरण वर्ग परीक्षण दिखाता है:
test byte ptr [eax+_classmap],dgt
द्वारा पीछा किया:
jne <success>
या
je <failure>
IA-86 निर्देश कोड उदाहरणों का उपयोग किया जाता है क्योंकि मुझे लगता है कि IA-86 निर्देश आज अधिक व्यापक रूप से ज्ञात हैं। अपने वर्ग के मुखौटे का मूल्यांकन करने वाला वर्ग नाम गैर-विनाशकारी रूप से है, जो वर्णिक (ईएक्सएक्स) वर्णों द्वारा अनुक्रमित कक्षा-तालिका के साथ है। एक गैर-शून्य परिणाम वर्ग सदस्यता को इंगित करता है। (EAX को अल (EAX के निम्न 8 बिट) को छोड़कर शून्य किया गया है जिसमें वर्ण है)।
इन पुराने कंपाइलरों में टोकन कुछ अलग थे। मुख्य शब्दों को टोकन के रूप में नहीं समझाया गया था। वे बस पार्सर भाषा में उद्धृत स्ट्रिंग स्थिरांक से मेल खाते थे। कोट किए गए तार सामान्य रूप से नहीं रखे जाते हैं। संशोधक का उपयोग किया जा सकता है। A + स्ट्रिंग का मिलान करता रहता है। (अर्थात + '-' एक अक्षर से मेल खाता है जब चरित्र सफल होता है), ऑपरेशन, (यानी, 'ई') स्ट्रिंग को टोकन में सम्मिलित करता है। पहला मैच होने तक SKIP_CLASS के प्रमुख पात्रों को छोड़ कर टोकन फॉर्मूला को व्हाइट स्पेस द्वारा नियंत्रित किया जाता है। ध्यान दें कि एक स्पष्ट स्किप_क्लास कैरेक्टर मैच स्किपिंग को रोक देगा जिससे स्किप को स्किप_क्लास कैरेक्टर के साथ शुरू किया जा सकेगा। स्ट्रिंग टोकन फार्मूला एक एकल उद्धरण क्विडड चरित्र या एक डबल उद्धृत स्ट्रिंग से मेल खाते स्किप_क्लास वर्णों को छोड़ देता है। ब्याज एक "उद्धृत स्ट्रिंग के भीतर" वर्ण का मिलान है:
string .. (''' .ANY ''' | '"' $(-"""" .ANY | """""","""") '"') MAKSTR[];
पहला वैकल्पिक किसी एकल उद्धरण उद्धृत चरित्र से मेल खाता है। सही विकल्प एक दोहरे उद्धरण उद्धृत स्ट्रिंग से मेल खाता है जिसमें एक एकल "चरित्र का प्रतिनिधित्व करने के लिए एक साथ दो" चरित्र का उपयोग करते हुए दोहरे उद्धरण वर्ण शामिल हो सकते हैं। यह सूत्र अपनी परिभाषा में प्रयुक्त तारों को परिभाषित करता है। आंतरिक सही विकल्प '' '$' (- "" "" .ANY | "" "" "", "" "") "" एक दोहरे उद्धरण उद्धृत स्ट्रिंग से मेल खाता है। हम एक दोहरे उद्धरण "वर्ण" से मेल खाने के लिए एकल 'उद्धृत वर्ण का उपयोग कर सकते हैं। हालांकि दोहरे "उद्धृत स्ट्रिंग के भीतर यदि हम एक" वर्ण का उपयोग करना चाहते हैं तो हमें दो "वर्णों का उपयोग करना चाहिए। उदाहरण के लिए एक उद्धरण को छोड़कर किसी भी पात्र से मेल खाते हुए आंतरिक बाएँ विकल्प में:
-"""" .ANY
आगे एक नकारात्मक झांकना - "" "" का उपयोग किया जाता है जब सफल होता है ("वर्ण से मेल नहीं खा रहा होता है") तो .ANY वर्ण (जो "वर्ण नहीं हो सकता क्योंकि -" "" उस संभावना को समाप्त कर देता है)। सही विकल्प पर चल रहा है - "" "" एक "चरित्र से मेल खाता है और असफल होना सही विकल्प था:"
"""""",""""
दो एकल वर्णों के साथ उन्हें प्रतिस्थापित करने के लिए दो "वर्णों का मिलान करने की कोशिश करता है," "" "" "थ्व सिंगल" वर्ण डालने के लिए। दोनों आंतरिक विकल्प समापन स्ट्रिंग उद्धरण वर्ण से मेल खाते हैं और MAKSTR [] को एक स्ट्रिंग ऑब्जेक्ट बनाने के लिए बुलाया गया है। $ अनुक्रम, लूप, जबकि सफल, ऑपरेटर एक अनुक्रम के मिलान में उपयोग किया जाता है। टोकन सूत्र अग्रणी स्किप क्लास वर्ण (श्वेत स्थान) को छोड़ दें। एक बार पहला मैच होने के बाद स्किप_क्लास स्किपिंग अक्षम कर दी जाती है। हम [] का उपयोग करके अन्य भाषाओं में प्रोग्राम किए गए कार्यों को कॉल कर सकते हैं। [], MAKBIN [], MAKOCT [], MAKHEX [], MAKFLOAT [], और MAKINT [] को लाइब्रेरी फंक्शन की आपूर्ति की जाती है, जो एक मिलान टोकन स्ट्रिंग को एक टाइप की गई वस्तु में बदल देती है। नीचे दिया गया फॉर्मूला काफी जटिल टोकन पहचान को दिखाता है:
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
उपरोक्त संख्या टोकन सूत्र पूर्णांक और फ्लोटिंग पॉइंट संख्या को पहचानता है। - विकल्प हमेशा सफल होते हैं। गणना में संख्यात्मक वस्तुओं का उपयोग किया जा सकता है। सूत्र की सफलता पर टोकन ऑब्जेक्ट को पार्स स्टैक पर धकेल दिया जाता है। प्रतिपादक सीसा (+ 'E' | 'e', 'E') में दिलचस्प है। हम हमेशा MAKEFLOAT [] के लिए एक अपरकेस ई की इच्छा रखते हैं। लेकिन हम 'ई' की जगह एक कम केस 'ई' का इस्तेमाल करते हैं।
आपने वर्ण वर्ग और टोकन फॉर्मूला की संगति देखी होगी। पार्सिंग फॉर्मूला जारी है कि बैकट्रैकिंग विकल्प और ट्री कंस्ट्रक्शन ऑपरेटरों को जोड़ना। बैकट्रैकिंग और नॉन-बैकट्रैकिंग वैकल्पिक ऑपरेटरों को अभिव्यक्ति स्तर के भीतर नहीं मिलाया जा सकता है। आपके पास ((b। B \ c) गैर-बैकट्रैकिंग नहीं हो सकती है withe \ backtracking विकल्प। (a \ b \ c), (a | b | c) और ((a | b) \ c) मान्य हैं। ए \ बैकट्रैकिंग विकल्प पार्स स्थिति को उसके बाएं विकल्प का प्रयास करने से पहले बचाता है और विफलता पर सही विकल्प का प्रयास करने से पहले पार्स राज्य को पुनर्स्थापित करता है। विकल्पों के अनुक्रम में पहला सफल विकल्प समूह को संतुष्ट करता है। आगे के विकल्पों का प्रयास नहीं किया गया है। फैक्टरिंग और समूहीकरण एक निरंतर आगे बढ़ाने के लिए प्रदान करता है। इससे पहले कि वह अपने बाएं विकल्प का प्रयास करे, बैकट्रैक विकल्प पार्स की एक सहेजी हुई स्थिति बनाता है। जब पार्स आंशिक मैच कर सकता है और तब विफल हो जाता है, तो पीछे की आवश्यकता होती है:
(a b | c d)\ e
उपर्युक्त में यदि कोई रिटर्न विफलता वैकल्पिक सीडी का प्रयास करता है। यदि c c के बाद विफलता वापस आती है तो वैकल्पिक विकल्प का प्रयास किया जाएगा। यदि एक सफल और बी विफल हो जाता है तो पार्स वील को पीछे हटा दिया जाता है और ई प्रयास किया जाता है। इसी तरह एक असफल c सफल और b में विफल रहता है कि पार्स को पीछे हटा दिया गया है और वैकल्पिक e लिया गया है। Backtracking एक सूत्र के भीतर सीमित नहीं है। यदि कोई भी पार्सिंग फॉर्मूला किसी भी समय आंशिक मैच करता है और फिर विफल हो जाता है तो पार्स को शीर्ष बैकट्रैक और इसके विकल्प पर ले जाया जाता है। एक संकलित विफलता हो सकती है यदि कोड आउटपुट हो गया है तो बैकट्रैक बनाया गया था। संकलन शुरू करने से पहले एक बैकट्रैक सेट किया गया है। असफलता लौटना या उसमें पीछे आना एक संकलक विफलता है। बैकट्रैक ढेर हो गए हैं। हम नकारात्मक का उपयोग कर सकते हैं - और सकारात्मक? झांकना / आगे देखने के लिए परिचालकों के परीक्षण के बिना पार्स को आगे बढ़ाएं। स्ट्रिंग परीक्षण होना एक ऐसी झलक है जिसके आगे केवल इनपुट स्थिति को सहेजने और रीसेट करने की आवश्यकता है। आगे एक नज़र एक पार्सिंग अभिव्यक्ति होगी जो विफल होने से पहले एक आंशिक मैच बनाती है। आगे एक नज़र बैकट्रैकिंग का उपयोग करके लागू किया गया है।
Parser भाषा न तो LL या LR पार्सर है। लेकिन एक पुनरावर्ती सभ्य पार्सर लिखने के लिए एक प्रोग्रामिंग भाषा जिसमें आप पेड़ निर्माण का कार्यक्रम करते हैं:
:<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.
एक सामान्य रूप से प्रयुक्त पार्सिंग उदाहरण एक अंकगणितीय अभिव्यक्ति है:
Exp = Term $(('+':ADD|'-':SUB) Term!2);
Term = Factor $(('*':MPY|'/':DIV) Factor!2);
Factor = ( number
| id ( '(' +[Exp $(',' Exp)]+ ')' :FUN!2
| --)
| '(' Exp ')" )
(^' Factor:XPO!2 |--);
एक पाश का उपयोग करके एक्सप और टर्म एक बाएं हाथ का पेड़ बनाता है। सही पुनरावृत्ति का उपयोग करने वाला कारक एक दाहिने हाथ का पेड़ बनाता है:
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
यहाँ cc संकलक का एक सा है, c शैली टिप्पणियों के साथ SLIC का एक अद्यतन संस्करण। फ़ंक्शन प्रकार (व्याकरण, टोकन, चरित्र वर्ग, जनरेटर, PSEUDO, या MACHOP उनकी आईडी के बाद उनके प्रारंभिक सिंटैक्स द्वारा निर्धारित किए जाते हैं। इन टॉप-डाउन पार्सर के साथ आप एक प्रोग्राम को परिभाषित करने वाले सूत्र के साथ शुरू करते हैं:
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.
// ध्यान दें कि पेड़ बनाने के दौरान आईडी को कैसे बंद किया जाता है और बाद में संयुक्त किया जाता है।
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) "*/";
ध्यान दें कि कैसे पार्सर भाषा टिप्पणी और त्रुटि पुनर्प्राप्ति को संभालती है।
मुझे लगता है कि मैंने सवाल का जवाब दे दिया है। SLICs उत्तराधिकारी का एक बड़ा हिस्सा लिखने के बाद, cc भाषा अपने आप में यहाँ है। अभी तक इसके लिए कोई कंपाइलर नहीं है। लेकिन मैं इसे असेंबली कोड, नग्न asm c या c ++ फ़ंक्शन में संकलित कर सकता हूं।