bison生成的规则文件的覆盖范围

问题描述 投票:0回答:2

我有一个非常巨大的野牛规则文件,想知道是否有一种简单的方法可以从后面的程序中覆盖这些规则。

我用 bison 生成了一个解析器。针对不同的文件运行解析器,并希望查看 .yy 文件中哪些行已被触及。

code-coverage bison
2个回答
1
投票

据我所知,没有官方方法可以生成这样的报告。但如果你愿意稍微深入了解野牛的内部结构,这是有可能做到的。

请注意,您只能为解析器语义操作生成覆盖率报告。 “解析器规则”没有其他直接翻译;规则被编译成状态机,状态与规则的对应关系是多对多的。但这会告诉您每条规则完成了多少次,这可能就是您想知道的。

还要注意,解析器不区分规则最终语义操作和中间规则操作,因为中间规则操作实际上被编译为生成的非终结符的归约操作。

本文的其余部分是非官方的,不应依赖于与 Bison 的所有未来版本一起使用。它也不能与其他野牛骨骼一起使用(尽管它可能会被改编);我是根据当前版本 3.8.2 编写的。

挂钩解析器的最简单方法是劫持宏

YY_REDUCE_PRINT
,跟踪工具使用该宏来跟踪归约操作。所以每次减少时都会执行它。即使跟踪没有编译到解析器中也会发生这种情况;在这种情况下,宏被定义为无操作。不过,
YY_REDUCE_PRINT
不是界面的官方部分,因此其名称和功能可能会更改,恕不另行通知。此外,它并不正式可用于自定义,并且生成的源代码不会尝试检查它是否之前已定义。所以你必须等到解析器模板中定义它,然后重新定义它。当然,重新定义它会使其无法用于跟踪日志,因此这与调试跟踪不兼容。原来,
½initial-action
代码块是在
YY_REDUCE_PRINT
定义之后注入的,所以这就是我重新定义的地方。这也不能保证。

我使用

lalr1.cc
骨架,使用几个最近的 bison 版本(3.7.1 和 3.8.2)非常轻松地测试了以下代码。这似乎有效,但您的里程可能会有所不同。

代码非常简单。首先,重新定义

YY_REDUCE_PRINT
,将其放入您的
.yy
文件中。您可能希望使其以某些配置宏为条件,以便保留生成调试跟踪的可能性。重新定义的
YY_REDUCE_PRINT
宏所做的就是向覆盖率直方图添加 1。 (这里,
drv
是解析器驱动程序的一个实例,按照 Calc++ 示例):

%initial-action {
#undef YY_REDUCE_PRINT
#define YY_REDUCE_PRINT(Rule) drv.register_rule(Rule)
}

直方图本身需要实现;它可以进入

driver.hh
driver.cc
:

标题:

  // Register execution of a semantic action.
  void register_rule(int rule);
  // Count of executions of each rule.
  std::vector<unsigned> rule_count;

实施:

void
driver::register_rule(int ruleno) {
  if (ruleno > 0) {
    if (ruleno > rule_count.size()) rule_count.resize(ruleno);
    ++rule_count[ruleno - 1];
  } 
}

规则编号与生成的报告文件中的编号相对应。规则0(接受规则)不计算在内。


0
投票

这是使用 bison 3.6 的解决方案: 在 texput.tex 中为 LaTex 构建并打印语法树

syntaxtree-2.y:

%{
/*
 Einfacher Baum aus Strings, typedef genügt
 */
#include <iostream>
#include <string>
using namespace std;

#include "tree.hpp"
typedef tree<string> syntaxTree;
syntaxTree * syntaxTree_epsilon_node () {
    return new syntaxTree("$\\epsilon$");
}
syntaxTree * root;

int yylex();
int yyerror(string s);
#define YYDEBUG 1
%}
%union {syntaxTree * tree;}
%token t_plus t_minus t_mal t_div t_kla_auf t_kla_zu t_fehler t_zahl
%initial-action {
#undef  YY_REDUCE_PRINT
#define YY_REDUCE_PRINT(Rule) { if (yytname[yyr1[Rule]][0] != '$') { \
        int n = 0; \
        root = yyval.tree = new syntaxTree(yytname[yyr1[Rule]]); \
        for (int i = 1 - yyr2[Rule]; i <= 0; i++) \
            if (yytname[YY_ACCESSING_SYMBOL (yyssp[i])][0] != '$') \
                n++, yyval.tree->append(yyvsp[i].tree); \
        if (!n) yyval.tree->append(syntaxTree_epsilon_node()); \
    } \
}
} // %initial-action
%%
expr: term | expr t_plus {} term | expr t_minus term {};
term: factor | term t_mal {} factor| term t_div factor;
factor: t_zahl | t_kla_auf expr t_kla_zu | t_minus factor;
%%
#include "lex.yy.c"

int yyerror(string s) {
    cout << s << endl;
    return 0;
}

int main() {
    int rc =  yyparse();
    if (!rc)
        root->tikz("texput.tex");
    else
        cerr <<  "Parse-Ergebnis " << rc << endl;
    return rc;
}

扫描仪-2.l:

%{
#define PROCESS(id) {\
    yylval.tree =  new syntaxTree(yytext); \
    return id;\
}
%}
%%
"+"         PROCESS(t_plus);
"-"         PROCESS(t_minus);
"*"         PROCESS(t_mal);
"/"         PROCESS(t_div);
"("         PROCESS(t_kla_auf);
")"         PROCESS(t_kla_zu);
[0-9]+      PROCESS(t_zahl);
[ \t\n]     /* do nothing */;
.           PROCESS(t_fehler);
%%
int yywrap() {
    return 1;
}

树.hpp:

/*
 
Template-Klasse tree
 
*/

#pragma once
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
template <class T> class tree {
public:
    tree();
    ~tree();
    tree(T);
    tree(T, tree<T> *);
    tree(T, tree<T> *, tree<T> *);
    tree(T, tree<T> *, tree<T> *, tree<T> *);
    tree(T, vector<tree<T> *>);
    void set(const T & p);
    T get();
    void ascii(ostream & o = cout, int level = 0);
    void tikz(ostream & o = cout, int level = 0, int path = 0);
    void tikz(string filename, int path = 0);
    void postorder(ostream & o = cout, int level = 0);
    void append(tree *);
    vector<tree<T> *> & childs();
    tree<T> * childs(int);
    int size();
    tree * parent;
    tree<T> * operator [] (int);
protected:
    vector<tree *> child;
    T v;
    void tikz_path(ostream & o = cout, int level = 0);
};


template <class T> tree<T> * tree<T>::operator [] (int index) {
    return (index < 0 || index >= child.size()) ? nullptr : child[index];
}

template <class T> int tree<T>::size() {
    return child.size();
}

template <class T> tree<T>::tree(T _v) :v(_v) {}

template <class T> tree<T>::tree(T _v ,tree<T> * p) : v(_v) {
    append(p);
}

template <class T> tree<T>::tree(T _v ,tree<T> * p1, tree<T> * p2) : v(_v) {
    append(p1), append(p2);
}

template <class T> tree<T>::tree(T _v ,tree<T> * p1, tree<T> * p2, tree<T> * p3) : v(_v) {
    append(p1), append(p2), append(p3);
}

template <class T> tree<T>::tree(T _v, vector<tree<T> *> childs) : v(_v) {
    for (int i = 0; i < childs.size(); i++)
        append(childs[i]);
}


template <class T>  tree<T>::tree() {
}

template <class T>  tree<T>::~tree() {
    //for (auto i: child) delete i; // C++ 11 !!!!
        
    for (int i = 0; i < child.size(); i++)
        delete child[i];
}

template <class T> void tree<T>::set(const T & _v) {
    v = _v;
}

template <class T> T tree<T>::get() {
    return v;
}


template <class T> void tree<T>::append(tree * t) {
    if (t != nullptr) {
        child.push_back(t);
        t->parent = this;
    }
}

template <class T> vector<tree<T> *> & tree<T>::childs() {
    return child;
}

template <class T> tree<T> * tree<T>::childs(int n) {
    return (n < 0 || n >= child.size()) ? nullptr : child[n];
}

