คอมไพเลอร์จะรวบรวมตัวเองได้อย่างไร


168

ฉันกำลังค้นคว้า CoffeeScript บนเว็บไซต์http://coffeescript.org/และมีข้อความ

คอมไพเลอร์ CoffeeScript นั้นเขียนขึ้นใน CoffeeScript

คอมไพเลอร์รวบรวมได้อย่างไรหรือข้อความนี้มีความหมายว่าอย่างไร?


14
อีกคำสำหรับคอมไพเลอร์ที่สามารถคอมไพล์เองได้คือself-hostingคอมไพเลอร์ ดูprogrammers.stackexchange.com/q/263651/6221
oɔɯǝɹ

37
ทำไมคอมไพเลอร์ไม่สามารถรวบรวมตัวเองได้?
253751

48
มีคอมไพเลอร์อย่างน้อยสองชุด ที่มีอยู่ก่อนรวบรวมสำเนาใหม่ อันใหม่อาจจะเหมือนกันหรือเก่ากว่าก็ได้
bdsl

12
คุณอาจสนใจ Git: มีการติดตามซอร์สโค้ดแน่นอนในที่เก็บ Git
Greg d'Eon

7
นี่เป็นเรื่องเกี่ยวกับการถามว่า "เครื่องพิมพ์ของซีร็อกซ์สามารถพิมพ์แผนผังได้อย่างไร" คอมไพเลอร์รวบรวมข้อความเป็นรหัสไบต์ หากคอมไพเลอร์สามารถรวบรวมรหัสไบต์ที่ใช้งานได้คุณสามารถเขียนโค้ดคอมไพเลอร์ในภาษาที่เกี่ยวข้องแล้วส่งรหัสผ่านคอมไพเลอร์เพื่อสร้างเอาต์พุต
RLH

คำตอบ:


219

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

  1. คอมไพเลอร์ CoffeeScript ตัวแรกเขียนด้วย Ruby ผลิตเวอร์ชัน 1 ของ CoffeeScript
  2. ซอร์สโค้ดของคอมไพเลอร์ CS ถูกเขียนใหม่ใน CoffeeScript 1
  3. คอมไพเลอร์ CS ดั้งเดิมรวบรวมรหัสใหม่ (เขียนใน CS 1) เป็นคอมไพเลอร์เวอร์ชัน 2
  4. มีการเปลี่ยนแปลงรหัสแหล่งรวบรวมเพื่อเพิ่มคุณสมบัติภาษาใหม่
  5. คอมไพเลอร์ CS ตัวที่สอง (ตัวแรกที่เขียนใน CS) จะคอมไพล์ซอร์สโค้ดใหม่ที่ถูกแก้ไขเป็นคอมไพเลอร์เวอร์ชัน 3
  6. ทำซ้ำขั้นตอนที่ 4 และ 5 สำหรับการวนซ้ำแต่ละครั้ง

หมายเหตุ: ฉันไม่แน่ใจว่าจะมีการกำหนดหมายเลขเวอร์ชัน CoffeeScript ได้อย่างไรนั่นเป็นเพียงตัวอย่างเท่านั้น

กระบวนการนี้มักจะเรียกว่าความร่วมมือ ตัวอย่างของคอมไพเลอร์ความร่วมมือก็คือrustcคอมไพเลอร์สำหรับภาษาสนิม


5
เส้นทางอื่นสำหรับการ bootstrapping คอมไพเลอร์คือการเขียนล่ามสำหรับ (ส่วนย่อย) ของภาษาของคุณ
Aron

ในฐานะอีกทางเลือกหนึ่งในการ bootstrapping ด้วยคอมไพเลอร์หรือล่ามที่เขียนในภาษาอื่นเส้นทางการศึกษาที่เก่าแก่มากจะรวบรวมแหล่งข้อมูลคอมไพเลอร์ด้วยมือ ชัคมัวร์วิ่งผ่านวิธีการนี้สำหรับล่าม Forth ในบทที่ 9 "โปรแกรมที่ bootstrap" ในตอนท้ายของการเขียนโปรแกรมภาษาที่มุ่งเน้นปัญหา ( web.archive.org/web/20160327044521/www.colorforth.com/POL . htm ) โดยพิจารณาจากการทำสองครั้งก่อนด้วยมือ การป้อนรหัสที่นี่ทำผ่านแผงด้านหน้าที่อนุญาตให้จัดเก็บค่าโดยตรงไปยังที่อยู่หน่วยความจำที่ควบคุมโดยสวิตช์สลับสำหรับบิต
Jeremy W. Sherman

