Let’s Build a Compiler का पुनरावलोकन
(eli.thegreenplace.net)- 1988~1995 के बीच प्रकाशित Jack Crenshaw की ‘Let’s Build a Compiler’ ट्यूटोरियल को Python और WebAssembly के साथ फिर से बनाया गया एक प्रोजेक्ट
- मूल रूप में Pascal और Motorola 68000 Assembly का उपयोग होता था, लेकिन इस बार कोड को आधुनिक वातावरण में रन करने योग्य रूप में बदल दिया गया
- ट्यूटोरियल का मुख्य फोकस recursive-descent parser को खुद implement करना और शुरुआती चरण से ही वास्तविक assembly code generate करने की approach पर था
- Crenshaw का तरीका syntax-directed translation का उपयोग करता है, लेकिन type handling चरण में सीमाएँ दिखाता है
- इस पुनर्निर्माण का महत्व इस बात में है कि क्लासिक ट्यूटोरियल को आधुनिक डेवलपर्स के लिए सीधे रन करके experiment करने योग्य रूप में पुनर्जीवित किया गया है
क्लासिक ट्यूटोरियल का संदर्भ
- Jack Crenshaw की ‘Let’s Build a Compiler’ 1988~1995 के बीच जारी की गई एक compiler निर्माण परिचय पुस्तिका है, जिसे आज भी अक्सर reference के रूप में लिया जाता है
- original संस्करण Pascal में लिखा गया था और इसमें Motorola 68000 Assembly code output होता था
- 35 साल बाद 2025 में भी Hacker News जैसे प्लेटफॉर्म पर यह लगातार चर्चा में बनी रही
- लेखक ने पहली बार इस ट्यूटोरियल को 2003 में पढ़ा था और उस समय से प्रभावित रहे; 2025 में उन्होंने इसे Python और WebAssembly में port किया
Python और WebAssembly में पुनर्निर्माण
- केवल पढ़ने तक सीमित न रहकर, लेखक ने tutorial compiler को Python में port किया और output को WebAssembly (WASM) के रूप में generate करने के लिए implement किया
- परिणाम सार्वजनिक GitHub repo में उपलब्ध है: eliben/letsbuildacompiler
TUTORIAL.mdमें बताया गया है कि original के हर भाग को Python code में कैसे map किया गया है- उपयोगकर्ता original ट्यूटोरियल पढ़ते हुए directly executable code के साथ experiments कर सकता है
KISS भाषा उदाहरण और WASM output
- Crenshaw द्वारा डिज़ाइन की गई KISS भाषा के sample program को Python version compiler से compile करने का परिणाम दिखाया गया है
- उदाहरण में
procedure,whileloop, तथा value passing और reference passing शामिल हैं
- उदाहरण में
- निकलने वाली WASM text में by-reference parameter हैंडल करने वाली logic मौजूद है, जबकि optimization लगभग नहीं है
- ग्लोबल variable
Xकाmainसे implicit return होना testing convenience के लिए जोड़ा गया हिस्सा है - generated WASM code का उपयोग वास्तविक रन के जरिए expected परिणाम validate करने वाले tests में किया गया
ट्यूटोरियल की ताकत
- Crenshaw का ट्यूटोरियल चरण-दर-चरण recursive-descent parser बनाते हुए चलता है और जटिल theory की बजाय काम करने वाला code generation दिखाने पर केंद्रित रहता है
- उस समय
lexऔरyaccमानक माने जाते थे, लेकिन हाथ से लिखे गए parser की simplicity और clarity का असर बहुत बड़ा था - बाद के 20 सालों में लेखक का झुकाव manual recursive-descent parsing की तरफ हो गया
- उस समय
- साथ ही जब अधिकतर lectures parsing पर फोकस करते थे, Crenshaw ने शुरुआती स्तर से ही assembly code generation शामिल किया
सीमाएँ और सुधार की संभावनाएँ
- ट्यूटोरियल syntax-directed translation के तरीके से parsing के दौरान सीधे code generate करता है
- यह सीखने के लिए उपयोगी है, पर type जानकारी पहले से नहीं होने के कारण optimization करना कठिन हो जाता है
- खासकर type introduction के बाद, यानी part 14 के बाद, IR या AST जैसे structured तरीके की जरूरत साफ दिखने लगती है
- Crenshaw ने part 14 के बाद tutorial क्यों बंद किया, यह स्पष्ट नहीं है, लेकिन संभवतः इन सीमाओं से इसका संबंध रहा होगा
- लेखक के अनुसार part 14 को turning point मानकर पहले AST बनाना, फिर type checking और code generation करना बेहतर होता
निष्कर्ष
- मूल ट्यूटोरियल आज भी compiler निर्माण परिचय पुस्तिका के रूप में पढ़ने में सरलता और व्यवहारिकता के साथ मजबूत बना हुआ है
- यह Python·WASM संस्करण आधुनिक डेवलपर्स को पुरानी तकनीकों पर निर्भर हुए बिना सीखने के लिए एक बेहतर रूप देता है
- GitHub repo के माध्यम से कोई भी इसे आसान प्रयोग के लिए चला सकता है, और इसे compiler structure को hands-on तरीके से समझने वाली आधुनिक reinterpretation के रूप में देखा जा सकता है
1 टिप्पणियां
Hacker News की राय
मुझे यह ट्यूटोरियल पसंद आया कि यह frontend की बारीकियों में फँसे बिना शुरुआत से ही काम करने वाला assembly code जनरेट करता है
Ghuloum के approach की तरह, भाषा के बहुत छोटे हिस्से से शुरू करके पूरे सिस्टम को धीरे-धीरे बढ़ाने का तरीका खास तौर पर आकर्षक लगा
हाल में मिली एक अच्छी किताब यह लिंक है; हालाँकि C और x86 शुरुआती लोगों के लिए आदर्श target नहीं हैं, लेकिन पहला compiler बनाने के लिए यह शानदार सामग्री थी
संदर्भ के लिए Ghuloum का paper यहाँ है
पहले parsing सबसे अहम हिस्सा हुआ करती थी, इसलिए curriculum उसी हिसाब से बना, लेकिन आजकल ज़्यादा महत्वपूर्ण यह है कि language features को implement कैसे किया जाए
अब अगर आप खुद compiler बना रहे हों, तो “Claude, इस grammar के लिए recursive descent parser बना दो” कहने पर लगभग एक ही बार में नतीजा मिल जाता है
academia आम तौर पर layer आधारित सोचती है, जबकि practitioners pipe आधारित approach लेते हैं
layer तरीका build होने वाला code देता है, लेकिन उसे चलाना कठिन होता है; pipe तरीका चलाना आसान बनाता है, पर structure कमज़ोर रहता है
आखिरकार असली बात यह है कि development को executable न्यूनतम इकाइयों में बाँटा जाए
मुझे लगा इस लेख ने सच में मुद्दे के केंद्र को पकड़ा है
कॉलेज जाने से पहले से ही मुझे compilers में दिलचस्पी थी, और यह सामग्री सबसे सुलभ शुरुआती परिचय थी
17 साल की उम्र में recursive descent parser खुद बनाते हुए मुझे समझ आया कि जो समस्या जटिल लगती है, वह सही primitive में तोड़ने पर सरल हो जाती है
algorithms पर सामग्री बहुत है, लेकिन समस्याओं को primitives के ज़रिए कैसे पकड़ा जाए, इस पर सामग्री कम मिलती है
पहले yacc जैसे table-based parser मुख्यधारा में थे, लेकिन आज recursive descent ज़्यादा practical और flexible है
LLM code generation की वजह से यह approach और आसान हो गई है
सीखने वाले toy compiler में AST, IR, और optimization को छोड़कर सीधे code generation तक जाना भी काफ़ी उपयोगी हो सकता है
पहले कंपनी में C के subset को support करने वाला एक test tool बनाते समय हमने parser से code generate कराने के बजाय उसे executable data structure लौटाने दिया था
उदाहरण के लिए,
ForLoopStatementclass मेंtestExpressionहोता था, औरExecute()method में उसे सीधे call किया जाता थाFred Brooks की The Mythical Man-Month में भी इसका उल्लेख है
वैचारिक रूप से यह बहुत स्वाभाविक और साफ-सुथरा लगता है
यह व्याख्या रोचक लगी कि Jack Crenshaw का ट्यूटोरियल syntax-directed translation तरीका इस्तेमाल करता है
जिज्ञासा है कि क्या इसका मतलब सिर्फ single-pass compiler है, या यह इससे अधिक विशिष्ट अवधारणा है
यह तो समझ आता है कि statically typed language में type-based optimization कठिन होती है, लेकिन क्या type checking के स्तर पर भी कोई पाबंदी होती है?
लेकिन IR के बिना LICM, CSE, GVN जैसे advanced optimization संभव नहीं हैं
व्यक्तिगत रूप से मैं function-level 2-pass compilation पसंद करता हूँ — पहले pass में IR बनाओ, फिर तुरंत code generation करके state हटा दो; इससे तेज़ और efficient नतीजा मिलता है
single-pass compiler होने पर भी चरणों को अलग रखकर अंत में सिर्फ code generation किया जा सकता है
Crenshaw का ट्यूटोरियल व्यावहारिक स्तर तक तो नहीं पहुँचता, लेकिन अगर इसे precedence climbing technique से बढ़ाया जाए तो यह कहीं ज़्यादा उपयोगी हो जाता है
इस पर अच्छा लेख इस लिंक में है
मैंने “Let’s Build a Compiler” से जुड़े threads फिर से देखे
2007 से 2023 तक इसके कई HN रिकॉर्ड मिलते हैं
खास तौर पर Jack Crenshaw interview में comments नहीं हैं, फिर भी वह बहुत दिलचस्प पढ़ाई थी
अपने प्रोजेक्ट का परिचय और थोड़ा प्रचार: cwerg.org
यह Python और recursive descent parsing का उपयोग करता है, और frontend तथा backend को IR के ज़रिए अलग करता है
यह x86 और ARM के लिए ELF binaries बनाता है और असली उपयोग को लक्ष्य करता है
हालाँकि यह जटिल है और ट्यूटोरियल शैली में नहीं है
मुझे पुराने USENET के comp.compilers newsgroup में Jack Crenshaw का ट्यूटोरियल सीखने की याद है
जानकारी के लिए, वह group अभी भी सक्रिय है
आधुनिक compiler approach के लिए मैं यह Cornell blog post सुझाऊँगा
हर बार इसका उपयोग करने पर ऐसा लगता है जैसे किसी pyramid के ऊपर कुछ पत्थर और रख दिए हों
LLVM को backend की तरह इस्तेमाल करने वाली भाषाओं में आम तौर पर compile speed धीमी होती है
Zig इसे समझता है और अपना backend बना रहा है, जबकि Rust अब भी धीमे compilation से बँधा हुआ है
मुझे लगता है LLVM यह भ्रम पैदा करता है कि जटिलता अपने-आप गुणवत्ता की गारंटी है, और यह developer की स्वायत्तता को कम करने वाली तकनीक है
यह कुछ दूसरी लोकप्रिय technologies जैसी भी लगती है जिनके initials मिलते-जुलते हैं
मैंने भी कुछ इसी वजह से tiny-optimizing-compiler नाम का ट्यूटोरियल लिखा था
यह compiler के middle-end और backend पर केंद्रित एक संक्षिप्त उदाहरण है
GitHub लिंक
बचपन में मैं इस ट्यूटोरियल को प्रिंट करके साथ लेकर घूमता था और पढ़ता था
कम समय में compiler को पूरा बनते देखना सच में शानदार था
Beej’s Guide जैसी ऐसी सामग्री CS शिक्षा के सबसे मूल्यवान दस्तावेज़ों में से है, लेकिन इन्हें जितनी सराहना मिलनी चाहिए उतनी नहीं मिलती