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
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
全站熱搜
留言列表