Formal language的啟發-2 (for ini file)
 
自從上一個 SECS message 的程式之後,就想試試看,如果我要再寫一個 state machine 來辨認其他格式的東西,
程式的架構會變動多少。
於是,我挑了一個我們常常會遇到的題目,ini file。
這個程式的基本元素還是一樣,一個 acitve state、一次只看一個字元、使用 fire event 而本身不處理辨認之後的事。
他可以有section,可以用"-"來 comment,也可以一次 comment out 整個 section。(例  -[section name] 
只對含有"="及[section name]的行有反應,其他的都忽略。寫註解很方便。
換行符號只偵測chr(10),這樣子可以處理*nix 及 windows 的文件檔。MAC OX 的就抱歉了。
 
從這隻程式及上一隻的程式來看,有幾個結論:
1 如果可以化為 state machine 的程式,光從程式碼來看,外觀都差不多。但是可以辨認的文件格式卻很不一樣。
2 辨認同一種的格式的 state machine ,其diagram 可以有很多不同的長相。
3 辨認不同格式的 state machine,需要不同的 diagram。也就是要為不同的格式,設計不同的 state machine,寫出不同的程式。
4 由1,2,3,要達成程式碼 reusable,應該就是設計出一個 state machine 的程式表示方式,讓會重覆用到的地方不用重寫。
以我的程式來說,會有 event 定義的部份,會有 loop 的部份,會有 state assign 的部份,及花最多地方的字元比對的部份。
如果字元比對的部份,可以寫成用集合觀念的,那,上一隻程式跟這一隻程式,就會更像,只要換集合內的元素即可。
再進一步,把每個 state 其實只做了少許的事:比對、設新 state,raise event。所以可以把 state 包裝起來,只是也許會喪失程式可讀性。
這個部份可以留做下次的實驗。
 
state diagram ,底下是程式碼:
 
 
 
Option Explicit
Dim c_s As String
Event PError(ErrorName As String)
Event SectionNameGot(SectionName As String)
Event SettingNameGot(SectionName As String, SettingName As String)
Event settingValueGot(SectionName As String, SettingName As String, SettingValue As String)


Function init(s As String)
c_s = s
End Function

Function action()
Dim SectionName As String
Dim SettingName As String
Dim SettingValue As String

If Len(c_s) = 0 Then
    RaiseEvent PError("SourceEmpty")
End If

Dim l As Long
Dim st As Integer
Dim i As Long
Dim checkString As String
st = 1
l = 0
For i = 1 To Len(c_s)
    checkString = Mid(c_s, i, 1)
    Select Case st
        Case 1
            If checkString = "[" Then
                st = 2
            ElseIf checkString = "-" Then
                st = 10
            End If
        Case 2
            If checkString = "[" Then
                'do nothing
            ElseIf checkString = "]" Then
                st = 1
            Else
                SectionName = checkString
                st = 3
            End If
        Case 3
            If checkString = "]" Then
                st = 4
                RaiseEvent SectionNameGot(SectionName)
            Else
                SectionName = SectionName & checkString
            End If
        Case 4
            If checkString = Chr(10) Then
                st = 5
            End If
        Case 5
            If checkString = "[" Then
                st = 2
            ElseIf checkString = "-" Then
                st = 11
            ElseIf checkString = " " Then
                'do nothing
            Else
                SettingName = checkString
                st = 6
            End If
        Case 6
            If checkString = "=" Then
                st = 7
                RaiseEvent SettingNameGot(SectionName, SettingName)
            ElseIf checkString = Chr(10) Then
                st = 5
            Else
                SettingName = SettingName & checkString
            End If
        Case 7
            SettingValue = checkString
            st = 8
        Case 8
            If checkString = Chr(10) Then
                st = 9
                st = 5
                RaiseEvent settingValueGot(SectionName, SettingName, SettingValue)
            ElseIf i = Len(c_s) Then
                SettingValue = SettingValue & checkString
                RaiseEvent settingValueGot(SectionName, SettingName, SettingValue)
            Else
                SettingValue = SettingValue & checkString
            End If
        Case 9
            'pass to state5
        Case 10
            If checkString = Chr(10) Then
                st = 1
            End If
        Case 11
            If checkString = Chr(10) Then
                st = 5
            End If
    End Select
Next

End Function
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 betaparticle 的頭像
    betaparticle

    betaparticle的部落格

    betaparticle 發表在 痞客邦 留言(0) 人氣()