ความสัมพันธ์ระหว่างภาษาการเขียนโปรแกรมนิพจน์ทั่วไปและภาษาที่เป็นทางการคืออะไร


25

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

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

ตอนนี้จากสิ่งที่ฉันสามารถรวบรวมได้ภาษาทางการเป็นชุดของกฎการผลิตที่ใช้กับชุดสัญลักษณ์เฉพาะ (ตัวอักษรของภาษา) กฎการผลิตเหล่านี้กำหนดชุดการแปลงเช่น:

b -> a

aaa->c

สิ่งนี้สามารถนำไปใช้ได้เช่น:

abab->aaaa aaaa-> ca

เช่นเดียวกับบันทึกย่อหากเรากำหนดว่าตัวอักษรของภาษาทางการของเราคือ {a, b, c} จากนั้น a และ b ไม่ใช่เทอร์มินัลและ c เป็นเทอร์มินัลเนื่องจากไม่สามารถเปลี่ยนได้ (โปรดแก้ไขให้ฉันด้วยถ้าฉันผิด ที่).

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

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

นั่นคือสิ่งที่มาจากมุมมองที่สับสนของฉัน อาจมีหลายสิ่งหลายอย่างผิดปกติกับสิ่งที่ฉันพูดและนั่นคือเหตุผลที่ฉันขอความช่วยเหลือ


* เว้นแต่คุณจะพิจารณาสิ่งที่ต้องการ(a|b)*b*c->trueเป็นกฎการผลิตซึ่งในกรณีนี้กฎนั้นจะต้องมีสถานะออโตมาตา จำกัด (เช่น: regex) มันไม่สมเหตุสมผลอย่างที่เราเพิ่งพูดไป


2
คุณกำลัง confising อย่างเป็นทางการไวยากรณ์ด้วยอย่างเป็นทางการภาษา ไวยากรณ์เป็นชุดของการเขียนกฎที่อธิบายเป็นภาษา ภาษาคือชุดของสตริงที่อธิบายโดยไวยากรณ์ ดังนั้นไวยากรณ์จึงเป็นทางเลือกแทนนิพจน์ทั่วไป: เป็นวิธีการอธิบายภาษา
reinierpost

@reierierpost คุณพูดถูกแล้วหลังจากดูบันทึกการบรรยายของมหาวิทยาลัยฉันได้รับข้อมูลบางอย่างจากฉันเห็นความผิดพลาดของฉัน
Zwander

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

คำตอบ:


24

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

  1. วิเคราะห์คำศัพท์: กระบวนการข้อความดิบให้เป็นชิ้นเช่นคำหลัก , ค่าคงที่ตัวเลข , สตริง , ตัวบ่งชี้และอื่น ๆ นี่คือการดำเนินการแบบคลาสสิกโดยใช้เครื่องสถานะ จำกัด บางอย่างที่คล้ายกันในจิตวิญญาณเพื่อหุ่นยนต์ จำกัด แน่นอน (DFA)

  2. Parser: เรียกใช้หลังจากการวิเคราะห์คำและแปลงข้อความดิบเป็นแผนผังไวยากรณ์ที่มีคำอธิบายประกอบ ไวยากรณ์ของภาษาการเขียนโปรแกรมคือ (โดยประมาณแรก) ที่ไม่มีบริบท (อันที่จริงต้องมีชุดย่อยที่เข้มงวดยิ่งขึ้น) และสิ่งนี้ช่วยให้อัลกอริธึมที่มีประสิทธิภาพบางอย่างในการแยกโค้ด lexified ในแผนผังไวยากรณ์ นี่คล้ายกับปัญหาของการรับรู้ว่าสตริงที่กำหนดนั้นเป็นของไวยากรณ์ไวยากรณ์ที่ไม่มีบริบทหรือไม่ความแตกต่างที่เราต้องการพิสูจน์ในรูปแบบของทรีไวยากรณ์

