iT邦幫忙

2023 iThome 鐵人賽

DAY 4
0
自我挑戰組

Lex & Yacc 學習筆記系列 第 4

[Day4] Lex - State

  • 分享至 

  • xImage
  •  

本篇內容

  • 介紹State語法
  • 介紹Begin語法
  • 介紹ECHO語法

State - 對不同段落做不同處理

在C++中,我們利用”//”雙斜線來表示單行的註解。當我們在讀取檔案時,若是遇到註解,可以跳過註解的部分嗎?
這時,我們可以使用”state”(狀態)這個語法,來定義檔案中不同區塊的讀取規則。

首先,在Lex檔案中,我們需要先自行定義state的名稱。
在下面的例子中,我們將註解的state命名為”COMMENT”,定義於”Definition”區塊中。

%x COMMENT

接著,我們使用BEGIN表示進入某個state。
以剛剛的例子來說,單行註解的符號為雙斜線,故在讀到雙斜線時,便會進入”COMMENT”的state。

\/\/            { BEGIN COMMENT; }

在正則表達式中,我們使用<>來表示該規則只適用於特定的state。
例如,我們若不想讀取COMMENT state的內容時,便可直接跳過該區段。(要注意換行符號!)

<COMMENT>[^\n]* { ; }

最後,當該state結束時,同樣可以利用BEGIN切換至其他state。初始state預定義為0 (Initial)。
在單行註解中,以換行符號作為結束。因此,在讀取到換行符號時,要回到初始state。

<COMMENT>\n     { BEGIN 0; }

如此一來,即使是不同的規則也可以在同一個編譯器下操作了!

範例 - C++程式碼讀取

說明

給定一個C++程式碼,請將程式碼輸出到terminal中,但略過註解處。

程式實作

Definitions

註解的state在這裡定義。

%{
%}

%x COMMENT

Rules

這裡分別定義一般state與註解state的規則。

%%

\/\/              { BEGIN COMMENT; }
<COMMENT>[^\n]*   { ; }
<COMMENT>\n       { BEGIN 0; ECHO; }

.|\n              { ECHO; }

在這裡,我們碰到了一個新玩意ECHO。熟悉script語法的讀者應該對此不陌生,就是把指定字串輸出到terminal中。在這裡的用法也一樣,非常方便。

Subroutines

這部分跟前一個範例一樣。

%%

int yywrap(void) {
    return 1;
}

int main(void) {
    const char* sFile = "file.cpp";
    FILE* fp = fopen(sFile, "r");
    if (fp == NULL) {
        printf("cannot open %s\n", sFile);
        return -1;
    }
    yyin = fp;
    yylex();
    return 0;
}

完整程式碼

%{
%}

%x COMMENT

%%

\/\/              { BEGIN COMMENT; }
<COMMENT>[^\n]*   { ; }
<COMMENT>\n       { BEGIN 0; ECHO; }

.|\n              { ECHO; }

%%

int yywrap(void) {
    return 1;
}

int main(void) {
    const char* sFile = "file.cpp";
    FILE* fp = fopen(sFile, "r");
    if (fp == NULL) {
        printf("cannot open %s\n", sFile);
        return -1;
    }
    yyin = fp;
    yylex();
    return 0;
}

執行結果

輸入內容

#include <cstdio>

int main() {
    int age = 100;  // Input user's age
    char* name = "BarleyTea";   // Input user's name
    printf("Hi, my name is %s. I am %d years old.\n", name, age);   // print user info
}

輸出結果

#include <cstdio>

int main() {
    int age = 100;
    char* name = "BarleyTea";
    printf("Hi, my name is %s. I am %d years old.\n", name, age);
}

結語

State是一項很實用的工具,尤其是一份檔案裡遇到不同區塊的規則不同的狀況時,便可以用State來定義每個區塊的規則。

ECHO則是lex當中最簡單的內建函式,可以直接印出讀取到的字串。

參考資料

  • Levine, John R., Tony Mason and Doug Brown [1992]. Lex & Yacc. O’Reilly & Associates, Inc. Sebastopol, California.

上一篇
[Day3] Lex - Regular Expression
下一篇
[Day5] Lex - yyout
系列文
Lex & Yacc 學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言