Page 1 of 4

มาทำ scanner ด้วย flex กัน !!

PostPosted: Wed Jul 02, 2008 9:24 pm
by natz
lex & yacc

หมายเหตุ ว่า
Code: Select all
ส่วนของ lex เราใช้โปรแกรม flex
ส่วนของ yacc เราใช้โปรแกรม bison

คำชี้แจงว่า
Code: Select all
flex และ bison เป็นโปรแกรมโปรแกรมหนึ่ง(สองอันก็สองโปรแกรม) ซึ่งทำงานบน linux

เราไม่แน่ใจนะว่าใน windows มีให้ใช้หรือเปล่า แล้วใช้โปรแกรมอะไร
แต่ว่าเราลอง search ว่าflex on windows มันก็มี .exe ให้ดาวน์โหลดนะ
แต่ยังไม่ได้ลองใช้

อยากได้ข้อมูลเพิ่มเติม เข้า http://www.google.co.th แล้วลอง search flex , bison หรือ lex & yacc ดูนะ


นี่ก็ได้ลองศึกษาไปแล้วบ้าง แต่ทำต่อไม่ได้ เลยเอามาเขียน
เผื่อจะมีประโยชน์และก็รอคนอื่นทำต่อด้วย

วิธีการติดตั้ง
เราใช้ ubuntu อยู่เป็น linux อะนะ
วิธีการลงก็ง่ายๆ
พิมพ์ code ข้างล่างลงใน terminal นะ
Code: Select all
sudo apt-get install flex
sudo apt-get install bison


แล้วก็มาว่าด้วย flex กันต่อ

flex ก็เหมือน compiler ที่ compile โค๊ดภาษา c อะแหละ
ซึ่ง compiler ภาษา c มันจะ compile ไฟล์ .c ให้เป็น ภาษาเครื่อง (.exe -- executable file)
แต่ว่าไอ้เจ้า flex เนี่ย จะ compile ไฟล์นามสกุล .l ให้เป็นไฟล์ภาษา c (ไฟล์ .c )
แล้วเราก็เอา ไฟล์ภาษา c ที่ได้มา compile ต่อเป็นภาษาเครื่อง

แล้วเราก็จะได้โปรแกรมที่รับ input แล้วเอาไปตัดเป็น tokens ตามที่เราตั้งกฎไว้

ยกตัวอย่าง ตามทีเราเขียนไว้นะ

PostPosted: Wed Jul 02, 2008 9:26 pm
by natz
ไฟล์ nazt.l

Code: Select all
/*** Definition section ***/

%{
/* C code to be copied verbatim */
#include <stdio.h>
%}

/* This tells flex to read only one input file */
%option noyywrap

%%
    /*** Rules section ***/

    /* [0-9]+ matches a string of one or more digits */

[0-9]+  {
            /* yytext is a string containing the matched text. */
            printf("Saw an integer: %s\n", yytext);
        }

[a-z]    {
      printf("Saw an [a-z] character: %s\n", yytext);
   }

"go"       { printf ("Found go\n"); }
"transit"   { printf ("Found transit\n"); }
"q"[0-9]+   { printf ("Found state %s\n",yytext);}

[ \t\n]+        ;       /* ignore whitespace */

.               printf("Fuck !! Unknown character\n");


%%
/*** C Code section ***/

int main(void)
{
    /* Call the lexer, then quit. */
    yylex();
    return 0;
}



เราจะสนใจ ส่วน Rules section อย่างเดียวเลยนะ
มันจะมีรูปแบบดังนี้

เริ่มต้นด้วย
Code: Select all
%%
    /*** Rules section ***/
   ข้างในเป็นกฏ
%%

แล้วก็ปิด section แบบนี้

PostPosted: Wed Jul 02, 2008 9:35 pm
by natz
กฎมันก็ใช้ regular expression ตามระเบียบนะน่ะ

อย่างเช่น
Code: Select all
[0-9]+ 
{
            /* yytext is a string containing the matched text. */
            printf("Saw an integer: %s\n", yytext);
}

