基于Spirit解析器框架的DXF文件解析技术

2012-08-08 10:23孟凡辉王宏智
电子工业专用设备 2012年11期
关键词:类库文法代码

孟凡辉,王宏智,吴 旭

(中国电子科技集团公司第四十五研究所,北京 100176)

近年来,随着工业激光器产业的发展和技术进步,激光加工应用技术在国内得到了迅猛发展。为提高加工数据导入效率,减少数据输入人为误差,目前大多数的激光加工设备主控软件均包含了CAD数据图形文件自动导入功能。数据图形文件一般可分为矢量和位图两种格式。位图加工一般常见于动态光路振镜扫描系统的打标、雕刻等应用中,而矢量加工则更广泛地应用于激光划片、划线、切割、钻孔和结构化成型等静、动态光路加工领域。

矢量文件格式中,以 PLT、HPGL、HPGL2、DWGTM和DXF等格式最为常见。受AutoCAD软件庞大的用户群影响,DWGTM、DXF已然成为二维CAD设计绘图的事实标准,其中DWGTM格式是AutoCAD的专用内部文件格式。虽然Autodesk公司提供的ObjectARX二次开发包可以对DWG文件读写,但是开发出来的程序不能脱离宿主应用程序AutoCAD运行。ODA(Open Design Alliance)组织通过逆向工程技术获取了DWG格式的大部分技术细节,并推出了TeighaTM(曾用名OpenDWG、DWGDirect)C++API类库用于DWG数据读写,不过一般公司需要经过严格的申请入会流程才能得到使用许可。因此,相对开放的DXF(绘图交换格式)文件标准在各CAD/CAM软件系统中更为流行。DXF文件分为ASCII和二进制两种格式,本文仅讨论应用更为广泛的ASCII格式。

DXF数据解析通常被认为是一件繁琐的任务,程序员需要深入理解业务领域模型——DXF文件详细规范,同时设计解析器架构并精心编码,另外还要考虑兼容性问题。实际应用开发中多是采用轻量级DXF数据解析开发包,比如开源社区知名的dxflib[1]类库,结合具体应用执行部分数据解析,仅解析出需要的数据并进行数据处理。本文提出了一种基于Boost Spirit解析器架构的新方法,程序员仅需要专注于特定领域建模,无需过多考虑代码的架构及编码,即可实现简洁、高效的DXF文件解析器。

1 特定领域建模

特定领域建模 (Domain-specific modeling,DSM),是近些年来软件工程领域的一种新的模型驱动开发方法学,旨在大幅度的提高开发效率并简化软件开发。它试图使用特定领域语言(DSL)描述系统,DSL倾向于支持比通用建模语言 (如UML)更高级别的抽象。DSM往往还包括自动代码生成的想法:直接从DSM模型自动创建可执行源代码。摆脱手工创建和维护源代码,意味着DSM可以显著提高开发人员的工作效率。与手工编码相比,自动生成的代码比较可靠、生成的程序可减少缺陷从而提高代码质量[2]。在近十年中,早期采用DSM的软件人员已经提高了5到10倍的生产率。微软也自VS2005 SDK开始提供了DSL[3]。EBNF(Extended Backus-Naur Form,扩展巴科斯—诺尔范式)即为可应用于特定领域建模的一种元模型建模语言,而Boost Spirit类库实现的内联EBNF语法与语义API直接形成了创建解析器生成器的DSEL(特定领域嵌入式语言)。

1.1 Boost Spirit解析器框架

Boost Spirit是一个利用模板元编程技术实现的面向对象的递归下降解析器生成框架。借助于模板元编程技术的静态多态特性、模块化和可扩展性,表达式模板使编程人员能够在C++代码中使用近似于EBNF范式的文法,即内联的EBNF语法规范可以自由地混合于其它C++代码中,减少了传统编译器生成器(如YACC、Bison和ANTLR)中将EBNF文法转换为C、C++代码的额外步骤。[4]

Spirit类库涉及了几个基本概念,包括Rule(规则)、Scanner(扫描器)、Parser(解析器)、Match(匹配)、Semantic Action(语义动作)等,如图 1 所示,它们相互关联,功能交织构成了整个框架。框架的核心是解析器,它真正完成从头到尾识别由扫描器读入的线性数据流的工作。解析器尝试以一系列完整定义的规范来匹配输入,这些规范被称为语法规则。解析器通过匹配对象来通知客户程序分析的成功与否。成功匹配时,将执行客户程序提供的语义动作。最后,语义动作从解析器中获取结构化的信息,这些信息依赖于解析器传递的数据和解析器所处的语境层次[4]。

2.2 DXF文件结构[5]

DXF文件本质上由代码及其关联值对组成。代码(通常称为Group Code,组码)表明其后的值的类型。使用这些组码和值对,可以将DXF文件组织到由记录组成的区域中,这些记录由组码和数据值组成。在DXF文件中,每个组码和值都各占一行。每段都以一个后跟字符串SECTION的组码0开始,其后是组码2和表示该段名称的字符串(如HEADER)。每段都由定义其元素的组码和值组成。每段都以一个后跟字符串ENDSEC的组码0结束。DXF文件完整结构如表1所示。

图1 Spirit框架基本概念

表1 DXF文件结构组成