template <class T> void tree<T>::ascii(ostream & o, int level) {
    for (unsigned i=0; i < level; i++)
        o << "\t";
    o << v << " " << child.size() << endl;
    for (unsigned i=0; i < child.size(); i++) {
        child[i]->ascii(o, level + 1);
    }
}

template <class T> void tree<T>::postorder(ostream & o, int level) {
    for (unsigned i=0; i < child.size(); i++) {
        child[i]->postorder(o, level + 1);
    }
    o << v << " ";
    if (!level)
        o << endl;
}

template <class T> void tree<T>::tikz(string filename, int path) {
    fstream f;
    f.open (filename, fstream::out);
    tikz(f, 0, path);
    f.close();
}

template <class T> void tree<T>::tikz(ostream & o, int n, int path) {
    // Baum-Traversierung First-Order
    int i;
    if (!n) {
        o << "\\documentclass{standalone}\n";
        o << "\\usepackage{tikz,tikz-qtree}\n";
        o << "\\begin{document}\n";
        // "Normale" Baumansicht
        o << "\\begin{tikzpicture}\n[level distance=1.25cm,sibling distance=.25cm,every tree node/.style={anchor=north,align=center,draw,top color=white, bottom color=blue!20,minimum width=1.5em,minimum height=1.5em},every leaf node/.style={anchor=north,align=center,draw,rounded corners,top color=white, bottom color=red!20,minimum width=1.5em,minimum height=1.5em},blank/.style={draw=none,color=white!0, top color=white!0, bottom color=white!0},"
        // Horizontal wachsend, ggf. optisch geeigneter für Hohe Bäume und Hochformatansicht
        //o << [grow'=right,level distance=4cm,sibling distance=.25cm,every tree node/.style={anchor= west,align=center,draw,top color=white, bottom color=blue!20,minimum width=1.5em,,minimum height=1.5em},every leaf node/.style={anchor=north,align=center,draw,rounded corners,top color=white, bottom color=red!20,minimum width=1.5em,minimum height=1.5em},blank/.style={draw=none,color=white!0, top color=white!0, bottom color=white!0},]
        "]";
        o << "\n\\Tree\n";
    }
    for (i = 0; i < n; i++)
    o << "\t";
    if (child.size()) {
        o << "[." << "\\node(" << this << "){" << v << "};" << endl;
        for (unsigned i=0; i < child.size(); i++)
            child[i]->tikz(o, n + 1);
        for (i = 0; i < n; i++)
        o << "\t";
        o << "]\n";
    }
    else
        o << "" << "\\node(" << this << "){" << v << "};" << endl;
    if (!n) {
        if (path)
            tikz_path(o, 0);
        o << "\\end{tikzpicture}\n";
        o << "\\end{document}\n";
    }
    
}

template <class T> void tree<T>::tikz_path(ostream & o, int level) {
    if (!level)
        o << "\\draw [red, >->] plot [smooth, tension=.75] coordinates {\n";
    if (child.size() == 0) {
        o << "([xshift=-4mm]" << this << ")\n";
        o << "([yshift=-4mm]" << this << ")\n";
        o << "([xshift=+4mm]" << this << ")\n";
    }
/*  else if (child.size() == 1) {
        o << "([xshift=-4mm]" << this << ")\n";
        child[0]->tikz_path(o, level + 1);
        o << "([xshift=+4mm]" << this << ")\n";
    }*/
    else if (child.size() == 2) {
        o << "([xshift=-4mm]" << this << ")\n";
        child[0]->tikz_path(o, level + 1);
        o << "([yshift=-4mm]" << this << ")\n";
        child[1]->tikz_path(o, level + 1);
        o << "([xshift=+4mm]" << this << ")\n";
    }
    else  {
        o << "([xshift=-4mm]" << this << ")\n";
        for (int i = 0; i < child.size(); i++)
            child[i]->tikz_path(o, level + 1);
        o << "([xshift=+4mm]" << this << ")\n";
    }
    if (!level)
        o << "};\n";
}

品牌:

syntaxtree-2: syntaxtree-2.y scanner-2.l
    lex scanner-2.l
    bison syntaxtree-2.y -o y.tab.cpp
    ${CPP} y.tab.cpp -I${INCL} -o syntaxtree-2

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