59

ในกระดาษ สะท้อนความเชื่อมั่นที่เชื่อถือได้Ken Thompson หนึ่งในผู้สร้าง Unix เขียนภาพรวมที่น่าสนใจ (และอ่านได้ง่าย)ได้ว่าภาพรวมของ C คอมไพเลอร์รวบรวมอย่างไร แนวคิดที่คล้ายกันสามารถนำไปใช้กับ CoffeeScript หรือภาษาอื่น ๆ

แนวคิดของคอมไพเลอร์ที่คอมไพล์โค้ดของตัวเองนั้นคล้ายกับquine : ซอร์สโค้ดที่เมื่อเรียกใช้งานจะสร้างเอาต์พุตต้นฉบับซอร์สโค้ด นี่คือตัวอย่างหนึ่งของ quine CoffeeScript Thompson ให้ตัวอย่างของ quine C นี้:

char s[] = {
    '\t',
    '0',
    '\n',
    '}',
    ';',
    '\n',
    '\n',
    '/',
    '*',
    '\n',
    … 213 lines omitted …
    0
};

/*
 * The string s is a representation of the body
 * of this program from '0'
 * to the end.
 */

main()
{
    int i;

    printf("char\ts[] = {\n");
    for(i = 0; s[i]; i++)
        printf("\t%d,\n", s[i]);
    printf("%s", s);
}

ถัดไปคุณอาจสงสัยว่าคอมไพเลอร์ได้รับการสอนอย่างไรเช่นลำดับการหลบหนี '\n'แทนรหัส ASCII 10 คำตอบก็คือที่ใดที่หนึ่งในคอมไพเลอร์ C มีรูทีนที่ตีความตัวอักษรตัวอักษรที่มีเงื่อนไขเช่นนี้

…
c = next();
if (c != '\\') return c;        /* A normal character */
c = next();
if (c == '\\') return '\\';     /* Two backslashes in the code means one backslash */
if (c == 'r')  return '\r';     /* '\r' is a carriage return */
…

ดังนั้นเราสามารถเพิ่มเงื่อนไขหนึ่งข้อในรหัสด้านบน ...

if (c == 'n')  return 10;       /* '\n' is a newline */

... เพื่อสร้างคอมไพเลอร์ที่รู้ว่า'\n'เป็นตัวแทนของ ASCII 10. ที่น่าสนใจว่าคอมไพเลอร์และคอมไพเลอร์ที่ตามมาทั้งหมดจะถูกคอมไพล์โดยมัน "รู้" การแมปนั้นดังนั้นในซอร์สโค้ดรุ่นถัดไปคุณสามารถเปลี่ยนบรรทัดสุดท้ายเป็น

if (c == 'n')  return '\n';

…และมันจะทำในสิ่งที่ถูกต้อง! 10มาจากคอมไพเลอร์และไม่จำเป็นต้องกำหนดไว้อย่างชัดเจนในซอร์สโค้ดของคอมไพเลอร์ 1

นั่นคือตัวอย่างหนึ่งของคุณลักษณะภาษา C ที่นำมาใช้ในรหัส C ทวนกระบวนการนั้นซ้ำสำหรับคุณลักษณะภาษาทุกภาษาและคุณมีคอมไพเลอร์ "self-hosting": คอมไพเลอร์ C ที่เขียนด้วย C


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


7
แม้ว่าข้อมูลนี้เป็นบิตที่น่าสนใจ แต่ฉันไม่คิดว่ามันจะตอบคำถาม ตัวอย่างของคุณสมมติว่าคุณมีคอมไพเลอร์ bootstrapped อยู่แล้วหรืออย่างอื่นในภาษาใดที่คอมไพเลอร์ C เขียนไว้?
Arturo Torres Sánchez

