新聞中心
【獨(dú)家特稿】最近,人們對(duì)于領(lǐng)域特定語(yǔ)言F#中DSL原型設(shè)計(jì)的興趣卷土重來(lái)。這些語(yǔ)言不僅能夠?yàn)樘囟I(lǐng)域提供更好等級(jí)的提煉,從而有助于減少在通用語(yǔ)言中因低等級(jí)構(gòu)造而造成的錯(cuò)誤;而且通過(guò)提供額外配置、定制的業(yè)務(wù)邏輯等,它們?yōu)橛脩籼峁┝艘环N有效的機(jī)制,用于細(xì)調(diào)你的應(yīng)用程序??傊珼SL能夠讓你的應(yīng)用程序更加多樣化并具有更好的伸縮性。向您推薦Visual Studio 2010中F#的一些資源

成都創(chuàng)新互聯(lián)專(zhuān)注于新津縣企業(yè)網(wǎng)站建設(shè),成都響應(yīng)式網(wǎng)站建設(shè)公司,商城網(wǎng)站制作。新津縣網(wǎng)站建設(shè)公司,為新津縣等地區(qū)提供建站服務(wù)。全流程按需搭建網(wǎng)站,專(zhuān)業(yè)設(shè)計(jì),全程項(xiàng)目跟蹤,成都創(chuàng)新互聯(lián)專(zhuān)業(yè)和態(tài)度為您提供的服務(wù)
大致來(lái)講,領(lǐng)域特定語(yǔ)言的工作方式有兩種——你可以通過(guò)對(duì)以源DSL編寫(xiě)的源文本進(jìn)行轉(zhuǎn)譯來(lái)實(shí)施,或者通過(guò)將源文本編譯為可執(zhí)行代碼。這兩種方式都有著獨(dú)特的優(yōu)點(diǎn)和缺點(diǎn)。對(duì)于解釋器和編譯器的實(shí)施階段,很多都是類(lèi)似的,甚至一模一樣;例如,語(yǔ)法和語(yǔ)義檢查在兩種方式中是共同的。在獲得合適的內(nèi)部重現(xiàn)(inner representation)之后,編譯器實(shí)施包括幾個(gè)階段,逐步將這種重現(xiàn)分解為低等級(jí)的指令,生成匯編語(yǔ)言原生碼,或管理代碼(取決于目標(biāo)平臺(tái))。解釋器與之相反,很少執(zhí)行這些階段。作為替代,你可以實(shí)施所謂的DSL 的“操作語(yǔ)義”(operational semantic);例如,為內(nèi)部重現(xiàn)編寫(xiě)一個(gè)評(píng)估器。
圖1. 運(yùn)行中的Simply
你可以在Simply上進(jìn)行構(gòu)建,來(lái)創(chuàng)建新的DSL并將其嵌入到你自己定制的開(kāi)發(fā)外科中。此處演示的應(yīng)用程序 SimplyLogo從零開(kāi)始構(gòu)建,F(xiàn)# 代碼少于500 行。
在本文介紹的F#中DSL原型設(shè)計(jì),我們將為一個(gè)小型的DSL(由于其類(lèi)似 C 語(yǔ)言的語(yǔ)法和簡(jiǎn)潔,我將其稱(chēng)為“Simply”)編寫(xiě)一個(gè)解釋器,然后使用與Logo 那種語(yǔ)言類(lèi)似的內(nèi)置函數(shù)將其實(shí)例化。你可以通過(guò)在表達(dá)式語(yǔ)法器上來(lái)構(gòu)建以完成實(shí)例化。之前我們已經(jīng)在相關(guān)文章中進(jìn)行講述,在這篇文章中,你可以看到活躍模式(active pattern)提供了一個(gè)***的機(jī)制(雖然付出了一點(diǎn)速度的小代價(jià)),能夠用于構(gòu)建符合類(lèi)型安全規(guī)則的語(yǔ)法器,它與用戶語(yǔ)法中的正規(guī)的 BNF 句法非常相似;并且能夠在增強(qiáng)的AST 重現(xiàn)上實(shí)施語(yǔ)言檢查(本文)和評(píng)估器(下一篇文章)。使用這種語(yǔ)言,你可以快速生成圖像,這些圖像能夠使用簡(jiǎn)單的畫(huà)圖命令來(lái)定義——并且你可以在所有你需要的語(yǔ)境中使用這個(gè)核心評(píng)估器。在圖 1 中所示為該 DSL 的一種可能的嵌入。在本文中,我們主要關(guān)心的是構(gòu)建 Simply 的語(yǔ)法器和檢查源程序以確認(rèn)語(yǔ)法的正確性。
譯者注:為了學(xué)習(xí)這個(gè)系列的文章,你需要下載 F# May 2009 CTP 或Visual Studio 2010 Beta 1。
Simply 概述
Simply 是本文的DSL,它是一個(gè)具有靜態(tài)作用域、嵌套變量(nested variable)和函數(shù)聲明,以及簡(jiǎn)單循環(huán)構(gòu)造的小型編程語(yǔ)言。下面是一個(gè)很短的 Simply 程序:
- var x = 2
- fun x(a b) { a + b + x }
- fun x(y) { y + x(1 2) }
- repeat 100 as i { x(i) }
這段程序很容易讀懂,它包含四條命令,定義了一個(gè)變量、兩個(gè)函數(shù)和一個(gè)循環(huán)。為了分析這些命令的語(yǔ)法,你需要對(duì)上文中講述的語(yǔ)法器進(jìn)行擴(kuò)展。
對(duì)具有循環(huán)構(gòu)造、變量和函數(shù)的Simply進(jìn)行擴(kuò)展
前文中實(shí)施的語(yǔ)法器使用函數(shù)調(diào)用對(duì)算術(shù)表達(dá)式進(jìn)行語(yǔ)法分析并將其翻譯為定制的 AST 類(lèi)型。對(duì)于 Simply,你需要一個(gè)稍微更為高級(jí)的內(nèi)部重現(xiàn)來(lái)對(duì)表達(dá)式進(jìn)行語(yǔ)法分析,這些表達(dá)式包含了簡(jiǎn)單變量以及與其密切關(guān)聯(lián)的少量語(yǔ)言擴(kuò)展,用于定義變量和函數(shù),以及用簡(jiǎn)單的循環(huán)構(gòu)造(循環(huán)區(qū)塊)來(lái)表達(dá)循環(huán)。
如果你已經(jīng)將AST 定義放在其自身模塊中,下面你可以看到新的擴(kuò)展版本:
- namespace IntelliFactory.Simply
- module Ast =
- type var = string
- type Expr =
- | Number of float
- | BinOp of (float -> float -> float) * Expr * Expr
- | Var of var
- | FunApply of var * Expr list
- static member Sum (e1, e2) = BinOp (( + ), e1, e2)
- static member Diff (e1, e2) = BinOp (( - ), e1, e2)
- static member Prod (e1, e2) = BinOp (( * ), e1, e2)
- static member Ratio (e1, e2) = BinOp (( / ), e1, e2)
你可能已經(jīng)注意到,我對(duì)這個(gè)模塊的代碼格式進(jìn)行了細(xì)小的調(diào)整,以便符合 F# 編碼語(yǔ)法指南。我們的理想是用最少的代碼實(shí)現(xiàn)最多的功能,同時(shí)在需要增加代碼以及所表達(dá)的功能時(shí)仍然能夠進(jìn)行快速建模(prototyping)并且修改最小化?,F(xiàn)在,你可以在代碼中添加 AST 增強(qiáng),其指向不再是那些普通的算術(shù)表達(dá)式:
- type Command =
- | VarDef of var * Expr
- | FunDef of var * var list * Command
- | Repeat of Expr * var * Command
- | Sequence of Command list
- | Yield of Expr type Prog = Program of Command list
這些F#中DSL原型設(shè)計(jì)的代碼定義了:
一個(gè) Command 類(lèi)型,可以對(duì)變量定義繼續(xù)編碼(利用一個(gè)值進(jìn)行初始化) 函數(shù)定義(具有函數(shù)名稱(chēng)、常規(guī)的參數(shù)列表和一個(gè)體現(xiàn)函數(shù)主體的 Command 值) 循環(huán)區(qū)塊(具有控制變量、循環(huán)程度表達(dá)式和一個(gè)用于體現(xiàn)循環(huán)區(qū)塊主體的 Command 變量) Command 排序(對(duì)于定義需多個(gè)簡(jiǎn)單表達(dá)式的函數(shù)主體或循環(huán)區(qū)塊非常有用) 簡(jiǎn)單表達(dá)式執(zhí)行。一列這樣的表達(dá)構(gòu)成了一個(gè)程序。利用這些類(lèi)型,你現(xiàn)在可以擴(kuò)展你支持創(chuàng)建的表達(dá)式語(yǔ)法器。為了更加方便,你可以再次使用 Listing 1 中代碼,然后對(duì)其進(jìn)行稍微的增強(qiáng):
這個(gè)核心語(yǔ)法器中唯一的更改(格式更改除外)位于(|Factor|_|)活躍模式在:這個(gè)版本添加了簡(jiǎn)單的變量變量引用(第三條規(guī)則),以滿足增強(qiáng)的 AST 表達(dá)式語(yǔ)言中的相應(yīng)的附加規(guī)則。
到這里,你就可以真正地開(kāi)始加速,快速寫(xiě)下 DSl 語(yǔ)法器的其余部分。首先添加關(guān)鍵字和特定字符的規(guī)則:
- let (|LBRACE|_|) s = "{" |> MatchSymbol s
- let (|RBRACE|_|) s = "}" |> MatchSymbol s
- let (|EQ|_|) s = "=" |> MatchSymbol s
- let (|VAR|_|) s = "var" |> MatchSymbol s
- let (|FUN|_|) s = "fun" |> MatchSymbol s
- let (|REPEAT|_|) s = "repeat" |> MatchSymbol s
- let (|AS|_|) s = "as" |> MatchSymbol s
語(yǔ)法分析命令的規(guī)則是語(yǔ)法規(guī)則轉(zhuǎn)換為之前地定義的活躍模式的一種簡(jiǎn)單的翻譯。
- let rec (|Command|_|) = function
- | VAR (ID (v, EQ (Expression (expr, rest))))
- -> (Ast.Command.VarDef (v, expr), rest)
- |> Some | FUN (ID (f, LPAREN (Star (|ID|_|) [] ( pars, RPAREN (Command (body, rest))))))
- -> (Ast.Command.FunDef (f, pars, body), rest)
- |> Some | REPEAT (Expression (i, AS (ID (v, Command (body, rest)))))
- -> (Ast.Command.Repeat (i, v, body), rest)
- |> Some | LBRACE (Star (|Command|_|) [] (commands, RBRACE rest))
- -> (Ast.Command.Sequence commands, rest)
- |> Some | Expression (e, rest)
- -> (Ast.Command.Yield e, rest) |> Some | _ -> None
例如,讓我們看看上面(|Command|_|)活躍模式中的***條規(guī)則。它字母的意思是:
“批評(píng)‘var’關(guān)鍵字,然后是標(biāo)識(shí)符并將其與‘v’捆綁,然后是等于符號(hào),然后是一個(gè)綁定到‘expr’的表達(dá)式;然后返回帶有變量及其初始值的 Command.VarDef 值,還有其余的輸入字符串,作為一個(gè)成功的匹配。”
其他規(guī)則一樣易于理解和構(gòu)造。有一個(gè)細(xì)節(jié)需要進(jìn)一步解釋?zhuān)诤瘮?shù)定義或排序規(guī)則中如何使用(|Star|_|)活躍模式。記住,這是一個(gè)參數(shù)化(parameterized)的活躍模式,在它被應(yīng)用到你再次匹配的值之前,它具有了兩個(gè)變量。***個(gè)變量是一個(gè)活躍模式,你可以“運(yùn)行”零次或多次(名稱(chēng) Star,它反映了常規(guī)語(yǔ)言如 BNF 或常規(guī)表達(dá)式中的 star 操作符),第二變量是初始累加器,用于收集請(qǐng)求結(jié)果。由于該累加器的初始值通常是一個(gè)空列表,因此你可能會(huì)選擇以一種不需要初始值的方式重寫(xiě)這個(gè)活躍模式;因此這就給了你一直更為緊湊的方式來(lái)指定“零次或多次”這種類(lèi)型的規(guī)則。
***,你可以編寫(xiě)定義了這個(gè)程序語(yǔ)法的規(guī)則:
- let (|Prog|_|) = function
- | Star (|Command|_|) [] (commands, rest) -> (Ast.Prog.Program commands, rest)
- |> Some | _ -> None
或者,編寫(xiě)一個(gè)格式稍微有點(diǎn)冗長(zhǎng)的規(guī)則:
- let (|Prog|_|) s = match s with
- | Star (|Command|_|) [] (commands, rest) -> (Ast.Prog.Program commands, rest)
- |> Some | _ -> None
你可以在 Simply 程序上快速檢驗(yàn)?zāi)愕恼Z(yǔ)法器——只需通過(guò)選取代碼并按 Alt+Enter 鍵將 AST 和語(yǔ)言模塊載入到 F# Interactive 中,然后測(cè)試一個(gè) Simply 小程序:
- open Language " var x=1 var x=2 var x=3 fun foo(y)
- { fun bar(foo) { var xx=x+1 foo+x } bar(y*2)
- }
- repeat 1000 as x { foo(x) }" |> (|Prog|_|) |> printf "Result=%A\n";;
- > Result=Some (Program [VarDef ("x",Number 1.0);
- VarDef ("x",Number 2.0); VarDef ("x",Number 3.0);
- FunDef ("foo",["y"], Sequence [FunDef ("bar",["foo"], Sequence [VarDef ("x",BinOp (,Var "x",Number 1.0));
- Yield (BinOp (,Var "foo",Var "x"))]);
- Yield (FunApply ("bar",[BinOp (,Var "y",Number 2.0)]))]);
- Repeat (Number 1000.0,"x",Sequence [Yield (FunApply ("foo",[Var "x"]))])], "") >
你將看到,對(duì)于送入到識(shí)別 Simply 程序的主活躍模式中這個(gè)程序,輸出結(jié)果是 AST 值的轉(zhuǎn)存。
F#中DSL原型設(shè)計(jì):語(yǔ)法檢查和語(yǔ)義分析就到這里
網(wǎng)頁(yè)名稱(chēng):F#中DSL原型設(shè)計(jì):語(yǔ)法檢查和語(yǔ)義分析
本文鏈接:http://www.5511xx.com/article/djpedgc.html


咨詢
建站咨詢
