ล่ามสร้างรหัสเครื่องหรือไม่


42

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

ฉันมีภาษาที่เรียกว่า "Foobish" และคำหลักคือ

<OUTPUT> 'TEXT', <Number_of_Repeats>;

ดังนั้นถ้าฉันต้องการพิมพ์ไปยังคอนโซล 10 ครั้งฉันจะเขียน

OUTPUT 'Hello World', 10;

สวัสดี World.foobish- ไฟล์

ตอนนี้ฉันเขียนล่ามในภาษาที่ฉันเลือก - C # ในกรณีนี้:

using System;

namespace FoobishInterpreter
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            analyseAndTokenize(Hello World.foobish-file)//Pseudocode
            int repeats = Token[1];
            string outputString = Token[0];
            for (var i = 0; i < repeats; i++)
            {
                Console.WriteLine(outputString);
            }
        }
    }
}

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

คอมไพเลอร์จะสร้างภาษาเครื่องที่ทำงานบนฮาร์ดแวร์จริงหรือไม่?

ดังนั้นล่ามจึงไม่สร้างภาษาเครื่อง แต่คอมไพเลอร์ทำเพื่อการป้อนข้อมูลหรือไม่

ฉันมีความเข้าใจผิดใด ๆ ในวิธีการพื้นฐานที่คอมไพเลอร์และล่ามทำงานอย่างไร


21
คุณคิดว่าคอมไพเลอร์ C # ทำอะไร โดยพื้นฐานแล้วมันไม่ได้สร้างรหัสเครื่อง
Philip Kendall

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

@Giorgio: คุณหมายถึงเหมือน JIT เหรอ?
Robert Harvey

2
@RobertHarvey: ฉันหมายถึง Java Compiler (javac): เท่าที่ฉันรู้ว่ามันสร้าง bytecode สำหรับ JVM และอีกครั้ง AFAIK JIT ในภายหลัง (ที่รันไทม์) จะรวบรวมบางส่วนของไบต์ที่ใช้บ่อยในภาษาของเครื่อง
Giorgio

4
คอมไพเลอร์หมายถึงการแปล มันสามารถปล่อยทุกภาษา: c, ประกอบ, จาวาสคริปต์, รหัสเครื่อง
Esben Skov Pedersen

คำตอบ:


77

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

แต่วันนี้มีหลายรูปแบบในการใช้ "คอมไพเลอร์" และ "ล่าม" ตัวอย่างเช่น VB6 "คอมไพล์" เป็นรหัสไบต์ (รูปแบบของภาษาระดับกลาง ) ซึ่งจากนั้น "ตีความ" โดย VB Runtime กระบวนการที่คล้ายกันเกิดขึ้นใน C # ซึ่งสร้างCILซึ่งดำเนินการแล้วโดยJust-In-Time Compiler (JIT)ซึ่งในสมัยก่อนจะมีความคิดว่าเป็นล่าม คุณสามารถ "freeze-dry" เอาต์พุตของ JIT ลงในไบนารีที่ปฏิบัติการจริงได้โดยใช้NGen.exeซึ่งเป็นผลิตภัณฑ์ที่เป็นผลมาจากคอมไพเลอร์ในสมัยก่อน

ดังนั้นคำตอบสำหรับคำถามของคุณไม่ตรงไปตรงมาเหมือนครั้งก่อน

การอ่านเพิ่มเติม
Compilers vs. Interpreters บน Wikipedia


6
@Giorgio: ล่ามส่วนใหญ่ในปัจจุบันไม่ได้ใช้ซอร์สโค้ดจริง ๆ แต่เป็นการส่งออกของ AST หรือสิ่งที่คล้ายกัน คอมไพเลอร์มีกระบวนการที่คล้ายกัน ความแตกต่างนั้นไม่ใกล้เคียงกับที่คุณคิด
Robert Harvey

