ลิ้งค์รายละเอียด part 2 https://www.cs.duke.edu/courses/spring12/cps140/assign/proj2all.pdf
2. Parser
ในการประมวลผลว่า code ของโปรแกรมถูกต้องตามหลักไวยากรณ์หรือไม่ เราจะใช้วิธีการที่เรียกว่า SLR Parser มีตัวอย่างง่ายๆดังนี้ http://chulee.wikispaces.com/file/view/PL4.pdf/362081836/PL4.pdf
จากตัวอย่างจะเห็นได้ว่ามีสิ่งที่ต้องเตรียมในการทำ SLR Parser คือ เราจะต้องมี grammar หรือ rule ซึ่งก็คือกฏของไวยากณ์ในโปรแกรม และอีกอย่างหนึ่งก็คือ ตาราง parsetable ซึ่งแสดงอยู่ในเอกสารรายละเอียดของส่วนที่ 2 ดังนี้
Grammar
(0) P’ → P
(1) P → z i i b L t
(2) L → S ;
(3) L → L S ;
(4) S → c v i i D
(5) S → m v i i D
(6) S → h i i
(7) S → o v
(8) S → o v i
(9) S → l v
(10) S → r i L d
(11) D → n
(12) D → s
(13) D → e
(14) D → w
ParseTable
ในส่วนของ ParseTable จากเอกสารจะเห็นว่าเป็นตารางซึ่งยากต่อการ copy ไปใช้ต่อ ดังนั้น ParseTable จะเแปลงเป็นไฟล์แยกออกมาต่างหากเพื่อให้ง่ายต่อการ copy text เพื่อนำไปใช้เขียนโปรแกรมต่อ โดยมี url ดังลิ้งค์ด้านล่างนี้
https://www.cs.duke.edu/courses/spring12/cps140/assign/parsedata
เริ่มเขียน Code
1. สร้างคลาสชื่อว่า Parser โดยมีค่า Attribute ดังนี้

