เมื่อ lexing เพียงพอคุณต้องการ EBNF เมื่อใด
EBNF ไม่ได้เพิ่มพลังของไวยากรณ์มากนัก มันเป็นเพียงสัญลักษณ์ความสะดวกสบาย / ทางลัด / "น้ำตาลประโยค"เหนือกฎไวยากรณ์มาตรฐานฟอร์มฟอร์ม (CNF) ของ Chomsky ตัวอย่างเช่นทางเลือก EBNF:
S --> A | B
คุณสามารถประสบความสำเร็จใน CNF เพียงแค่แสดงรายการการผลิตทางเลือกแต่ละรายการแยกกัน:
S --> A // `S` can be `A`,
S --> B // or it can be `B`.
องค์ประกอบเสริมจาก EBNF:
S --> X?
คุณสามารถประสบความสำเร็จใน CNF โดยใช้nullableการผลิตที่เป็นหนึ่งที่สามารถถูกแทนที่ด้วยสตริงที่ว่างเปล่า (แสดงโดยเพียงแค่การผลิตที่ว่างเปล่าที่นี่ที่คนอื่นใช้ epsilon หรือแลมบ์ดาหรือวงกลมข้าม):
S --> B // `S` can be `B`,
B --> X // and `B` can be just `X`,
B --> // or it can be empty.
การผลิตในรูปแบบเดียวกับที่กล่าวB
ข้างต้นเรียกว่า "ลบ" เพราะสามารถลบสิ่งที่มันหมายถึงในการผลิตอื่น ๆ (ผลิตภัณฑ์สตริงที่ว่างเปล่าแทนสิ่งอื่น)
การทำซ้ำไม่เกินศูนย์จาก EBNF:
S --> A*
คุณสามารถ obtan โดยใช้การผลิตซ้ำซึ่งก็คือการฝังตัวอยู่ที่ไหนสักแห่งในนั้น สามารถทำได้สองวิธี อันแรกเหลือการเรียกซ้ำ (ซึ่งควรหลีกเลี่ยงเพราะตัวแยกวิเคราะห์แบบโคตรบนลงล่างไม่สามารถแยกวิเคราะห์ได้):
S --> S A // `S` is just itself ended with `A` (which can be done many times),
S --> // or it can begin with empty-string, which stops the recursion.
เมื่อรู้ว่ามันสร้างเพียงสตริงว่าง (ท้ายที่สุด) ตามด้วยศูนย์หรือมากกว่าA
นั้นสตริงเดียวกัน ( แต่ไม่ใช่ภาษาเดียวกัน! ) สามารถแสดงโดยใช้การเรียกซ้ำแบบขวา :
S --> A S // `S` can be `A` followed by itself (which can be done many times),
S --> // or it can be just empty-string end, which stops the recursion.
และเมื่อพูดถึง+
การทำซ้ำหนึ่งครั้งหรือมากกว่าจาก EBNF:
S --> A+
มันสามารถทำได้โดยแยกออกเป็นหนึ่งA
และใช้*
เป็นมาก่อน:
S --> A A*
ซึ่งคุณสามารถแสดงเป็น CNF ได้เช่นนี้ (ฉันใช้การเรียกซ้ำที่ถูกต้องที่นี่ลองคิดดูอีกแบบว่าเป็นแบบฝึกหัด):
S --> A S // `S` can be one `A` followed by `S` (which stands for more `A`s),
S --> A // or it could be just one single `A`.
เมื่อรู้แล้วว่าตอนนี้คุณสามารถจดจำไวยากรณ์สำหรับนิพจน์ทั่วไป (นั่นคือไวยากรณ์ปกติ ) เป็นรูปแบบที่สามารถแสดงในการผลิต EBNF เดียวที่ประกอบด้วยสัญลักษณ์เทอร์มินัลเท่านั้น โดยทั่วไปคุณสามารถรับรู้ไวยากรณ์ปกติเมื่อคุณเห็นการผลิตที่คล้ายกับสิ่งเหล่านี้:
A --> // Empty (nullable) production (AKA erasure).
B --> x // Single terminal symbol.
C --> y D // Simple state change from `C` to `D` when seeing input `y`.
E --> F z // Simple state change from `E` to `F` when seeing input `z`.
G --> G u // Left recursion.
H --> v H // Right recursion.
นั่นคือการใช้เพียงสตริงว่างสัญลักษณ์ terminal, อาคารผู้โดยสารไม่ง่ายสำหรับการแทนและการเปลี่ยนแปลงของรัฐและการใช้ recursion เดียวที่จะบรรลุการทำซ้ำ (ซ้ำซึ่งเป็นเพียงการเรียกซ้ำเชิงเส้น - หนึ่งซึ่งจะมีลักษณะเหมือนต้นไม้ไม่สาขา) ไม่มีอะไรขั้นสูงเหนือสิ่งเหล่านี้จากนั้นคุณแน่ใจว่ามันเป็นไวยากรณ์ปกติและคุณสามารถไปกับ lexer เพียงแค่นั้น
แต่เมื่อซินแท็กซ์ของคุณใช้การเรียกซ้ำในลักษณะที่ไม่สำคัญเพื่อสร้างโครงสร้างที่มีลักษณะคล้ายต้นไม้ที่มีโครงสร้างคล้ายกันในตัวเองคล้ายกับโครงสร้างต่อไปนี้
S --> a S b // `S` can be itself "parenthesized" by `a` and `b` on both sides.
S --> // or it could be (ultimately) empty, which ends recursion.
จากนั้นคุณสามารถเห็นได้อย่างง่ายดายว่าสิ่งนี้ไม่สามารถทำได้ด้วยการแสดงออกปกติเพราะคุณไม่สามารถแก้ไขมันเป็นการผลิต EBNF เดียวในทางใดทางหนึ่ง; คุณจะลงเอยด้วยการทดแทนS
อย่างไม่มีกำหนดซึ่งจะเพิ่มอีกa
s และb
s ทั้งสองด้านเสมอ lexers (มากขึ้นโดยเฉพาะ: Finite รัฐออโตใช้โดย lexers) ไม่สามารถนับจำนวนข้อ (? พวกเขาจะ จำกัด จำ) ดังนั้นพวกเขาจึงไม่ทราบว่าหลายa
ท่านอยู่ที่นั่นเพื่อให้ตรงกับพวกเขาอย่างเท่าเทียมกันด้วยดังนั้นหลายb
s Grammars เช่นนี้เรียกว่าgrammars ที่ไม่มีบริบท (อย่างน้อยที่สุด) และพวกเขาต้องการเครื่องมือแยกวิเคราะห์
ไวยากรณ์ที่ไม่มีบริบทเป็นที่รู้จักกันดีในการแยกวิเคราะห์ดังนั้นจึงถูกใช้อย่างกว้างขวางเพื่ออธิบายไวยากรณ์ของภาษาโปรแกรม แต่ยังมีอีกมากมาย บางครั้งจำเป็นต้องใช้ไวยากรณ์ทั่วไปเพิ่มเติม - เมื่อคุณมีสิ่งที่ต้องนับเพิ่มในเวลาเดียวกันโดยอิสระ ตัวอย่างเช่นเมื่อคุณต้องการอธิบายภาษาที่หนึ่งสามารถใช้วงเล็บกลมและวงเล็บสี่เหลี่ยม interleaved แต่พวกเขาจะต้องมีการจับคู่ขึ้นอย่างถูกต้องกับแต่ละอื่น ๆ (วงเล็บด้วยวงเล็บปีกกากลมกับรอบ) ชนิดของไวยากรณ์นี้เรียกว่าบริบท คุณสามารถรับรู้โดยที่มันมีมากกว่าหนึ่งสัญลักษณ์ทางด้านซ้าย (ก่อนที่ลูกศร) ตัวอย่างเช่น:
A R B --> A S B
คุณสามารถนึกถึงสัญลักษณ์เพิ่มเติมเหล่านี้ทางซ้ายเป็น "บริบท" สำหรับการใช้กฎ อาจมีปัจจัยพื้นฐานบาง postconditions ฯลฯ ตัวอย่างเช่นกฎดังกล่าวข้างต้นจะแทนR
เข้าไปS
แต่เมื่อมันอยู่ในระหว่างA
และB
ทิ้งเหล่านั้นA
และB
ตัวเองไม่เปลี่ยนแปลง ไวยากรณ์ชนิดนี้ยากที่จะแยกวิเคราะห์จริงๆเพราะต้องใช้เครื่องทัวริงแบบเต็มรูปแบบ มันเป็นอีกเรื่องหนึ่งดังนั้นฉันจะจบที่นี่