ภาษา C ขนาดเล็กที่จำลองการจำลองเครื่องจักร


11

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

Papadimitriou ใช้เครื่อง RAM สำหรับงานนี้ แต่ฉันกลัวว่าการเปรียบเทียบบางสิ่งที่แปลก (เป็นเครื่องทัวริง) กับสิ่งที่แปลก (โดยทั่วไปภาษาแอสเซมบลี) จะไม่น่าเชื่อถือสำหรับนักเรียนหลายคน

ข้อเสนอแนะใด ๆ ที่จะได้รับการต้อนรับมากที่สุด (พิเศษถ้าพวกเขามาพร้อมกับวรรณกรรมแนะนำ)


7
มีเหตุผลที่ว่าคอมพิวเตอร์มีโปรแกรมเดิมในภาษาประกอบ ... เขียนคอมไพเลอร์หรือล่ามเป็นจะไม่น่ารำคาญ และการเขียนคอมไพเลอร์หรือล่ามสำหรับเครื่องทัวริงอาจจะยากกว่า
Peter Shor

ต้องไม่เห็นด้วยกับ PS คอมไพเลอร์ TM ไม่ยากกว่าเช่นการแปลงอินสแตนซ์แฟคตอริ่งเป็น SAT หรือแบบฝึกหัดระดับปริญญาตรีอื่น ๆ ดูยังด้านบนทัวริงจำลองเครื่องบนเว็บ นี่คือตัวอย่างของคอมไพเลอร์เครื่องทัวริงที่เขียนด้วยทับทิมพร้อม source code ตัวอย่าง (สำหรับภาษาระดับสูง) อนิจจาดูเหมือนจะไม่ขัดมากกว่าที่มีอยู่ มันจะทำให้โครงการโอเพนซอร์สที่ดี
vzn

2
@OmarShehab การแก้ไขจะทำให้คำถามปรากฏขึ้นในหน้าแรก โปรดอย่าแก้ไขคำถามเก่าเมื่อการแก้ไขไม่ได้ปรับปรุงคำถามอย่างมีนัยสำคัญ นอกจากนี้การแก้ไขคำถามจำนวนมากที่ไม่ได้อยู่ในหน้าแรกนั้นไม่ดีเท่าที่ผลักคำถามใหม่ออกจากหน้าแรก ขอบคุณ
Kaveh

@kaveh เข้าใจ
Omar Shehab

คำตอบ:


15
  • smnutm

    ฉันสงสัยว่านี่เป็นวิธีที่ง่ายที่สุดที่เป็นไปได้ แต่ฉันชอบวิธีที่มันวางอยู่บนบางทฤษฎีพื้นฐานที่สุดในการคำนวณ (ซึ่งคุณอาจต้องการครอบคลุมด้วยเหตุผลอื่น ๆ )

    ปรากฏว่าAndrej Bauer ตอบคำถามที่คล้ายกันใน Mathoverflowไม่กี่เดือนหลัง

  • หากคุณตั้งค่าภาษา C เหมือนกันเส้นทางของคุณจะค่อนข้างหยาบกว่าเนื่องจากมีความหมายค่อนข้างซับซ้อน - คุณจะต้อง

    1. แสดงให้เห็นว่าเครื่องทัวริงสามารถจำลองกองและกองในเวลาเดียวกันและ
    2. แสดงวิธีที่ตัวแปรสามารถนำไปใช้กับสแต็กและ
    3. แสดงว่าการเรียกใช้โปรซีเจอร์สามารถดำเนินการได้ด้วยสแต็ก

    นี่คือเนื้อหาส่วนใหญ่ของคลาสคอมไพเลอร์โดยสุจริต


7

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


6

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

