什麼是 lex
lex 是幫我們做 lexical analysis 的工具,它負責將 source code 切成一些 token。
Compile 方法
1lex rule.l
2gcc lex.yy.c -ll
3./a.out < input
lex 的格式
利用 %%
將 code 切成三個區段,第一個和第二個是必須的。
1definition section
2%%
3rule section
4%%
5user subroutine
最簡單的 lex 程式
1%%
Definition Section
- 寫在此區的 C 程式碼需要加上
%{
和%}
,例如放 header 和全域變數等等。 - 可以給於一些定義。
1digit [0-9]
2letter [a-zA-Z]
3space [ \t]+
4identifier {letter}({digit}|{letter})*
5integer 0|([1-9]{digit}*)
- 可以定義一些 State,用
%s
或%x
,預設的 State 稱為INITIAL
。
1%s state1 state2 state3
Rule Section
- 前面那一項是要寫正規表示法。
- 比對的規則是先找最長的 rule,遇到一樣長的時候,找最前面的 rule。
1/* 以下這份 code 可以將程式的空白和換行移除。 */
2{space} { ; }
3\n { ; }
4. { ECHO; }
User Subroutine
- 用來寫一些 function。
- 可以自定義
main()
,若沒有則是用預設的main()
。
1main() {
2 yylex();
3}
正規表示法
regular expression | definition |
---|---|
. |
一個字元(\n 以外的所有字元) |
* |
重複零次以上 |
+ |
重複一次以上 |
? |
零次或一次 |
^ |
放在 [] 中,表示不包含 |
^ |
放在開頭,表示一行的開頭 |
$ |
放在結尾,表示一行的結尾 |
{a, b} |
重複 a ~ b 次 |
` | ` |
/ |
表示前面的表示法需要接在後面的表示法之前,yytext 只匹配到前面 |
%s
和 %x
的區別
- 使用
%s
時,沒有定義狀態的 rule,可以代表所有狀態。 - 使用
%x
時,則是 exclusive,沒有定義狀態的只會配到INITIAL
。
Test Case
1/*
2comment
3*/
Example
- 若運行以下程式碼,會輸出
id
,正確的 rule 需改成<INITIAL>{identifier}
,否則按規則將匹配到最長的 rule。
1%s COMMENT
2
3%%
4
5"/*" { BEGIN COMMENT; }
6<COMMENT>. { ; }
7<COMMENT>"*/" { ; }
8{identifier} { printf("id"); }
- 以下是正確的寫法,只要用
%x
就可以避免上述情況。
1%x COMMENT
2
3%%
4
5"/*" { BEGIN COMMENT; }
6<COMMENT>. { ; }
7<COMMENT>"*/" { ; }
8{identifier} { printf("id"); }
特殊指令
ECHO
,REJECT
,BEGIN
。
Lex Libiary
yytext
yyleng
yyin
yyout
yylex()
yymore()
yyless(n)
yywrap()