Compiling และ Interpretation
| English | ไทย |
|---|---|
| compiler/kəmˈpaɪlə/ | compiler |
| interpreter/ɪnˈtɜːprɪtə/ | interpreter |
| lexical analysis/ˈleksɪkl əˈnæləsɪs/ | lexical analysis |
| tokens/ˈtəʊkənz/ | tokens |
| syntax analysis/ˈsɪntæks əˈnæləsɪs/ | syntax analysis |
| abstract syntax tree/ˈæbstrækt ˈsɪntæks triː/ | ต้นไม้ไวยากรณ์นามธรรม |
| syntax error/ˈsɪntæks ˈerə/ | ข้อผิดพลาดด้านไวยากรณ์ |
| semantic analysis/səˈmæntɪk əˈnæləsɪs/ | semantic analysis |
| code generation/kəʊd ˌdʒenəˈreɪʃn/ | code generation |
| code optimisation/kəʊd ˌɒptɪmaɪˈzeɪʃn/ | code optimisation |
บั๊กที่ทำให้ยานอวกาศพังพินาศ ซึ่งพบได้จากลูกน้ำ
- NASA's Mariner 1 ถูกทำลาย 293 วินาทีหลังการปล่อยใน 1962. ความล้มเหลวมักถูก blamed กับตัวอักษรผิดเพียงตัวเดียวในซอฟต์แวร์นำทาง
- เรื่องราวนี้ถูกเล่าซ้ำแล้วซ้ำเล่าเพราะมันเป็นความกลัวที่นักเขียนโปรแกรมทุกคนรู้จัก: คอมไพเลอร์แปลโปรแกรมที่บอกสิ่งที่คุณไม่ได้ตั้งใจอย่างสบายใจ
- คอมไพเลอร์ไม่ใช่กระบวนการเดียวแต่เป็นห้า และแต่ละขั้นตอนจับข้อผิดพลาดประเภทต่าง ๆ ได้ การรู้ว่าขั้นตอนไหนจับอะไร บอกให้คุณได้ว่าข้อผิดพลาดนั้นมาจากจุดใด
- บทเรียนนี้คือวิธีที่ อินเทอร์โพรเตอร์ รันโปรแกรมโดยไม่สร้างอะไรออกมา และห้าขั้นตอนที่ คอมไพเลอร์ ผ่านไป
วิธีที่อินเทอร์โพรเตอร์รันโปรแกรม
- อินเทอร์โพรเตอร์แปลและรันซอร์สโค้ด พร้อมกัน โดยทำทีละบรรทัด
- สำหรับแต่ละบรรทัด มันอ่านบรรทัด วิเคราะห์ ตรวจสอบชนิดข้อมูล แล้ว ดำเนินการทันที และข้ามไปยังบรรทัดถัดไป
- มันไม่สร้าง ไฟล์ที่ runnable ได้: การแปลมีอยู่เพียงในหน่วยความจำและถูกทิ้งไป นั่นคือจุดสำคัญตามหลักสูตรพอดี คือมันสามารถรันโปรแกรมได้โดยไม่ต้องสร้างเวอร์ชันที่แปลแล้ว
- มันรายงานข้อผิดพลาดทันทีเมื่อเจอบรรทัดที่ผิดและมักจะหยุด ซึ่งให้ feedback ที่รวดเร็วขณะพัฒนา ทุกครั้งที่รันจะทำการแปลใหม่ ดังนั้นจึงช้ากว่า และทั้งซอร์สโค้ดและอินเทอร์โพรเตอร์ต้องมีอยู่ด้วย

แปลครั้งเดียวแล้วเก็บไว้ หรือแปลแล้วรันแล้วลืม
An interpreter:
ทำงานทีบรรทัด รายงานข้อผิดพลาดเมื่อเจอ; ไม่มีการบันทึกเป็นไฟล์ اجرable และโดยทั่วไปจะช้ากว่า
Interpreter สามารถรันโปรแกรมโดยไม่ต้องสร้างเวอร์ชันที่แปลแล้วของมัน
การแปลมีอยู่ในหน่วยความจำเพียงอย่างเดียว ทีบรรทัด และถูกทิ้งไป นั่นคือเหตุผลที่ต้องมี Interpreter อยู่ทุกครั้งเมื่อรันโปรแกรม
ขั้นตอนที่ 1: การวิเคราะห์.lexical analysis
- การวิเคราะห์ lexical รวมตัวอักษรแต่ละตัวจากซอร์สโค้ดเข้าด้วยกันเป็น token: คำสำคัญ (keywords), ชื่อตัวแปร (identifiers), ตัวดำเนินการ (operators) และค่าคงที่ (literals)
- ช่องว่างและ_heading are discarded, since they have no meaning to the compiler, and identifiers are entered into a symbol table.
- ดังนั้น
total ← count * 2จึงกลายเป็นลำดับ token เป็น identifier, assignment, identifier, operator, literal Lexer ไม่รู้และไม่สนใจว่าสิ่งนั้นมีความหมายหรือไม่
Lexical analysis (the lexer) เปลี่ยน:
Lexer จัดกลุ่มตัวอักษรเป็น Token และลบช่องว่าง/คอมเมนต์ออก; Parsing สร้างต้นไม้
Lexical analysis จัดกลุ่มตัวอักษรซอร์คเป็น ____ และลบช่องว่างและคอมเมนต์ออก
คำสำคัญ, Identifier, Operator และ Literals Lexer ไม่ได้ตัดสินว่าลำดับนี้เป็นโปรแกรมที่ถูกต้องหรือไม่
ขั้นตอนที่ 2: การวิเคราะห์ syntax
- การวิเคราะห์ syntax หรือการ parse ตรวจสอบว่าลำดับ token เข้ากับ ไวยากรณ์ ของภาษาหรือไม่ และสร้าง abstract syntax tree เพื่อแสดงโครงสร้าง
- การขาดวงเล็บ, การขาด
ENDIFหรือการใช้คำสำคัญผิดตำแหน่งจะถูกจับที่นี่ นี่คือสิ่งที่เรียกว่า syntax error และเป็นเหตุผลที่คอมไพเลอร์สามารถรายงานได้โดยไม่ต้องรันโปรแกรมเลย

ไวยากรณ์ที่ parser ตรวจสอบ
ขั้นตอนที่ 3: การวิเคราะห์ semantic analysis
- การวิเคราะห์ semantic ตรวจสอบว่าโปรแกรมที่ถูกต้องตามหลักไวยากรณ์นั้น มีความหมายจริงหรือไม่: ตัวแปรทุกตัวต้องประกาศก่อนใช้ ชนิดข้อมูลทั้งสองฝั่งของการ assign ต้องเข้ากันได้ ฟังก์ชันถูกเรียกด้วยจำนวน arguments ที่ถูกต้อง
total ← "seven" * 2เป็น syntax ที่ดีเยี่ยมแต่เป็นความไร้สาระเพียงอย่างเดียว มีเพียงขั้นตอนนี้เท่านั้นที่จับมันได้- นี่คือความแตกต่างที่ข้อสอบทดสอบ: syntax คือ รูปแบบ, semantics คือ ความหมาย
ข้อใดต่อไปนี้ถูกตรวจสอบโดย Semantic analysis แทนที่จะเป็น Syntax analysis?
วงเล็บคือไวยากรณ์ ดังนั้น Syntax; ช่องว่างคือ Lexer; Register คือ Code Generation; Declaration และชนิดข้อมูลคือความหมาย
ขั้นตอนที่ 4 และ 5: การสร้างโค้ดและการปรับปรุงประสิทธิภาพ
- การสร้างโค้ด เดินผ่าน tree และ emit target machine code โดยเลือก registers และวาง layout ข้อมูล
- การปรับปรุงประสิทธิภาพ ปรับปรุงโค้ดนั้นโดยไม่เปลี่ยนสิ่งที่มันทำ: ลบงานที่ซ้ำซ้อน คำนวณ constant expressions此时 compile time และเรียงลำดับ instructions ให้เหมาะกับ pipeline
- ผลลัพธ์คือ ไฟล์ runnable แบบ standalone ที่รันได้โดยไม่ต้องมีคอมไพเลอร์