2.3 DXF文法模型

实际上,DXF文本文件模型可以EBNF文法精确地表示,例如顶层非终结符dxffile的产生式规则可以定义如下:

限于篇幅,以上省略了除header_section以外其它几个段、实数、整数和字符串等非终结符的产生式规则。关于EBNF文法的更多细节,请参考ISO/IEC 14977 标准[6]。

以上文法在Spirit程序中对应编码如下所示:

HEADER=str_p("HEADER")>>eol_p;

可以看到,Spirit重载了C++语法中的>>、*、+、!和|等操作符来表示EBNF语法规则,其中eol_p、char_p、str_p、print_p 等内建原语(Primitives)作为基本构建块以形成更加复杂的产生式规则。

3 应用实践

本部分将举例阐释本文所描述的Spirit类库为基础的DXF文件解析方法。为叙述方便并突出重点,此处DXF文件中仅包含线段和圆两种几何实体类型。实际应用中,可能还需要考虑圆弧、多义线和BLOCK块等几何实体类型。

3.1 基本数据结构

图层和几何实体均有图层名称、线型、颜色和线宽等属性,其UML类图如图2所示。

图2 几何实体及图层相关类图

其中,定义了以下图层和实体指针两个容器类型以方便数据存储及后续处理。

3.2 语义动作

语义动作通常具有如下形式:expr[action],即表达式后跟着符号[],方括号内为语义动作。语义动作可以是符合一定接口的自定义回调函数或仿函数(functor),同时Spirit框架内部也包含几个最为常用的预定义仿函数。在下面的circle规则编码中,预定义仿函数assign()用于将解析器传递过来的圆的各种属性值(所属图层、线宽、颜色、线型、圆心坐标和半径等)赋给actions类中的相应成员变量。

其中,!表示对其后的表达式匹配0次或1次,这是为应对DXF文法的多变性所必需的,以提高代码的健壮性。如下定义AddCircle仿函数,以表示匹配circle解析器时的语义动作。

可以参考AddCircle仿函数的成员操作符()签名,定义更多的仿函数,例如以下代码所示的

语义动作仿函数通常较多,为此可以抽象出一个语义动作管理器类Actions,即将各仿函数作为管理器类的成员变量,由其集中统一管理,其UML类图如图3所示。

图3 Actions类图

3.3 语法规则

Spirit用户可以基于其框架设计定制符合应用需求的完备的语法规则。以下代码创建一个从预定义grammar类继承的派生类DXFgrammar。grammar类是一个模板类,其被派生类DXFgrammar参数化。而为了便于繁多语义动作的管理,DXFgrammar作为模板类又被语义动作管理器类Actions参数化。

其中,DXFgrammar类包含一个嵌套的类型名为ScannerT的模板结构体definition,语法规则在其构造函数中定义,实际的语法self作为引用参数传递至构造函数内部。Definition必须提供成员函数start(),以表示规则入口点。此处,dxffile为Start规则,规则展开具体代码可参考2.3节。

至此,dxf文件解析函数可以实现如下。其中,数据结构parse_info可以用来诊断解析过程中的错误,其hit字段表示解析是否成功,而length字段表示匹配长度。

3.4 编译运行情况说明

本实例源代码在Windows XP操作系统和VC6 SP6开发工具下编译通过。使用的Boost Spirit类库为1.6.4版本,这是支持VC6的最后一个版本。因为VC6自带的标准模板库Plauger STL对模板元编程技术的支持不够完善,建议使用STLport STL。

利用AutoCAD软件几个不同版本和第三方CAD工具导出大量DXF测试文件,对程序执行测试,均能正常运行且解析结果无误,文件解析兼容性也得到了部分验证。

4 结束语

在面对诸如本文所述的DXF文件解析之类的软件设计问题时,大多数程序员面临的挑战是,难于精确捕捉、识别问题域模型。DXF相对复杂的文法规则,使得传统纯手工编码时,问题域相关代码常散布于多处源代码之中,最终导致了脆弱与僵化的软件设计。而面向特定领域建模的软件设计,使得程序员能够在设计阶段居于更高的层次来关注、审视问题域,避免过早迷失于详细编码之中。

利用Spirit,可以方便地将DXF EBNF文法规则完全建模于Spirit语法派生类之中,从而降低了问题域核心模型代码与其余代码的耦合,极大地方便了程序编写、调试、测试和后期代码维护。得益于部分代码自动生成,对于一个轻量级DXF数据解析应用,基于Spirit的解决方案其源代码仅需千余行,这通常为传统纯手工编码方案所需源代码行数的1/10~1/30,因而也显著提高了程序员的生产效率。目前,Spirit类库已更新到2.5版本,包含了对二进制数据流的匹配解析功能,因而实际上,本文所展示的技术可以推广应用于适于EBNF文法规则精确表述的多种文本或二进制CAD/CAM数据格式(如 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 参考手册[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.

猜你喜欢
类库文法代码
用Java编写客户机/服务器端应用程序
Python在数据可视化中的应用
创世代码
创世代码
创世代码
创世代码
西夏文铜镜的真言文法与四臂观音像研究
数据结构课程教学改革方案和应用效果
数据结构可视化类库的设计与实现
Similarity measurement method of high-dimensional data based on normalized net lattice subspace①