ไวยากรณ์สำหรับภาษาการเขียนโปรแกรมถูกเขียนเป็นไวยากรณ์ที่ไม่มีบริบทและการเป็นตัวแทนนี้ถูกใช้โดยตัวแยกวิเคราะห์เพื่อสร้างตัวแยกวิเคราะห์อย่างรวดเร็วสำหรับพวกเขา ตัวอย่างง่ายๆจะมีข้อความที่ไม่ใช่เทอร์มินัลจากนั้นกฎของแบบฟอร์ม STATEMENT IF-STATEMENT โดยที่ IF-STATEMENT ถ้า CONDITION แล้ว BLOCK endif หรือสิ่งที่คล้ายกัน (โดย BLOCK STATEMENT | BLOCK; STATEMENT เป็นต้น) โดยปกติแล้วไวยากรณ์เหล่านี้จะถูกระบุในรูปแบบ Backus-Naur (BNF)

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

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


ขอบคุณสำหรับการตอบกลับ มันทำให้มีคำถามเพิ่มขึ้นมากมาย ฉันควรต่อท้ายคำถามของฉันหรือถามพวกเขาที่นี่
Zwander

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

1
@DW Gotcha ไชโย
Zwander

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

2
@Zwander แยกเชื้อสาย Recursive เป็นเพียงหนึ่งในเทคนิคการแยกวิเคราะห์ มันอาจหรือไม่อาจสร้างต้นไม้แยก โดยทั่วไปการวิเคราะห์จำนวนอัลกอริธึมเพื่อพัฒนากลยุทธ์การคำนวณเพื่อสำรวจโครงสร้างไวยากรณ์โดยนัยในข้อความโปรแกรม แผนผังไวยากรณ์ / การแยกวิเคราะห์นี้อาจหรืออาจไม่สามารถอธิบายได้ในกระบวนการขึ้นอยู่กับกลยุทธ์การรวบรวม (จำนวนขั้นตอน) สิ่งที่จำเป็นคือแม้ว่าท้ายที่สุดแล้วจะมีการสำรวจล่างขึ้นบนอย่างน้อยหนึ่งครั้งของการแยกวิเคราะห์ต้นไม้ไม่ว่าจะเป็นการสำรวจหรือการบอกเป็นนัยในโครงสร้างการคำนวณ
Babou

12

นี่เป็นของหนักสำหรับงานโรงเรียนมัธยม

คำตอบของ Yuval Filmus นั้นดีมากดังนั้นนี่เป็นคำตอบเพิ่มเติมเพื่อชี้แจงจุดที่เขาทำ

ภาษาทางการคือโครงสร้างทางคณิตศาสตร์ การใช้ภาษาโปรแกรมเป็นเพียงการใช้งานที่เป็นไปได้หลายอย่าง ในความเป็นจริงนักภาษาศาสตร์ Noam Chomsky ได้มีส่วนร่วมสำคัญในทฤษฎีต้นของภาษาที่เป็นทางการ เขาคิดค้นลำดับขั้น Chomskyซึ่งแบ่งประเภทภาษาทางการเป็นภาษาปกติไม่มีบริบท ฯลฯ นอกจากนี้ภาษานอกระบบยังใช้ในภาษาศาสตร์เพื่ออธิบายไวยากรณ์ของภาษาธรรมชาติเช่นภาษาอังกฤษ ลองคิดดูว่ามันเป็นจำนวนจริง: เราสามารถใช้ตัวเลขจริงเพื่ออธิบายทั้งสิ่งที่เป็นรูปธรรมเช่นระยะทางจากลอสแองเจลิสไปนิวยอร์กและสิ่งที่เป็นนามธรรมเช่นอัตราส่วนของเส้นรอบวงของวงกลมต่อเส้นผ่าศูนย์กลาง แม้ว่าสิ่งเหล่านี้ทั้งสองมีอยู่เป็นอิสระจากจำนวนจริงตัวเลขจริงเป็นระบบที่มีประโยชน์สำหรับการอธิบายพวกเขา ภาษาที่เป็นทางการเป็นระบบที่มีประโยชน์สำหรับการอธิบายทั้งภาษาอังกฤษและ Python เนื่องจากทั้งสองรูปแบบมีโครงสร้างคล้ายกัน

a++=da+=d-a เช่นจำนวนเงินดอลลาร์และจากนั้นสมการมีความหมาย