[0-9]+ อันนี้แปลว่า รับเลข 0-9 แล้วมีเครื่องหมาย + มันจะแปลว่ากี่ตัวก็ได้
ถ้าไม่มีมันจะเป็นเลขโดด 0-9 เท่านั้น ถ้าเจอ 10 มันจะแยกอ่านเป็น 1 กับ 0
แล้วในปีกกา
Code: Select all
{
          ในปีกกา มันคือคำสั่งว่าจะให้ทำอะไร ในตัวอย่างก็คือ
          ถ้ามันเจอตัวเลขมันจะปริ้นว่า
          Saw an integer แล้วแสดงตัวเลขที่มันเจอออกมา
}

PostPosted: Wed Jul 02, 2008 9:39 pm
by natz
Code: Select all
"q"[0-9]+   { printf ("Found state %s\n",yytext);}

อันนี้แปลว่า ถ้า เจอ q แล้วตามด้วยตัวเลขกี่ตัวก็ได้ให้พิมพ์ Found state แล้ว พิมพ์ว่าเจออะไร
เช่น q111 มันจะพิมพ์ว่า Found state q111


Code: Select all
.               printf("Fuck !! Unknown character\n");

ส่วนตรงนี้คือเมื่อเจอ string ที่นอกเหนือกฎทั้งหลายทั้งปวงที่เราตั้งไว้น่ะ

ส่วนอย่างอื่น ก็ลองศึกษาดูน้า แล้วมาสอนเค้าด้วยยยยยยยยยยย

PostPosted: Wed Jul 02, 2008 9:43 pm
by natz
คราวนี้มาสั่ง compile กัน

ตอนแรกเราก็ต้องแปลง ภาษา lex (ไฟล์นามสกุล .l) มาแปลงเป็นไฟล์ภาษา c ก่อนด้วยคำสั่ง

Code: Select all
flex nazt.l


ง่ายปะล่ะ แล้วเราจะได้ไฟล์ lex.yy.c ออกมา

แล้วเราก็มาคอมไพล์ให้เป็นภาษาเครื่องด้วยคำสั่ง

Code: Select all
cc lex.yy.c หรือจะคอมไพล์ว่า  cc lex.yy.c -o output_name ก็ได้


ก็จะได้ไฟล์ภาษาเครื่องออกมา

ถ้าแบบแรกเราก็จะ execute มันด้วยคำสั่ง

Code: Select all
./a.out


มันก็จะให้เรา input string เข้าไป

PostPosted: Wed Jul 02, 2008 9:46 pm
by natz
หรือจะใช้
bash โปรแกรมของเรา

แบบนี้

ไฟล์ชื่อ build
Code: Select all
#!/bin/bash         
echo
if [ -a lex.yy.c ]
then
   echo "found lex.yy.c"
   rm lex.yy.c
else
   echo "not found lex.yy.c"
fi

if [ -a nazt.l ]
then
   echo "found nazt.l"
   echo "lex nazt.l is running"
   lex nazt.l
   echo "lex nazt.l was completed"
   echo "compiling lex.yy.c"
   cc lex.yy.c
   echo "lex.yy.c was compiled to a.out"
   #rm lex.yy.c
else
   echo "not found nazt.l"
   exit;
fi
echo
echo "Executing a.out :"
./a.out
echo "a.out has been terminated"


แล้วเรียก ./build ทีเดียวเสร็จ

PostPosted: Wed Jul 02, 2008 9:49 pm
by natz
คราวนี้มาลองรันโปรแกรมกัน จะได้ผลดังนี้ๆๆๆๆ

คอมไพล์และเรียกโปรแกรมด้วยคำสั่ง ./build

Code: Select all
nazt@nazt-laptop:~$ ./build

found lex.yy.c
found nazt.l
lex nazt.l is running
lex nazt.l was completed
compiling lex.yy.c
lex.yy.c was compiled to a.out

Executing a.out :

nazt1234q112q1df
Code: Select all
Saw an [a-z] character: n
Saw an [a-z] character: a
Saw an [a-z] character: z
Saw an [a-z] character: t
Saw an integer: 1234
Found state q112
Found state q1
Saw an [a-z] character: d
Saw an [a-z] character: f