5
"คุณสามารถ" freeze-dry "เอาต์พุตของ JIT ไปยังไบนารีที่ปฏิบัติการจริงได้โดยใช้ NGen.exe ผลิตภัณฑ์ซึ่งจะเป็นผลมาจากคอมไพเลอร์ในสมัยก่อน": แต่วันนี้ยังเป็นผลลัพธ์ ของคอมไพเลอร์ (กล่าวคือคอมไพเลอร์ just-in-time) มันไม่สำคัญว่าเมื่อคอมไพเลอร์ทำงาน แต่สิ่งที่มันทำ คอมไพเลอร์รับเป็นตัวแทนของชิ้นส่วนของรหัสและส่งออกการเป็นตัวแทนใหม่ ล่ามจะแสดงผลลัพธ์ของการเรียกใช้งานโค้ดดังกล่าว นี่เป็นกระบวนการที่แตกต่างกันสองกระบวนการไม่ว่าคุณจะผสมกันอย่างไรและเมื่อคุณทำสิ่งใด
Giorgio

4
"คอมไพเลอร์" เป็นคำที่พวกเขาเลือกที่จะแนบกับ GCC พวกเขาเลือกที่จะไม่เรียกคอมไพเลอร์ของ NGen ถึงแม้ว่ามันจะสร้างรหัสเครื่องแทนที่จะเลือกที่จะแนบคำศัพท์นั้นกับขั้นตอนก่อนหน้านี้ซึ่งอาจเรียกได้ว่าล่ามแม้ว่าจะเป็นผู้สร้างรหัส (บางคนก็ทำเช่นนั้น) ประเด็นของฉันคือทุกวันนี้ไม่มีหลักการผูกมัดที่คุณสามารถเรียกให้เรียกคอมไพเลอร์หรือล่ามอย่างเด็ดขาดนอกจากนี้ "นั่นคือสิ่งที่พวกเขาเรียกมันเสมอ"
Robert Harvey

4
ตามความเข้าใจที่ จำกัด ของฉันไปทุกวันนี้ซีพียู x86 กำลังอยู่ในช่วงครึ่งทางของการเป็นเอ็นจิ้น JIT ที่ทำงานบนฮาร์ดแวร์อยู่แล้ว
Leushenko

4
@RobertHarvey ในขณะที่ฉันยอมรับว่าไม่มีเส้นแบ่งที่ชัดเจนระหว่างเทคนิคที่ใช้ในล่ามและคอมไพเลอร์จะมีการแบ่งหน้าที่ค่อนข้างชัดเจนในฟังก์ชั่น: ถ้าผลลัพธ์ของการดำเนินการเครื่องมือที่กำหนดด้วยรหัสของโปรแกรม โปรแกรมเครื่องมือเป็นล่าม หากผลลัพธ์คือผลลัพธ์ของการแปลของโปรแกรมในรูปแบบที่เป็นนามธรรมน้อยกว่ามันเป็นคอมไพเลอร์ หากผลการแปลเป็นรูปแบบที่เป็นนามธรรมมากขึ้นถ้า decompiler อย่างไรก็ตามกรณีที่มากกว่าหนึ่งในผลลัพธ์เหล่านี้ไม่ชัดเจน
จูลส์

34

บทสรุปที่ฉันให้ไว้ด้านล่างใช้ "คอมไพเลอร์หลักการเทคนิคและเครื่องมือ", Aho, Lam, Sethi, Ullman, (Pearson International Edition, 2007), หน้า 1, 2 ด้วยการเพิ่มแนวคิดบางอย่างของฉันเอง

ทั้งสองกลไกพื้นฐานสำหรับการประมวลผลโปรแกรมที่มีการรวบรวมและการตีความ

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

source program --> | compiler | --> target program

หากภาษาเป้าหมายเป็นรหัสเครื่องสามารถเรียกใช้งานได้กับโปรเซสเซอร์บางตัวโดยตรง:

input --> | target program | --> output

การรวบรวมเกี่ยวข้องกับการสแกนและแปลโปรแกรมอินพุตทั้งหมด (หรือโมดูล) และไม่เกี่ยวข้องกับการดำเนินการ

การตีความใช้เป็นอินพุตโปรแกรมต้นทางและอินพุตและสร้างเอาต์พุตของโปรแกรมต้นฉบับ

source program, input --> | interpreter | --> output

การตีความมักเกี่ยวข้องกับการประมวลผล (การวิเคราะห์และการดำเนินการ) โปรแกรมหนึ่งคำสั่งพร้อมกัน