9
@ ArturoTorresSánchezคำอธิบายที่แตกต่างกันทำงานได้ดีสำหรับคนที่แตกต่างกัน ฉันไม่ได้ตั้งใจจะย้ำสิ่งที่พูดในคำตอบอื่น ๆ แต่ฉันพบว่าคำตอบอื่น ๆ พูดในระดับที่สูงกว่าที่ฉันคิด ฉันเองชอบภาพประกอบที่เป็นรูปธรรมเกี่ยวกับการเพิ่มคุณสมบัติหนึ่งคุณลักษณะและให้ผู้อ่านคาดการณ์จากนั้นแทนที่จะเป็นภาพรวมที่ตื้น
200_success

5
ตกลงฉันเข้าใจมุมมองของคุณ เป็นเพียงคำถามที่ว่า "คอมไพเลอร์สามารถรวบรวมตัวเองได้อย่างไรหากคอมไพเลอร์ในการรวบรวมคอมไพเลอร์ไม่มีตัวตน" และ "วิธีการเพิ่มคุณสมบัติใหม่ให้กับคอมไพเลอร์ bootstrapped"
Arturo Torres Sánchez

17
คำถามนั้นคลุมเครือและเปิดกว้าง ดูเหมือนว่าบางคนตีความว่าหมายถึง "คอมไพเลอร์ CoffeeScript จะรวบรวมตัวเองได้อย่างไร" การตอบกลับอย่างรวดเร็วดังที่ระบุไว้ในความคิดเห็นคือ "ทำไมจึงไม่สามารถรวบรวมตัวเองได้เหมือนกับที่รวบรวมรหัสใด ๆ " ฉันตีความมันให้หมายถึง "คอมไพเลอร์ที่โฮสต์ด้วยตนเองจะเกิดขึ้นได้อย่างไร" และได้แสดงให้เห็นว่าคอมไพเลอร์สามารถสอนเกี่ยวกับคุณลักษณะภาษาของตนเองได้อย่างไร มันตอบคำถามในวิธีที่ต่างกันโดยจัดทำภาพประกอบระดับต่ำว่ามีการนำไปใช้อย่างไร
200_success

1
@ ArturoTorresSánchez: "[I] n ภาษาใดแปลคอมไพเลอร์ C?" นานมาแล้วฉันยังคงคอมไพเลอร์ C ดั้งเดิมที่บันทึกไว้ในภาคผนวก K&R เก่า (อันหนึ่งสำหรับ IBM 360) หลายคนรู้ว่าครั้งแรกที่มี BCPL แล้ว B และ C นั้นเป็นรุ่นปรับปรุงของ B. อันที่จริงมีมากมาย บางส่วนของคอมไพเลอร์เก่าที่ยังคงเขียนใน B และไม่เคยถูกเขียนใหม่ถึง C ตัวแปรที่อยู่ในรูปแบบตัวอักษร / หลักเดียวตัวชี้เลขคณิตไม่ได้ถูกสันนิษฐานว่าจะถูกปรับขนาดโดยอัตโนมัติ ฯลฯ รหัสเก่าเป็นพยานถึง bootstrapping จาก B ถึง C คอมไพเลอร์ "C" ตัวแรกถูกเขียนขึ้นใน B.
Eliyahu Skoczylas

29

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

  1. คอมไพเลอร์ CoffeeScript เป็นโปรแกรมที่สามารถรวบรวมโปรแกรมที่เขียนใน CoffeeScript
  2. คอมไพเลอร์ CoffeeScript เป็นโปรแกรมที่เขียนด้วย CoffeeScript

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

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

คอมไพเลอร์รวบรวมได้อย่างไรหรือข้อความนี้มีความหมายว่าอย่างไร?

ใช่นั่นคือสิ่งที่คำสั่งนั้นมีความหมายและฉันหวังว่าคุณจะเห็นในตอนนี้ว่าคำสั่งนั้นเป็นความจริงอย่างไร


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

