แปลความหมายแล้วรวบรวม: ความแตกต่างที่มีประโยชน์?


29

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

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

ในความเป็นจริงการใช้งานส่วนใหญ่จะมาบรรจบกับกลยุทธ์พื้นฐานเดียวกัน คอมไพเลอร์สร้าง bytecode ซึ่งแปลหรือเรียบเรียงเป็นรหัสเนทีฟผ่าน JIT มันเป็นการผสมผสานระหว่างความคิดดั้งเดิมของการรวบรวมและการตีความ

ดังนั้นฉันถาม: มีความแตกต่างที่เป็นประโยชน์ระหว่างการใช้งานตีความและการใช้งานที่รวบรวมในวันนี้?


7
@DeadMG ไม่ใช่เรื่องใหม่อย่างที่คุณคิด: ประวัติโดยย่อของ just-in-time ...
yannis

4
@DeadMG เนื่องจากว่าภาษาใหม่ส่วนใหญ่ได้รับการแนะนำในช่วง 10 ปีที่ผ่านมาหรือส่วนใหญ่ทำงานบน VM บางประเภทฉันจะบอกว่าเขามีประเด็น แน่นอนว่ายังมี (และจะมีอีกหลายทศวรรษที่จะมาถึง) ภาษาที่รวบรวมเป็นรหัสภาษาและ JIT จะยังคงความหรูหรา (หรือไม่ถ้าพวก PyPy มีวิธีของพวกเขา) ใช่ฉันเป็นไปได้เกินจริง แต่ฉันยอมรับว่ากระแสหลัก (สำหรับตอนนี้และในอนาคตที่คาดการณ์ได้) ดูเหมือนจะเป็นคอมไพเลอร์ bytecode + อาจเป็น JIT

4
@DeadMG คุณต้องมีหนวดเครายาวสีขาวหากรุ่น VM เป็น "ใหม่" สำหรับคุณ P-codeได้รับการแนะนำในปี 1966 ก่อน IBM Aix เริ่มตั้งแต่ปี 1986
SK-logic

6
สิ่งต่าง ๆ เช่นกระสุนยูนิกซ์, Tcl และเหมือนกันจะถูกตีความอย่างหมดจดเสมอดังนั้นความแตกต่างทำให้รู้สึกอย่างน้อยใน CS วิชาการ แต่มันเป็นความจริงที่ว่าเมื่อผู้โค้ดโคลงเคลงกับล่ามและคอมไพเลอร์พวกเขาไม่ได้เข้าใจอะไรในกรณีส่วนใหญ่
SK-logic

3
@ SK-logic ฉันคิดว่าความคิดเห็นของคุณเป็นคำตอบที่ดีกว่าจากนั้นคำตอบใด ๆ ที่โพสต์จริง ๆ
Winston Ewert

คำตอบ:


23

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

ในทางกลับกันการคอมไพล์หมายถึงการแปลงโปรแกรมในภาษาหนึ่งเป็นภาษาอื่น โดยทั่วไปจะสันนิษฐานว่าเมื่อมีการคอมไพล์แล้วโค้ดจะถูกรวบรวมเป็นภาษา "ระดับล่าง" (เช่นรหัสเครื่อง, VM bytecode บางประเภท ฯลฯ ) รหัสที่รวบรวมนี้ยังคงถูกตีความในภายหลัง

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


3
ใช่โปรแกรมเมอร์ควรมีความเข้าใจพื้นฐาน แต่ฉันสงสัยว่าคำศัพท์ที่คอมไพล์หรือตีความแล้วไม่ได้เป็นไปตามนั้น
Winston Ewert

2
ขอขอบคุณ!! การตีความเป็นเพียงคำพ้องสำหรับ "ดำเนินการ" และนั่นคือวิธีที่โปรแกรมทั้งหมดทำงาน
Gardenhead

9

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

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

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

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

หากไม่มีล่ามเคอร์เนลคุณจะต้องบูตด้วย Lisp ที่มีอยู่เช่น SBCL

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

การแปลความหมาย: หินก้าวสำคัญในเส้นทางที่นำไปสู่การรวบรวม!


