ฉันจะทำให้การทำนายโทเค็น DFA ง่ายขึ้นได้อย่างไร

Lexer DFA ส่งผลให้เกิดข้อผิดพลาด "รหัสใหญ่เกินไป"

ฉันกำลังพยายามแยกวิเคราะห์ Java Server Pages โดยใช้ ANTLR 3

Java มีขีดจำกัดที่ 64k สำหรับโค้ดไบต์ของวิธีเดียว และฉันยังคงพบข้อผิดพลาด "โค้ดใหญ่เกินไป" เมื่อคอมไพล์ซอร์ส Java ที่สร้างโดย ANTLR

ในบางกรณี ฉันสามารถแก้ไขได้โดยประนีประนอมกับเล็กเซอร์ของฉัน ตัวอย่างเช่น JSP ใช้โทเค็น "ชื่อ" ของ XML ซึ่งสามารถรวมอักขระได้หลากหลาย ฉันตัดสินใจยอมรับเฉพาะอักขระ ASCII ในโทเค็น "ชื่อ" ของฉัน ซึ่งทำให้การทดสอบบางอย่างใน and lexer ง่ายขึ้นอย่างมาก อนุญาตให้คอมไพล์ได้

อย่างไรก็ตาม ฉันมาถึงจุดที่ฉันไม่สามารถตัดมุมได้อีกต่อไป แต่ DFA ยังคงซับซ้อนเกินไป

ฉันควรทำอย่างไรกับเรื่องนี้?

มีข้อผิดพลาดทั่วไปที่ส่งผลให้เกิด DFA ที่ซับซ้อนหรือไม่

มีวิธียับยั้งการสร้าง DFA หรือไม่ อาจอาศัยภาคแสดงความหมายหรือการค้นหาล่วงหน้าแบบตายตัวเพื่อช่วยในการทำนาย

การเขียน lexer นี้ด้วยมือจะเป็นเรื่องง่าย แต่ก่อนที่ฉันจะเลิกใช้ ANTLR ฉันต้องการให้แน่ใจว่าฉันไม่ได้มองข้ามบางสิ่งที่ชัดเจน

พื้นหลัง

ANTLR 3 lexers ใช้ DFA เพื่อตัดสินใจว่าจะโทเค็นอินพุตอย่างไร ใน DFA ที่สร้างขึ้น มีเมธอดที่เรียกว่า specialStateTransition() วิธีนี้มีคำสั่ง switch พร้อมด้วยตัวพิมพ์เล็กและตัวพิมพ์ใหญ่สำหรับแต่ละรัฐใน DFA ภายในแต่ละกรณี จะมีชุดคำสั่ง if ชุดหนึ่งสำหรับการเปลี่ยนจากสถานะแต่ละครั้ง เงื่อนไขของคำสั่ง if แต่ละรายการจะทดสอบอักขระอินพุตเพื่อดูว่าตรงกับการเปลี่ยนแปลงหรือไม่

เงื่อนไขการทดสอบอักขระเหล่านี้อาจซับซ้อนมาก โดยปกติจะมีแบบฟอร์มดังต่อไปนี้:

int ch = … ; /* "ch" is the next character in the input stream. */
switch(s) { /* "s" is the current state. */
  …
  case 13 :
    if ((('a' <= ch) && (ch <= 'z')) || (('A' <= ch) && (ch <= 'Z')) || … )
      s = 24; /* If the character matches, move to the next state. */
    else if …

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

ฉันพบไวยากรณ์ ANTLR 2 ในเครื่องมือ Jsp2x แต่ฉันไม่พอใจกับแผนผังการแยกวิเคราะห์ของมัน และฉันต้องการรีเฟรชทักษะ ANTLR ของฉัน ดังนั้นฉันคิดว่าฉันจะลองเขียนของตัวเอง ฉันใช้ ANTLRWorks และฉันพยายามสร้างกราฟสำหรับ DFA แต่ดูเหมือนว่าจะมีข้อบกพร่องใน ANTLRWorks ที่ป้องกันได้


person erickson    schedule 22.09.2011    source แหล่งที่มา
comment
ดูคำถามนี้สำหรับกรณีของโค้ด ใหญ่เกินไป โดยที่การเปลี่ยนแปลงไวยากรณ์จะลบ specialStateTransition ออกทั้งหมด   -  person Gunther    schedule 22.09.2011
comment
@ กุนเธอร์ อ่า ใช่ ภาคแสดงภายในไวยากรณ์นั้นทำให้เกิดสิ่งนั้น! ฉันลืมช่วงถามตอบนั้นไปหมดแล้ว! ฉันจะทำให้มันเป็นที่โปรดปราน   -  person Bart Kiers    schedule 23.09.2011


คำตอบ (2)


ไวยากรณ์ที่มีขนาดใหญ่มาก (โทเค็นที่แตกต่างกันจำนวนมาก) มีปัญหานั้น แต่น่าเสียดาย (ไวยากรณ์ SQL ก็ประสบปัญหานี้เช่นกัน)

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

โดยทั่วไป ปัญหานี้ได้รับการแก้ไขด้วยการแบ่งไวยากรณ์ lexer ออกเป็น 2 ไวยากรณ์ของ lexer หรือมากกว่า จากนั้นนำเข้าไวยากรณ์ "หลัก" เดียว ในแง่ ANTLR สิ่งเหล่านี้เรียกว่า ไวยากรณ์คอมโพสิต ดูหน้า ANTLR Wiki เกี่ยวกับพวกเขา: http://www.antlr.org/wiki/display/ANTLR3/Composite+Grammars

แก้ไข

ตามที่ @Gunther กล่าวถึงอย่างถูกต้องในความคิดเห็นใต้ OP ดูคำถาม & คำตอบ: เหตุใดคลาส antlr lexer java ของฉันจึงมีโค้ดใหญ่เกินไป โดยที่การเปลี่ยนแปลงเล็กน้อย (การลบเพรดิเคตบางตัวออก) ทำให้ข้อผิดพลาด "โค้ดใหญ่เกินไป" นี้หายไป

person Bart Kiers    schedule 22.09.2011

จริงๆ แล้ว การสร้างไวยากรณ์ผสมไม่ใช่เรื่องง่ายเสมอไป ในหลายกรณี AntTask นี้ช่วยได้ เพื่อแก้ไขปัญหานี้ (จะต้องรันทุกครั้งหลังจากคอมไพล์ไวยากรณ์ใหม่ แต่กระบวนการนี้ไม่น่าเบื่อนัก)

น่าเสียดายที่แม้แต่สคริปต์เวทย์มนตร์นี้ก็ไม่ได้ช่วยในบางกรณีที่ซับซ้อน คอมไพเลอร์อาจเริ่มบ่นเกี่ยวกับบล็อก การเปลี่ยนผ่าน DFA (ฟิลด์สตริงคงที่ []) ที่มีขนาดใหญ่เกินไป

ฉันพบวิธีง่ายๆ ในการแก้ปัญหาโดย การย้าย (โดยใช้คุณลักษณะการปรับโครงสร้างใหม่ของ IDE) ฟิลด์ดังกล่าวไปยังคลาสอื่น ด้วยชื่อที่สร้างขึ้นโดยพลการ จะช่วยได้เสมอเมื่อย้ายเพียงหนึ่งฟิลด์ขึ้นไปในลักษณะดังกล่าว

person Andremoniy    schedule 18.09.2012