คลาสสิกภาษาการเขียนโปรแกรมจะมีสองไวยากรณ์: ไวยากรณ์ศัพท์และไวยากรณ์ประโยค ไวยากรณ์ของคำศัพท์เกี่ยวข้องกับตัวอักษรเช่นตัวอักษรเครื่องหมายอัฒภาควงเล็บปีกกาและวงเล็บ มันมักจะเป็นไวยากรณ์ปกติดังนั้นจึงสามารถแสดงด้วยนิพจน์ปกติหรือ DFA หรือ NFA (มีบทพิสูจน์ในทฤษฎีภาษาทางการซึ่งแสดงให้เห็นว่าทั้งสามมีความเท่าเทียมกันในอำนาจ - หมายถึงพวกเขายอมรับชุดภาษาเดียวกัน) ขั้นตอน lexing ของคอมไพเลอร์หรือล่ามเป็นประเภทล่ามขนาดเล็กสำหรับไวยากรณ์ภาษาปกติ มันอ่านกฎของไวยากรณ์และปฏิบัติตามกฎเหล่านั้นมันก้อนขึ้นอักขระแต่ละตัวเป็นโทเค็น ตัวอย่างเช่นหากภาษามีifคำสั่งที่มีลักษณะคล้าย C มากขึ้น lexer อาจจับตัวอักษรiและfเข้าสู่โทเค็นเดี่ยวIFแล้วมองหาวงเล็บเปิดและเอาท์พุทโทเค็นจับแล้วสิ่งระหว่างวงเล็บแล้วพบว่าวงเล็บปิดและเอาท์พุทOPEN_PAREN CLOSE_PARENเมื่อ lexer สร้างโทเค็นเสร็จแล้วมันจะส่งมอบ parser ซึ่งกำหนดว่าโทเค็นจริง ๆ แล้วสร้างงบที่ถูกต้องของภาษาการเขียนโปรแกรมหรือไม่ ดังนั้นถ้าคุณเขียนip a == bใน Python lexer จะพยายามอย่างดีที่สุดในการเดาว่าโทเค็นชนิดใดip(อาจเป็นตัวบ่งชี้โดย lexers ส่วนใหญ่) และส่งไปยัง parser ซึ่งบ่นเพราะคุณไม่มี ตัวระบุในตำแหน่งนั้น

a

ลองดูที่กฎไวยากรณ์สำหรับifคำสั่งของงูใหญ่ นี่คือกฎ:

if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]

กฎนั้นบอกเราว่า parser จะคิดได้อย่างไรว่าสตริงของโทเค็นที่ส่งมาจาก lexer นั้นเป็นif- สถานะ ifคำในราคาเดียวใดต้องการให้ปรากฏเช่นเดียวกับที่ในรหัสที่มาเพื่อแยกวิเคราะห์จะมองหาคำว่าธรรมดา ตัวแยกวิเคราะห์จะพยายามจับคู่โทเค็นบางอย่างกับกฎสำหรับtest:

test: or_test ['if' or_test 'else' test] | lambdef

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

หาก parser จัดการเพื่อจับคู่โทเค็นบางtestอันมันจะพยายามจับคู่โคลอน suiteหากประสบความสำเร็จก็จะพยายามให้ตรงกับราชสกุลบางมากขึ้นโดยใช้กฎสำหรับ ส่วน('elif' test ':' suite)*วิธีการที่เราสามารถมีจำนวนของการเกิดซ้ำของข้อความตัวอักษรใด ๆelifตามสิ่งที่แมตช์ตามลำไส้ใหญ่ตามด้วยสิ่งที่ตรงกับtest suiteเราสามารถมีศูนย์ซ้ำได้ เครื่องหมายดอกจันที่ท้ายหมายถึง "ศูนย์หรือมากที่สุดเท่าที่เราต้องการ"

['else' ':' suite]ที่ส่วนท้ายสุดคือ ส่วนนั้นอยู่ในวงเล็บเหลี่ยม นั่นหมายความว่าเราสามารถมีศูนย์หรือหนึ่ง แต่ไม่มีอีกต่อไป เพื่อให้ตรงนี้ความต้องการ parser เพื่อให้ตรงกับข้อความตัวอักษรลำไส้ใหญ่และแล้วelse suiteนี่คือกฎสำหรับsuite:

suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT

มันเป็นบล็อกในภาษา C เหมือนกัน เนื่องจากงูใหญ่ใช้การขึ้นบรรทัดใหม่และเยื้องไปสู่สิ่งที่หมายถึงผล lexer NEWLINE, INDENTและDEDENTราชสกุลที่จะบอก parser ที่บรรทัดใหม่เริ่มต้นที่รหัสเริ่มจะเยื้องและที่มันกำลังจะกลับไปอยู่ในระดับที่ด้านนอกของการเยื้อง

หากความพยายามในการแข่งขันใด ๆ เหล่านี้ล้มเหลวโปรแกรมแยกวิเคราะห์จะทำเครื่องหมายข้อผิดพลาดและหยุด หากการแยกวิเคราะห์ของโปรแกรมทั้งหมดประสบความสำเร็จตัวแยกวิเคราะห์มักจะสร้างแผนภูมิแยกเป็น Yu Yu ที่ครอบคลุมในคำตอบของเขาและอาจเป็นตารางสัญลักษณ์และโครงสร้างข้อมูลอื่น ๆ ที่เก็บข้อมูลความหมาย หากภาษานั้นถูกพิมพ์แบบคงที่คอมไพเลอร์จะเดินแผนผังการแยกวิเคราะห์และค้นหาข้อผิดพลาดประเภท นอกจากนี้ยังเดินแผนผังการแยกวิเคราะห์เพื่อสร้างรหัสระดับต่ำ (ภาษาแอสเซมบลี, Java bytecode, .Net Intermediate Language หรือสิ่งที่คล้ายกัน) ซึ่งเป็นสิ่งที่ใช้งานได้จริง

ขณะที่การออกกำลังกายผมอยากแนะนำให้สละไวยากรณ์ของภาษาการเขียนโปรแกรมที่คุณคุ้นเคยกับ (อีกครั้งหลาม , Javaและนี่คือC # , Javascript , C ) และพยายามที่จะมือแจงสิ่งที่ง่ายเช่นอาจจะหรือx = a + b; if (True): print("Yay!")หากคุณกำลังมองหาบางสิ่งที่ง่ายกว่านี้อีกทั้งยังมีไวยากรณ์ที่ดีสำหรับJSONซึ่งโดยทั่วไปจะครอบคลุมเฉพาะไวยากรณ์สำหรับวัตถุตัวอักษรใน Javascript (เช่น{'a': 1, 'b': 2}) โชคดีนี่คือสิ่งที่ทำให้สมองงอ แต่มันน่าสนใจจริงๆเมื่อคุณไม่ได้อยู่ในกำหนดเวลาที่บ้า


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

1
@ แซนเดอร์ฉันเพิ่งเรียนจบวิทยาลัยและวิชาเลือกของฉันส่วนใหญ่เป็นแบบนี้ ฉันจำได้ว่ากำลังสับสนโดยสิ้นเชิงและยังดูดซึมได้ทั้งหมด คุณอาจยังต้องการเอกสารที่เกี่ยวกับการออกแบบคอมไพเลอร์ที่กล่าวถึงในบล็อกนี้หรือหนังสือรู้เบื้องต้นเกี่ยวกับทฤษฎีการคำนวณโดยไมเคิลซิปเซอร์และจอห์นซีมาร์ตินรู้เบื้องต้นเกี่ยวกับภาษาและทฤษฎีของการคำนวณ คุณสามารถค้นหาสำเนามือสองราคาถูกได้ใน Amazon ทั้งสองสร้างทฤษฎีภาษาทางการเกี่ยวกับเรียบง่ายอย่างที่ควรจะเป็น
tsleyson

10

โดยสังเขป

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

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

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

ที่นี่ง่ายมากโดยเฉพาะอย่างยิ่งเกี่ยวกับภาษาธรรมชาติ

พร้อมรายละเอียดที่มากขึ้น

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

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

คำเป็นหน่วยงานเชิงวากยสัมพันธ์เพื่อเป็นตัวแทนของแนวคิดเชิงความหมายระดับต้น ๆ แต่แนวคิดพื้นฐานเหล่านี้จะต้องมีการรวมกันในหลากหลายวิธีเพื่อให้ความหมายที่ซับซ้อนมากขึ้น เราเขียน the dogเพื่อสื่อว่าเราหมายถึงสุนัขที่เฉพาะเจาะจงและthe dog bites the catเพื่อถ่ายทอดความคิดที่ซับซ้อนมากขึ้น แต่วิธีการจัดระเบียบจะต้องได้รับการแก้ไขตามกฎเพื่อให้เราสามารถบอกได้ว่าสุนัขตัวใดและแมวตัวใดกัดตัวจริง

ดังนั้นเราจึงมีกฎเช่นsentence -> subject verb complementที่ควรจะจับคู่ประโยคและบอกเราว่าความคิดที่เกี่ยวข้องกับแต่ละส่วนนั้นมีความชัดเจน กฎเหล่านี้เป็นกฎเกี่ยวกับวากยสัมพันธ์เนื่องจากพวกเขาบอกเราว่าจะจัดระเบียบข้อความของเราอย่างไร subjectตัวเองสามารถกำหนดโดยกฎsubject -> article nounและอื่น ๆ

เช่นเดียวกับในวิชาคณิตศาสตร์ คุณมีนิพจน์ทางคณิตศาสตร์ที่เขียนด้วยไวยากรณ์ที่เป็นทางการมาก และความหมายของการแสดงออกสามารถทำได้โดยการวิเคราะห์โครงสร้างประโยค ตัวอย่างเช่น 2x+1=23x123

equation -> expression "=" expression  
expression -> expression "+" expression 
expression -> number

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

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

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

เช่นเดียวกับคำพูด ลำดับตัวอักษร (หรือเสียง) บางคำเป็นคำที่ถูกต้องตามกฎหมาย

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

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

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

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

statement -> assignment
statement -> loop
loop ->  "while" expression "do" statement
assignment -> "identifier" "=" expression
expression -> "identifier"
expression -> "integer"
expression -> expression "operator" expression

ด้วยกฎดังกล่าวคุณสามารถเขียน:

while aaa /= bbb do aaa = aaa + bbb / 6 ซึ่งเป็นคำสั่ง

และวิธีการผลิตสามารถแสดงโดยโครงสร้างต้นไม้ที่เรียกว่าต้นไม้แยกหรือต้นไม้ไวยากรณ์ (ไม่สมบูรณ์ที่นี่):

                          statement
                              |
            _______________  loop _______________
           /      /                 \            \
      "while" expression           "do"       statement
       __________|_________                       |
      /          |         \                  assignment
 expression "operator" expression          _______|_______
     |           |          |             /       |       \
"identifier"   "/="   "identifier" "identifier"  "="   expression
     |                      |            |                 |
    aaa                    bbb          aaa             ... ...

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

กฎดังกล่าวเรียกว่าไม่มีบริบทเนื่องจากไม่มีเทอร์มินัลสามารถถูกแทนที่โดยพลการโดยใช้กฎที่เกี่ยวข้องใด ๆ โดยไม่ขึ้นอยู่กับบริบทที่ปรากฏ ชุดของกฎที่กำหนดภาษานั้นเรียกว่าไวยากรณ์ที่ไม่มีบริบท

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

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

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

parser ของคอมไพเลอร์สามารถสร้างโครงสร้างข้อมูลที่สอดคล้องกับ parse-tree และส่งไปยังขั้นตอนต่อไปของกระบวนการรวบรวม แต่มันไม่จำเป็นต้อง การรันจำนวนอัลกอริธึมการแยกวิเคราะห์เพื่อพัฒนากลยุทธ์การคำนวณเพื่อสำรวจโครงสร้างไวยากรณ์ที่อยู่ในข้อความของโปรแกรม แผนผังไวยากรณ์ / การแยกวิเคราะห์นี้อาจหรืออาจไม่สามารถอธิบายได้ในกระบวนการขึ้นอยู่กับกลยุทธ์การรวบรวม (จำนวนขั้นตอน) สิ่งที่จำเป็นคือแม้ว่าท้ายที่สุดแล้วจะมีการสำรวจล่างขึ้นบนอย่างน้อยหนึ่งครั้งของการแยกวิเคราะห์ต้นไม้ไม่ว่าจะเป็นการสำรวจหรือการบอกเป็นนัยในโครงสร้างการคำนวณ

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

ตัวอย่างประโยคสามารถวิเคราะห์ได้ด้วยกฎthe dog bites the cat sentence -> subject verb complementรู้ความหมายของ 3 subtrees subject, verbและcomplementกฎที่ประกอบด้วยพวกเขาบอกเราว่าเรื่องที่จะทำดำเนินการและว่าแมวเป็นหนึ่งในผู้ที่ถูกกัด

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

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


ยอดเยี่ยมมีประโยชน์มาก ฉันเข้าใจว่ามีการใช้ regex ในกระบวนการ tokenization (ตัวอย่างเช่นตัวอักษรสตริงสามารถกำหนดโดย"[^"]*"ในรูปแบบที่ง่ายที่สุดโดยไม่สนใจตัวอักษรหลบหนี ฯลฯ ) แต่มันยังใช้ในการสร้างต้นไม้ไวยากรณ์ (พูดในแง่ของภาษาโปรแกรม) ฉันไม่เข้าใจว่าสถานะออโตมาต้า จำกัด โดยนิยาม จำกัด ต้นไม้ไวยากรณ์แม้ifคำสั่งเดียวสามารถไม่มีที่สิ้นสุดในทางทฤษฎีเนื่องจากการทำรัง ดังนั้น regex การเป็นออโตเมทริก จำกัด ของรัฐจึงไม่สามารถใช้เพื่อวัตถุประสงค์ในการสร้างทรีไวยากรณ์
Zwander

@Zwander ขอบคุณ 4 การแก้ไข - ตัวอย่าง regex ของคุณถูกต้อง (ฉันควรยกตัวอย่าง) BTW, Regex ยังเป็นภาษาที่มีความหมายของตัวเองในโลกของชุดของสตริงและมีไวยากรณ์Context-Free ( CF ) มันจะใช้สำหรับโทเค็นของสตริงภาษาอย่างน้อยสำหรับภาษาการเขียนโปรแกรมมักจะไม่ได้ในการกำหนดไวยากรณ์ขนาดใหญ่ที่ใช้สำหรับต้นไม้ไวยากรณ์ยกเว้นมือสั้นในขยาย BNF (EBNF) การเพิ่ม Regex ในบางรูปแบบให้กับพิธีการที่ซับซ้อนมากขึ้นไม่ได้เปลี่ยนพลังการแสดงออกในกรณีส่วนใหญ่ ข้อสังเกตของคุณเกี่ยวกับอนันต์นั้นไม่ถูกต้องนัก ดูความคิดเห็นต่อไป
babou

@Zwander มีการอธิบายอย่างเป็นทางการทั้งหมด (ภาษาที่เป็นทางการ) นั่นคือสมมติฐานพื้นฐาน แม้ว่าคุณสนใจพูดไวยากรณ์ CF ด้วยกฎที่ไม่มีที่สิ้นสุดคุณจะต้องให้คำอธิบายที่ จำกัด ของกฎนั้น นอกจากนี้อินฟินิตี้เล่นเทคนิคกับคุณ (ไม่มีที่ว่างสำหรับที่) ifคำสั่งมากมาย (พลขนาดใหญ่) แต่มักจะ จำกัด อนันต์กำหนดขอบเขตเป็นif whileความแตกต่างระหว่าง CF และปกติคือ CF control / ยอมให้ซ้อน (เช่น parenthetization) ในขณะที่ปกติไม่ได้ แต่ทั้งคู่มีการอธิบายอย่างละเอียดและอนุญาตให้ใช้สตริงที่ไม่ จำกัด
babou

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

1
(((A-B)+3)×C)

2

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

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


1

ภาษาทางการเป็นชุดของคำ - ที่คำเป็นสตริงของสัญลักษณ์จากตัวอักษรบางตัว

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

ดังนั้นภาษาปกติที่สอดคล้องกับนิพจน์(a|b)*c*dจึงถูกกำหนดโดยกฎการผลิต

S->ACd
A->
A->aA
A->bA
C->
C->cC

คำที่กฎการผลิตเหล่านี้สร้างขึ้นจากสัญลักษณ์เริ่มต้น S นั้นจะเป็นสตริงที่การแสดงออกปกติยอมรับ


0

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

พฤติกรรมการรวมสามวิธีเดียวกันนั้นพบได้ในนิพจน์ทั่วไป โยนสายย่อยและคุณมีความคล้ายคลึงกับ EBNF

ดังนั้นจึงมีความคล้ายคลึงกันมากระหว่างพีชคณิตของนิพจน์ทั่วไปและพีชคณิตของคำสั่ง รายละเอียดนี้ได้รับการสำรวจโดย Dijkstra ใน "The Unification of Three Calculi" นอกจากนี้ยังเป็นพื้นฐานของ CCS ของ Milner ซึ่งให้คำตอบสำหรับคำถาม: ถ้าเราเพิ่มความเท่าเทียม

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