Linux中国 Linux中国门户站!
设为主页 设为主页
收藏本站 收藏本站
 
当前位置 :首页 ->Linux技术 ->Linux程序设计 ->正文

使用 Flex 和 Bison 更好地进行错误处理

来源:IBM DW中国 作者:Christian Hagen  时间:2007-04-22 点击: [收藏] [投稿]
尽管使用 Flex 和 Bison 生成程序非常简单,但是要让这些程序产生用户友好的语法和语义错误消息却很困难。本文将介绍 Flex 和 Bison 的错误处理特性,并展示怎么样使用它们,然后详细介绍它们的一些缺陷。

简介

正如 UNIX® 开发人员所了解的那样,Flex 和 Bison 的功能非常强大,非常适合开发词法和语法解析器,尤其是语言编译器和解释器。如果我们不熟悉它们所实现的工具 —— 分别是 Lex 和 Yacc —— 可以参考一下本文 参考资料 一节中有关 Flex 和 Bison 文档的链接,以及其他介绍这两个程序的文章。

本文介绍了更高级的一些主题:用来在编译器和解释器中更好地实现错误处理能力的特性和技术。为了展示这些技术,我使用了一个示例程序 ccalc,它基于 Bison 手册中的计算机实现了一个增强的计算器。我们可以从本文后面 下载 一节下载 ccalc 和相关文件。

增强包括使用了很多变量。在 ccalc 中,变量是通过在初始化中首次使用时定义的,例如 a = 3。如果变量是在初始化之前使用的,那就会产生语义错误,使用值为 0 来创建这个变量,并打印一条消息。

示例源文件

示例源代码中包括 7 个文件:

  • ccalc.c:主程序,以及一些进行输入、输出和错误处理的函数
  • ccalc.h:包括了对所有模块的定义
  • cmath.c:数学函数
  • parse.y:Bison 使用的输入文法
  • lex.l:Flex 的输入
  • makefile:简单的 makefile
  • defs.txt:示例输入文件

这个程序接收两个参数:

  • -debug:产生调试输出
  • filename:输入文件名;默认值为 defs.txt

Bison 使用的设置

为了处理变量名和实际值,Bison 的语义类型必须进行增强:


清单 1. 更好的 Bison 语义类型
/* generate include-file with symbols and types */
%defines
/* a more advanced semantic type */
%union {
  double      value;
  char        *string;
}

有些文法规则可以产生特定的语义类型,这需要像清单 2 中一样对 Bison 进行声明。要获得一个可移植性更好的 Bison 文法版本,我们需要重新定义 +-*/() 符号。下面这个例子没有使用左括号 (,而是使用了结束符符号 LBRACE,这是由词法分析提供的。另外,操作符的优先顺序也必须进行声明。

对于 Flex 来说,所生成的代码通常都依赖于平台所使用的代码页(codepage)。尽管我们可以使用其他代码页,但是必须要对输入进行转换。因此与 Bison 代码不同,Flex 代码尚不能进行移植。


清单 2. Bison 声明
/* terminal symbols */

%token <string>   IDENTIFIER
%token <value>    VALUE
%type <value>     expression

/* operator-precedence
 * top-0: -
 *     1: * /
 *     2: + -
*/

%left ADD SUB
%left MULT DIV
%left NEG

%start program

这段文法与 Bison 手册非常类似,不同之处在于它使用了名字作为终端符号和标识符的简写形式。标识符是在赋值语句中进行定义和初始化的,并且可以在任何允许使用的地方使用。清单 3 给出了一个示例文法:


清单 3. 示例 Bison 文法
program
    : statement SEMICOLON program
    | statement SEMICOLON
    | statement error SEMICOLON program
    ;

statement
    : IDENTIFIER ASSIGN expression
    | expression
    ;

expression
    : LBRACE expression RBRACE
    | SUB expression %prec NEG
    | expression ADD expression
    | expression SUB expression
    | expression MULT expression
    | expression DIV expression
    | VALUE
    | IDENTIFIER
    ;

program 的第三个输出让这个分析程序可以获得错误,从中搜索分号,然后继续执行(通常错误对于解析器来说都是非常严重的)。

为了让这个例子更加有趣,规则体中的真正数学函数都是以单独函数的形式实现的。在进行高级文法分析时,我们要尽量保证规则简短,并使用函数来实现一些不会直接处理解析的过程:


清单 4. 使用单独的函数来实现数学规则
| expression DIV expression
  {
    $$ = ReduceDiv($1, $3);
  }

最后,函数 yyerror() 必须要进行定义。这个函数是在所生成的解析器检测到语法错误时调用的,它又会调用一个小函数 PrintError(),后者会打印增强的错误消息。详细内容请参看源代码。

Flex 的设置

Flex 所生成的词法分析器必须要根据语义类型提供终止符号。清单 5 定义了空格、实际值、标识符和符号所使用的语法。

 如果您对本文有任何疑问或者建议,请到讨论区发表您的意见: >> 论坛入口 <<



上一篇:使用 GStreamer 进行多用途的多媒体处理   下一篇:程序员眼中的qmail(qmail源代码分析)

文章评论】 【收藏本文】 【推荐好友】 【打印本文】 【我要投稿】 【论坛讨论
更多相关文章
Power by linux-cn.com 粤ICP备05006655号