6
ใบแจ้งยอด 2 ของคุณไม่สมบูรณ์ / ไม่ถูกต้องและทำให้เข้าใจผิดมาก ตั้งแต่ที่คำตอบแรกบอกไว้ว่าคำแรกไม่ได้เขียนในสคริปต์กาแฟ .. นั่นเกี่ยวข้องกับคำถามของเขา และสำหรับ "คอมไพเลอร์สามารถรวบรวมตัวเองได้อย่างไรหรือข้อความนี้มีความหมายว่าอย่างไร" คุณพูดว่า "ใช่" ฉันคิดว่าอย่างนั้น (แม้ว่าใจของฉันจะเล็กไปหน่อย) ฉันเห็นว่ามันเคยใช้ในการรวบรวมเวอร์ชั่นก่อนหน้าของตัวเองมากกว่าตัวของมันเอง แต่มันใช้ในการรวบรวมตัวเองด้วยหรือไม่ ฉันคิดว่ามันไร้ประโยชน์
barlop

2
@barlop: เปลี่ยนคำสั่ง 2 เป็น " วันนี้คอมไพเลอร์ CoffeeScript เป็นโปรแกรมที่เขียนด้วย CoffeeScript" นั่นช่วยให้คุณเข้าใจดีขึ้นหรือไม่ คอมไพเลอร์คือ "just" โปรแกรมที่แปลอินพุต (รหัส) เป็นเอาต์พุต (โปรแกรม) ดังนั้นหากคุณมีคอมไพเลอร์สำหรับภาษา Foo ให้เขียนซอร์สโค้ดสำหรับ Foo-compiler ในภาษา Foo เองและป้อนแหล่งนั้นไปยัง Foo-compiler แรกของคุณคุณจะได้รับ Foo-compiler ตัวที่สองเป็นเอาต์พุต สิ่งนี้ทำโดยภาษาจำนวนมาก (เช่นคอมไพเลอร์ C ทั้งหมดที่ฉันรู้จักเขียนด้วยภาษา ... C)
DarkDust

3
คอมไพเลอร์ไม่สามารถรวบรวมได้ ไฟล์เอาต์พุตไม่ได้เป็นอินสแตนซ์เดียวกับคอมไพเลอร์ที่สร้างไฟล์เอาต์พุต ฉันหวังว่าคุณจะเห็นในตอนนี้ว่าคำสั่งนั้นเป็นเท็จ
pabrams

3
@pabrams ทำไมคุณคิดเช่นนั้น ผลลัพธ์อาจเหมือนกับคอมไพเลอร์ที่ใช้สร้างมันขึ้นมา ตัวอย่างเช่นถ้าฉันรวบรวม GCC 6.1 กับ GCC 6.1 ฉันจะได้รับเวอร์ชัน GCC 6.1 ที่คอมไพล์ด้วย GCC 6.1 และถ้าฉันใช้สิ่งนั้นเพื่อคอมไพล์ GCC 6.1 ฉันก็จะได้เวอร์ชั่น GCC 6.1 ที่คอมไพล์ด้วย GCC 6.1 ซึ่งควรจะเหมือนกัน (ไม่สนใจสิ่งต่าง ๆ เช่นเวลาประทับ)
user253751

9

คอมไพเลอร์รวบรวมได้อย่างไรหรือข้อความนี้มีความหมายว่าอย่างไร?

มันหมายความว่าอย่างแน่นอน ก่อนอื่นสิ่งที่ต้องพิจารณา มีสี่วัตถุที่เราต้องดู:

  • ซอร์สโค้ดของโปรแกรม CoffeScript ใด ๆ
  • แอสเซมบลี (สร้างขึ้น) ของโปรแกรม CoffeScript ใด ๆ
  • ซอร์สโค้ดของคอมไพเลอร์ CoffeScript
  • แอสเซมบลี (สร้างขึ้น) ของคอมไพเลอร์ CoffeScript

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

ตอนนี้คอมไพเลอร์ CoffeScript นั้นเป็นเพียงโปรแกรม CoffeScript เองและสามารถคอมไพล์ได้โดยคอมไพเลอร์ CoffeScript

มันดูเหมือนว่าสับสนของคุณเกิดจากข้อเท็จจริงที่ว่าเมื่อคุณสร้างภาษาใหม่ของคุณเองคุณไม่ได้มีคอมไพเลอร์ยังคุณสามารถใช้เพื่อรวบรวมคอมไพเลอร์ของคุณ ดูเหมือนปัญหาไข่ไก่ใช่ไหม

แนะนำกระบวนการที่เรียกว่าความร่วมมือ

  1. คุณเขียนคอมไพเลอร์ในภาษาที่มีอยู่แล้ว (ในกรณี CoffeScript คอมไพเลอร์ดั้งเดิมถูกเขียนใน Ruby) ที่สามารถคอมไพล์ชุดย่อยของภาษาใหม่
  2. คุณเขียนคอมไพเลอร์ที่สามารถคอมไพล์ชุดย่อยของภาษาใหม่ในภาษาใหม่นั้นเอง คุณสามารถใช้คุณสมบัติภาษาเท่านั้นที่คอมไพเลอร์จากขั้นตอนข้างต้นสามารถรวบรวมได้
  3. คุณใช้คอมไพเลอร์จากขั้นตอนที่ 1 เพื่อรวบรวมคอมไพเลอร์จากขั้นตอนที่ 2 สิ่งนี้จะทำให้คุณมีแอสเซมบลีที่เขียนขึ้นในส่วนย่อยของภาษาใหม่และคุณสามารถรวบรวมชุดย่อยของภาษาใหม่ได้

ตอนนี้คุณต้องเพิ่มคุณสมบัติใหม่ สมมติว่าคุณใช้งานwhile-loops เท่านั้น แต่ยังต้องการfor-loops นี่ไม่ใช่ปัญหาเนื่องจากคุณสามารถเขียนfor-loop ใด ๆในลักษณะที่เป็นwhile-loop ซึ่งหมายความว่าคุณสามารถใช้while-loops ในซอร์สโค้ดของคอมไพเลอร์ของคุณเท่านั้นเนื่องจากแอสเซมบลีที่คุณมีอยู่สามารถรวบรวมได้เท่านั้น แต่คุณสามารถสร้างฟังก์ชั่นภายในคอมไพเลอร์ของคุณที่สามารถ pase และคอมไพล์for-loops ได้ จากนั้นคุณใช้แอสเซมบลีที่คุณมีอยู่แล้วและคอมไพล์รุ่นคอมไพเลอร์ใหม่ และตอนนี้คุณมีชุดคอมไพเลอร์ที่สามารถแยกวิเคราะห์และคอมไพล์for-loops! ตอนนี้คุณสามารถกลับไปที่ไฟล์ต้นฉบับของคอมไพเลอร์ของคุณและเขียนwhile-loops ใด ๆ ที่คุณไม่ต้องการเป็นfor-loops

ล้างและทำซ้ำจนกว่าคุณสมบัติภาษาทั้งหมดที่ต้องการสามารถรวบรวมได้ด้วยคอมไพเลอร์

whileและforเห็นได้ชัดว่าเป็นเพียงตัวอย่างเท่านั้น แต่สิ่งนี้ใช้ได้กับคุณสมบัติภาษาใหม่ที่คุณต้องการ และตอนนี้คุณอยู่ในสถานการณ์ที่ CoffeScript อยู่ในขณะนี้: คอมไพเลอร์รวบรวมตัวเอง

มีวรรณกรรมออกมามากมาย Reflections on Trusting Trustเป็นคลาสสิกทุกคนที่สนใจในหัวข้อนั้นควรอ่านอย่างน้อยหนึ่งครั้ง


5
(ประโยค "คอมไพเลอร์ CoffeeScript เขียนด้วยตัวเองใน CoffeeScript" เป็นความจริง แต่ "คอมไพเลอร์สามารถรวบรวมตัวเอง" เป็นเท็จ)
pabrams

