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


12

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

ฉันคิดว่ามันจะต้องเป็นแบบกดลงอัตโนมัติเพราะ presense ของวงเล็บหมายถึงความจำเป็นในการนับและ DFA / NFA ไม่สามารถทำการนับโดยพล สมมติฐานนี้ถูกต้องหรือไม่ ตัวอย่างเช่นนิพจน์ a (bc *) d อาจต้องการ PDA เพื่อให้การจัดการนิพจน์ย่อยในวงเล็บถูกต้อง


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

สำหรับคำตอบที่จริงคุณอาจจะมองไปที่แหล่งที่มาของแผน 9 Grep สำหรับ grep.y
Bruce Ediger

คำตอบ:


8

คุณถูก. มันเป็นเรื่องง่ายที่จะแสดงให้เห็นว่าไวยากรณ์ของการแสดงออกปกติไม่ได้เป็นปกติโดยใช้เทคนิคมาตรฐาน

ความเป็นไปได้อย่างหนึ่งคือการใช้โฮโมมอร์ฟิซึม (ซึ่งปิดอยู่) เพื่อกำจัดสัญลักษณ์ทั้งหมดยกเว้นวงเล็บซึ่งทำให้คุณมีภาษา Dyckซึ่งเป็นที่รู้จักกันดีว่าไม่ธรรมดา หากมีข้อสงสัยให้ใช้แทรกสูบน้ำบน P( p ) pREG(p)p

ที่กล่าวว่าคุณอาจไม่ต้องการรหัส PDA ด้วยมือ พิจารณาการใช้เครื่องกำเนิดไฟฟ้า parser เช่นANTLRหรือbyacc หากในมืออื่น ๆ ที่คุณต้องการตรวจสอบแยกของภาษาโดยการเขียนโปรแกรม parsers ตัวเองคุณควรดำเนินการต่อด้วยขั้นตอนวิธีการแยกวิเคราะห์พื้นฐานอื่น ๆ เช่นCYK , เออร์ลีย์ , โคตร recursiveและLR


ขอบคุณ เขียนโค้ดสำหรับงานเหล่านี้จะสร้างความเข้าใจที่ดีและไม่ได้ตั้งใจจะให้เป็นที่มีประสิทธิภาพสาธารณูปโภคที่มีอยู่เช่น lex, yacc กระทิง ฯลฯ
ฟิลไรท์

@PhilWright: ฉันเห็นแล้วดี! ฉันแก้ไขตัวชี้เพิ่มเติมสำหรับกรณีนี้
Raphael

ฉันชอบโปรแกรมแยกวิเคราะห์โคตรแบบ recursive ที่เขียนด้วยมือสำหรับอันนี้
Dave Clarke

หากเขียนตัวแยกวิเคราะห์ด้วยตัวเองสำหรับสิ่งนี้เชื้อสายแบบเรียกซ้ำ (หลังจากแฟ็กตอริ่งและการนวด) เป็นตัวเลือกตัวแยกวิเคราะห์ LCC สำหรับ C < sites.google.com/site/lccretargetablecompiler > C มีส่วนที่น่าสนใจในการจัดการตัวดำเนินการจำนวนมาก แต่บางทีการสร้างมือที่ง่ายที่สุดก็คือการแยกวิเคราะห์
vonbrand

3

ฉันแนะนำให้คุณอ่านคำตอบที่ดีของ Jukka สำหรับคำถาม "การจับคู่นิพจน์ทั่วไปโดยใช้นิพจน์ทั่วไป " ใน cstheory เช่นกัน ข้อความที่ตัดตอนมา:

ตัวอย่างเช่นเราสามารถแก้ไขสัญกรณ์มาตรฐานดังต่อไปนี้เพื่อรับนิพจน์ปกติ "ที่บีบอัด" :

  • คุณได้รับอนุญาตให้ลบคำนำหน้าใด ๆ ที่ประกอบด้วยลำดับ ((s)
  • คุณได้รับอนุญาตให้ลบคำต่อท้ายใด ๆ ที่ประกอบด้วยลำดับ)

นั่นคือ((a|b)*c)de(f|g)สามารถแสดงใน "บีบอัด" สัญกรณ์ใช้ตัวอย่างเช่นรูปแบบใด ๆ ต่อไปนี้: a|b)*c)de(f|gหรือหรือ((a|b)*c)de(f|g(a|b)*c)de(f|g)

[ ... ]

เครื่องหมาย "ที่ถูกบีบอัด" (ของนิพจน์ทั่วไป) เป็นภาษาปกติ

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


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

4
คุณ (และ Jukka) ไม่ได้แยกวิเคราะห์ regexps เพียงจำพวกเขาได้ “ ใช่นั่นคือ regexp (บีบอัด)”
Gilles 'หยุดความชั่วร้าย'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.