Intro
คอมไพเลอร์ทั่วไปทำตามขั้นตอนต่อไปนี้:
- การแยกวิเคราะห์: ข้อความต้นฉบับจะถูกแปลงเป็นโครงสร้างไวยากรณ์นามธรรม (AST)
- ความละเอียดของการอ้างอิงไปยังโมดูลอื่น (C เลื่อนขั้นตอนนี้จนถึงการเชื่อมโยง)
- การตรวจสอบความหมาย: กำจัดข้อความที่ถูกต้องทางไวยากรณ์ซึ่งไม่สมเหตุสมผลเช่นรหัสที่ไม่สามารถเข้าถึงได้หรือการประกาศที่ซ้ำกัน
- การแปลงที่เท่าเทียมกันและการปรับให้เหมาะสมในระดับสูง: AST ถูกแปลงเพื่อแสดงการคำนวณที่มีประสิทธิภาพมากขึ้นด้วยความหมายเดียวกัน ซึ่งรวมถึงเช่นการคำนวณต้นของนิพจน์ย่อยทั่วไปและนิพจน์คงที่การกำจัดการมอบหมายในท้องถิ่นมากเกินไป (ดูSSA ) เป็นต้น
- การสร้างรหัส: AST ถูกแปลงเป็นรหัสระดับต่ำเชิงเส้นพร้อมการกระโดดการจัดสรรการลงทะเบียนและสิ่งที่คล้ายกัน การเรียกฟังก์ชั่นบางอย่างสามารถอินไลน์ได้ในขั้นตอนนี้บางลูปที่ไม่ได้ควบคุม ฯลฯ
- การเพิ่มประสิทธิภาพตาแมว: สแกนรหัสระดับต่ำเพื่อความไร้ประสิทธิภาพในท้องถิ่นที่ง่ายซึ่งจะถูกกำจัด
คอมไพเลอร์สมัยใหม่ส่วนใหญ่ (เช่น gcc และ clang) ทำซ้ำสองขั้นตอนสุดท้ายอีกครั้ง พวกเขาใช้ภาษาระดับกลางต่ำ แต่ไม่ขึ้นกับแพลตฟอร์มสำหรับการสร้างรหัสเริ่มต้น จากนั้นภาษานั้นจะถูกแปลงเป็นรหัสเฉพาะแพลตฟอร์ม (x86, ARM และอื่น ๆ ) ทำสิ่งเดียวกันโดยใช้แพลตฟอร์มที่ปรับให้เหมาะสมที่สุด ซึ่งรวมถึงเช่นการใช้คำแนะนำเวกเตอร์เมื่อเป็นไปได้คำสั่งการเรียงลำดับใหม่เพื่อเพิ่มประสิทธิภาพการทำนายสาขาและอื่น ๆ
หลังจากนั้นรหัสวัตถุก็พร้อมสำหรับการเชื่อมโยงแล้ว คอมไพเลอร์โค้ดเนทีฟส่วนใหญ่รู้วิธีเรียก linker เพื่อสร้างไฟล์ที่เรียกใช้งานได้ แต่ไม่ใช่ขั้นตอนการคอมไพล์ต่อ ในภาษาเช่นการเชื่อมโยง Java และ C # อาจเป็นแบบไดนามิกทั้งหมดทำโดย VM ที่เวลาโหลด
จดจำพื้นฐาน
- ทำให้มันใช้งานได้
- ทำให้สวย
- ทำให้มีประสิทธิภาพ
ลำดับคลาสสิกนี้ใช้กับการพัฒนาซอฟต์แวร์ทั้งหมด แต่มีการกล่าวซ้ำ ๆ
มีสมาธิในขั้นตอนแรกของลำดับ สร้างสิ่งที่ง่ายที่สุดที่อาจเป็นไปได้
อ่านหนังสือ!
อ่านDragon Bookโดย Aho และ Ullman นี่เป็นแบบคลาสสิคและยังคงใช้งานได้ดีในปัจจุบัน
การออกแบบคอมไพเลอร์สมัยใหม่ยังได้รับการยกย่อง
หากสิ่งนี้ยากเกินไปสำหรับคุณในตอนนี้ให้อ่าน intros แยกวิเคราะห์ก่อน โดยทั่วไปการแยกวิเคราะห์ไลบรารี่จะรวมถึง intros และตัวอย่าง
ตรวจสอบให้แน่ใจว่าคุณสะดวกสบายในการทำงานกับกราฟโดยเฉพาะต้นไม้ สิ่งเหล่านี้คือโปรแกรมสิ่งของที่ทำจากระดับตรรกะ
กำหนดภาษาของคุณได้ดี
ใช้เครื่องหมายใดก็ได้ที่คุณต้องการ แต่ให้แน่ใจว่าคุณมีคำอธิบายที่สมบูรณ์และสอดคล้องกับภาษาของคุณ ซึ่งรวมถึงทั้งไวยากรณ์และความหมาย
ถึงเวลาแล้วที่จะเขียนตัวอย่างโค้ดในภาษาใหม่ของคุณเป็นกรณีทดสอบสำหรับคอมไพเลอร์ในอนาคต
ใช้ภาษาที่คุณชื่นชอบ
มันโอเคที่จะเขียนคอมไพเลอร์ใน Python หรือ Ruby หรือภาษาใด ๆ ก็ตามที่ง่ายสำหรับคุณ ใช้อัลกอริทึมง่าย ๆ ที่คุณเข้าใจดี เวอร์ชันแรกไม่จำเป็นต้องเร็วหรือมีประสิทธิภาพหรือมีคุณสมบัติครบถ้วน จำเป็นต้องแก้ไขให้ถูกต้องและแก้ไขได้ง่าย
การเขียนคอมไพเลอร์เป็นภาษาต่าง ๆ ถ้าจำเป็น
เตรียมเขียนข้อสอบมากมาย
ภาษาทั้งหมดของคุณควรได้รับการคุ้มครองโดยกรณีทดสอบ อย่างมีประสิทธิภาพมันจะถูกกำหนดโดยพวกเขา ทำความคุ้นเคยกับกรอบการทดสอบที่คุณต้องการ เขียนข้อสอบตั้งแต่วันแรก เน้นการทดสอบ 'บวก' ที่ยอมรับรหัสที่ถูกต้องซึ่งต่างจากการตรวจจับรหัสที่ไม่ถูกต้อง
ทำการทดสอบทั้งหมดเป็นประจำ แก้ไขการทดสอบที่เสียหายก่อนดำเนินการต่อ มันน่าละอายที่จะจบลงด้วยภาษาที่ไม่เหมาะสมซึ่งไม่สามารถรับรหัสที่ถูกต้องได้
สร้างโปรแกรมแยกวิเคราะห์ที่ดี
เครื่องกำเนิดไฟฟ้าตัวแยกวิเคราะห์เป็นจำนวนมาก เลือกสิ่งที่คุณต้องการ คุณอาจเขียน parser ของคุณเองตั้งแต่เริ่มต้น แต่มันก็คุ้มค่าถ้าไวยากรณ์ของภาษาของคุณตายง่าย
โปรแกรมวิเคราะห์คำควรตรวจจับและรายงานข้อผิดพลาดทางไวยากรณ์ เขียนกรณีทดสอบจำนวนมากทั้งบวกและลบ ใช้รหัสที่คุณเขียนซ้ำในขณะที่กำหนดภาษา
ผลลัพธ์ของ parser ของคุณเป็นต้นไม้ที่เป็นนามธรรม
หากภาษาของคุณมีโมดูลผลลัพธ์ของ parser อาจเป็นการแสดงที่ง่ายที่สุดของ 'รหัสวัตถุ' ที่คุณสร้าง มีวิธีง่าย ๆ มากมายในการถ่ายโอนต้นไม้ไปยังไฟล์และโหลดกลับอย่างรวดเร็ว
สร้างตัวตรวจสอบความหมาย
ส่วนใหญ่ภาษาของคุณอาจช่วยให้โครงสร้างที่ถูกต้อง syntactically ที่อาจไม่มีเหตุผลในบริบทบางอย่าง ตัวอย่างคือการประกาศซ้ำของตัวแปรเดียวกันหรือผ่านพารามิเตอร์ประเภทที่ไม่ถูกต้อง ตัวตรวจสอบความถูกต้องจะตรวจสอบข้อผิดพลาดดังกล่าวดูที่แผนผัง
เครื่องมือตรวจสอบจะแก้ไขการอ้างอิงถึงโมดูลอื่น ๆ ที่เขียนในภาษาของคุณโหลดโมดูลอื่น ๆ เหล่านี้และใช้ในกระบวนการตรวจสอบ ตัวอย่างเช่นขั้นตอนนี้จะทำให้แน่ใจว่าจำนวนพารามิเตอร์ที่ส่งไปยังฟังก์ชันจากโมดูลอื่นถูกต้อง
อีกครั้งเขียนและเรียกใช้กรณีทดสอบจำนวนมาก กรณีเล็ก ๆ น้อย ๆ ที่ขาดไม่ได้ในการแก้ไขปัญหาที่ฉลาดและซับซ้อน
สร้างรหัส
ใช้เทคนิคที่ง่ายที่สุดที่คุณรู้ บ่อยครั้งที่มันเป็นการตกลงที่จะแปลโครงสร้างภาษาโดยตรง (เช่นif
คำสั่ง) ไปยังเท็มเพลตโค้ดที่มีค่าพารามิเตอร์เบา ๆ ซึ่งไม่เหมือนกับเท็มเพลต HTML
อีกครั้งให้ละเว้นประสิทธิภาพและมุ่งเน้นไปที่ความถูกต้อง
กำหนดเป้าหมาย VM ระดับต่ำที่ไม่ขึ้นกับแพลตฟอร์ม
ฉันสมมติว่าคุณไม่สนใจสิ่งที่อยู่ในระดับต่ำเว้นแต่คุณจะสนใจรายละเอียดเฉพาะของฮาร์ดแวร์ รายละเอียดเหล่านี้เต็มไปด้วยเลือดและซับซ้อน
ทางเลือกของคุณ:
- LLVM: ช่วยให้สามารถสร้างรหัสเครื่องได้อย่างมีประสิทธิภาพโดยปกติคือ x86 และ ARM
- CLR: เป้าหมาย. NET, ส่วนใหญ่ใช้ x86 / Windows; มี JIT ที่ดี
- JVM: ตั้งเป้าไปที่โลก Java ซึ่งค่อนข้างหลากหลายแพลตฟอร์มมี JIT ที่ดี
ละเว้นการเพิ่มประสิทธิภาพ
การเพิ่มประสิทธิภาพเป็นเรื่องยาก การเพิ่มประสิทธิภาพเกือบทุกครั้งเป็นสิ่งที่เกิดก่อนกำหนด สร้างรหัสที่ไม่มีประสิทธิภาพ แต่ถูกต้อง ใช้ภาษาทั้งหมดก่อนที่จะลองปรับรหัสผลลัพธ์ให้เหมาะสม
แน่นอนว่าการปรับให้เหมาะสมที่สุดนั้นน่ายินดีที่จะแนะนำ แต่หลีกเลี่ยงสิ่งที่มีไหวพริบและมีขนดกก่อนคอมไพเลอร์ของคุณจะเสถียร
แล้วอะไรล่ะ
หากสิ่งเหล่านี้ไม่ได้ข่มขู่คุณเกินไปโปรดดำเนินการต่อ! สำหรับภาษาที่เรียบง่ายแต่ละขั้นตอนอาจจะง่ายกว่าที่คุณคิด
การเห็น 'Hello world' จากโปรแกรมที่คอมไพเลอร์ของคุณสร้างขึ้นอาจคุ้มค่ากับความพยายาม