4
ไม่เป็นความจริงอย่างสมบูรณ์ คอมไพเลอร์สามารถรวบรวมตัวเอง มันไม่สมเหตุสมผลเลย สมมติว่าคุณมีไฟล์ปฏิบัติการที่สามารถคอมไพล์เวอร์ชัน X ของภาษาได้ คุณเขียนคอมไพเลอร์ที่สามารถคอมไพล์เวอร์ชั่น X + 1 และคอมไพล์มันด้วยคอมไพเลอร์ที่คุณมี (ซึ่งคือเวอร์ชั่น X) คุณจบลงด้วยการปฏิบัติการที่สามารถรวบรวมรุ่น X + 1 ของภาษา ตอนนี้คุณสามารถไปและใช้ไฟล์ปฏิบัติการใหม่นั้นเพื่อคอมไพล์เลอร์ใหม่ แต่อะไรจะจบ? คุณมีไฟล์ที่สามารถทำงานได้ตามที่คุณต้องการ คอมไพเลอร์สามารถรวบรวมโปรแกรมที่ถูกต้องใด ๆดังนั้นจึงสามารถรวบรวมตัวเองได้อย่างสมบูรณ์!
Polygnome

1
แน่นอนว่ามันไม่เคยได้ยินมาก่อนที่จะสร้างสักสองสามครั้งฟรีไอพอดปาสกาลที่ทันสมัยสร้างคอมไพเลอร์ทั้งหมด 5 ครั้ง
plugwash

1
@pabrams การเขียน "อย่าสัมผัส" และ "วัตถุที่น่าสนใจอย่าแตะต้อง" ไม่สร้างความแตกต่างให้กับข้อความที่ต้องการในวลี ตราบใดที่ผู้ฟังข้อความ (โปรแกรมเมอร์) เข้าใจข้อความที่ตั้งใจไว้ของวลี (โครงสร้างของคอมไพเลอร์สามารถรวบรวมแหล่งที่มา) โดยไม่คำนึงถึงวิธีการเขียนการสนทนานี้ไม่มีประโยชน์ อาร์กิวเมนต์ของคุณไม่ถูกต้อง หากคุณไม่สามารถแสดงให้เห็นว่าผู้ชมเป้าหมายของข้อความนั้นไม่ใช่โปรแกรมเมอร์แล้วคุณก็จะถูกต้อง
DarkDestry

2
@pabrams 'Good english' เป็นภาษาอังกฤษที่สื่อสารความคิดอย่างชัดเจนกับผู้ชมที่ต้องการและในแบบที่นักเขียนหรือผู้พูดตั้งใจพูด หากผู้ชมที่ตั้งใจเป็นโปรแกรมเมอร์และโปรแกรมเมอร์เข้าใจมันเป็นภาษาอังกฤษที่ดี การพูดว่า "แสงมีทั้งอนุภาคและคลื่น" ซึ่งเทียบเท่ากับ "แสงมีทั้งโฟตอนและคลื่นแม่เหล็กไฟฟ้า" สำหรับนักฟิสิกส์พวกเขาหมายถึงสิ่งเดียวกัน หมายความว่าเราควรใช้ประโยคที่ยาวและชัดเจนกว่าเสมอ? No! เพราะมันมีความซับซ้อนในการอ่านเมื่อความหมายชัดเจนอยู่แล้วสำหรับผู้ชมที่ต้องการ
DarkDestry

7

คำอธิบายเล็ก ๆ แต่สำคัญ

ที่นี่คอมไพเลอร์คำศัพท์คัดค้านความจริงที่ว่ามีสองไฟล์ที่เกี่ยวข้อง หนึ่งคือไฟล์ปฏิบัติการที่ใช้เป็นไฟล์อินพุตที่เขียนใน CoffeScript และสร้างเป็นไฟล์เอาต์พุตไฟล์ปฏิบัติการอื่นไฟล์อ็อบเจ็กต์ลิงก์ได้หรือไลบรารีที่แบ่งใช้ อีกอันคือไฟล์ต้นฉบับของ CoffeeScript ซึ่งเพิ่งเกิดขึ้นเพื่ออธิบายขั้นตอนการรวบรวม CoffeeScript

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