gotransitq12a21
Code: Select all
Found go
Found transit
Found state q12
Saw an [a-z] character: a
Saw an integer: 21


ตัวแดงๆ คือ input ที่เราใส่เข้าไปนะ

PostPosted: Wed Jul 02, 2008 9:54 pm
by natz
SRC CODE

ไฟล์
nazt.l
Code: Select all
/*** Definition section ***/

%{
/* C code to be copied verbatim */
#include <stdio.h>
%}

/* This tells flex to read only one input file */
%option noyywrap

%%
    /*** Rules section ***/

    /* [0-9]+ matches a string of one or more digits */

[0-9]+  {
            /* yytext is a string containing the matched text. */
            printf("Saw an integer: %s\n", yytext);
        }

[a-z]    {
      printf("Saw an [a-z] character: %s\n", yytext);
   }

"go"       { printf ("Found go\n"); }
"transit"   { printf ("Found transit\n"); }
"q"[0-9]+   { printf ("Found state %s\n",yytext);}

[ \t\n]+        ;       /* ignore whitespace */

   .               printf("Fuck !! Unknown character\n");


%%
/*** C Code section ***/

int main(void)
{
    /* Call the lexer, then quit. */
    yylex();
    return 0;
}


ไฟล์ lex.yy.cc

Code: Select all
เอาออก แม่งยาวจัดใครอยากได้เอาไปลอง compile msn มาจ้าา


ไฟล์ build
Code: Select all
#!/bin/bash         
echo
if [ -a lex.yy.c ]
then
   echo "found lex.yy.c"
   rm lex.yy.c
else
   echo "not found lex.yy.c"
fi

if [ -a nazt.l ]
then
   echo "found nazt.l"
   echo "lex nazt.l is running"
   lex nazt.l
   echo "lex nazt.l was completed"
   echo "compiling lex.yy.c"
   cc lex.yy.c
   echo "lex.yy.c was compiled to a.out"
   #rm lex.yy.c
else
   echo "not found nazt.l"
   exit;
fi
echo
echo "Executing a.out :"
./a.out
echo "a.out has been terminated"

PostPosted: Wed Jul 02, 2008 9:55 pm
by natz

ทำได้เท่านี้แหละ น้อยนิดมากๆๆๆๆๆ ทำต่อไม่เป็น

ใครทำอะไรได้มาสอนด้วยนะ

โดยเฉพาะ yacc น่ะ


จะรอจ้าาาา

PostPosted: Wed Jul 02, 2008 10:01 pm
by HolyShadow
ยาวชะมัด เหอๆๆ งานเยอะแยะมากมายยยยยย

PostPosted: Wed Jul 02, 2008 10:03 pm
by natz
ปล. ใน windows รู้สึกใช้ cygwin ได้นะ แต่ไม่เคยทำได้ หรือไม่ โปรแกรมพวก virtual pc ก็ได้น้าา พวก VM Ware

อ้อ แล้วการใช้ lex กับ yacc รวมกันลองโหลดนี่ไปดูนะ

http://epaperpress.com/lexandyacc/download/code.zip
จากเว็ป
http://epaperpress.com/lexandyacc/


ใครเข้าใจมาสอนด้วยยยย


ได้มานาน ยังไม่เข้าใจซักทีแค่ คอมไพล์มันได้แค่นั้นอะ

PostPosted: Wed Jul 02, 2008 10:07 pm
by XEON
:o thx ja

PostPosted: Wed Jul 02, 2008 10:12 pm
by jjmedz
:o ช้านดูโง่กว่าเดิมอีกก

PostPosted: Wed Jul 02, 2008 10:13 pm
by azoonnoe
ขอบคุนมากๆนะนัท

แต่ว่า

ดูแระปวดหัวอ่ะ

ทามไมยากจังเนี่ย

เค้าจารอดมะเนี่ย

:cry:

PostPosted: Wed Jul 02, 2008 10:14 pm
by azoonnoe
HolyShadow wrote:ยาวชะมัด เหอๆๆ งานเยอะแยะมากมายยยยยย


เหงด้วยอย่างแรง

TT