- private Stack stack = new Stack(); แสต็กเอาไว้เก็บค่าระหว่างขั้นตอนการประมวลผลด้วยวิธี SLR Parser ซึ่งจะเก็บ Object หลายประเภทจึงไม่ใส่ว่าเป็น stack ชนิดใด (เป็น stack ที่เก็บ Object)
- private ArrayList<Token> tokens; ใช้เก็บ ArrayList ที่ได้จากการทำ Scanner ในส่วนที่ 1
- private ArrayList<String> grammars = new ArrayList<>(); ใช้ในการเก็บกฏไวยากรร์เพื่อใช้ในการทำ SLR Parser
- private ArrayList<String> rulesOutput = new ArrayList<String>(); ใช้เก็บ Output ที่แสดงผลว่า แต่ละ step ในการทำ SLR Parser ใช้กฏไวยากรณ์ข้อใด
- private ArrayList<String> derivationOutput = new ArrayList<String>(); ใช้เก็บ Output ที่แสดงผลการ Derivation ในแต่ละ step ในการทำ SLR Parser
- private HashMap<String, Integer> parseTableHeader = new HashMap<String, Integer>(); ใช้เก็บ index ส่วนหัวของตาราง ParseTable ที่เป็นตัวอักษร ให้เป็นการเข้าถึง index นั้นด้วยตัวเลขแทน
- private String[][] parseTable = ..... // ใช้เก็บข้อมูลของตาราง ParseTable ที่ถูกแปลงจาก https://www.cs.duke.edu/courses/spring12/cps140/assign/parsedata ให้มาอยู่ในรูปของ Array2 มิติ ซึ่งมีผลดีคือสามารถช่วยให้เราเขียนโปรแกรมได้สั้นลงอย่างมาก เพราะสามารถเข้าถึงข้อมูลในแต่ละ index ได้ทันที
ซึ่งมีวิธีการแปลงคือให้ดูจากเอกสาร https://www.cs.duke.edu/courses/spring12/cps140/assign/proj2all.pdf หน้า 6-7 คือให้เขียนตารางในหน้า 6 ให้อยู่ในรูปของ Array 2 มิติ แล้วนำ ข้อมูลในหน้า 7 มาต่อท้าย และส่วนไหนที่เป็นช่องว่างให้แทนด้วยเครื่องหมาย "&" สุดท้ายแล้วจะได้ Array2 มิติที่มีข้อมูลดังนี้ - private String[][] parseTable = { { "&", "z", "i", "b", "t", ";", "c", "v", "m", "h", "o", "l", "r", "d", "n", "s", "e", "w", "$", "P", "L", "S", "D" },{ "0", "s2", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "1", "&", "&", "&" },{ "1", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "acc", "&", "&", "&", "&" },{ "2", "&", "s3", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "3", "&", "s4", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "4", "&", "&", "s5", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "5", "&", "&", "&", "&", "&", "s8", "&", "s9", "s10", "s11", "s12", "s13", "&", "&", "&", "&", "&", "&", "&", "6", "7", "&" },{ "6", "&", "&", "&", "s14", "&", "s8", "&", "s9", "s10", "s11", "s12", "s13", "&", "&", "&", "&", "&", "&", "&", "&", "15", "&" },{ "7", "&", "&", "&", "&", "s16", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "8", "&", "&", "&", "&", "&", "&", "s17", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "9", "&", "&", "&", "&", "&", "&", "s18", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "10", "&", "s19", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "11", "&", "&", "&", "&", "&", "&", "s20", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "12", "&", "&", "&", "&", "&", "&", "s21", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "13", "&", "s22", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "14", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "r1", "&", "&", "&", "&" },{ "15", "&", "&", "&", "&", "s23", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "16", "&", "&", "&", "r2", "&", "r2", "&", "r2", "r2", "r2", "r2", "r2", "r2", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "17", "&", "s24", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "18", "&", "s25", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "19", "&", "s26", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "20", "&", "s27", "&", "&", "r7", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "21", "&", "&", "&", "&", "r9", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "22", "&", "&", "&", "&", "&", "s8", "&", "s9", "s10", "s11", "s12", "s13", "&", "&", "&", "&", "&", "&", "&", "28", "7", "&" },{ "23", "&", "&", "&", "r3", "&", "r3", "&", "r3", "r3", "r3", "r3", "r3", "r3", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "24", "&", "s29", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "25", "&", "s30", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "26", "&", "&", "&", "&", "r6", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "27", "&", "&", "&", "&", "r8", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "28", "&", "&", "&", "&", "&", "s8", "&", "s9", "s10", "s11", "s12", "s13", "s31", "&", "&", "&", "&", "&", "&", "&", "15", "&" },{ "29", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "s33", "s34", "s35", "s36", "&", "&", "&", "&", "32" },{ "30", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "s33", "s34", "s35", "s36", "&", "&", "&", "&", "37" },{ "31", "&", "&", "&", "&", "r10", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "32", "&", "&", "&", "&", "r4", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "33", "&", "&", "&", "&", "r11", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "34", "&", "&", "&", "&", "r12", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "35", "&", "&", "&", "&", "r13", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "36", "&", "&", "&", "&", "r14", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" },{ "37", "&", "&", "&", "&", "r5", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&", "&" } };
2. สร้าง Constructor โดยให้รับ ArrayList ที่ได้จากการทำ Scanner ในส่วนที่ 1 และใน constructor นี้จะทำการ instance variable ต่างๆที่จำเป็นในการทำ SLR Parser ด้วย

เมื่อรับ ArrayListToken มาแล้วให้เพิ่มสมาชิกเข้าไปอีก 1 ตัว คือ "$" เพื่อใช้ในการทำ SLR Parser หลังจากนั้นให้ เพิ่มกฏของไวยากรณ์เข้าไปใน grammars ตามลำดับโดยดูจากรูปนี้ หรือตามเอกสารในส่วนที่ 2

ต่อไปให้เพิ่มสมาชิกลงใน parseTableHeader โดยให้ดูจาก array2มิติ parseTable แถวที่ 0 ว่ามีชื่อว่าอะไรบ้าง (ไม่นับรวมส่วนที่เป็นช่องว่าง) ให้กำหนดค่าตัวเลขลงไป โดยให้ใช้ตัวอักษาเป็น key ของ hashmap โดยตัวเลขที่เพิ่มเข้าไปก็คือ index ของตัวอักษรตำแหน่งนั้น อย่างในโปรแกรม Mouse Cat นี้มีสมาชิก HashMap ทั้งหมด 22 ตัว และเมื่อเพิ่มเสร็จแล้วก็เป็นการจบ constructer

3. การทำ SLR Parser
สร้างเมธอดชื่อว่า checkSyntax เพื่อเริ่มทำ SLR Parser โดยอ้างอิงจากอัลกอริทึมจะได้ code ประมาณนี้ (อาจจะมีบัค)


สร้างฟังก์ชัน shift และ reduce


การแสดงผล Output ต้อง พิมพ์จากด้านหลังไปด้านหน้าทั้ง ruleOutput และ derivationOutput เพื่อที่จะให้แสดงผลลัพธ์ได้อย่างถูกต้อง

ทดสอบ Input Output
ตัวอย่าง code ทดสอบจากลิ้งค์นี้ https://www.cs.duke.edu/courses/spring12/cps140/assign/studentdata/


Output แบบเต็ม
code
size 10 10
begin
mouse jerry 8 5 west ;
hole 7 7 ;
cat tom 5 5 north ;
move jerry ;
clockwise jerry ;
clockwise jerry ;
clockwise jerry ;
halt
Output
P -> size 10 10 begin L halt
L -> L S ;
S -> clockwise jerry
L -> L S ;
S -> clockwise jerry
L -> L S ;
S -> clockwise jerry
L -> L S ;
S -> move jerry
L -> L S ;
S -> cat tom 5 5 D
D -> north
L -> L S ;
S -> hole 7 7
L -> S ;
S -> mouse jerry 8 5 D
D -> west
size 10 10 begin L halt
size 10 10 begin L S ; halt
size 10 10 begin L clockwise jerry ; halt
size 10 10 begin L S ; clockwise jerry ; halt
size 10 10 begin L clockwise jerry ; clockwise jerry ; halt
size 10 10 begin L S ; clockwise jerry ; clockwise jerry ; halt
size 10 10 begin L clockwise jerry ; clockwise jerry ; clockwise jerry ; halt
size 10 10 begin L S ; clockwise jerry ; clockwise jerry ; clockwise jerry ; halt
size 10 10 begin L move jerry ; clockwise jerry ; clockwise jerry ; clockwise jerry ; halt
size 10 10 begin L S ; move jerry ; clockwise jerry ; clockwise jerry ; clockwise jerry ; halt
size 10 10 begin L cat tom 5 5 D ; move jerry ; clockwise jerry ; clockwise jerry ; clockwise jerry ; halt
size 10 10 begin L cat tom 5 5 north ; move jerry ; clockwise jerry ; clockwise jerry ; clockwise jerry ; halt
size 10 10 begin L S ; cat tom 5 5 north ; move jerry ; clockwise jerry ; clockwise jerry ; clockwise jerry ; halt
size 10 10 begin L hole 7 7 ; cat tom 5 5 north ; move jerry ; clockwise jerry ; clockwise jerry ; clockwise jerry ; halt
size 10 10 begin S ; hole 7 7 ; cat tom 5 5 north ; move jerry ; clockwise jerry ; clockwise jerry ; clockwise jerry ; halt
size 10 10 begin mouse jerry 8 5 D ; hole 7 7 ; cat tom 5 5 north ; move jerry ; clockwise jerry ; clockwise jerry ; clockwise jerry ; halt
size 10 10 begin mouse jerry 8 5 west ; hole 7 7 ; cat tom 5 5 north ; move jerry ; clockwise jerry ; clockwise jerry ; clockwise jerry ; halt
จบการทำงานของส่วนที่ 2 (Parser)
ต่อส่วนที่ 3(SyntaxTree)
[…] ต่อส่วนที่ 2(Parser) […]
ตอบลบ[…] Part 2 เราได้ส่วนของ Parserไปแล้วเช่นกัน […]
ตอบลบ