4
  1. คอมไพเลอร์ CoffeeScript ถูกเขียนครั้งแรกในทับทิม
  2. คอมไพเลอร์ CoffeeScript นั้นถูกเขียนใหม่ใน CoffeeScript

เนื่องจากคอมไพเลอร์ CoffeeScript รุ่น Ruby มีอยู่แล้วมันถูกใช้เพื่อสร้างเวอร์ชัน CoffeeScript ของคอมไพเลอร์ CoffeeScript

ป้อนคำอธิบายรูปภาพที่นี่ นี้เป็นที่รู้จักกันเป็นคอมไพเลอร์ตัวเองโฮสติ้ง

เป็นเรื่องปกติอย่างมากและมักเกิดจากความปรารถนาของผู้เขียนในการใช้ภาษาของตนเองเพื่อรักษาการเติบโตของภาษานั้น


3

มันไม่ใช่เรื่องของคอมไพเลอร์ที่นี่ แต่เป็นเรื่องของความหมายของภาษาเนื่องจากคอมไพเลอร์เป็นเพียงโปรแกรมที่เขียนในบางภาษา

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

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

เครื่องพิมพ์ 3 มิติเกือบจะเป็นเครื่องจักรสากล คุณสามารถพิมพ์ทั้งเครื่องพิมพ์ 3D โดยใช้เครื่องพิมพ์ 3D (คุณไม่สามารถสร้างทิปที่ละลายพลาสติก)


ฉันชอบการเปรียบเทียบการกลึง ซึ่งแตกต่างจากความคล้ายคลึงของเครื่องกลึงแม้ว่าความไม่สมบูรณ์ในการคำนวณซ้ำคอมไพเลอร์แรกจะถูกส่งไปยังคอมไพเลอร์ที่ตามมาทั้งหมด ตัวอย่างเช่นคำตอบข้างต้นกล่าวถึงการเพิ่มคุณสมบัติ for-loop ที่คอมไพเลอร์ดั้งเดิมใช้ในขณะที่ลูปเท่านั้น เอาท์พุทเข้าใจถึง for-loops แต่การใช้งานจะอยู่ในขณะที่ลูป หากต้นฉบับในขณะที่การใช้ลูปนั้นมีข้อบกพร่องหรือไม่มีประสิทธิภาพก็จะเป็นเสมอ!

@ Physics-Compute ที่ผิดปกติ ในกรณีที่ไม่มีข้อบกพร่องของความอาฆาตพยาบาทมักจะไม่เผยแพร่เมื่อรวบรวมคอมไพเลอร์
plugwash

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

@plugwash ดู "ภาพสะท้อนของความไว้วางใจที่เชื่อถือได้" โดย Ken Thompson - ece.cmu.edu/~ganger/712.fall02/papers/p761-thompson.pdf

3

พิสูจน์โดยอุปนัย

ขั้นตอนอุปนัย

คอมไพเลอร์เวอร์ชัน n + 1 ถูกเขียนด้วย X

ดังนั้นจึงสามารถคอมไพล์ได้โดยคอมไพเลอร์เวอร์ชันที่ n (เขียนด้วย X)

เคสฐาน

แต่คอมไพเลอร์รุ่นแรกที่เขียนด้วย X จะต้องรวบรวมโดยคอมไพเลอร์สำหรับ X ที่เขียนด้วยภาษาอื่นที่ไม่ใช่ X ขั้นตอนนี้เรียกว่า bootstrapping the compiler


1
คอมไพเลอร์คอมไพเลอร์ตัวแรกสำหรับภาษา X สามารถเขียนได้อย่างง่ายดายใน X วิธีที่เป็นไปได้คือคอมไพเลอร์ตัวแรกสามารถตีความได้ (โดยล่าม X เขียนเป็นภาษาอื่นที่ไม่ใช่ X)
Kaz

0

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

Cross-compilers ย้ายจากระบบหนึ่งไปยังอีกระบบหนึ่งคอมไพเลอร์ข้ามภาษารวบรวมข้อมูลจำเพาะภาษาหนึ่งเป็นข้อกำหนดภาษาอื่น

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

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

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