ในทางปฏิบัติตัวประมวลผลภาษาจำนวนมากใช้การผสมผสานของสองวิธี เช่นโปรแกรม Java ถูกแปลเป็นครั้งแรก (เรียบเรียง) เป็นโปรแกรมระดับกลาง (รหัสไบต์):

source program --> | translator | --> intermediate program

ผลลัพธ์ของขั้นตอนนี้จะถูกดำเนินการ (ตีความ) โดยเครื่องเสมือน:

intermediate program + input --> | virtual machine | --> output

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

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

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

อย่างไรก็ตามการรวบรวมและตีความเป็นกระบวนการที่แตกต่างกันสองประเภทดังที่อธิบายไว้ในแผนภาพด้านบน

เพื่อตอบคำถามเบื้องต้น

คอมไพเลอร์จะสร้างภาษาเครื่องที่ทำงานบนฮาร์ดแวร์ทางกายภาพโดยตรง

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

ดังนั้นล่ามจึงไม่สร้างภาษาเครื่อง แต่คอมไพเลอร์ใช้สำหรับการป้อนข้อมูลหรือไม่

หากการสร้างคุณอ้างถึงเอาต์พุตแล้วคอมไพเลอร์จะสร้างโปรแกรมเป้าหมายซึ่งอาจเป็นภาษาเครื่องแปลภาษาไม่ได้


7
กล่าวอีกนัยหนึ่ง: ล่ามใช้โปรแกรม P และสร้างเอาท์พุท O, คอมไพเลอร์รับ P และสร้างโปรแกรม P output ที่เอาต์พุต O; ล่ามมักจะมีส่วนประกอบที่คอมไพเลอร์ (เช่นเพื่อ bytecode การเป็นสื่อกลางหรือคำสั่งเครื่อง JIT) และในทำนองเดียวกันผู้แปลอาจรวมถึงการแปล (เช่นสำหรับการประเมินการคำนวณเวลารวบรวม)
Jon Purdy

"ผู้แปลอาจรวมถึงล่าม (เช่นสำหรับการประเมินการคำนวณเวลารวบรวม)": จุดดี ฉันเดามาโคร Lisp และเทมเพลต C ++ อาจถูกประมวลผลล่วงหน้าด้วยวิธีนี้
Giorgio

ได้ง่ายรหัส C preprocessor คอมไพล์ C แหล่งที่มากับคำสั่ง CPP เป็น C defined A && !defined Bธรรมดาและมีล่ามนิพจน์บูลีนเช่น
Jon Purdy

@ JonPurdy ฉันจะเห็นด้วยกับเรื่องนี้ แต่ฉันจะเพิ่มคลาส "ล่ามแบบดั้งเดิม" ซึ่งไม่ได้ใช้การเป็นตัวแทนระดับกลางนอกเหนือจากรุ่นที่มาโทเค็น ตัวอย่างจะเป็น shell, BASIC จำนวนมาก, Lisp แบบคลาสสิก, Tcl ก่อนหน้า 8.0 และ bc
hobbs

1
@naxa - ดูคำตอบของ Lawrence และความคิดเห็นของ Paul Draper เกี่ยวกับประเภทของคอมไพเลอร์ แอสเซมเบลอร์เป็นคอมไพเลอร์ชนิดพิเศษที่ (1) ภาษาเอาต์พุตมีไว้สำหรับการเรียกใช้งานโดยตรงจากเครื่องจักรหรือเครื่องเสมือนและ (2) มีการโต้ตอบแบบหนึ่งต่อหนึ่งที่ง่ายมากระหว่างคำสั่งอินพุตและคำสั่งเอาต์พุต
จูลส์

22

คอมไพเลอร์จะสร้างภาษาเครื่อง

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

