ข้อผิดพลาดทางไวยากรณ์เกิดขึ้นในกระบวนการใด (โทเค็นหรือแยกวิเคราะห์)


23

ฉันพยายามที่จะเข้าใจการรวบรวมและการตีความทีละขั้นตอนหาภาพรวม ดังนั้นฉันจึงพบคำถามขณะอ่านhttp://www.cs.man.ac.uk/~pjj/farrell/comp3.htmlบทความนี้

มันบอกว่า :

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

แต่ฉันไม่สามารถหาวิธี tokenizer สามารถโทเค็นสตรีมที่กำหนดอย่างถูกต้องซึ่งมีข้อผิดพลาดทางไวยากรณ์

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

ดังนั้นวิธีที่จะเอาชนะบรรทัดที่มีความเสียหายของคำศัพท์ในขณะที่โทเค็น

มีตัวอย่างของโทเค็นภายในลิงก์ด้านบนที่ส่วนหัวของTokenizer

ตามที่ฉันเข้าใจรูปแบบของโทเค็นดูเหมือนว่าหากมีสิ่งผิดปกติในโทเค็นรหัสจะเสียหายเช่นกัน

คุณช่วยอธิบายความเข้าใจผิดของฉันได้ไหม?

คำตอบ:


32

tokenizer เป็นเพียงการแยกวิเคราะห์การเพิ่มประสิทธิภาพ เป็นไปได้อย่างสมบูรณ์ที่จะใช้ parser โดยไม่มี tokenizer

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

$a + $b

สามารถแสดงโดยโทเค็น

Variable('$a'),
Plus('+'),
Variable('$b')

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

$a $b + +

จะสร้างกระแสโทเค็นอย่างมีความสุข

Variable('$a'),
Variable('$b'),
Plus('+'),
Plus('+')

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

ตัวแยกวิเคราะห์อาจยังล้มเหลวในระยะ tokenizer ตัวอย่างเช่นอาจมีอักขระที่ผิดกฎหมาย:

$a × ½ — 3

PHP tokenizer จะไม่สามารถจับคู่อินพุตนี้กับกฎของมันและจะสร้างข้อผิดพลาดก่อนที่การแยกวิเคราะห์หลักจะเริ่มขึ้น

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


ดังนั้นเราจึงคิดว่า tokenizer เป็นส่วนหนึ่งของ parser และข้อผิดพลาดทางไวยากรณ์สามารถเกิดขึ้นได้ทั้งขั้นตอน tokenizing หรือขั้นตอนการแยกตามรูปแบบข้อผิดพลาดทางไวยากรณ์ ขอขอบคุณสำหรับการชี้แจง.
FZE

4
@FZE: คุณสามารถคิดแบบนั้น แต่มันทำให้เข้าใจผิด Lexing ไม่ได้เป็นเพียงแค่การแยกวิเคราะห์การเพิ่มประสิทธิภาพ ค่อนข้าง lexing แผนที่ตัวแทนทางกายภาพ (บางส่วนของตัวละคร) ลงในการเป็นตัวแทนตรรกะ (โทเค็นที่แสดงโดยตัวละครเหล่านั้น) สิ่งนี้แยกตัวแยกวิเคราะห์จาก minutiae เช่นวิธีที่จุดสิ้นสุดของบรรทัดแสดงหรือไม่ว่าคุณตัดสินใจที่จะเป็นตัวแทนตรรกะ - และandหรือ&&หรืออย่างอื่น มันแยกส่วนใหญ่และแตกต่างจากการแยกวิเคราะห์ การเพิ่มประสิทธิภาพ (ถ้ามี) เป็นผลข้างเคียงเกือบโดยไม่ได้ตั้งใจ
Jerry Coffin

@JerryCoffin ขอบคุณสำหรับคำอธิบายเพิ่มเติมมันสมเหตุสมผลมากกว่าตอนนี้
FZE

2
@JerryCoffin, amon ถูกต้องนั่นคือความแตกต่างไม่ใช่พื้นฐาน คุณสามารถสร้างไวยากรณ์ BNF ที่มีลักษณะเหนียวซึ่งครอบคลุมทั้งส่วน "lexer" และ "parser" เรามักจะแบ่งกฎออกเป็นระดับต่ำ (เช่นตัวเลขตัวดำเนินการเพิ่มเติม) และระดับสูง (ผลรวม) แต่ไวยากรณ์นั้นไม่ได้แยกความแตกต่างดังกล่าว
พอลเดรเปอร์

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

16

โดยปกติคุณคาดหวังว่าข้อผิดพลาดทางไวยากรณ์ส่วนใหญ่จะมาจาก parser ไม่ใช่ lexer

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

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


11

Tokenizer เพียงแยกสตรีมอักขระออกเป็นโทเค็น จาก tokenizer POV นี่ใช้ได้อย่างสมบูรณ์:

1 * * 1

และแปลเป็นเช่น: ["1", MULTIPLY, MULTIPLY, "1"] ตัวแยกวิเคราะห์เท่านั้นที่สามารถปฏิเสธนิพจน์ดังกล่าวได้ - มันรู้ว่าตัวดำเนินการทวีคูณไม่สามารถติดตามตัวดำเนินการคูณอื่นได้ ตัวอย่างเช่นใน JavaScript สิ่งนี้ก่อให้เกิด:

Uncaught SyntaxError: Unexpected token *(…)

มีข้อผิดพลาดซึ่งอาจตรวจพบโดย tokenizer ตัวอย่างที่ยังไม่เสร็จสายอักขระตัวอักษร: หรือตัวเลขที่ไม่ถูกต้อง:"abc 0x0abcdefgพวกเขายังอาจถูกรายงานว่าเป็นข้อผิดพลาดทางไวยากรณ์แม้ว่า:

Uncaught SyntaxError: Unexpected token ILLEGAL

ILLEGALหมายเหตุอย่างไรก็ตามโทเค็นที่ไม่ได้รับการยอมรับและมีการรายงานว่า

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