ห้าขั้นตอน และแต่ละขั้นจับสิ่งที่ขั้นก่อนหน้าจับไม่ได้
ขั้นตอนของการ Compiling
ดูว่า Compiler ทำอะไรกับซอร์คของคุณ แต่ละขั้นตอนส่งผลลัพธ์ไปยังขั้นตอนถัดไป — ตัวอักษรกลายเป็น Token, Token กลายเป็นต้นไม้, ต้นไม้กลายเป็นโค้ดเครื่องที่ถูกปรับแต่งแล้ว
จับคู่แต่ละขั้นตอนของ Compiler กับสิ่งที่มันทำ
แต่ละขั้นตอนแปลงโปรแกรมให้ก้าวหน้า更进一步: tokens, จากนั้น tree, จากนั้นตรวจสอบ, จากนั้นโค้ดที่ถูก Optimise แล้ว
เรียงลำดับขั้นตอนของ Compiler
Lexical → syntax → semantic → code generation → optimisation
Code optimisation มุ่งเน้นไปที่:
Optimisation ปรับปรุงโค้ดที่สร้าง出来 (Constant folding, ลบความซ้ำซ้อน, เรียงลำดับเพื่อ Pipeline)
ตัวอย่างที่คำนวณแล้ว: ขั้นตอนไหนจับข้อผิดพลาดอะไร
x ← 5 +: tokens ไม่เข้ากับ grammar มี operator แต่ไม่มี right operand ดังนั้น syntax analysisx ← y + 1ที่yไม่เคยถูก declare: รูปแบบดีแต่ความหมายไม่ดี ดังนั้น semantic analysisIF a > b THEN OUTPUT aที่ไม่มีENDIF: syntax analysis อีกครั้ง- โปรแกรมที่รันและ print ค่าเฉลี่ยผิด: ไม่มีขั้นตอนไหนจับได้ นั่นคือ logic error และมีการ test เท่านั้นที่หาได้ ชนขั้นตอนและอธิบายว่าทำไมขั้นตอนก่อนหน้าถึงปล่อยให้มันผ่าน
จับคู่แต่ละบรรทัดที่ผิดพลาดกับขั้นตอน Compiler ที่ตรวจจับมัน
ไวยากรณ์คือรูปแบบ, ความหมายคือเนื้อหา และข้อผิดพลาดทางตรรกะเป็นสิ่งที่ถูกต้องทั้งในรูปและเนื้อหาแต่ผิดเจตนา
ตัวอย่างที่คำนวณแล้ว: เปรียบเทียบผู้แปลทั้งสอง
- ให้ข้อแตกต่างสองประการระหว่างวิธีที่คอมไพเลอร์และอินเทอร์โพรเตอร์จัดการโปรแกรม [4]
- คอมไพเลอร์แปล ทั้ง programa ก่อนที่จะรันและสร้าง executable ซึ่ง luego runs without the compiler; an interpreter translates and executes one statement at a time and produces no executable, so the interpreter must be present every run.
- คอมไพเลอร์รายงาน ทั้งหมด ข้อผิดพลาดรวมกันหลังการแปล; อินเทอร์โพรเตอร์รายงาน ข้อผิดพลาดแรก เมื่อเจอบรรทัดนั้นแล้วหยุด
- คะแนนแต่ละข้อคือการจับคู่: บอกว่าอันหนึ่งทำอะไรและอีกอันทำอะไรแทน
คะแนนที่หลุดหายไป
- อินเทอร์โพรเตอร์สร้าง เวอร์ชันที่แปลแล้วไม่มี นั่นคือวลีที่หลักสูตรใช้และเป็นคะแนนที่มอบให้
- Lexer สร้าง tokens และ discard whitespace และ comments; มันไม่ตรวจสอบว่าโปรแกรมถูกต้องหรือไม่
- Syntax คือรูปแบบ, Semantics คือความหมาย ตัวแปรที่ไม่ được declare เป็น semantic error ไม่ใช่ syntax error
- Optimization ต้องไม่เปลี่ยน สิ่งที่โปรแกรมทำ เปลี่ยนแค่ความเร็วหรือความกระชับในการกระทำเท่านั้น
คุณเข้าใจแล้ว
- ** Interpreter (ตัวแปลภาษา)** จะแปลและดำเนินการคำสั่งทีละบรรทัด โดยไม่สร้างไฟล์ที่นำไปรันได้ (executable) และรายงานข้อผิดพลาดบรรทัดแรกทันที จากนั้นจะทำการแปลซ้ำทุกครั้งที่รัน
- การวิเคราะห์лексิก (lexical analysis) สร้าง ทोकèn (tokens) และทิ้งช่องว่างและคอมเมนต์; การวิเคราะห์ไวยากรณ์ (syntax analysis) ตรวจสอบไวยากรณ์และสร้าง ต้นไม้ไวยากรณ์นามธรรม (abstract syntax tree) เพื่อจับความผิดพลาดทางไวยากรณ์
- การวิเคราะห์ความหมาย (semantic analysis) ตรวจสอบความหมาย: การประกาศตัวแปร, ประเภทข้อมูล, จำนวนอาร์กิวเมนต์
- การสร้างโค้ด (code generation) ปล่อยโค้ดเครื่องและ การปรับปรุงประสิทธิภาพ (optimisation) ปรับปรุงให้ดีขึ้นโดยไม่เปลี่ยนพฤติกรรม เพื่อให้ได้ไฟล์ที่รันได้ด้วยตัวเอง