孟凡輝,王宏智,吳 旭
(中國(guó)電子科技集團(tuán)公司第四十五研究所,北京 100176)
近年來(lái),隨著工業(yè)激光器產(chǎn)業(yè)的發(fā)展和技術(shù)進(jìn)步,激光加工應(yīng)用技術(shù)在國(guó)內(nèi)得到了迅猛發(fā)展。為提高加工數(shù)據(jù)導(dǎo)入效率,減少數(shù)據(jù)輸入人為誤差,目前大多數(shù)的激光加工設(shè)備主控軟件均包含了CAD數(shù)據(jù)圖形文件自動(dòng)導(dǎo)入功能。數(shù)據(jù)圖形文件一般可分為矢量和位圖兩種格式。位圖加工一般常見(jiàn)于動(dòng)態(tài)光路振鏡掃描系統(tǒng)的打標(biāo)、雕刻等應(yīng)用中,而矢量加工則更廣泛地應(yīng)用于激光劃片、劃線、切割、鉆孔和結(jié)構(gòu)化成型等靜、動(dòng)態(tài)光路加工領(lǐng)域。
矢量文件格式中,以 PLT、HPGL、HPGL2、DWGTM和DXF等格式最為常見(jiàn)。受AutoCAD軟件龐大的用戶群影響,DWGTM、DXF已然成為二維CAD設(shè)計(jì)繪圖的事實(shí)標(biāo)準(zhǔn),其中DWGTM格式是AutoCAD的專(zhuān)用內(nèi)部文件格式。雖然Autodesk公司提供的ObjectARX二次開(kāi)發(fā)包可以對(duì)DWG文件讀寫(xiě),但是開(kāi)發(fā)出來(lái)的程序不能脫離宿主應(yīng)用程序AutoCAD運(yùn)行。ODA(Open Design Alliance)組織通過(guò)逆向工程技術(shù)獲取了DWG格式的大部分技術(shù)細(xì)節(jié),并推出了TeighaTM(曾用名OpenDWG、DWGDirect)C++API類(lèi)庫(kù)用于DWG數(shù)據(jù)讀寫(xiě),不過(guò)一般公司需要經(jīng)過(guò)嚴(yán)格的申請(qǐng)入會(huì)流程才能得到使用許可。因此,相對(duì)開(kāi)放的DXF(繪圖交換格式)文件標(biāo)準(zhǔn)在各CAD/CAM軟件系統(tǒng)中更為流行。DXF文件分為ASCII和二進(jìn)制兩種格式,本文僅討論應(yīng)用更為廣泛的ASCII格式。
DXF數(shù)據(jù)解析通常被認(rèn)為是一件繁瑣的任務(wù),程序員需要深入理解業(yè)務(wù)領(lǐng)域模型——DXF文件詳細(xì)規(guī)范,同時(shí)設(shè)計(jì)解析器架構(gòu)并精心編碼,另外還要考慮兼容性問(wèn)題。實(shí)際應(yīng)用開(kāi)發(fā)中多是采用輕量級(jí)DXF數(shù)據(jù)解析開(kāi)發(fā)包,比如開(kāi)源社區(qū)知名的dxflib[1]類(lèi)庫(kù),結(jié)合具體應(yīng)用執(zhí)行部分?jǐn)?shù)據(jù)解析,僅解析出需要的數(shù)據(jù)并進(jìn)行數(shù)據(jù)處理。本文提出了一種基于Boost Spirit解析器架構(gòu)的新方法,程序員僅需要專(zhuān)注于特定領(lǐng)域建模,無(wú)需過(guò)多考慮代碼的架構(gòu)及編碼,即可實(shí)現(xiàn)簡(jiǎn)潔、高效的DXF文件解析器。
特定領(lǐng)域建模 (Domain-specific modeling,DSM),是近些年來(lái)軟件工程領(lǐng)域的一種新的模型驅(qū)動(dòng)開(kāi)發(fā)方法學(xué),旨在大幅度的提高開(kāi)發(fā)效率并簡(jiǎn)化軟件開(kāi)發(fā)。它試圖使用特定領(lǐng)域語(yǔ)言(DSL)描述系統(tǒng),DSL傾向于支持比通用建模語(yǔ)言 (如UML)更高級(jí)別的抽象。DSM往往還包括自動(dòng)代碼生成的想法:直接從DSM模型自動(dòng)創(chuàng)建可執(zhí)行源代碼。擺脫手工創(chuàng)建和維護(hù)源代碼,意味著DSM可以顯著提高開(kāi)發(fā)人員的工作效率。與手工編碼相比,自動(dòng)生成的代碼比較可靠、生成的程序可減少缺陷從而提高代碼質(zhì)量[2]。在近十年中,早期采用DSM的軟件人員已經(jīng)提高了5到10倍的生產(chǎn)率。微軟也自VS2005 SDK開(kāi)始提供了DSL[3]。EBNF(Extended Backus-Naur Form,擴(kuò)展巴科斯—諾爾范式)即為可應(yīng)用于特定領(lǐng)域建模的一種元模型建模語(yǔ)言,而B(niǎo)oost Spirit類(lèi)庫(kù)實(shí)現(xiàn)的內(nèi)聯(lián)EBNF語(yǔ)法與語(yǔ)義API直接形成了創(chuàng)建解析器生成器的DSEL(特定領(lǐng)域嵌入式語(yǔ)言)。
Boost Spirit是一個(gè)利用模板元編程技術(shù)實(shí)現(xiàn)的面向?qū)ο蟮倪f歸下降解析器生成框架。借助于模板元編程技術(shù)的靜態(tài)多態(tài)特性、模塊化和可擴(kuò)展性,表達(dá)式模板使編程人員能夠在C++代碼中使用近似于EBNF范式的文法,即內(nèi)聯(lián)的EBNF語(yǔ)法規(guī)范可以自由地混合于其它C++代碼中,減少了傳統(tǒng)編譯器生成器(如YACC、Bison和ANTLR)中將EBNF文法轉(zhuǎn)換為C、C++代碼的額外步驟。[4]
Spirit類(lèi)庫(kù)涉及了幾個(gè)基本概念,包括Rule(規(guī)則)、Scanner(掃描器)、Parser(解析器)、Match(匹配)、Semantic Action(語(yǔ)義動(dòng)作)等,如圖 1 所示,它們相互關(guān)聯(lián),功能交織構(gòu)成了整個(gè)框架。框架的核心是解析器,它真正完成從頭到尾識(shí)別由掃描器讀入的線性數(shù)據(jù)流的工作。解析器嘗試以一系列完整定義的規(guī)范來(lái)匹配輸入,這些規(guī)范被稱(chēng)為語(yǔ)法規(guī)則。解析器通過(guò)匹配對(duì)象來(lái)通知客戶程序分析的成功與否。成功匹配時(shí),將執(zhí)行客戶程序提供的語(yǔ)義動(dòng)作。最后,語(yǔ)義動(dòng)作從解析器中獲取結(jié)構(gòu)化的信息,這些信息依賴于解析器傳遞的數(shù)據(jù)和解析器所處的語(yǔ)境層次[4]。
DXF文件本質(zhì)上由代碼及其關(guān)聯(lián)值對(duì)組成。代碼(通常稱(chēng)為Group Code,組碼)表明其后的值的類(lèi)型。使用這些組碼和值對(duì),可以將DXF文件組織到由記錄組成的區(qū)域中,這些記錄由組碼和數(shù)據(jù)值組成。在DXF文件中,每個(gè)組碼和值都各占一行。每段都以一個(gè)后跟字符串SECTION的組碼0開(kāi)始,其后是組碼2和表示該段名稱(chēng)的字符串(如HEADER)。每段都由定義其元素的組碼和值組成。每段都以一個(gè)后跟字符串ENDSEC的組碼0結(jié)束。DXF文件完整結(jié)構(gòu)如表1所示。

圖1 Spirit框架基本概念

表1 DXF文件結(jié)構(gòu)組成
實(shí)際上,DXF文本文件模型可以EBNF文法精確地表示,例如頂層非終結(jié)符dxffile的產(chǎn)生式規(guī)則可以定義如下:


限于篇幅,以上省略了除header_section以外其它幾個(gè)段、實(shí)數(shù)、整數(shù)和字符串等非終結(jié)符的產(chǎn)生式規(guī)則。關(guān)于EBNF文法的更多細(xì)節(jié),請(qǐng)參考ISO/IEC 14977 標(biāo)準(zhǔn)[6]。
以上文法在Spirit程序中對(duì)應(yīng)編碼如下所示:

HEADER=str_p("HEADER")>>eol_p;
可以看到,Spirit重載了C++語(yǔ)法中的>>、*、+、!和|等操作符來(lái)表示EBNF語(yǔ)法規(guī)則,其中eol_p、char_p、str_p、print_p 等內(nèi)建原語(yǔ)(Primitives)作為基本構(gòu)建塊以形成更加復(fù)雜的產(chǎn)生式規(guī)則。
本部分將舉例闡釋本文所描述的Spirit類(lèi)庫(kù)為基礎(chǔ)的DXF文件解析方法。為敘述方便并突出重點(diǎn),此處DXF文件中僅包含線段和圓兩種幾何實(shí)體類(lèi)型。實(shí)際應(yīng)用中,可能還需要考慮圓弧、多義線和BLOCK塊等幾何實(shí)體類(lèi)型。
圖層和幾何實(shí)體均有圖層名稱(chēng)、線型、顏色和線寬等屬性,其UML類(lèi)圖如圖2所示。

圖2 幾何實(shí)體及圖層相關(guān)類(lèi)圖
其中,定義了以下圖層和實(shí)體指針兩個(gè)容器類(lèi)型以方便數(shù)據(jù)存儲(chǔ)及后續(xù)處理。

語(yǔ)義動(dòng)作通常具有如下形式:expr[action],即表達(dá)式后跟著符號(hào)[],方括號(hào)內(nèi)為語(yǔ)義動(dòng)作。語(yǔ)義動(dòng)作可以是符合一定接口的自定義回調(diào)函數(shù)或仿函數(shù)(functor),同時(shí)Spirit框架內(nèi)部也包含幾個(gè)最為常用的預(yù)定義仿函數(shù)。在下面的circle規(guī)則編碼中,預(yù)定義仿函數(shù)assign()用于將解析器傳遞過(guò)來(lái)的圓的各種屬性值(所屬圖層、線寬、顏色、線型、圓心坐標(biāo)和半徑等)賦給actions類(lèi)中的相應(yīng)成員變量。

其中,!表示對(duì)其后的表達(dá)式匹配0次或1次,這是為應(yīng)對(duì)DXF文法的多變性所必需的,以提高代碼的健壯性。如下定義AddCircle仿函數(shù),以表示匹配circle解析器時(shí)的語(yǔ)義動(dòng)作。


可以參考AddCircle仿函數(shù)的成員操作符()簽名,定義更多的仿函數(shù),例如以下代碼所示的

語(yǔ)義動(dòng)作仿函數(shù)通常較多,為此可以抽象出一個(gè)語(yǔ)義動(dòng)作管理器類(lèi)Actions,即將各仿函數(shù)作為管理器類(lèi)的成員變量,由其集中統(tǒng)一管理,其UML類(lèi)圖如圖3所示。

圖3 Actions類(lèi)圖
Spirit用戶可以基于其框架設(shè)計(jì)定制符合應(yīng)用需求的完備的語(yǔ)法規(guī)則。以下代碼創(chuàng)建一個(gè)從預(yù)定義grammar類(lèi)繼承的派生類(lèi)DXFgrammar。grammar類(lèi)是一個(gè)模板類(lèi),其被派生類(lèi)DXFgrammar參數(shù)化。而為了便于繁多語(yǔ)義動(dòng)作的管理,DXFgrammar作為模板類(lèi)又被語(yǔ)義動(dòng)作管理器類(lèi)Actions參數(shù)化。


其中,DXFgrammar類(lèi)包含一個(gè)嵌套的類(lèi)型名為ScannerT的模板結(jié)構(gòu)體definition,語(yǔ)法規(guī)則在其構(gòu)造函數(shù)中定義,實(shí)際的語(yǔ)法self作為引用參數(shù)傳遞至構(gòu)造函數(shù)內(nèi)部。Definition必須提供成員函數(shù)start(),以表示規(guī)則入口點(diǎn)。此處,dxffile為Start規(guī)則,規(guī)則展開(kāi)具體代碼可參考2.3節(jié)。
至此,dxf文件解析函數(shù)可以實(shí)現(xiàn)如下。其中,數(shù)據(jù)結(jié)構(gòu)parse_info可以用來(lái)診斷解析過(guò)程中的錯(cuò)誤,其hit字段表示解析是否成功,而length字段表示匹配長(zhǎng)度。

本實(shí)例源代碼在Windows XP操作系統(tǒng)和VC6 SP6開(kāi)發(fā)工具下編譯通過(guò)。使用的Boost Spirit類(lèi)庫(kù)為1.6.4版本,這是支持VC6的最后一個(gè)版本。因?yàn)閂C6自帶的標(biāo)準(zhǔn)模板庫(kù)Plauger STL對(duì)模板元編程技術(shù)的支持不夠完善,建議使用STLport STL。
利用AutoCAD軟件幾個(gè)不同版本和第三方CAD工具導(dǎo)出大量DXF測(cè)試文件,對(duì)程序執(zhí)行測(cè)試,均能正常運(yùn)行且解析結(jié)果無(wú)誤,文件解析兼容性也得到了部分驗(yàn)證。
在面對(duì)諸如本文所述的DXF文件解析之類(lèi)的軟件設(shè)計(jì)問(wèn)題時(shí),大多數(shù)程序員面臨的挑戰(zhàn)是,難于精確捕捉、識(shí)別問(wèn)題域模型。DXF相對(duì)復(fù)雜的文法規(guī)則,使得傳統(tǒng)純手工編碼時(shí),問(wèn)題域相關(guān)代碼常散布于多處源代碼之中,最終導(dǎo)致了脆弱與僵化的軟件設(shè)計(jì)。而面向特定領(lǐng)域建模的軟件設(shè)計(jì),使得程序員能夠在設(shè)計(jì)階段居于更高的層次來(lái)關(guān)注、審視問(wèn)題域,避免過(guò)早迷失于詳細(xì)編碼之中。
利用Spirit,可以方便地將DXF EBNF文法規(guī)則完全建模于Spirit語(yǔ)法派生類(lèi)之中,從而降低了問(wèn)題域核心模型代碼與其余代碼的耦合,極大地方便了程序編寫(xiě)、調(diào)試、測(cè)試和后期代碼維護(hù)。得益于部分代碼自動(dòng)生成,對(duì)于一個(gè)輕量級(jí)DXF數(shù)據(jù)解析應(yīng)用,基于Spirit的解決方案其源代碼僅需千余行,這通常為傳統(tǒng)純手工編碼方案所需源代碼行數(shù)的1/10~1/30,因而也顯著提高了程序員的生產(chǎn)效率。目前,Spirit類(lèi)庫(kù)已更新到2.5版本,包含了對(duì)二進(jìn)制數(shù)據(jù)流的匹配解析功能,因而實(shí)際上,本文所展示的技術(shù)可以推廣應(yīng)用于適于EBNF文法規(guī)則精確表述的多種文本或二進(jìn)制CAD/CAM數(shù)據(jù)格式(如 RS-274X、HPGL2、Excellon2、Sieb&Meyer、ODB++和IPC-2581等)文件的解析處理。
[1] dxflib library doc[DB/OL],http://www.ribbonsoft.com/en/dxflib-documentation,2012.
[2] Wikipedia,Domain-specific modeling[DB/OL],http://en.wikipedia.org/wiki/Domain-specific_modeling,2011-10-17.
[3] Kelly,S.and Tolvanen,J.-P.,Domain-Specific Modeling:Enabling Full Code Generation,John Wiley&Sons,New Jersey.2008.
[4] Joelde Guzman,Spiritframework documentation[DB/OL],http://boost-spirit.com/distrib/spirit_1_6_4/libs/spirit/index.html,Sep.2002.
[5] Autodesk公司,DXF 參考手冊(cè)[DB/OL],http://docs.autodesk.com/ACD/2011/CHS/landing.html,2011.
[6] ISO/IEC 14977,Information technology-Syntactic metalanguage-Extended BNF,International Organization for Standardization[S],1996.