พิจารณาภาษาบล็อกโครงสร้างการเขียนโปรแกรมด้วยifและwhileงบด้วยไม่ใช่ recursiveฟังก์ชั่นที่กำหนดไว้และซับรูทีนที่มีชื่อบูลตัวแปรสุ่มและการแสดงออกบูลทั่วไปและกับอาร์เรย์แบบบูเดียวมากมายtape[n]กับตัวชี้อาร์เรย์จำนวนเต็มnที่สามารถเพิ่มขึ้นหรือ decremented, n++หรือn--. ตัวชี้nเป็นศูนย์เริ่มต้นและอาร์เรย์tapeเป็นศูนย์ทั้งหมดเริ่มต้น ดังนั้นภาษาคอมพิวเตอร์นี้อาจเหมือนกับภาษา C หรือ Python แต่มีข้อ จำกัด ในประเภทข้อมูล ที่จริงแล้วมันมีข้อ จำกัด เหลือเกินที่เราไม่มีวิธีใช้ตัวชี้nในนิพจน์บูลีน สมมติว่าtapeเป็นเพียงไม่ จำกัด ทางด้านขวาเราสามารถประกาศตัวชี้อันเดอร์โฟลว์ "ข้อผิดพลาดของระบบ" หากnมีค่าเป็นลบ นอกจากนี้ภาษาของเรายังมีexitข้อความที่มีหนึ่งอาร์กิวเมนต์เพื่อส่งคำตอบบูลีน

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

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

  1. ด้วยพรีคอมไพเลอร์เราสามารถขยายประเภทข้อมูลบูลีนให้เป็นตัวอักษรสัญลักษณ์ขนาดใหญ่ขึ้น แต่มีขอบเขต จำกัด เช่น ASCII เราสามารถสันนิษฐานได้ว่าtapeใช้ค่าในตัวอักษรที่ใหญ่กว่านี้ เราสามารถวางเครื่องหมายไว้ที่จุดเริ่มต้นของเทปเพื่อป้องกันไม่ให้ตัวชี้ไม่ไหลและตัวทำเครื่องหมายที่เคลื่อนที่ได้ในตอนท้ายของเทปเพื่อป้องกันไม่ให้ TM เล่นสเก็ตจนถึงอินฟินิตี้บนเทปโดยไม่ตั้งใจ เราสามารถใช้การดำเนินการไบนารีโดยพลการระหว่างสัญลักษณ์และการแปลงเป็นบูลีนifและwhileคำสั่ง (จริง ๆ แล้วifสามารถนำไปใช้ได้ด้วยwhileเช่นกันหากไม่พร้อมใช้งาน)

  2. kkiik

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

  4. เราสามารถจัดระเบียบเทปหน่วยความจำจากอาร์เรย์สัญลักษณ์หนึ่งมิติsymbol[n]เป็นแถวสัญลักษณ์สองมิติโดยใช้สูตรที่symbol[x,y] n = (x+y)*(x+y) + yตอนนี้เราสามารถใช้แต่ละแถวของหน่วยความจำในการแสดงความจำนวนเต็มไม่ได้ลงนามในไบนารีที่มีสัญลักษณ์การเลิกจ้างที่จะได้รับหนึ่งมิติ random-access, memory[x]หน่วยความจำจำนวนเต็มมูลค่า เราสามารถใช้การอ่านจากหน่วยความจำไปยังการลงทะเบียนจำนวนเต็มและการเขียนจากการลงทะเบียนไปยังหน่วยความจำ ขณะนี้คุณลักษณะหลายอย่างสามารถใช้งานได้กับฟังก์ชั่น: เลขคณิตเครื่องหมายและจุดลอยตัวสตริงสัญลักษณ์ ฯลฯ

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

ณ จุดนี้การก่อสร้างมีคุณสมบัติเพียงพอของภาษาการเขียนโปรแกรมระดับสูงที่การทำงานต่อไปเป็นหัวข้อของภาษาโปรแกรมและคอมไพเลอร์มากกว่าทฤษฎี CS นอกจากนี้ยังง่ายต่อการเขียนเครื่องจำลองทัวริงในภาษาที่พัฒนานี้ มันไม่ง่ายอย่างแน่นอน แต่เป็นมาตรฐานในการเขียนคอมไพเลอร์สำหรับภาษา แน่นอนว่าคุณต้องการคอมไพเลอร์ด้านนอกเพื่อสร้าง outer TM จากรหัสในภาษา C-like หรือ Python-like นี้ แต่สามารถทำได้ในภาษาคอมพิวเตอร์ใด ๆ

โปรดทราบว่าการดำเนินการร่างภาพนี้ไม่เพียง แต่สนับสนุนการทำวิทยานิพนธ์ทัวริสต์ของโบสถ์ของนักตรรกวิทยาสำหรับคลาสฟังก์ชั่นแบบเรียกซ้ำ แต่ยังรวมถึงการขยายวิทยานิพนธ์ กล่าวอีกนัยหนึ่งมันมีค่าใช้จ่ายพหุนาม ในความเป็นจริงถ้าเราได้รับเครื่อง RAM หรือ (ต้นไม้โปรดของฉัน) เป็น tree-tape TM สิ่งนี้สามารถลดค่าใช้จ่ายให้เป็นค่าใช้จ่าย polylogarithmic สำหรับการคำนวณแบบอนุกรมกับหน่วยความจำ RAM


5

คอมไพเลอร์ LLVM อนุญาตให้หนึ่ง "สถาปัตยกรรม" ใหม่ตรงไปตรงมาค่อนข้างตรงไปตรงมา พวกเขาเรียกสิ่งนี้ว่าการเขียน back-endใหม่และให้คำแนะนำโดยละเอียดและตัวอย่างสำหรับวิธีการทำ ฉันสงสัยว่าคุณจะต้องกระโดดผ่านห่วงบางอย่างเกี่ยวกับหน่วยความจำเข้าถึงโดยสุ่มถ้าคุณไม่ต้องการกำหนดเป้าหมายเครื่อง RAM ทัวริง แต่นี่เป็นไปได้แน่นอนเพราะฉันได้เห็นหลายโครงการที่ทำให้ LLVM สร้าง VHDL หรือภาษาเครื่องอื่น ๆ ที่แตกต่างกันมาก

สิ่งนี้จะมีผลที่น่าสนใจในการมีคอมไพเลอร์การปรับให้เหมาะสมที่ทันสมัย


1

