หนังสือที่ดีที่สุดที่จะตอบคำถามของคุณอาจเป็น: Cooper และ Torczon, "Engineering a Compiler," 2003. หากคุณมีสิทธิ์เข้าใช้ห้องสมุดมหาวิทยาลัยคุณควรยืมสำเนา
ในคอมไพเลอร์ผู้ผลิตเช่น llvm หรือ gcc นักออกแบบพยายามทุกวิถีทางเพื่อให้อัลกอริธึมด้านล่างโดยที่คือขนาดของอินพุต สำหรับการวิเคราะห์บางส่วนสำหรับขั้นตอน "การเพิ่มประสิทธิภาพ" ซึ่งหมายความว่าคุณต้องใช้การวิเคราะห์พฤติกรรมมากกว่าการสร้างรหัสที่ดีที่สุดอย่างแท้จริงnO(n2)n
lexer เป็นเครื่องสถานะ จำกัด ดังนั้นในขนาดของอินพุต (เป็นตัวอักษร) และสร้างกระแสของโทเค็นที่ส่งผ่านไปยังตัวแยกวิเคราะห์O ( n )O(n)O(n)
สำหรับคอมไพเลอร์หลายภาษาสำหรับหลาย ๆ ภาษาตัวแยกวิเคราะห์คือ LALR (1) และประมวลผลสตรีมโทเค็นในเวลาในจำนวนโทเค็นอินพุต ในระหว่างการแยกวิเคราะห์คุณมักจะต้องติดตามตารางสัญลักษณ์ แต่สำหรับหลายภาษาที่สามารถจัดการได้ด้วยตารางแฮช ("พจนานุกรม") การเข้าถึงพจนานุกรมแต่ละครั้งคือแต่บางครั้งคุณอาจต้องเดินผ่านสแต็กเพื่อค้นหาสัญลักษณ์ ความลึกของสแต็กคือโดยที่คือความลึกในการซ้อนของขอบเขต (ในภาษา C-like มีวงเล็บปีกกากี่ชั้นที่อยู่ข้างใน)O ( 1 ) O ( s ) sO(n)O(1)O(s)s
จากนั้นต้นไม้แยกวิเคราะห์จะ "แบน" ลงในกราฟควบคุมการไหล โหนดของกราฟการควบคุมการไหลอาจเป็นคำแนะนำ 3 ที่อยู่ (คล้ายกับภาษาแอสเซมบลี RISC) และขนาดของกราฟการควบคุมการไหลโดยทั่วไปจะเป็นแบบเชิงเส้นในขนาดของแผนภูมิการแยก
จากนั้นชุดของขั้นตอนการกำจัดความซ้ำซ้อนจะถูกนำไปใช้โดยทั่วไป (นี่มักเรียกว่า "การปรับให้เหมาะสม" แม้ว่าจะไม่ค่อยมีอะไรที่ดีที่สุดเกี่ยวกับผลลัพธ์ แต่เป้าหมายที่แท้จริงคือการปรับปรุงโค้ดให้มากที่สุดเท่าที่จะทำได้ภายในเวลาและข้อ จำกัด ด้านพื้นที่ที่เราวางไว้บนคอมไพเลอร์) ขั้นตอนการกำจัดซ้ำซ้อน โดยทั่วไปจำเป็นต้องมีการพิสูจน์ข้อเท็จจริงบางอย่างเกี่ยวกับกราฟการควบคุมการไหล พิสูจน์เหล่านี้มักจะทำโดยใช้การวิเคราะห์การไหลของข้อมูล การวิเคราะห์การไหลของข้อมูลส่วนใหญ่ได้รับการออกแบบเพื่อให้พวกเขามาบรรจบกันในผ่านกราฟการไหลโดยที่คือ (พูดโดยประมาณ) ความลึกในการซ้อนของลูปการวนและการผ่านกราฟการไหลใช้เวลาd O ( n ) nO(d)dO(n)โดยที่คือจำนวนคำแนะนำ 3-addressn
สำหรับการเพิ่มประสิทธิภาพที่ซับซ้อนยิ่งขึ้นคุณอาจต้องการทำการวิเคราะห์ที่ซับซ้อนมากขึ้น ณ จุดนี้คุณเริ่มทำงานในการแลกเปลี่ยน คุณต้องการให้อัลกอริทึมการวิเคราะห์ของคุณใช้เวลาน้อยกว่าO(n2)เวลาในขนาดของโฟลว์กราฟของโปรแกรมทั้งหมด แต่หมายความว่าคุณต้องทำโดยไม่มีข้อมูล (และโปรแกรมปรับปรุงการแปลง) ซึ่งอาจมีราคาแพงในการพิสูจน์ ตัวอย่างคลาสสิกของเรื่องนี้คือการวิเคราะห์นามแฝงซึ่งสำหรับหน่วยความจำคู่หนึ่งคุณต้องการพิสูจน์ว่าการเขียนสองรายการนั้นไม่สามารถกำหนดเป้าหมายตำแหน่งหน่วยความจำเดียวกันได้ (คุณอาจต้องการทำการวิเคราะห์นามแฝงเพื่อดูว่าคุณสามารถย้ายคำสั่งหนึ่งเหนือคำสั่งได้หรือไม่) แต่เพื่อให้ได้ข้อมูลที่ถูกต้องเกี่ยวกับนามแฝงคุณอาจต้องวิเคราะห์เส้นทางการควบคุมที่เป็นไปได้ทั้งหมดผ่านโปรแกรมซึ่งเป็นเลขชี้กำลังในจำนวนสาขา ในโปรแกรม (และอธิบายเป็นจำนวนโหนดในกราฟโฟลว์ควบคุม)
ต่อไปคุณจะได้รับการจัดสรรลงทะเบียน การจัดสรรการลงทะเบียนสามารถใช้ถ้อยคำเป็นปัญหาการระบายสีกราฟและการระบายสีกราฟด้วยจำนวนสีน้อยที่สุดเป็นที่รู้จักกันว่า NP-Hard ดังนั้นคอมไพเลอร์ส่วนใหญ่จึงใช้วิธีฮิวริสติกแบบโลภร่วมกับการลงทะเบียนหกโดยมีเป้าหมายในการลดจำนวนการหกลงทะเบียนให้ดีที่สุดเท่าที่จะทำได้ภายในเวลาอันสมควร
ในที่สุดคุณก็เข้าสู่การสร้างรหัส โดยทั่วไปการสร้างรหัสจะทำบล็อกพื้นฐานขั้นสูงสุดในเวลาที่บล็อกพื้นฐานคือชุดของโหนดกราฟการควบคุมการเชื่อมต่อเชิงเส้นที่มีรายการเดียวและทางออกเดียว สิ่งนี้สามารถจัดรูปแบบใหม่เป็นกราฟที่ครอบคลุมปัญหาที่กราฟที่คุณพยายามครอบคลุมคือกราฟการพึ่งพาของชุดคำแนะนำ 3 ที่อยู่ในบล็อกพื้นฐานและคุณพยายามคลุมด้วยกราฟชุดที่แสดงถึงเครื่องที่มีอยู่ คำแนะนำ ปัญหานี้เป็นเลขชี้กำลังในขนาดของบล็อกพื้นฐานที่ใหญ่ที่สุด (ซึ่งโดยหลักการแล้วอาจเป็นคำสั่งเดียวกับขนาดของโปรแกรมทั้งหมด) ดังนั้นจึงมักจะทำกับฮิวริสติกที่มีเซตย่อยเล็ก ๆ การตรวจสอบ