2007年6月30日土曜日

有限オートマトンによる字句解析

有限オートマトンを利用した字句解析。
文字列に対してそれが実数であるか整数であるかを判別し、その結果を返す。



// オートマトンによる字句解析
#module AUTO_MATON
/*
    STATE_FIRST         : 初期状態。          0~9でSTATE_INPUT_INTEGERへ、+-でSTATE_SIGNへ。
    STATE_SIGN          : 符号解析後。        0~9でSTATE_INPUT_INTEGERへ。
    STATE_INPUT_INTEGER : 整数部入力状態。    0~9でSTATE_INPUT_INTEGERへ、.でSTATE_INPUT_FLOATへ。
    STATE_INPUT_FLOAT   : 小数点以下入力状態。0~9でSTATE_INPUT_FLOATへ。
*/

#enum STATE_ERROR = 0
#enum STATE_FIRST
#enum STATE_SIGN
#enum STATE_INPUT_INTEGER
#enum STATE_INPUT_FLOAT

#enum global IS_ERROR = 0
#enum global IS_INTEGER
#enum global IS_FLOAT

// モジュール初期化用命令
#deffunc init
    // 受理集合に属する状態を定義
    dim canAccept, STATE_INPUT_FLOAT + 1
    canAccept(STATE_INPUT_INTEGER) = IS_INTEGER
    canAccept(STATE_INPUT_FLOAT)   = IS_FLOAT
    return

// 文字列が数値か否かを判別する関数
#defcfunc isDigit@AUTO_MATON str sArg, local tmp
    tmp = sArg : tmp = peek(tmp, 0)
    return ('0' <= tmp) & (tmp <= '9')

// 次の状態を返す関数
#defcfunc nextState@AUTO_MATON int nowState, str sArg, local result
    result = STATE_ERROR
    switch nowState
        case STATE_FIRST
            if (sArg == "+") | (sArg == "-") : result = STATE_SIGN
        case STATE_SIGN
            if isDigit(sArg) : result = STATE_INPUT_INTEGER
            swbreak
        case STATE_INPUT_INTEGER
            if isDigit(sArg) : result = STATE_INPUT_INTEGER
            if sArg = "."    : result = STATE_INPUT_FLOAT
            swbreak
        case STATE_INPUT_FLOAT
            if isDigit(sArg) : result = STATE_INPUT_FLOAT
            swbreak
        default
            // エラー
            swbreak
    swend
    return result

// 受理される文字列か否か判定する命令
#defcfunc judge str sArg, local state, local tmp
    state = STATE_FIRST : tmp = sArg
    repeat strlen(sArg)
        state = nextState(state, strmid(tmp, cnt1))
        if state == STATE_ERROR : break
    loop
    return canAccept(state)
#global
    init
// モジュールここまで

// 以下サンプルコード
    sQuestion = "+123""456""-3.14""1e-03""10.""I may be refused."
    repeat length(sQuestion)
        switch judge(sQuestion(cnt))
            case IS_INTEGER
                mes sQuestion(cnt) + "は整数として受理されます。"
                swbreak
            case IS_FLOAT
                mes sQuestion(cnt) + "は実数として受理されます。"
                swbreak
            default
                mes sQuestion(cnt) + "は受理されませんでした。"
                swbreak
        swend
    loop
    stop

0 件のコメント: