การออกแบบคอมไพเลอร์คืออะไร? ประเภท เครื่องมือก่อสร้าง ตัวอย่าง

⚡ สรุปอย่างชาญฉลาด

ขั้นตอนการทำงานของคอมไพเลอร์อธิบายถึงหกขั้นตอนที่แปลงโค้ดต้นฉบับให้เป็นโค้ดเครื่อง ได้แก่ การวิเคราะห์คำศัพท์ การวิเคราะห์ไวยากรณ์ การวิเคราะห์ความหมาย การสร้างโค้ดระดับกลาง การปรับปรุงโค้ดให้เหมาะสม และการสร้างโค้ด โดยได้รับการสนับสนุนจากการจัดการตารางสัญลักษณ์และการจัดการข้อผิดพลาด

  • 🔤 การวิเคราะห์คำศัพท์: เครื่องสแกนจะจัดกลุ่มตัวอักษรเป็นโทเค็นและบันทึกไว้ในตารางสัญลักษณ์
  • 🌳 การวิเคราะห์ไวยากรณ์: ตัวแยกวิเคราะห์จะตรวจสอบไวยากรณ์และสร้างแผนผังการแยกวิเคราะห์แบบลำดับชั้นจากโทเค็น
  • ✔️ การวิเคราะห์ความหมาย: ในขั้นตอนนี้ จะตรวจสอบความเข้ากันได้ของประเภทและความหมายโดยใช้โครงสร้างต้นไม้ทางไวยากรณ์
  • ⚙️ Code รุ่น: มีการสร้างโค้ดระดับกลาง ปรับแต่งให้เหมาะสม และสุดท้ายแปลงเป็นโค้ดเครื่องเป้าหมาย
  • 📋 ขั้นตอนการสนับสนุน: ตารางสัญลักษณ์และรูทีนการจัดการข้อผิดพลาดจะทำงานร่วมกับทุกขั้นตอนการคอมไพล์

ขั้นตอนการทำงานของคอมไพเลอร์ พร้อมตัวอย่าง: กระบวนการและขั้นตอนการคอมไพล์

การออกแบบคอมไพเลอร์มีขั้นตอนอะไรบ้าง?

A ผู้รวบรวม คอมไพเลอร์ทำงานในหลายขั้นตอน และแต่ละขั้นตอนจะแปลงโปรแกรมต้นฉบับจากรูปแบบหนึ่งไปเป็นอีกรูปแบบหนึ่ง แต่ละขั้นตอนจะรับอินพุตจากขั้นตอนก่อนหน้าและส่งเอาต์พุตไปยังขั้นตอนถัดไปของคอมไพเลอร์ คอมไพเลอร์มีทั้งหมด 6 ขั้นตอน แต่ละขั้นตอนช่วยในการแปลงภาษาโปรแกรมระดับสูงให้เป็นรหัสเครื่อง ขั้นตอนของคอมไพเลอร์มีดังนี้:

  1. การวิเคราะห์คำศัพท์
  2. การวิเคราะห์ไวยากรณ์
  3. การวิเคราะห์เชิงความหมาย
  4. เครื่องสร้างโค้ดระดับกลาง
  5. Code เพิ่มประสิทธิภาพ
  6. Code เครื่องกำเนิดไฟฟ้า

เฟสของคอมไพเลอร์

เฟสของคอมไพเลอร์

ขั้นตอนทั้งหมดนี้จะแปลงโค้ดต้นฉบับโดยการแบ่งออกเป็นโทเค็น สร้างแผนผังการวิเคราะห์ และปรับปรุงประสิทธิภาพของโค้ดต้นฉบับผ่านขั้นตอนต่างๆ

ระยะที่ 1: การวิเคราะห์คำศัพท์

การวิเคราะห์คำศัพท์เป็นขั้นตอนแรก เมื่อคอมไพเลอร์สแกนซอร์สโค้ด กระบวนการนี้สามารถดำเนินการจากซ้ายไปขวา ทีละตัวอักษร และจัดกลุ่มตัวอักษรเหล่านั้นเป็นโทเค็น

ในขั้นตอนนี้ กระแสอักขระจากโปรแกรมต้นฉบับจะถูกจัดกลุ่มเป็นลำดับที่มีความหมายโดยการระบุโทเค็น จากนั้นจะทำการบันทึกโทเค็นที่ตรงกันลงในตารางสัญลักษณ์และส่งโทเค็นนั้นไปยังขั้นตอนถัดไป

หน้าที่หลักของเฟสนี้คือ:

  • ระบุหน่วยคำศัพท์ในซอร์สโค้ด
  • จำแนกหน่วยคำศัพท์ออกเป็นคลาสต่างๆ เช่น ค่าคงที่ คำสงวน และบันทึกไว้ในตารางต่างๆ โดยจะไม่สนใจความคิดเห็นในโปรแกรมต้นฉบับ
  • ระบุโทเค็นที่ไม่ใช่ส่วนหนึ่งของภาษา

ตัวอย่าง: x = y + 10

เหรียญ ประเภท
X ระบุ
= ตัวดำเนินการมอบหมาย
Y ระบุ
+ ตัวดำเนินการเพิ่มเติม
10 จำนวน

ขั้นตอนที่ 2: การวิเคราะห์ไวยากรณ์

การวิเคราะห์ไวยากรณ์คือการค้นหาโครงสร้างในโค้ด โดยจะตรวจสอบว่าข้อความนั้นเป็นไปตามรูปแบบที่คาดหวังหรือไม่ เป้าหมายหลักของขั้นตอนนี้คือการตรวจสอบให้แน่ใจว่าโค้ดต้นฉบับที่โปรแกรมเมอร์เขียนนั้นถูกต้องหรือไม่

การวิเคราะห์ไวยากรณ์นั้นอิงตามกฎของภาษาโปรแกรมเฉพาะ โดยการสร้างแผนผังการวิเคราะห์ด้วยความช่วยเหลือของโทเค็น นอกจากนี้ยังกำหนดโครงสร้างของภาษาต้นฉบับและไวยากรณ์หรือโครงสร้างประโยกของภาษานั้นด้วย

ต่อไปนี้คือรายการของงานที่ดำเนินการในขั้นตอนนี้:

  • รับโทเค็นจากตัววิเคราะห์คำศัพท์
  • ตรวจสอบว่านิพจน์นั้นถูกต้องตามหลักไวยากรณ์หรือไม่
  • รายงานข้อผิดพลาดทางไวยากรณ์ทั้งหมด
  • สร้างโครงสร้างแบบลำดับชั้นที่เรียกว่า แผนผังการวิเคราะห์ (parse tree)

ตัวอย่าง

ตัวระบุ/ตัวเลขใดๆ ก็ตามถือเป็นนิพจน์ ถ้า x เป็นตัวระบุ และ y+10 เป็นนิพจน์ ดังนั้น x = y+10 จึงเป็นคำสั่ง ลองพิจารณาแผนผังการวิเคราะห์ไวยากรณ์สำหรับตัวอย่างต่อไปนี้:

(a+b)*c

ตัวอย่างการวิเคราะห์ไวยากรณ์

ในแผนผังโครงสร้างข้อมูล (Parse Tree):

  • โหนดภายใน: เรคอร์ดที่มีฟิลด์ตัวดำเนินการและฟิลด์ย่อยสองฟิลด์
  • Leaf: ระเบียนที่มี 2 ฟิลด์ขึ้นไป โดยฟิลด์หนึ่งสำหรับโทเค็น และอีกฟิลด์หนึ่งสำหรับข้อมูลอื่นๆ เกี่ยวกับโทเค็น
  • ตรวจสอบให้แน่ใจว่าส่วนประกอบต่างๆ ของโปรแกรมนั้นสอดคล้องกันอย่างมีความหมาย
  • รวบรวมข้อมูลประเภทและตรวจสอบความเข้ากันได้ของประเภท
  • ตรวจสอบว่าตัวดำเนินการนั้นได้รับอนุญาตจากภาษาต้นฉบับหรือไม่

ระยะที่ 3: การวิเคราะห์เชิงความหมาย

การวิเคราะห์เชิงความหมายจะตรวจสอบความสอดคล้องเชิงความหมายของโค้ด ใช้แผนผังไวยากรณ์ของเฟสก่อนหน้าพร้อมกับตารางสัญลักษณ์เพื่อตรวจสอบว่าซอร์สโค้ดที่กำหนดมีความสอดคล้องทางความหมาย นอกจากนี้ยังตรวจสอบว่าโค้ดสื่อความหมายที่เหมาะสมหรือไม่

ตัววิเคราะห์ความหมายจะตรวจสอบความไม่ตรงกันของชนิดข้อมูล ตัวดำเนินการที่ไม่เข้ากัน ฟังก์ชันที่เรียกใช้ด้วยอาร์กิวเมนต์ที่ไม่ถูกต้อง ตัวแปรที่ไม่ได้ประกาศ ฯลฯ

หน้าที่ของขั้นตอนการวิเคราะห์ความหมายมีดังนี้:

  • ช่วยให้คุณจัดเก็บข้อมูลประเภทที่รวบรวมได้ และบันทึกไว้ในตารางสัญลักษณ์หรือโครงสร้างต้นไม้ทางไวยากรณ์
  • อนุญาตให้คุณทำการตรวจสอบประเภทข้อมูล
  • ในกรณีที่ประเภทข้อมูลไม่ตรงกัน และไม่มีกฎการแก้ไขประเภทข้อมูลที่แน่ชัดซึ่งสอดคล้องกับการดำเนินการที่ต้องการ จะแสดงข้อผิดพลาดทางความหมาย
  • รวบรวมข้อมูลประเภทและตรวจสอบความเข้ากันได้ของประเภท
  • ตรวจสอบว่าภาษาต้นทางอนุญาตให้ใช้ตัวดำเนินการเหล่านั้นหรือไม่

ตัวอย่าง

float x = 20.2;
float y = x*30;

ในโค้ดข้างต้น ตัววิเคราะห์ความหมายจะแปลงค่าจำนวนเต็ม 30 เป็นค่าทศนิยม 30.0 ก่อนทำการคูณ

ระยะที่ 4: ระดับกลาง Code รุ่น

เมื่อขั้นตอนการวิเคราะห์ความหมายเสร็จสิ้น คอมไพเลอร์จะสร้างโค้ดระดับกลางสำหรับเครื่องเป้าหมาย ซึ่งแสดงถึงโปรแกรมสำหรับเงื่อนไขสัมบูรณ์บางประการtracเครื่องจักร t

รหัสระดับกลางอยู่ระหว่างภาษาโปรแกรมระดับสูงและภาษาโปรแกรมระดับเครื่อง รหัสระดับกลางนี้จำเป็นต้องถูกสร้างขึ้นในลักษณะที่ทำให้สามารถแปลงเป็นรหัสเครื่องเป้าหมายได้อย่างง่ายดาย

หน้าที่ของตัวกลาง Code รุ่น:

  • ควรสร้างมันขึ้นมาจากตัวแทนเชิงความหมายของโปรแกรมต้นฉบับ
  • เก็บค่าที่คำนวณได้ระหว่างกระบวนการแปล
  • ช่วยให้คุณแปลงโค้ดขั้นกลางเป็นภาษาเป้าหมายได้
  • ช่วยให้คุณรักษาลำดับความสำคัญของภาษาต้นฉบับไว้ได้
  • มันเก็บจำนวนตัวถูกดำเนินการที่ถูกต้องตามคำสั่งนั้น

ตัวอย่าง

ตัวอย่างเช่น:

total = count + rate * 5

รหัสกลางโดยใช้วิธีรหัสที่อยู่คือ:

t1 := int_to_float(5)
t2 := rate * t1
t3 := count + t2
total := t3

เฟส 5: Code การเพิ่มประสิทธิภาพ

ขั้นตอนต่อไปคือการปรับปรุงประสิทธิภาพของโค้ดระดับกลาง ขั้นตอนนี้จะลบโค้ดที่ไม่จำเป็นออกและจัดเรียงลำดับคำสั่งใหม่เพื่อให้โปรแกรมทำงานได้เร็วขึ้นโดยไม่สิ้นเปลืองทรัพยากร เป้าหมายหลักของขั้นตอนนี้คือการปรับปรุงโค้ดระดับกลางเพื่อให้ได้โค้ดที่ทำงานได้เร็วขึ้นและใช้พื้นที่น้อยลง

หน้าที่หลักของเฟสนี้คือ:

  • มันช่วยให้คุณกำหนดจุดสมดุลระหว่างความเร็วในการประมวลผลและความเร็วในการคอมไพล์ได้
  • ช่วยปรับปรุงระยะเวลาการทำงานของโปรแกรมเป้าหมาย
  • สร้างโค้ดที่กระชับขึ้น แต่ยังคงอยู่ในรูปแบบการแสดงผลระดับกลาง
  • ลบโค้ดที่ไม่สามารถเข้าถึงได้และกำจัดตัวแปรที่ไม่ใช้งานแล้ว
  • ลบคำสั่งที่ไม่เปลี่ยนแปลงออกจากลูป

ตัวอย่าง: พิจารณารหัสต่อไปนี้:

a = intofloat(10)
b = c * a
d = e + b
f = d

สามารถกลายเป็น:

b = c * 10.0
f = e + b

เฟส 6: Code รุ่น

Code การสร้างโค้ด (Generation) เป็นขั้นตอนสุดท้ายของกระบวนการคอมไพเลอร์ โดยจะรับข้อมูลจากขั้นตอนการปรับแต่งโค้ด (Code Optimization) และสร้างโค้ดเพจ (Page Code) หรือโค้ดออบเจ็กต์ (Object Code) ออกมาเป็นผลลัพธ์ วัตถุประสงค์ของขั้นตอนนี้คือการจัดสรรพื้นที่จัดเก็บและสร้างโค้ดเครื่องที่สามารถย้ายตำแหน่งได้ (Relocatable Machine Code)

นอกจากนี้ยังจัดสรรตำแหน่งหน่วยความจำสำหรับตัวแปรต่างๆ ด้วย คำสั่งในโค้ดระดับกลางจะถูกแปลงเป็นคำสั่งเครื่อง ขั้นตอนนี้จะแปลงโค้ดที่ปรับให้เหมาะสมหรือโค้ดระดับกลางให้เป็นภาษาเป้าหมาย

ภาษาเป้าหมายคือรหัสเครื่อง ดังนั้น ตำแหน่งหน่วยความจำและรีจิสเตอร์ทั้งหมดจึงถูกเลือกและจัดสรรในขั้นตอนนี้ รหัสที่สร้างขึ้นในขั้นตอนนี้จะถูกประมวลผลเพื่อรับอินพุตและสร้างเอาต์พุตที่คาดหวัง

ตัวอย่าง

a = b + 60.0 อาจแปลงเป็นค่าในรีจิสเตอร์ได้ดังนี้:

MOVF a, R1
MULF #60.0, R2
ADDF R1, R2

การจัดการตารางสัญลักษณ์

ตารางสัญลักษณ์ประกอบด้วยระเบียนสำหรับตัวระบุแต่ละตัว โดยมีฟิลด์สำหรับคุณลักษณะของตัวระบุ ส่วนประกอบนี้ช่วยให้คอมไพเลอร์ค้นหาระเบียนตัวระบุและเรียกใช้ได้อย่างรวดเร็ว นอกจากนี้ ตารางสัญลักษณ์ยังช่วยในการจัดการขอบเขตอีกด้วย ตารางสัญลักษณ์และตัวจัดการข้อผิดพลาดจะโต้ตอบกับทุกขั้นตอน และตารางสัญลักษณ์จะได้รับการอัปเดตตามไปด้วย

เกิดข้อผิดพลาดในการจัดการกิจวัตร

ในกระบวนการออกแบบคอมไพเลอร์ ข้อผิดพลาดอาจเกิดขึ้นได้ในทุกขั้นตอนดังต่อไปนี้:

  • ตัววิเคราะห์คำศัพท์: โทเค็นที่สะกดผิด
  • ตัววิเคราะห์ไวยากรณ์: วงเล็บหายไป
  • ตัวสร้างรหัสระดับกลาง: ตัวถูกดำเนินการไม่ตรงกันกับตัวดำเนินการ
  • Code เครื่องมือเพิ่มประสิทธิภาพ: เมื่อไม่สามารถเข้าถึงข้อความดังกล่าวได้
  • Code Generator: เมื่อหน่วยความจำเต็มหรือไม่ได้จัดสรรรีจิสเตอร์ที่เหมาะสม
  • ตารางสัญลักษณ์: เกิดข้อผิดพลาดเนื่องจากมีการประกาศตัวระบุหลายรายการ

ข้อผิดพลาดที่พบบ่อยที่สุด ได้แก่ ลำดับอักขระที่ไม่ถูกต้องในการสแกน ลำดับโทเค็นที่ไม่ถูกต้องในประเภท ข้อผิดพลาดเกี่ยวกับขอบเขต และการวิเคราะห์ความหมายที่ไม่ถูกต้อง

อาจพบข้อผิดพลาดได้ในขั้นตอนใดขั้นตอนหนึ่งข้างต้น หลังจากพบข้อผิดพลาดแล้ว ขั้นตอนดังกล่าวจำเป็นต้องจัดการกับข้อผิดพลาดเหล่านั้นเพื่อดำเนินการคอมไพล์ต่อไป ข้อผิดพลาดเหล่านี้จะต้องถูกรายงานไปยังตัวจัดการข้อผิดพลาด ซึ่งจะจัดการกับข้อผิดพลาดเพื่อดำเนินการคอมไพล์ต่อไป โดยทั่วไป ข้อผิดพลาดจะถูกรายงานในรูปแบบของข้อความ

คำถามที่พบบ่อย

ใช่แล้ว ผู้ช่วย AI สามารถอธิบายแต่ละขั้นตอนได้ tracอธิบายวิธีการแปลงโค้ดตัวอย่างเป็นโทเค็นและโครงสร้างต้นไม้การวิเคราะห์ไวยากรณ์ และชี้ให้เห็นจุดที่เกิดข้อผิดพลาดทางไวยากรณ์หรือความหมาย สื่อเหล่านี้มีประโยชน์ในการช่วยเรียนรู้ แต่ควรตรวจสอบคำอธิบายกับเนื้อหาในหลักสูตรด้วย

การเรียนรู้ของเครื่องสามารถทำนายได้ว่าขั้นตอนการปรับแต่งใดที่จะสร้างโค้ดที่เร็วที่สุดสำหรับโปรแกรมและเครื่องที่กำหนด ซึ่งเป็นการปรับแต่งที่แต่ก่อนต้องอาศัยการคาดเดาด้วยมือ อย่างไรก็ตาม คอมไพเลอร์ยังคงต้องรับประกันว่าโปรแกรมที่ได้รับการปรับแต่งแล้วจะทำงานเหมือนกับโปรแกรมต้นฉบับทุกประการ

ส่วนหน้า (front-end) ทำหน้าที่วิเคราะห์คำศัพท์ ไวยากรณ์ และความหมาย รวมถึงโค้ดระดับกลาง และขึ้นอยู่กับภาษาต้นฉบับ ส่วนหลัง (back-end) ทำหน้าที่เพิ่มประสิทธิภาพและการสร้างโค้ด และขึ้นอยู่กับเครื่องเป้าหมาย การแบ่งส่วนนี้ช่วยให้การเปลี่ยนเป้าหมายง่ายขึ้น

ไม่ การวิเคราะห์คำศัพท์ (การสแกน) จะจัดกลุ่มตัวอักษรเป็นโทเค็น ในขณะที่การวิเคราะห์ไวยากรณ์ (การวิเคราะห์โครงสร้างประโยค) จะจัดเรียงโทเค็นเหล่านั้นเป็นแผนผังไวยากรณ์ตามกฎไวยากรณ์ การวิเคราะห์คำศัพท์จะทำงานก่อนและส่งโทเค็นไปยังตัววิเคราะห์ไวยากรณ์

สรุปโพสต์นี้ด้วย: