วันจันทร์ที่ 20 ตุลาคม พ.ศ. 2557

สอนเขียนโปรแกรม Compiler เพื่อแสดงผล Animation ด้วยภาษา JAVA เบื้องต้น (Part 1 Scanner)

ในช่วงที่ผมเรียนอยู่ในมหาวิทยาลัย ผมได้มีโอกาสเรียนวิชา Automata โดยรายละเอียดของเรื่องเกียวกับ Automata นั้นสามารถคลิกดูได้ที่ลิ้งค์ หรือ search หาตาม google

วิชานี้ อาจารย์ได้มอบหมายให้นักศึกษาทำโปรเจคซึ่งเกี่ยวกับการประมวลผลภาษาโปรแกรม ซึ่งก็คือโปรแกรมแมวไล่จับหนู โดยเป็นโปรแกรมที่ให้เราเขียน code เพื่อสั่งให้แมววิ่งไล่จับหนู แล้วโปรแกรมที่เราเขียนจะประมวลผล code ที่เรา input เข้าไป ไปแสดงผลเป็น animation  แมววิ่งไล่จับหนู

รายละเอียดของโปรเจคนี้นั้นถูกแปลมาจากโปรเจคในวิชา CompSci 140, Spring 2012 Mathematical Foundations of CS Assignments ของต่างประเทศอีกทีหนึ่ง ซึ่งต้องขอขอบพระคุณมา ณ ที่นี้ด้วย โดยลิงค์รายละเอียดในการทำโปรเจค(ภาษาอังกฤษ)มีดังนี้

  1. https://www.cs.duke.edu/courses/spring12/cps140/assign/proj1.pdf

  2. https://www.cs.duke.edu/courses/spring12/cps140/assign/data/

  3. https://www.cs.duke.edu/courses/spring12/cps140/assign/proj2all.pdf

  4. https://www.cs.duke.edu/courses/spring12/cps140/assign/parsedata

  5. https://www.cs.duke.edu/courses/spring12/cps140/assign/studentdata/

  6. https://www.cs.duke.edu/courses/spring12/cps140/assign/proj3.pdf


จากลิ้งค์รายละเอียดข้างต้นจะเห็นว่าภายในตัวโปรเจคจะถูกแบ่งเป็น 3 ส่วนคือ

  1. Scanner

  2. Parser

  3. Syntax Tree


โดยรายละเอียดในการเขียนโปรแกรมแสดงผล Animation Mouse Cat แต่จะส่วนนั้นมีดังนี้

1.Scanner


ในส่วนที่ 1 คือการทำ Scanner โดยในรายละเอียดจากเอกสารก็คือการแบ่ง code ที่เรา input เข้ามา ทำการตัด comment ออกให้หมด แล้วแยกออกมาเป็นคำๆ  โดยแต่ละคำที่แยกออกมานั้นจะต้องถูกต้องตามกฏเบื้องต้นของโปรแกรมเพื่อที่จะนำไปประมวลผลต่อในส่วนที่ 2  ซึ่งจะแบ่งคำเป็นกลุ่มของ keyword,variable,integer และ symbol

1.ขั้นตอนแรกให้สร้าง Editor ขึ้นมาเพื่อใช้ในการเขียน code และแสดงผล output ในส่วนต่างๆ Untitled ตัวอย่าง editor ที่มีช่องให้ input code และมี แท็บ 4 แท็บเพื่อแสดงผล output ในส่วนต่างๆ และมีปุ่ม compile เพื่อประมวลผลโปรแกรม (ออกแบบโดยใช้ JSwingDesigner/WindowBuilder)

2. สร้างคลาสชื่อว่า Token เพื่อเก็บกลุ่มคำที่ถูกประมวลผลในส่วนของ Scanner โดย Object token นี้จะเก็บข้อมูลดังนี้ String fullName(ชื่อเต็ม), shortName(ชื่อย่อ), characterValue(ค่าของ Token เป็น character), intValue (ค่าของ Token เป็น จำนวนเต็ม )

Untitled

3. สร้างคลาสชื่อว่า Type เพื่อเก็บกลุ่มคำที่ถูกประมวลผลในส่วนของ Scanner โดย Object type นี้จะเก็บข้อมูลดังนี้ type(ประเภท เป็น Integer หรือ Variable), characterValue(ค่าของ Token เป็น character), intValue (ค่าของ Token เป็น จำนวนเต็ม ) ซึ่งคลาส Type นี้จะถูกนำมาใช้ในการแสดงผลข้อมูลในส่วนของ Scanner

Untitled

4. สร้างคลาสชื่อว่า CheckToken ซึ่งคลาสนี้มีความสำคัญมากๆ เพราะว่าต้องใช้ในการประมวลผล code ที่เรา input เข้ามาเพื่อแสดงผลในส่วนที่ 1 ให้ถูกต้อง

Untitledattribute ทั้งหมดของคลาส Tokenizer ซึ่งจะมีค่า attribute ที่สำคัญๆคือ

  • ArrayList<Token> tokens = new ArrayList<Token>(); ใช้เก็บ Token ที่ประมวลผลได้ (นำไปใช้ต่อใน part 2)

  • ArrayList<Type> type = new ArrayList<Type>(); ใช้เก็บ Typr ที่ประมวลผลได้ ซึ่งจะใช้แสดงผลใน part นี้

  • private Parser parser; ใช่ใน part ที่ 2

  • private static final ArrayList<String> keyWordPattern = new ArrayList<String>(); ใช้เก็บคำสำคัญซึ่งมีทั้งหมด 14 คำได้แก่ begin , halt , cat , mouse , clockwise , move , north , south , east , west , hole , repeat , size , end โดยเหตุผลที่เก็บใส่ ArrayList เพราะว่าเวลาเราเช็คว่า Token นั้นเป็นคำสำคัญหรือไม่ เราสามารถใช้เมธอด contains ของ ArrayList เพื่อใช้ในการค้นหาคำได้ แทนที่จะต้องมาวนลูปค้นหาคำทีละคำ

  • private static final String terminatePattern = ";"; คือ Regular Experssion มีความหมายคือ เช็คว่าเป็นเครื่องหมาย ; หรือไม่

  • private static final String variablePattern = "([0-9]*[a-zA-Z]+[0-9]*)+"; คือ Regular Experssion มีความหมายคือ เช็คว่าเป็นตัวแปรที่ตั้งชื่อถูกตามกฏหรือไม่ โดยในที่นี้คือ ตัวแปรต้องมีตัวอักษรอย่างน้อยหนึ่งตัว

  • private static final String integerPattern = "[0-9]{1,3}"; คือ Regular Experssion มีความหมายคือ เช็คว่าเป็นตัวเลขจำนวนเต็มที่ถูกต้องหรือไม่ โดยในที่นี้คือ ตัวเลขไม่เกิน 3 หลัก

  • private static final String integerErrorPattern = "[0-9][0-9][0-9][0-9]+"; คือ Regular Experssion มีความหมายคือ เช็คว่าเป็นตัวเลขจำนวนเต็มที่ผิดหรือไม่

  • private static final String symbolErrorPattern = "[^0-9a-zA-Z]+"; คือ Regular Experssion มีความหมายคือ เช็คว่าเป็นตัวแปรที่ผิดหรือไม่

  • private static final String semicolonErrorPattern = ".+;";  คือ Regular Experssion มีความหมายคือ เช็คว่าเครื่องหมาย ; อยู่ติดกับตัวอักษรอื่นหรือไม่

  • private String output ,warning ,error ใช้เก็บข้อความเพื่อนำกลับไปแสดงผลใน part ที่ 1


5. การทำงานของคลาส CheckToken

Untitled

ให้ constructor ทำการเพิ่มคำ keyword ลงใน ArrayListที่เก็บ keyword

Untitled

