2006/Sep/12

รู้จัก lex & yacc ไหมครับ ?

หนึ่งในเรื่องที่คนเรียนคอมพ์หลายคนขยาด
แต่เป็นหนึ่งในเรื่องที่ผมชอบมากที่สุดตอนเรียน

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

เสียดายที่เวลาจำกัดทำให้อาจารย์สามารถสอนได้แค่ lex
ส่วน yacc ต้องไปศึกษาต่อเอง (ซึ่งแน่นอนว่าไม่ได้ทำ)

สรุปว่า เรียนจบมาโดยที่ยังไม่รู้ว่าจะนำ lex & yacc ไปใช้ประโยชน์อย่างไร


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

แน่นอนว่าต้องเริ่มรื้อฟื้นศึกษากันใหม่พอสมควร


lex

ส่วน lex ตอนแรกก็ไม่มีปัญหาอะไรมาก
ตัด ๆ ข้อความออกเป็น token แล้วส่งให้ yacc ไปตรวจไวยากรณ์และตีความต่อ

ปัญหาเกิดขึ้นเมื่อต้องการให้ใส่ "ข้อความ" ได้

กำหนดไวยากรณ์ไว้แบบนี้
ERRORMSG( ข้อความ )

ดูเหมือนจะง่าย ๆ แต่ถ้าต้องการให้ข้อความสามารถใช้เครื่องหมายวงเล็บได้ล่ะ ?
เช่น ERRORMSG( ผิดพลาด(255) ) เป็นต้น

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


yacc

ตัวยากคือเจ้านี่แหละครับ

yacc มีหน้าที่ตรวจสอบว่า token ต่าง ๆ ที่รับมาจาก lex นั้นเรียงลำดับถูกต้องตามที่ควรจะเป็น
โดยเราจะต้องเขียน "กฎไวยากรณ์" ให้ครบในทุก ๆ กรณี

ถึงแม้จะยาก แต่ก็เป็นส่วนที่สนุกที่สุดแล้วล่ะ

กฎที่เขียนออกมาตอนแรกเจอ conflict มากมาย
ที่ทำให้ข้อความเดียวกันสามารถตีความได้หลายแบบ (ambiguous)

อันนี้ต้องลองผิดลองถูกล้วน ๆ เพราะเพิ่งจับ yacc เป็นครั้งแรก
ผลลัพธ์สุดท้ายเมื่อแก้ conflict ได้หมด ก็เป็นไปตามที่หนังสือว่าไว้

" Languages that yacc has trouble parsing are often hard for people to parse in their heads; you'll end up with a better language design once you change your language to remove the conflicts. "

- จากหนังสือ lex & yacc

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

สำหรับใครที่คิดจะใช้ yacc แนะนำว่า ต้องศึกษากลไกการทำงานของ yacc เสียก่อน
ว่ามีวิธีการ shift & reduce อย่างไร คุณจะใช้ประโยชน์จาก yacc ได้หรือไม่ก็อยู่ตรงนี้แหละ


flex = lex และ bison = yacc

lex กับ yacc ต้นฉบับมันเก่าแล้ว ก็มีคนพัฒนาตัวใหม่ ๆ ออกมาหลายตัวด้วยกัน
ตัวที่ผมใช้คือเจ้าสองตัวนี้
  • flex สำหรับ lex
  • bison สำหรับ yacc
เป็นโอเพนซอร์ส นำมาคอมไพล์และติดตั้งบนลินุกซ์ได้โดยไม่มีปัญหา


bison กับภาษา C++

อันนี้เป็นคำเตือนสำหรับผู้ที่จะใช้ flex & bison กับโปรแกรมที่พัฒนาด้วยภาษา C++

ตอนแรกผมใช้ภาษา C ในการศึกษาวิธีการใช้งาน flex & bison
และพัฒนากฎขึ้นมาให้ทำงานตามต้องการ

แต่โปรแกรมที่จะนำไปใช้จริง ๆ มันเป็นภาษา C++ ครับ

โดยปกติโปรแกรมภาษา C สามารถนำไปใช้งาน
กับคอมไพเลอร์ภาษา C++ ได้อย่างไม่มีปัญหา
แต่ไม่ใช่สำหรับเจ้า flex & bison


พอเปลี่ยนคอมไพเลอร์จาก gcc ไปเป็น g++
ก็พบปัญหาว่า ลิงก์ไม่ผ่าน เนื่องจากฟังก์ชัน yylex() หายไป

ค้นข้อมูลและอ่านซอร์สโค้ดที่ flex & bison สร้างขึ้นมาให้โดยละเอียด
ก็พบว่า ตัว bison เองมีโหมดสำหรับภาษา C++ โดยเฉพาะ
ซึ่งในโหมดภาษา C++ นี้ ตัว bison จะสร้างโค้ดของ yacc ขึ้นมาให้เป็นคลาส (class) ครับ

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


นั่นหมายความว่า ถ้าต้องการใช้ bison กับ g++
คุณจะต้องใช้ yacc ผ่านคลาสที่ bison สร้างขึ้นมาให้เท่านั้นครับ
ไม่มีทางเลือกอื่น นอกจากจะขยันเขียน yylex() ขึ้นมาเอง


ตอนนี้งานก็เลยยังไม่เสร็จซะที
ต้องมาศึกษาเพิ่มว่า คลาส yacc ตัวนี้ใช้งานยังไง

หวังว่าจะเสร็จได้ทันพรุ่งนี้นะ....


เอาน่า ศึกษาไว้ทีเดียวคุ้ม
เริ่มใช้เป็นแล้วก็สามารถเอาไปประยุกต์ใช้ได้อีกหลายอย่างเลย ^^



อัพเดต

กว่าจะทำให้ใช้กับ C++ ได้ ก็หกโมงเย็นของวันที่ 13 พอดี
พรุ่งนี้ต้องนำเข้าไปรวมกับโปรแกรมจริง เสียเวลาเพิ่มอีก 1 วัน T_T

เปลี่ยนไปใช้ ANTLR แล้วชีวิตอาจจะดีขึ้นบ้าง
#1  by  veer At 2006-09-12 19:46, 
มาเขียน tutorial ด้วย
#2  by  house At 2006-09-12 20:27, 
เคยไปนั่งเรียนไม่กี่คาบ งงเป็นไก่ตาแตกเลย
#3  by  Compman At 2006-09-12 22:26, 
คิดถึงด้วยคน ....

ตอนนั้นเรียนไปยังไงไม่รู้แฮะ ...ลืมหมดแย้ววว T-T
แต่ยังรู้สึกภูมิใจว่า ชีวิตนี้ได้สัมผัสอะไรแบบนี้ด้วย ^^
#4  by  #G~nap# At 2006-09-13 09:22, 
ลืมหมดแล้วแฮะ
#5  by  mk (203.121.164.162) At 2006-09-13 11:25, 
รุ่นผมได้ทันเรียน แล้วก็สนุกมากด้วยคั๊บ
(ปั่นงานสนุกสนาน เหอๆ)

คิดถึงสมัยเรียนจัง~~
#6  by  ไอ้แพท.. At 2006-09-13 13:10, 
> veer
เดี๋ยวจะลองเอามาศึกษาดูนะครับ
เปลี่ยนจาก LR เป็น LL นี่จะมึนมั้ยเนี่ย ^^"

> house
ติดไว้ก่อนนะ ตอนนี้ยังแก้ให้มันเป็น C++ ไม่ได้เลย
#7  by  PaePae At 2006-09-13 15:35, 
ไม่รู้จัก
#8  by  plynoi แว่วศรี At 2006-09-14 17:51, 

<< Home