1
IMO นี่คือคำตอบที่ดีที่สุด ฉันทำงานด้วยภาษาของเล่นของตัวเองและย่อหน้าสุดท้ายอธิบายถึงวิธีการพัฒนาของฉัน มันทำให้การทำงานกับแนวคิดใหม่ง่ายขึ้นมาก +1 เช่นกันสำหรับการกล่าวถึงกระบวนการบูต CLISP
sinan

ในทางทฤษฎีภาษา "ตีความ" ใด ๆ ที่สามารถทำให้เป็น "รวบรวม" โดยการสร้างไฟล์ EXE ประกอบด้วยล่ามรวมทั้งรหัสที่มาหรือ bytecode สำหรับโปรแกรมตีความ แม้ว่าอาจจะไม่ได้ผลมากนัก
dan04

อ่านข้อมูลเกี่ยวกับวิธีที่ Wirth และ al คิดค้นรหัส P เพื่อให้ง่ายต่อการย้าย PASCAL ไปยังสถาปัตยกรรมเครื่องใหม่ นั่นคือในช่วงต้นปี 1970
John R. Strohm

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

1

ในความเป็นจริงการใช้งานหลายภาษายังคงตีความอย่างเคร่งครัดคุณอาจไม่ได้ตระหนักถึงพวกเขา หากต้องการตั้งชื่อไม่กี่: ภาษาเชลล์ UNIX, เชลล์ Windows cmd และ PowerScript, Perl, awk, sed, MATLAB, Mathematica และอื่น ๆ


3
ฉันเชื่อว่า Perl จะถูกรวบรวมภายใน bytecode และอย่างน้อย Mathematica ก็สามารถรวบรวมได้ และไม่มีอะไรสั่งการดำเนินการ awk และ sed (ฉันเชื่อว่าบางส่วนของ GNU coreutils รวบรวมการแสดงออกปกติเพื่อ จำกัด ออโตมาตาก่อนการประหารชีวิตซึ่งจะนำพวกเขาไปไว้ในหมวดหมู่

1
ที่จริงฉันค่อนข้างมั่นใจว่า Perl, MATLAB, Mathematica ทั้งหมดรวบรวมไปเป็น bytecode ฉันไม่คุ้นเคยกับ PowerScript คุณหมายถึง Powershell หรือไม่ ถ้าเป็นเช่นนั้นการใช้ CLR และใช้ bytecode
Winston Ewert

@ WinstonEwert ขอโทษฉันหมายถึง PowerShell ความเข้าใจของฉันคือการแปลเป็นรูปแบบกลางไม่ได้หมายความว่าสิ่งที่ไม่ได้ตีความ Heck ล่ามพื้นฐานของดาร์ทเมาท์แปลต้นฉบับเป็นโทเค็นก่อนการตีความ แต่ละเครื่องมือที่ฉันกล่าวถึงมีโหมดที่มัน 1) อ่านบรรทัดของแหล่งที่มา 2) แปลบรรทัดนั้นในรูปแบบที่ปฏิบัติการ (อาจเป็นรหัสกลางบางอย่างมากกว่ารหัสพื้นเมือง), 3) รันรหัสสำหรับบรรทัดนั้น 4) วนกลับไปที่ 1) มันสอดคล้องกับความเข้าใจของฉันในการเป็นล่าม
Charles E. Grant

2
Bytecode ทำการรวบรวมนัย คอมไพเลอร์ bytecode เป็นเพียงโปรแกรมที่ใช้แหล่งที่มาและแปลงเป็น bytecode ดังนั้นการใช้ bytecode ทั้งหมดจะต้องเกี่ยวข้องกับคอมไพเลอร์ bytecode แต่จะต้องตีความ bytecode ด้วย (หรือ JITted) ดังนั้นอะไรก็ตามที่ใช้ bytecode จึงเป็น interpreter / compiler hybrid
Winston Ewert

4
จริงๆแล้วสิ่งที่ฉันทำคือผู้คนขว้างคำแถลงเช่น "python ถูกตีความ" และ "Java ถูกคอมไพล์" โดยไม่เข้าใจการใช้งาน ฉันกำลังค้นหาว่ามันมีประโยชน์หรือไม่ในการอธิบายการใช้งานในข้อกำหนดเหล่านั้น ความจริงมักจะซับซ้อนกว่าและการพยายามต้มให้แปล / เรียบเรียงไม่เป็นประโยชน์
Winston Ewert

1

ผมคิดว่า: แน่นอนใช่

ในความเป็นจริงการใช้งานส่วนใหญ่จะมาบรรจบกับกลยุทธ์พื้นฐานเดียวกัน

จริงๆแล้ว C ++ มีเป้าหมายที่จะย้ายพอร์ตไปยังคอมไพเลอร์โดเมนบางแนวคิดระดับสูงที่มักจะมอบให้กับล่าม แต่มันยังคงอยู่ในส่วนของชนกลุ่มน้อย ...


2
รอจนกระทั่ง Clang + LLVM เป็นเครื่องมือคอมไพเลอร์ที่ได้รับความนิยม
SK-logic

@ SK-logic แม้จะมีชื่อฉันเชื่อว่า Clang + LLVM สร้างรหัสเนทิฟ
Winston Ewert

1
@Winston Ewert เฉพาะในกรณีที่คุณต้องการ คุณสามารถหยุดในระดับ LLVM IR และทำสิ่งที่คุณต้องการด้วย - ตีความมัน JIT รวบรวมมันเครื่องดนตรีตามที่คุณต้องการ คุณสามารถแปลเป็น Javascript แล้วผ่านล่าม: github.com/kripken/emscripten/wiki
SK-logic

@ SK- ตรรกะสิ่งที่ประณีต! ไม่ทราบว่า LLVM สามารถทำได้
Winston Ewert

1
ความสวยงามของ llvm เป็นการแยกโดยเจตนาระหว่างส่วนหน้าและส่วนหลัง และเครื่องมือสำหรับการควบคุมตรงกลางก่อนกำหนดเป้าหมายชุดคำสั่ง คุณสามารถรวมโครงการทั้งหมดของคุณเป็น bytecode และปรับให้เหมาะสมกับทุกสิ่งด้วยคอมไพเลอร์อื่น ๆ ที่คุณจะต้องมีแหล่งไฟล์เดียวหรืออย่างน้อยหนึ่งแหล่งที่มีทางลงผ่านแผนผังแหล่งข้อมูลเพื่อให้คอมไพเลอร์ทำงานในแหล่งรวมเดียว นอกจากนี้ยังมีชุดเครื่องมือหนึ่งชุดภายใต้ llvm โดยทั่วไปสำหรับทุกเป้าหมายคุณไม่จำเป็นต้องสร้างสำหรับแต่ละเป้าหมายคอมไพเลอร์หนึ่งตัวเหมาะกับทุกคน (อย่างน้อยก็ถึง asm ของเป้าหมาย)
old_timer

-1

ความแตกต่างที่มีประโยชน์: โปรแกรมที่ตีความสามารถแก้ไขได้ด้วยการเพิ่มหรือเปลี่ยนฟังก์ชั่นที่รันไทม์


8
เรื่องไร้สาระ รหัสการปรับเปลี่ยนตนเอง (เครื่องจักร) เป็นเคล็ดลับที่เก่าแก่ที่สุดในหนังสือเล่มนี้ จากนั้นอีกครั้งบางคนโต้แย้งว่าแม้แต่รหัสเนทีฟก็ถูกตีความโดยล่ามแปลเป็นซิลิคอน (ซีพียู) ในที่สุด แต่ถ้าเราสมมติว่ารหัสทั้งหมดถูกตีความและไม่มีความแตกต่างในการทำ

2
@delnan ถูกต้อง ฉันจะเพิ่มว่าภาษาที่ทันสมัยสามารถแก้ไขตัวเองโดยการสร้างคลาสใหม่แบบไดนามิกและการโหลด / ยกเลิกการโหลดห้องสมุด (หรือ "แอสเซมบลี" ใน. NET ตัวอย่าง)
Jalayn

5
Common Lisp ถูกคอมไพล์ แต่คุณยังสามารถแทนที่นิยามฟังก์ชันในรันไทม์ได้อย่างง่ายดาย
SK-logic

นั่นเป็นคุณลักษณะที่น่าสนใจและจำเป็น (เช่นใน Prolog) ของการตีความ
CapelliC
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.