ฉันกำลังค้นคว้า CoffeeScript บนเว็บไซต์http://coffeescript.org/และมีข้อความ
คอมไพเลอร์ CoffeeScript นั้นเขียนขึ้นใน CoffeeScript
คอมไพเลอร์รวบรวมได้อย่างไรหรือข้อความนี้มีความหมายว่าอย่างไร?
ฉันกำลังค้นคว้า CoffeeScript บนเว็บไซต์http://coffeescript.org/และมีข้อความ
คอมไพเลอร์ CoffeeScript นั้นเขียนขึ้นใน CoffeeScript
คอมไพเลอร์รวบรวมได้อย่างไรหรือข้อความนี้มีความหมายว่าอย่างไร?
คำตอบ:
คอมไพเลอร์รุ่นแรกไม่สามารถสร้างด้วยเครื่องจากภาษาโปรแกรมเฉพาะ ความสับสนของคุณเป็นที่เข้าใจ คอมไพเลอร์รุ่นต่อมาที่มีฟีเจอร์ภาษามากขึ้น (ด้วยซอร์สที่เขียนใหม่ในภาษาใหม่เวอร์ชันแรก) สามารถสร้างได้โดยคอมไพเลอร์ตัวแรก เวอร์ชันนั้นสามารถรวบรวมคอมไพเลอร์ต่อไปและอื่น ๆ นี่คือตัวอย่าง:
หมายเหตุ: ฉันไม่แน่ใจว่าจะมีการกำหนดหมายเลขเวอร์ชัน CoffeeScript ได้อย่างไรนั่นเป็นเพียงตัวอย่างเท่านั้น
กระบวนการนี้มักจะเรียกว่าความร่วมมือ ตัวอย่างของคอมไพเลอร์ความร่วมมือก็คือrustc
คอมไพเลอร์สำหรับภาษาสนิม
ในกระดาษ สะท้อนความเชื่อมั่นที่เชื่อถือได้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พล็อตเรื่องบิดที่อธิบายไว้ในบทความคือเนื่องจากคอมไพเลอร์สามารถ "สอน" ข้อเท็จจริงเช่นนี้มันยังสามารถสอนผิดเพื่อสร้างไฟล์ที่ถูกโทรจันด้วยวิธีที่ยากต่อการตรวจจับและการกระทำของการก่อวินาศกรรมยังคงอยู่ ในคอมไพเลอร์ทั้งหมดที่ผลิตโดยคอมไพเลอร์ที่เสีย
คุณได้รับคำตอบที่ดีมากแล้ว แต่ฉันต้องการเสนอมุมมองที่แตกต่างให้กับคุณซึ่งหวังว่าจะได้รับความกระจ่างแก่คุณ ก่อนอื่นเรามาสร้างข้อเท็จจริงสองประการที่เราสามารถเห็นด้วยกับ:
ฉันแน่ใจว่าคุณสามารถยอมรับว่าทั้ง # 1 และ # 2 เป็นจริง ตอนนี้ดูที่ทั้งสองงบ คุณเห็นตอนนี้เป็นเรื่องปกติหรือไม่ที่คอมไพเลอร์ CoffeeScript สามารถคอมไพล์คอมไพเลอร์ CoffeeScript ได้?
คอมไพเลอร์ไม่สนใจสิ่งที่รวบรวม ตราบใดที่มันเป็นโปรแกรมที่เขียนด้วย CoffeeScript ก็สามารถรวบรวมได้ และคอมไพเลอร์ CoffeeScript เองก็เกิดขึ้นเป็นโปรแกรมเช่นนี้ คอมไพเลอร์ CoffeeScript ไม่สนใจว่ามันเป็นคอมไพเลอร์ CoffeeScript ที่มันกำลังรวบรวม สิ่งที่เห็นคือโค้ดของ CoffeeScript ระยะเวลา
คอมไพเลอร์รวบรวมได้อย่างไรหรือข้อความนี้มีความหมายว่าอย่างไร?
ใช่นั่นคือสิ่งที่คำสั่งนั้นมีความหมายและฉันหวังว่าคุณจะเห็นในตอนนี้ว่าคำสั่งนั้นเป็นความจริงอย่างไร
คอมไพเลอร์รวบรวมได้อย่างไรหรือข้อความนี้มีความหมายว่าอย่างไร?
มันหมายความว่าอย่างแน่นอน ก่อนอื่นสิ่งที่ต้องพิจารณา มีสี่วัตถุที่เราต้องดู:
ตอนนี้มันควรจะชัดเจนว่าคุณสามารถใช้แอสเซมบลีที่สร้างขึ้น - ปฏิบัติการ - ของคอมไพเลอร์ CoffeScript เพื่อรวบรวมโปรแกรม CoffeScript ใด ๆ โดยพลการและสร้างแอสเซมบลีสำหรับโปรแกรมนั้น
ตอนนี้คอมไพเลอร์ CoffeScript นั้นเป็นเพียงโปรแกรม CoffeScript เองและสามารถคอมไพล์ได้โดยคอมไพเลอร์ CoffeScript
มันดูเหมือนว่าสับสนของคุณเกิดจากข้อเท็จจริงที่ว่าเมื่อคุณสร้างภาษาใหม่ของคุณเองคุณไม่ได้มีคอมไพเลอร์ยังคุณสามารถใช้เพื่อรวบรวมคอมไพเลอร์ของคุณ ดูเหมือนปัญหาไข่ไก่ใช่ไหม
แนะนำกระบวนการที่เรียกว่าความร่วมมือ
ตอนนี้คุณต้องเพิ่มคุณสมบัติใหม่ สมมติว่าคุณใช้งาน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เป็นคลาสสิกทุกคนที่สนใจในหัวข้อนั้นควรอ่านอย่างน้อยหนึ่งครั้ง
ที่นี่คอมไพเลอร์คำศัพท์คัดค้านความจริงที่ว่ามีสองไฟล์ที่เกี่ยวข้อง หนึ่งคือไฟล์ปฏิบัติการที่ใช้เป็นไฟล์อินพุตที่เขียนใน CoffeScript และสร้างเป็นไฟล์เอาต์พุตไฟล์ปฏิบัติการอื่นไฟล์อ็อบเจ็กต์ลิงก์ได้หรือไลบรารีที่แบ่งใช้ อีกอันคือไฟล์ต้นฉบับของ CoffeeScript ซึ่งเพิ่งเกิดขึ้นเพื่ออธิบายขั้นตอนการรวบรวม CoffeeScript
คุณใช้ไฟล์แรกกับไฟล์ที่สองสร้างไฟล์ที่สามซึ่งมีความสามารถในการรวบรวมคอมมิชชันเดียวกับไฟล์แรก (อาจเป็นไปได้มากกว่านั้นหากไฟล์ที่สองกำหนดคุณสมบัติที่ไม่ได้ใช้ในไฟล์แรก) และอาจแทนที่ไฟล์แรกหากคุณ ปรารถนามาก
เนื่องจากคอมไพเลอร์ CoffeeScript รุ่น Ruby มีอยู่แล้วมันถูกใช้เพื่อสร้างเวอร์ชัน CoffeeScript ของคอมไพเลอร์ CoffeeScript
นี้เป็นที่รู้จักกันเป็นคอมไพเลอร์ตัวเองโฮสติ้ง
เป็นเรื่องปกติอย่างมากและมักเกิดจากความปรารถนาของผู้เขียนในการใช้ภาษาของตนเองเพื่อรักษาการเติบโตของภาษานั้น
มันไม่ใช่เรื่องของคอมไพเลอร์ที่นี่ แต่เป็นเรื่องของความหมายของภาษาเนื่องจากคอมไพเลอร์เป็นเพียงโปรแกรมที่เขียนในบางภาษา
เมื่อเราพูดว่า "ภาษาเขียน / นำไปใช้" เราหมายถึงมีการใช้งานคอมไพเลอร์หรือล่ามสำหรับภาษานั้น มีภาษาการเขียนโปรแกรมที่คุณสามารถเขียนโปรแกรมที่ใช้ภาษานั้น (เป็นคอมไพเลอร์ / ล่ามสำหรับภาษาเดียวกัน) ภาษาเหล่านี้เรียกว่าภาษาสากลภาษาสากล
เพื่อให้สามารถเข้าใจสิ่งนี้ได้ให้นึกถึงเครื่องกลึงโลหะ มันเป็นเครื่องมือที่ใช้ในการสร้างรูปร่างโลหะ เป็นไปได้โดยใช้เพียงแค่เครื่องมือนั้นในการสร้างเครื่องมืออีกชิ้นที่เหมือนกันโดยการสร้างชิ้นส่วน ดังนั้นเครื่องมือดังกล่าวจึงเป็นเครื่องจักรสากล แน่นอนสิ่งแรกถูกสร้างขึ้นโดยใช้วิธีการอื่น (เครื่องมืออื่น ๆ ) และอาจมีคุณภาพต่ำกว่า แต่อันแรกนั้นถูกใช้เพื่อสร้างอันใหม่ที่มีความแม่นยำสูงกว่า
เครื่องพิมพ์ 3 มิติเกือบจะเป็นเครื่องจักรสากล คุณสามารถพิมพ์ทั้งเครื่องพิมพ์ 3D โดยใช้เครื่องพิมพ์ 3D (คุณไม่สามารถสร้างทิปที่ละลายพลาสติก)
คอมไพเลอร์เวอร์ชัน n + 1 ถูกเขียนด้วย X
ดังนั้นจึงสามารถคอมไพล์ได้โดยคอมไพเลอร์เวอร์ชันที่ n (เขียนด้วย X)
แต่คอมไพเลอร์รุ่นแรกที่เขียนด้วย X จะต้องรวบรวมโดยคอมไพเลอร์สำหรับ X ที่เขียนด้วยภาษาอื่นที่ไม่ใช่ X ขั้นตอนนี้เรียกว่า bootstrapping the compiler
คอมไพเลอร์ใช้ข้อกำหนดระดับสูงและเปลี่ยนเป็นการใช้งานในระดับต่ำเช่นสามารถดำเนินการกับฮาร์ดแวร์ได้ ดังนั้นจึงไม่มีความสัมพันธ์ระหว่างรูปแบบของข้อกำหนดและการดำเนินการจริงนอกเหนือจากความหมายของภาษาที่มีการกำหนดเป้าหมาย
Cross-compilers ย้ายจากระบบหนึ่งไปยังอีกระบบหนึ่งคอมไพเลอร์ข้ามภาษารวบรวมข้อมูลจำเพาะภาษาหนึ่งเป็นข้อกำหนดภาษาอื่น
การเรียบเรียงโดยทั่วไปคือการแปลเพียงอย่างเดียวและระดับมักจะเป็นภาษาระดับสูงกว่าไปเป็นภาษาระดับล่าง แต่มีหลายรูปแบบ
คอมไพเลอร์ Bootstrapping เป็นหลักสูตรที่สับสนมากที่สุดเพราะพวกเขารวบรวมภาษาที่พวกเขาเขียนมาอย่าลืมขั้นตอนแรกในการบูตสเต็ปซึ่งต้องมีเวอร์ชันที่มีอยู่น้อยที่สุด คอมไพเลอร์ bootstrapped จำนวนมากทำงานกับคุณสมบัติขั้นต่ำของภาษาการเขียนโปรแกรมก่อนและเพิ่มคุณสมบัติภาษาที่ซับซ้อนเพิ่มเติมไปข้างหน้าตราบใดที่คุณสมบัติใหม่สามารถแสดงได้โดยใช้คุณสมบัติก่อนหน้า หากไม่ใช่กรณีดังกล่าวก็จะต้องมีส่วนหนึ่งของ "คอมไพเลอร์" ที่จะพัฒนาในภาษาอื่นก่อน
self-hosting
คอมไพเลอร์ ดูprogrammers.stackexchange.com/q/263651/6221