เมธอด compile ใช้ในการประมวลผลส่วนที่ 1 (Scanner) โดยเริ่มต้น จะทำการ instance variable ต่างๆ และรับ code ที่เป็น input เข้ามาผ่านตัวแปร text เมื่อรับ input มาแล้วจะแยกบรรทัดของ code ต่อโดยใช้ เมธอด splitLine เก็บใส่อาเรย์ของ String หลังจากนั้นจึงวนลูปทีละบรรทัด(บรรทัดที่ 54 ) ในแต่ละบรรทัดของ code ก็จะทำการแยกคำ โดยใช้ StringTokenizer เพื่อแยกคำออกมาเป็นคำๆ เพื่อนำไปประมวลผลโดยใช้เรื่อง Regular Expression

  • ใน if แรก(บรรทัดที่ 59)จะทำการประมวลผลว่าคำ(ต่อไปขอเรียกว่า token) นั้นเป็น keyword หรือเครื่องหมาย ; หรือไม่ ถ้าเป็นก็จะเพิ่มใส่ ArrayListToken โดยปกติชื่อย่อของ keyword จะใช้ตัวอักษรตัวแรก แต่ก็มีบางคำที่ไม่ใช่ตัวอักษรตัวแรกคือ size(z) move(o) clockwise(l) end(d) halt(t) จึงต้องมีการเช็ค if เอาไว้Untitled

  • ใน if อันต่อมา (บรรทัดที่ 74) จะเป็นการประมวลผลว่า token นั้นเป็นตัวเลขหรือไม่ ถ้าเป็นก็จะเก็บใส่ ArrayListToken ชื่อเต็มคือ integer ชื่อย่อ i และมีส่วนที่เพิ่มเติมคือ ต้องเช็คดูว่าเลขจำนวนนั้นถูกเก็บใน  ArrayListType หรือยัง ถ้ายังก็จะเพิ่มเข้าไป แต่ถ้ามีแล้วก็จะไม่ทำอะไร

  • ใน if อันต่อมา (บรรทัดที่ 83) จะเป็นการประมวลผลว่า token นั้นเป็นตัวแปรหรือไม่ ถ้าเป็นก็จะเก็บใส่ ArrayListType ชื่อเต็มคือ variable ชื่อย่อ v และมีส่วนที่เพิ่มเติมคือ ต้องเช็คดูว่าชื่อตัวแปรนั้นนั้นถูกเก็บใน  ArrayListType หรือยัง ถ้ายังก็จะเพิ่มเข้าไป แต่ถ้ามีแล้วก็จะไม่ทำอะไร
    Untitled

  • ใน if บรรทัดที่ 91 และ 93 จะเป็นการเช็คว่าเราใส่สัญลักษณ์พิเศษนอกเหนือจากที่โปรแกรมกำหนด (symbl error) หรือ ใส่เครื่องหมาย ; ไม่เว้นวรรคหลังตัวแปรหรือไม่ มิเช่นนั้นก็จะเพิ่มข้อความแจ้งเตือน error

  • if บรรทัดที่ 96 คือการเช็คว่าใส่ตัวเลขจำนวนเต็มผิดรูปแบบหรือไม่ ซึ่งส่วนนี้จะไม่ใช่ error แต่จะถูกมองเป็นตัวแปรแทน ซึ่งจะแจ้งเตือน warning

  • else คือเช็คว่าเราตั้งชื่อตัวแปรผิดรูปแบบหรือไม่ มิเช่นนั้นจะเพิ่มข้อความ error

  • lineOfCode++ เอาไว้ใช้นับบรรทัด เพื่อใช้ในการบอกบรรทัดของ code ที่มีข้อผิดพลาด!!!

  • บรรทัดที่ 109 คือการเรียกใช้เมธอดเพื่อประมวลผลในส่วนที่ 2 (Parser)

  • บรรทัดที่ 110 111 112 .ใช้ในการจัด format ของข้อความ output เพื่อที่จะเตรียม Return ข้อความ output ไปแสดงผล


Untitled

Untitled

ทดสอบ Input Output


ลิ้งค์ไฟล์ทดสอบ https://www.cs.duke.edu/courses/spring12/cps140/assign/data/

Untitled

Untitled

Untitled

จบการทำงานของส่วนที่ 1 (Scanner)


ต่อส่วนที่ 2(Parser)

1 ความคิดเห็น: