如何综合编译器测试数据?

问题描述 投票:1回答:1

我正在写一个简单的编译器作为学校工作。我正在寻找一种自动化的方法来生成正面和负面的测试数据,以测试我的编译器,给出正式的语法和其他规范。我正在处理的语言是中等大小,有38个左右的非终端。为了便于说明,这里是语法的快照:

program: const_decl* declaration* ENDMARKER

# statement
stmt: flow_stmt | '{' stmt* '}' | NAME [stmt_trailer] ';' | ';'

stmt_trailer: arglist | ['[' expr ']'] '=' expr

flow_stmt: if_stmt | for_stmt | while_stmt | read_stmt ';' | write_stmt ';' | return_stmt ';'

return_stmt: 'return' ['(' expr ')']

if_stmt: 'if' '(' condition ')' stmt ['else' stmt]

condition: expr ('<'|'<='|'>'|'>='|'!='|'==') expr | expr

for_stmt: ('for' '(' NAME '=' expr ';' condition ';'
    NAME '=' NAME ('+'|'-') NUMBER ')' stmt)

是否有任何工具可以在语法的帮助下生成输入文件?手写测试过于乏味或太弱而无法发现问题。这里有一种语言的例子:

void main() {
  int N;
  int temp;
  int i, j;
  int array_size;

  reset_heap;
  scanf(N);

  for (i = 0; i < N; i = i + 1) {
    scanf(array_size);
    if (array_size > max_heap_size) {
      printf("array_size exceeds max_heap_size");
    } else {
      for (j = 0; j < array_size; j = j + 1) {
        scanf(temp);
        heap[j] = temp;
      }
      heap_sort(array_size);
      print_heap(array_size);
    }
  }
}

自动生成可控测试数据可以节省时间。鉴于语言的简单性,必须有一些方法来有效地做到这一点。非常感谢任何指针和洞察力。

testing compiler-construction
1个回答
1
投票

非常感谢任何指针和洞察力。

这应该有How to avoid combinatorial explosion when generating test data的副标题。

虽然有些工具可以为语法生成测试数据,但我不会感到惊讶,我已经创建了几个应用程序。

我在此发现的最好的系列文章之一是Eric Lippert,Every Binary Tree There Is,认为BNF转换为二元运算符,然后在读取树时转换为AST。然而他使用Catalan(每个分支有两个叶子),当我写我的应用程序时,我更喜欢Motzikin(一个分支可以有一个或两个叶子)。

他也用LINQ在C#中做了他,我用prazxswpoi在Prolog做了我的。

基于BNF或DCG生成数据并不难,真正的诀窍是限制扩展区域和扩展的大小并注入不良数据。

通过扩展区域可以说你想测试三层深层的嵌套if语句,但必须有编译的有效代码。显然,您需要样板代码才能使其编译,然后通过添加或删除else子句开始更改深层嵌套。因此,您需要设置约束,以使样板代码保持不变,并且测试部分是可变的。

通过扩展的大小,可以说你想测试条件表达式。您可以轻松地计算出,如果您有许多操作员,并且您希望将它们全部组合测试,那么很快就会遇到组合爆炸。诀窍是确保你测试足够深,并且有足够的宽度但不是每个组合。司法使用约束有助于此。

所以这一切的重点在于你从一个接收BNF并生成有效代码的工具开始。然后修改BNF以添加约束并修改生成器以了解生成代码示例的约束。

然后修改BNF以获取无效数据,同样修改生成器以了解这些规则。

在此之后,您可以开始在自动化级别上进行分层。

如果你确实走这条路并决定你必须学习Prolog,请先看看DCG。我没有和水星一起做过这件事,但如果我再次这样做,水星就是名单上的佼佼者。

虽然我的实际代码不公开,但Mercurythis是最接近它的公共代码。

一路走来,我在this玩得很开心。

当生成诸如保留字或类型值的终端时,您可以使用包含有效和无效数据的预定义列表,例如,对于Code Golf,如果语言区分大小写,我会在列表中包括ififIfIF等。对于值类型,如无符号字节,我将包括iF-10255

当我用256+-*测试基本二进制数学表达式时,我用三个基本数字^-2-101生成了所有测试。我认为它没用,因为我已经有数百个测试用例,但由于生成所有测试用例只花了几分钟而运行它几个小时,令我惊讶的是它发现了一个我没有覆盖的模式。这里的观点与大多数人对许多测试用例的说法相反,请记住,只有在计算机上通过更改一些约束才能进行大量测试。

© www.soinside.com 2019 - 2024. All rights reserved.