คอมไพเลอร์สามารถรวบรวมจากภาษาระดับสูงเป็นภาษาระดับสูง (เช่น GWT ซึ่งรวบรวม Java เป็น ECMAScript) จากภาษาระดับสูงเป็นภาษาระดับต่ำ (เช่น Gambit ซึ่งรวบรวม Scheme ถึง C) จากภาษาระดับสูงถึงรหัสเครื่อง (เช่น GCJ ซึ่งรวบรวม Java เป็นรหัสท้องถิ่น) จากภาษาระดับต่ำถึงภาษาระดับสูง (เช่น Clue ซึ่งรวบรวม C ถึง Java, Lua, Perl, ECMAScript และ Common เสียงกระเพื่อม) จากภาษาระดับต่ำถึงภาษาระดับต่ำ (เช่น Android SDK ซึ่งรวบรวม JVML bytecode ถึง Dalvik bytecode) จากภาษาระดับต่ำถึงรหัสเครื่อง (เช่นคอมไพเลอร์ C1X ซึ่งเป็นส่วนหนึ่งของ HotSpot ซึ่งรวบรวม JVML bytecode เป็นรหัสเครื่อง), รหัสเครื่องเป็นภาษาระดับสูง (เรียกว่า "decompiler" ใด ๆ เช่น Emscripten ซึ่งรวบรวมรหัสเครื่องจักร LLVM เป็น ECMAScript)รหัสเครื่องเป็นภาษาระดับต่ำ (เช่นคอมไพเลอร์ JIT ใน JPC ซึ่งรวบรวมรหัสเนทีฟ x86 เป็น JVML bytecode) และรหัสเนทีฟเป็นรหัสเนทีฟ (เช่นคอมไพเลอร์ JIT ใน PearPC ซึ่งรวบรวมรหัสเนทีฟ PowerPC เป็นรหัสเนทีฟ x86)

โปรดทราบด้วยว่า "รหัสเครื่อง" เป็นคำที่คลุมเครือจริงๆด้วยเหตุผลหลายประการ ตัวอย่างเช่นมี CPU ที่ใช้งานโค้ด JVM แบบดั้งเดิมและมีล่ามซอฟต์แวร์สำหรับรหัสเครื่อง x86 ดังนั้นอะไรที่ทำให้ "รหัสเครื่องดั้งเดิม" หนึ่งอัน แต่ไม่ใช่อีกรหัสหนึ่ง นอกจากนี้ทุกภาษาคือรหัสสำหรับเครื่องนามธรรมสำหรับภาษานั้น

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

  • หากภาษาAถูกมองว่าอยู่ในระดับเดียวกับ abstraction เท่ากับภาษาBคอมไพเลอร์อาจถูกเรียกว่าtranspiler (เช่น Ruby-to-ECMAScript-transpiler หรือ ECMAScript2015-to-ECMAScript5-transpiler)
  • หากการรับรู้ภาษาAอยู่ในระดับที่ต่ำกว่าระดับนามธรรมกว่าภาษาBคอมไพเลอร์อาจถูกเรียกว่าdecompiler (เช่น x86-machine-code-to-C-decompiler)
  • ถ้า language A == language Bคอมไพเลอร์อาจถูกเรียกว่าoptimizer , obfuscatorหรือminifier (ขึ้นอยู่กับหน้าที่เฉพาะของคอมไพเลอร์)

ซึ่งทำงานบนฮาร์ดแวร์ทางกายภาพโดยตรง

ไม่จำเป็น. มันอาจจะทำงานในล่ามหรือใน VM มันอาจจะถูกรวบรวมเป็นภาษาอื่นเพิ่มเติม

ดังนั้นล่ามจึงไม่สร้างภาษาเครื่อง แต่คอมไพเลอร์ใช้สำหรับการป้อนข้อมูลหรือไม่

ล่ามไม่ได้ผลิตอะไรเลย มันเพิ่งรันโปรแกรม

คอมไพเลอร์สร้างบางอย่าง แต่ไม่จำเป็นต้องเป็นภาษาเครื่องมันอาจเป็นภาษาใดก็ได้ มันอาจเป็นภาษาเดียวกันกับภาษาที่ป้อน! ตัวอย่างเช่น Supercompilers, LLC มีคอมไพเลอร์ที่ใช้จาวาเป็นอินพุตและสร้างจาวาที่ได้รับการปรับให้เหมาะสม มีคอมไพล์เลอร์ ECMAScript จำนวนมากซึ่งใช้ ECMAScript เป็นอินพุตและสร้าง ECMAScript ที่ปรับขนาดให้เล็กที่สุดและ obfuscated เป็นเอาต์พุตของพวกเขา


คุณอาจสนใจ:


16