ฉันไม่ได้อยู่ในทฤษฎี cs แต่ฉันมีบางสิ่งบางอย่างที่อาจเป็นประโยชน์ ฉันได้รับการอนุมัติอีกครั้ง ฉันออกแบบหน่วยประมวลผลอย่างง่ายที่สามารถตั้งโปรแกรมได้โดยตรงด้วยชุดย่อยขนาดเล็กของ C ไม่มีรหัสการประกอบรหัสเดียวเช่น C คุณสามารถใช้เครื่องมือเดียวกับที่ฉันใช้และแก้ไขโปรเซสเซอร์นี้เพื่อออกแบบเครื่องจำลองทัวริงของคุณ ฉันใช้เวลา 4 วันในการออกแบบจำลองและทดสอบโปรเซสเซอร์นี้มีคำแนะนำเล็กน้อย! เครื่องมือที่ฉันใช้ทำให้ฉันสามารถสร้างรหัสสังเคราะห์ VHDL ที่แท้จริงได้ มันเป็นโปรเซสเซอร์ที่ใช้งานได้จริง

นี่คือลักษณะของโปรแกรม: ตัวอย่างโปรแกรม C-Like Assembly

นี่คือรูปภาพของโปรเซสเซอร์โดยใช้เครื่องมือวิทยานิพนธ์: วงจรประมวลผล

เครื่องมือ "Novakod Studio" ใช้ภาษาคำอธิบายฮาร์ดแวร์ระดับสูง ตัวอย่างเช่นนี่คือรหัสของตัวนับโปรแกรม: psC - ตัวอย่างรหัส C แบบขนานและแบบซิงโครนัส พอพูดถึงถ้าใครสนใจนี่คือข้อมูลสาธารณะที่จะติดต่อฉัน: https://repertoire.uqac.ca/Fiche.aspx?id=JjstNzsH0&link=1

ลัค


การกำหนดแอดเดรสหน่วยความจำใช้จำนวนบิตคงที่เพื่อค้นหาที่อยู่หรือไม่
vzn

ใช่ แต่มันง่ายในการเปลี่ยนขนาดหน่วยความจำ (int DataMemory [SIZE] ภาษารองรับจำนวนเต็มความยาวผันแปร (int: 10) แต่เนื่องจากมันมีเป้าหมาย FPGA อาร์เรย์จึงคงที่และขนาดคงที่
Luc Morin

1

วิธีคิดเกี่ยวกับการนำเสนอโดยผู้ใช้ GMB ที่นี่(เครื่องทัวริงด้วยเทปเดียวสามารถจำลองเครื่องทัวริงด้วย N เทปโดยการเชื่อมต่อเทป N กับเทปเดียวและอ่านเทปใดเทปหนึ่งด้วยการกระโดด N ตำแหน่งในแต่ละครั้ง เครื่องที่มีเทป N สามารถใช้ ... )และเขียนโปรแกรมทัวริงของเครื่องที่ใช้งานเครื่อง RAM แบบง่ายๆ เครื่อง RAM อาจเป็นซีพียูที่เรียบง่ายใช้งานจริงมี LLVM หรือ GCC แบ็กเอนด์ที่พร้อมใช้งาน จากนั้นสามารถใช้ GCC / LLVM สำหรับการคอมไพล์ข้ามโปรแกรม C สำหรับ CPU นั้นและโปรแกรมเครื่องทัวริงที่จำลองเครื่อง RAM เรียกใช้การจำลองด้วยเครื่อง RAM โดยให้เครื่องจำลอง RAM ดำเนินการเอาต์พุต GCC / LLVM การใช้งานเครื่องทัวริงอาจเป็นรหัส C ที่ง่ายมากที่เหมาะกับไฟล์ C ขนาดเล็ก

สิ่งที่เกี่ยวกับเครื่อง RAM นั้นมีโครงการสาธิตอยู่ซึ่งมีการจำลอง CPU แบบ 32 บิตโดยไมโครคอนโทรลเลอร์ขนาด 8 บิตและตัวจำลองบูทลินุกซ์ 32 บิตแบบจำลองลินุกซ์ ช้าเหมือนนรก แต่Dmitry Grinberg ตามที่ผู้เขียนเขียนไว้ บางที Zylin CPU (GitHub user zylin)อาจเป็นทางเลือกที่ทำงานได้สำหรับเครื่อง RAM จำลอง ผู้สมัครRAМเครื่องอีกอาจจะ ProjectOberon ดอทคอมโดยนิคลัสเวิร์ ธ

("dot" และ "com" ในข้อความของฉันเป็นเพราะฉันเพิ่ง 2015_10_21 ลงทะเบียนบัญชีของฉันที่ cstheory.stackexchange และเว็บแอปไม่อนุญาตให้มีลิงก์มากกว่า 2 ลิงก์สำหรับผู้ใช้มือใหม่ เพื่อให้พวกเขาสามารถดูได้โดยอัตโนมัติจากบัญชี stackexchange อื่น ๆ ของฉันที่ฉันอาจจะโง่ แต่ฉันไม่ใช่โทรลล์)

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