♥ 學習筆記Learning 程式語言 Coding

[程式] lex 基本概念-Practice

多練習,才是王道!底下來熟悉lex語法代表的意義吧!
像雷米這樣對抽象化沒太多慧根的人,有個具體的例子學起來就輕鬆多了。

同樣引用自此網站:http://epaperpress.com/lexandyacc/

Lex Practice

表格一、樣式(Pattern)比對原始值

Metacharacter Matches  
. any character except newline 除換行以外的任何型別
\n newline 新行
* zero or more copies of the preceding expression 零或多個複製前面的表達式
+ one or more copies of the preceding expression 一或多個複製前面的表達式
? zero or one copy of the preceding expression 零或一個複製前面的表達式
^ beginning of line 起始行
$ end of line 結束行
a|b a or b a或b
(ab)+ one or more copies of ab (grouping) 一或多個複製ab(合併)
"a+b" literal “a+b” (C escapes still work) 文字”a+b”  這句我看不懂Orz
[] character class 型別類別

表格二、樣式比對範例  雷米碎碎念:看例子果然清楚多了!

Expression Matches 酷喔!用表情符號超方便!
abc abc XD XD
abc* ab abc abcc abccc ... XD* X, XD, XDD, XDDD… (可以少c)
abc+ abc, abcc, abccc, abcccc, ... Orz+ Orz, Orzz, Orzzz, Orzzz…(不可少c)
a(bc)+ abc, abcbc, abcbcbc, ... O(rz)+ Orz,Orzrz, Orzrzrz (後面兩個重複)
a(bc)? a, abc O(rz)? O, Orz (意思是有bc或沒bc二選一)
[abc] one of: a, b, c [Orz]O, r, z 其中一個
[a-z] any letter, a through z 比對英文字母a~z
[a\-z] one of: a, -, z 比對a,-,z三者之一(加一個右斜線差很多!)
[-az] one of: - a z 比對-,a,z三者之一
[A-Za-z0-9]+ one or more alphanumeric characters 一個或多個英文與數字
[ \t\n]+ whitespace 白鍵
[^ab] anything except: a, b 任何值,除了a,b之外(所以可以用來去括號囉!?)
[a^b] a, ^, b 意思是將^放到中間以後,會當作符號來判別。
[a|b] a, |, b 將|放在[ ] 類別中,會被當作符號來判別。
a|b a, b 將|直接使用,則代表兩者。

雷米碎碎念:
嗯嗯!(點頭點頭~)所以,依照上面這堆例子,我們大概可以知道樣式(pattern)要怎麼定義了。

接著我們開始步入真正的重點,lex file的寫法囉!副檔名為*.l。

lex正規表示式的組成方式在表一,樣式比對的範例在表二。
在一般的型別類別[ ]中,一般運算子會失去它們的意義。
其中兩個運算子hyphen (“-“)和circumflex (“^“)允許在一個型別類別[ ]中,
當hyphen (“-“)使用在兩個型別之間表示型別的範圍,當circumflex (“^“)放在第一個位置表示減掉後頭的敘述。

如果兩個樣式比對到相同的字串,則會以長的字串為主。
如果發生比對到兩個相同長度的情況,則會以第一個樣式為主。

definitions
%%
rules
%%
subroutines

輸入給lex的內容分為三個段落,利用%%來分段。

第一個例子可能是最簡短lex檔案:

%%

輸入一次複製到輸出一個字元。
第一個%%是必須用來做為規則段落。
然而,如果我們沒有指定規則,那麼這個預設的段落會去比對任何東西並且複製到輸出。
預設的輸入與輸出分別是stdin和stdout,這裡用相同的例子來表示預設的編碼。

%%
    /* match everything except newline */
.   ECHO;
/* match newline */
\n  ECHO;
%%
int yywrap(void) {
return 1;
}
int main(void) {
   yylex();
    return 0;
}

兩個樣式(patterns)已經指定在規則段落。
每個樣式必須開始從第一列開始,接著是空白(whitespace)如白鍵、標籤、換行(space, tab, newline) 和一個與樣式相關的操作。
這些操作可能是一行C語言或是多行C語言,寫在括號內。任何沒有在一開始逐字複製到C檔案的內容,我們可以使用這個方法去指定一些指令在lex檔案裡。

在這個範例中,有兩個樣式”.”和”\n”,伴隨著ECHO這個關聯動作。
許多巨集(macros)和變數(variables)是由lex預先定義的。
ECHO是一個巨集(macros)代表的是由這個樣式(pattern)去寫程式去做比對。
對任何一個尚未比對的字串來說,這是預設的行為。 

一般情況下, ECHO 被定義為…

#define ECHO fwrite(yytext, yyleng, 1, yyout)

變數yytext是一個被用來比對字串的指標 (NULL-terminated),yyleng 是用來比對字串的長度。
yyout 是輸出檔且預設為 stdout 標準輸出。函式yywrap會被lex呼叫當輸入已經耗盡,當你已經做完時回傳1,如果還有更多的存取則回傳0。
每個C程式都有一個main 函式,在這種情況下,我們簡單的使用yylex做為main 函式對lex的輸入口。
lex有些實作方式包含在函式庫中複製main與yywrap,因此不需要明確的程式碼。 
這就是為什麼第一個範例程式可以正常運作。

About the author

蕾咪

蕾咪,來自台東,卻不定期旅居歐洲的工程師女孩,身兼作家、部落客、創業家等多重身份。畢業於台大電子所,曾在義大利商與美商擔任研發工程師;走訪世界後,發現對台灣有段割捨不了的愛,讓我們一起努力成為想要的自己吧!:) 合作邀稿請聯繫:ramihaha@gmail.com

Leave a Comment