ฉันคิดว่าคุณควรทิ้งความคิดของ "ผู้แปลและล่าม" อย่างสิ้นเชิงเพราะมันเป็นขั้วที่ผิดพลาด

  • คอมไพเลอร์เป็นหม้อแปลง : มันแปลงโปรแกรมคอมพิวเตอร์ที่เขียนในภาษาต้นฉบับและผลเทียบเท่าในภาษาเป้าหมาย โดยปกติแล้วภาษามาเป็นระดับที่สูงกว่าที่ภาษาเป้าหมาย - และถ้าหากมันเป็นวิธีอื่น ๆ ที่เรามักจะเรียกชนิดของหม้อแปลงที่Decompiler
  • ล่ามเป็นเครื่องมือดำเนินการ มันรันโปรแกรมคอมพิวเตอร์ที่เขียนในภาษาเดียวตามข้อกำหนดของภาษานั้น เราส่วนใหญ่ใช้คำสำหรับซอฟต์แวร์ (แต่ในทางใดก็ตามซีพียูแบบคลาสสิคสามารถดูได้เป็น "ล่าม" ที่ใช้ฮาร์ดแวร์สำหรับรหัสเครื่อง)

คำว่าส่วนรวมสำหรับการเขียนโปรแกรมภาษานามธรรมประโยชน์ในโลกแห่งความจริงคือการดำเนินการ

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

การดำเนินภาษาโปรแกรมเดียวสามารถเกี่ยวข้องกับจำนวนของคอมไพเลอร์และล่ามใด ๆมักจะอยู่ในหลายรูปแบบ (แบบสแตนด์อโลนบน the-fly) จำนวนใด ๆ ของเครื่องมืออื่น ๆ เช่นการวิเคราะห์แบบคงที่และเพิ่มประสิทธิภาพและจำนวนของการดำเนินการใด ๆ มันยังสามารถรวมการใช้งานทั้งหมดของภาษากลางจำนวนเท่าใดก็ได้ (ซึ่งอาจไม่เกี่ยวข้องกับภาษาที่กำลังนำมาใช้)

ตัวอย่างของแผนการใช้งานรวมถึง:

  • AC คอมไพเลอร์ที่แปลงรหัสเครื่อง C เป็น x86 และ x86 CPU ที่ประมวลผลรหัสนั้น
  • AC คอมไพเลอร์ที่แปลง C เป็น LLVM IR, คอมไพเลอร์แบ็กเอนด์ LLVM ที่แปลง LLVM IR เป็นรหัสเครื่อง x86 และซีพียู x86 ที่ประมวลผลรหัสนั้น
  • AC คอมไพเลอร์ที่แปลง C เป็น LLVM IR และล่าม LLVM ที่ดำเนินการ LLVM IR
  • คอมไพเลอร์ Java ที่แปลง Java เป็น JVM bytecode และ JRE พร้อมล่ามที่เรียกใช้งานโค้ดดังกล่าว
  • คอมไพเลอร์ Java ที่แปลง Java เป็น JVM bytecode และ JRE พร้อมทั้งล่ามที่ดำเนินการบางส่วนของรหัสนั้นและคอมไพเลอร์ที่แปลงส่วนอื่น ๆ ของรหัสนั้นเป็นรหัสเครื่อง x86 และ x86 CPU ที่ประมวลผลรหัสนั้น
  • คอมไพเลอร์ Java ที่แปลง Java เป็น JVM bytecode และ ARM CPU ที่เรียกใช้งานโค้ดดังกล่าว
  • คอมไพเลอร์ AC # ที่แปลง C # เป็น CIL, CLR ที่มีคอมไพเลอร์ที่แปลง CIL เป็นรหัสเครื่อง x86 และ x86 CPU ที่ประมวลผลรหัสนั้น
  • ล่ามทับทิมที่ดำเนินการทับทิม
  • สภาพแวดล้อม Ruby ที่มีทั้งล่ามที่เรียกใช้ Ruby และคอมไพเลอร์ที่แปลง Ruby เป็นรหัสเครื่อง x86 และ x86 CPU ที่ประมวลผลรหัสนั้น

... และต่อไป


+1 สำหรับการชี้ให้เห็นว่าแม้การเข้ารหัสที่ออกแบบมาสำหรับการเป็นตัวแทนระดับกลาง (เช่น java bytecode) สามารถมีการใช้งานฮาร์ดแวร์
จูลส์

7

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

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

ล่ามจะทำในสิ่งที่โปรแกรมของคุณควรทำ

ด้วยคำจำกัดความเหล่านี้สถานที่ที่มันคลุมเครือเป็นกรณีที่ผู้แปล / ล่ามของคุณสามารถคิดว่าทำสิ่งต่าง ๆ ขึ้นอยู่กับว่าคุณดูอย่างไร ตัวอย่างเช่น Python ใช้รหัส Python ของคุณและรวบรวมเป็น Python bytecode ที่คอมไพล์แล้ว หาก Python bytecode นี้ทำงานผ่านล่าม Python bytecode ก็จะทำสิ่งที่โปรแกรมของคุณควรจะทำ ในสถานการณ์ส่วนใหญ่ แต่นักพัฒนาหลามคิดว่าทั้งสองขั้นตอนเหล่านั้นจะถูกดำเนินการในขั้นตอนขนาดใหญ่เพื่อให้พวกเขาเลือกที่จะคิดว่าCPythonล่ามเป็นตีความ sourcecode ของพวกเขาและความจริงที่ว่ามันก็รวบรวมไปพร้อมกันถือว่าเป็นรายละเอียดการดำเนินงาน . ด้วยวิธีนี้มันเป็นเรื่องของมุมมอง


5

ต่อไปนี้เป็นความคิดที่เข้าใจง่ายระหว่างคอมไพเลอร์และล่าม

พิจารณา 3 ภาษา: ภาษาโปรแกรม , P (เขียนโปรแกรม) ภาษาโดเมน D (สำหรับสิ่งที่เกิดขึ้นกับโปรแกรมที่กำลังทำงาน); และภาษาเป้าหมาย , T (บางภาษาที่สาม)

แนวคิด

  • เรียบเรียงแปล P เพื่อ T เพื่อให้คุณสามารถประเมิน T (D); แต่ทว่า

  • ล่ามประเมิน P (D) โดยตรง


1
ล่ามที่ทันสมัยส่วนใหญ่ไม่ได้ประเมินภาษาต้นฉบับโดยตรง แต่เป็นการแสดงระดับกลางของภาษาต้นฉบับ
Robert Harvey

4
@ RobertHarvey นั่นไม่ได้เปลี่ยนความแตกต่างทางความคิดระหว่างเงื่อนไข
Lawrence

1
ดังนั้นสิ่งที่คุณอ้างถึงจริงๆในฐานะล่ามคือส่วนที่ประเมินค่าการนำเสนอระดับกลาง ส่วนที่สร้างการนำเสนอระดับกลางคือคอมไพเลอร์ตามคำจำกัดความของคุณ
Robert Harvey

6
@ RobertHarvey ไม่ได้จริงๆ ข้อกำหนดจะขึ้นอยู่กับระดับของนามธรรมที่คุณทำงานอยู่ หากคุณดูด้านล่างเครื่องมือสามารถทำอะไรก็ได้ โดยการเปรียบเทียบให้บอกว่าคุณไปต่างประเทศและพาบ็อบเพื่อนสองภาษามาด้วย หากคุณสื่อสารกับคนในท้องถิ่นด้วยการพูดคุยกับบ๊อบผู้ซึ่งจะพูดคุยกับคนในท้องถิ่นบ๊อบทำหน้าที่เป็นล่ามให้คุณ (แม้ว่าเขาจะเขียนด้วยภาษาของพวกเขาก่อนพูด) หากคุณถาม Bob เพื่อรับวลีและ Bob เขียนเป็นภาษาต่างประเทศและคุณสื่อสารกับคนในท้องถิ่นโดยอ้างอิงงานเขียนเหล่านั้น (ไม่ใช่ Bob) Bob ทำหน้าที่เป็นคอมไพเลอร์ให้คุณ
Lawrence

1
คำตอบที่ยอดเยี่ยม เร็ว ๆ นี้: ทุกวันนี้คุณอาจได้ยิน "transpiler" นั่นคือคอมไพเลอร์ที่ P และ T เป็นระดับที่ใกล้เคียงกันของนามธรรม (เช่น transpiler ES5 ถึง ES6)
Paul Draper
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.