网管联盟 | 网管论坛 | 网管u家 | 网管博客 | 网管软件 | 网管求职 | 小游戏 | 网管搜索 | 网管原创 | 网管聚合 | 网管读摘 | 网管焦点 | 世界素材 | 会员投稿 | 会员中心 
中国网管联盟
Windows Linux Cisco 网络技术 数据库 黑客攻防 DotNet Java PHP 认证 新闻资讯 服务器 存储资讯 网络设备 网管学堂 技术专题 焦点 网吧频道
 当前位置: > bitsCN.com > linux > 新手入门 > 软件使用 > 使用Flex和Bison 更好地进行错误处理  

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

2006-08-30  作者:网管整理  来源:bitsCN.com  点评 投稿 收藏

更好的输入函数

网管有家bitscn.net

    使用原来的错误消息,很难判断语义的错误。当然,这个例子非常容易修复,因为我们立即就可以找出有错误的那一行。在更加复杂的语法和对应输入中,这可能并不简单。让我们编写一个输入函数来从文件中读取相应的行。

网管联盟bitsCN@com

    Flex 具有一个非常有用的宏 YY_INPUT,它负责为符号解释读入数据。我们可以在 YY_INPUT 宏中添加一个对 GetNextChar() 函数的调用,后者从文件中读取数据,并保留了下一个要读取的字符的位置信息。GetNextChar() 使用了一个缓冲区来存放一行输入。这两个变量保存了当前行号和该行中下一个字符的位置: 网管有家www.bitscn.net


清单 8. 更好的 Flex YY_INPUT 宏

#define YY_INPUT(buf,result,max_size)  {\
    result = GetNextChar(buf, max_size); \
    if (  result <= 0  ) \
      result = YY_NULL; \
    }
             网管有家www.bitscn.net 

网管网www.bitscn.com

    使用这个增强的错误打印函数 PrintError()(在前面讨论过,它可以很好地显示有问题的输入行,完整的 PrintError() 源代码请参看 示例源代码),我们就具有了一个用户友好的消息,它显示了下一个字符的位置: 网管u家u.bitsCN.com


清单 9. 更好的 Flex 错误:字符位置

       |....+....:....+....:....+....:....+....:....+....:....+
     1 |a = 3;
     2 |3 aa = a * 4;
...... !.....^
Error: syntax error, unexpected IDENTIFIER, expecting SEMICOLON
     3 |b = aa / ( a - 3 );
...... !.......^
Error: reference to unknown variable 'aa'
...... !.................^
Error: division by zero!
             

中国网管论坛bbs.bitsCN.com


网管有家www.bitscn.net

    这个示例函数可以从其他函数(例如 ReduceDiv())中进行调用,从而打印语义错误,例如 division by zero 或 unknown identifiers。 网管联盟bitsCN@com

    如果我们希望标记一下最后使用的符号,就可以对 Flex 规则进行扩展,并修改错误的打印。函数 BeginToken() 和 PrintError()(二者都可以在示例源代码中找到)是关键:BeginToken() 是由每条规则进行调用的,这样它就可以记住每个符号的开始和结束,每次打印错误时都会调用 PrintError()。这样,我们就可以生成一条有用的消息了,例如:

网管u家www.bitscn.net


清单 10. 更好的 Flex 错误:表示确切的符号位置

     2 |3 aa = a * 4;
...... !..^^............
Error: syntax error, unexpected IDENTIFIER, expecting SEMICOLON
             网管网www.bitscn.com 

网管联盟bitsCN@com

缺点 网管论坛bbs_bitsCN_com

    所生成的词法解析器可能会在检测到某个符号之前读入多个字符。因此,这个过程不可能精确地显示确切的位置。它最终取决于为 Flex 所提供的规则。规则越复杂,位置的精确程度就越低。这个例子中的规则可以由 Flex 通过提前查找一个字符来进行处理,这会让位置的预测更加精确。

网管朋友网www_bitscn_net

Bison 的定位机制 网管网www_bitscn_com

    下面让我们来看一下 division by zero 这个错误。最后一次符号读取(结束括号)并不是这个错误的根源。表达式 (a-3) 的值就是 0。对于更好的错误消息来说,我们需要知道表达式的位置。要实现这种功能,我们可以在 YYLTYPE 类型的全局变量 yylloc 中提供这个符号的确切位置。使用宏 YYLLOC_DEFAULT(请参看 Bison 文档 中默认的定义),Bison 可以计算出某个表达式的位置。

网管网www.bitscn.com

记住,只有当您在文法中使用位置时才会定义类型。这是一个常见的错误。

网管u家bitscn.net

    默认的位置类型 YYLTYPE 如清单 11 所示。我们可以对这个类型重新进行定义,使其包括更多信息,例如 Flex 所读取的文件名。 网管u家www.bitscn.net


清单 11. 默认位置类型 YYLTYPE

typedef struct YYLTYPE
{
  int first_line;
  int first_column;
  int last_line;
  int last_column;
} YYLTYPE;
             

网管论坛bbs_bitsCN_com


网管有家www.bitscn.net

    在上一节中,我们看到了 BeginToken() 函数,它是在新符号开始时调用的。此时就应该存储这个位置了。在我们的例子中,一个符号不能跨越多行,因此 first_line 和 last_line 是相同的,它们都保存了当前的行号。其他属性有符号的起点(first_column)和终点(last_column),这是通过符号的起点和长度计算出来的。

网管有家www.bitscn.net

    要使用这个位置,我们必须对规则处理函数进行处理,如清单 12 所示。符号 $3 的位置是通过 @3 进行引用的。为了防止拷贝这个规则中的整个结构,我们生成了一个指针 &@3。这看起来可能有点奇怪,但却是正确的。

网管论坛bbs_bitsCN_com


清单 12. 记住规则中的位置

| expression DIV expression
  {
    $ = ReduceDiv($1, $3, &@3);
  }
             
网管联盟bitsCN@com

网管u家u.bitsCN.com

     在处理函数中,我们获得了一个指向保存了位置信息的 YYLTYPE 结构的指针,这样可以生成一条很好的错误消息。

网管u家u.bitsCN.com


清单 13. 在 ReduceDiv 中使用保存的位置

extern
double ReduceDiv(double a, double b, YYLTYPE *bloc) {
  if (  b == 0  ) {
    PrintError("division by zero! Line %d:c%d to %d:c%d",
                        bloc->first_line, bloc->first_column,
                        bloc->last_line, bloc->last_column);
    return MAXFLOAT;
  }
  return a / b;
}
             网管朋友网www_bitscn_net 

网管网www.bitscn.com

现在错误消息可以帮助我们来定位问题了。除零操作错误在第 3 行的第 10 列到 18 列之间。

网管下载dl.bitscn.com


清单 14. 更好的 ReduceDiv() 错误消息

       |....+....:....+....:....+....:....+....:....+....:....+
     1 |a = 3;
     2 |3 aa = a * 4;
...... !..^^...........
Error: syntax error, unexpected IDENTIFIER, expecting SEMICOLON
     3 |b = aa / ( a - 3 );
...... !....^^...............
Error: reference to unknown variable 'aa'
...... !.................^..
 Error: division by zero! Line 3:10 to 3:18
final content of variables
   Name------------------ Value----------
   'a                   ' 3
   'b                   ' 3.40282e+38
   'aa                  ' 0
             

网管论坛bbs_bitsCN_com

网管u家u.bitscn@com


  网管u家u.bitsCN.com

结束语

中国网管联盟bitsCN.com

    Flex 和 Bison 是用来解析文法的一对功能强大的组合。通过使用本文中介绍的技巧,我们可以构建更好的解释器,它们可以生成像您自己喜欢的编译器中一样的有用的、容易理解的错误消息。 网管u家u.bitscn@com

TAGs   错误   处理   进行   更好   使用   我们   可以   Bison   位置   这个      
 上一篇:Fedora 2 简单美化及设置方法   下一篇:使用 GStreamer 进行多用途的多媒体处理
使用Flex和Bison 更好地进行错误处理 评论:
loading.. 评论加载中…
评论:请自觉遵守互联网相关政策法规,评论不得超过250字。

验证码: 注册用户
本类热门排行:
最新推荐文章:
网管论坛交流: