数据结构成为小语言
數據結構成為小語言
?
面向語言的開發并不一定意味著,一定要自己開發解析器或編譯器。這就是說,我們將在下一章學習創建解析器,然后,把這樣的解析器和本章介紹的方法照結合起來,去構建一個簡單的編譯器??梢酝ㄟ^創建數據結構和函數或模塊,就能夠做很多事,數據結構描述了準備做什么,而函數或模塊定義了如何解釋結構。
幾乎可以用任何語言創建數據結構來表示一個程序,但是 F# 更適合。F# 的文字列表和數組很容易定義,不要求龐大的類型注解;它的聯合類型能夠創建結構,來表達相關的概念,但卻不一定要包含相同類型的數據,可以用它來創建樹型結構,這在創建語言時是非常有用的;最后,由于函數可以看作是值,因此,我們可以很容易把函數嵌入到數據結構中,這樣,F# 的表達式就能成為語言的一部分,通常作為一個動作,來響應語言的特定條件。
我們先來看一下在FSharp.PowerPack.dll 中預定義的 DSL,通過 Arg(參數)模塊能夠快速構建命令行參數解析器。它是通過 F# 的聯合和列表類型而實現的,先創建小語言,然后,用參數模塊中的大量函數進行解釋。
參數模塊公開了一個元組類型argspec,它由兩個字符串和一個聯合類型 spec 組成。元組中的第一個字符串指定了命令行參數的名字,元組中的第二項是聯合類型 spec,它指定了參數的內容,例如,它可以指定后面跟著的是字符串值,或者只是一個標志;它還可以指定如果發現命令行標記,應該做什么。元組中最后的字符串是關于這個標志做什么的文本描述,當命令行參數錯誤時會打印到控制臺,對程序員來說也是一個有用的注釋。
參數模塊公開了兩個函數用于解析參數:parse,它解析在命令行中傳入的命令;和parse_argv,它要求直接傳遞參數給它。我們應該傳遞描述命令行參數的 argspec 類型列表的函數,所有被傳遞給函數的命令行參數都沒有前綴 -,最后,是描述用法的字符串。
這個模塊還公開了第三個函數,可以傳遞argspec 類型的列表,并直接寫出用法。
下面的例子演示了如何以這種方法構建參數解析器,把從命令行收集的參數保存到標識符中準備以后使用,這里,是把它們定到控制臺:
?
let myFlag = ref true
let myString = ref ""
let myInt = ref 0
let myFloat = ref 0.0
let (myStringList : string list ref) = ref []
?
let argList =
??? [ ("-set", Arg.Set myFlag, "Sets the value myFlag");
????? ("-clear", Arg.Clear myFlag, "Clears the value myFlag");
????? ("-str_val", Arg.String(fun x -> myString:= x), "Sets the value myString");
????? ("-int_val", Arg.Int(fun x -> myInt :=x), "Sets the value myInt");
????? ("-float_val", Arg.Float(fun x -> myFloat:= x), "Sets the value myFloat") ]
?
ifSystem.Environment.GetCommandLineArgs().Length <> 1 then
? Arg.parse
??? argList
??? (funx -> myStringList := x :: !myStringList)
??? "Argmodule demo"
else
? Arg.usage
??? argList
??? "Argmodule demo"
? exit1
?
printfn "myFlag: %b" !myFlag
printfn "myString: %s" !myString
printfn "myInt: %i" !myInt
printfn "myFloat: %f" !myFloat
printfn "myStringList: %A"!myStringList
?
當運行前面的代碼,沒有命令行參數,或者命令行參數錯誤時,程序會輸出下面的結果:
?
Arg module demo
? -set:Sets the value my_flag
? -clear:Clears the value my_flag
? -str_val<string>: Sets the value my_string
? -int_val<int>: Sets the value my_int
? -float_val<float>: Sets the value my_float
? --help:display this list of options
? -help:display this list of options
?
當用下面的命令行運行前面的示例時:
?
args.exe -clear -str_val "helloworld" -int_val 10 -float_val 3.14 "file1" "file2""file3"::
?
輸出如下:
?
myFlag: false
myString: hello world
myInt: 10
myFloat: 3.140000
myStringList: ["file3";"file2"; "file1"]
?
我特別喜歡這樣的 DSL,因為它使問題更清晰,程序需要什么參數,如果接收到參數,應該進行什么樣的處理。幫助文本也保存在這個結構中,有兩個目的:如果命令行參數有錯誤,函數會自動輸出一個幫助消息;當我們忘記什么參數時,可以提醒。我也喜歡用這種方式創建命令行解析器,因為,我用命令語言寫過幾個命令行解析器,那可不是令人滿意的體驗,最終必須寫大量的代碼,詳細說明如何拆分命令行。如果你用.NET 寫過代碼,那么,通常會花太多的時間在調用字符串類型的IndexOf 和Substring 方法。
總結
- 上一篇: 电压转换电路整理
- 下一篇: 区块链项目的价值评估关键词:数据|筱静观