หมายเหตุ:เมื่อฉันใช้ "ซับซ้อน" ในชื่อเรื่องฉันหมายถึงนิพจน์มีตัวดำเนินการและตัวถูกดำเนินการจำนวนมาก ไม่ใช่ว่าการแสดงออกของตัวเองนั้นซับซ้อน
ฉันเพิ่งทำงานกับคอมไพเลอร์เรียบง่ายเพื่อประกอบ x86-64 ฉันได้เสร็จสิ้นการรวบรวมส่วนหน้าหลักของคอมไพเลอร์ - lexer และ parser - และตอนนี้ฉันสามารถสร้างการแสดงบทคัดย่อต้นไม้ไวยากรณ์ของโปรแกรมของฉัน และเนื่องจากภาษาของฉันจะถูกพิมพ์แบบสแตติกฉันกำลังทำขั้นตอนต่อไป: พิมพ์การตรวจสอบซอร์สโค้ด อย่างไรก็ตามฉันมีปัญหาและไม่สามารถแก้ไขด้วยตนเองได้อย่างสมเหตุสมผล
ลองพิจารณาตัวอย่างต่อไปนี้:
โปรแกรมแยกวิเคราะห์ของคอมไพเลอร์ของฉันได้อ่านบรรทัดของรหัสนี้:
int a = 1 + 2 - 3 * 4 - 5
และแปลงเป็น AST ต่อไปนี้:
=
/ \
a(int) \
-
/ \
- 5
/ \
+ *
/ \ / \
1 2 3 4
ตอนนี้จะต้องพิมพ์ตรวจสอบ AST มันเริ่มต้นด้วยการตรวจสอบ=
ผู้ประกอบการก่อน มันจะตรวจสอบด้านซ้ายมือของผู้ปฏิบัติงานก่อน จะเห็นว่าตัวแปรa
ถูกประกาศเป็นจำนวนเต็ม ดังนั้นตอนนี้ต้องตรวจสอบว่านิพจน์ทางด้านขวาประเมินเป็นจำนวนเต็ม
ผมเข้าใจวิธีนี้สามารถทำได้ถ้าการแสดงออกเป็นเพียงค่าเดียวเช่นหรือ1
'a'
แต่สิ่งนี้จะเกิดขึ้นได้อย่างไรสำหรับนิพจน์ที่มีค่าและตัวถูกดำเนินการหลายค่าซึ่งเป็นนิพจน์ที่ซับซ้อนเช่นที่กล่าวข้างต้น เมื่อต้องการกำหนดค่าของนิพจน์อย่างถูกต้องดูเหมือนว่าตัวตรวจสอบชนิดจะเกิดขึ้นจริงต้องดำเนินการแสดงออกและบันทึกผลลัพธ์ แต่นี่ดูเหมือนจะเอาชนะจุดประสงค์ของการแยกขั้นตอนการรวบรวมและการดำเนินการอย่างชัดเจน
วิธีเดียวที่ฉันคิดว่าสิ่งนี้สามารถทำได้คือการตรวจสอบใบไม้ซ้ำของแต่ละนิพจน์ย่อยใน AST และตรวจสอบว่าชนิดของใบไม้ทั้งหมดตรงกับประเภทของผู้ปฏิบัติงานที่คาดหวัง ดังนั้นเริ่มต้นจาก=
โอเปอเรเตอร์ตัวตรวจสอบชนิดจะสแกน AST ทางด้านซ้ายทั้งหมดและตรวจสอบว่าลีฟเป็นจำนวนเต็มทั้งหมด จากนั้นจะทำซ้ำสิ่งนี้สำหรับแต่ละโอเปอเรเตอร์ในนิพจน์ย่อย
ฉันได้ลองค้นคว้าหัวข้อในสำเนา"The Dragon Book" ของฉันแล้ว แต่ดูเหมือนจะไม่ได้ลงรายละเอียดมากนักและเพียงแค่ย้ำสิ่งที่ฉันรู้แล้ว
อะไรคือวิธีการปกติที่ใช้เมื่อคอมไพเลอร์คือการตรวจสอบประเภทของการแสดงออกที่มีผู้ประกอบการและตัวถูกดำเนินการหลาย มีวิธีใดบ้างที่ฉันกล่าวถึงข้างต้นใช้? ถ้าไม่เป็นเช่นนั้นวิธีการอะไรและพวกเขาจะทำงานอย่างไร
double a = 7/2
จะพยายามตีความทางด้านขวาเป็นสองเท่าดังนั้นจะพยายามตีความตัวเศษและส่วนเป็นสองเท่าและแปลงหากจำเป็น a = 3.5
ผลที่ตามมา ด้านล่างขึ้นจะดำเนินการส่วนจำนวนเต็มและแปลงเฉพาะเมื่อขั้นตอนสุดท้าย (ที่ได้รับมอบหมาย) a = 3.0
ดังนั้น
int a = 1 + 2 - 3 * 4 - 5
แต่ไปที่int a = 5 - ((4*3) - (1+2))