rose入门1 nodeQuery&ASTTraverse

来源:互联网 发布:淘宝包邮怎么设置 编辑:程序博客网 时间:2024/06/07 22:44

1,ROSE安装的回顾

mac上面的rose安装最终以失败而告终,原因是EDG包找不到,虽然昨天起rose官网已经恢复正常了。

现在理解了为什么下载的rose安装包文件名清楚的写道“withou-EDG”。EDG是c/c++的前端分析器,它负责生成语法树,而Sage3是在这个语法树的基础上进行了自己的包装。

EDG以二进制包的形式提供给rose使用,它和GCC版本、操作系统、ROSE版本有关系,所以在make的最后阶段,会根据这些信息去rose官网上找对应的EDG二进制包。

虽然不一定完整,但是EDG二进制包在这里可以看到https://github.com/rose-compiler/edg-binaries

当然,如果向EDG开发团队申请科研license,可以拿到edg源码包,这样就不用找特定类型的binary了。不过有点麻烦,我还是继续用我的rhel版本。


2,rose的参考材料介绍

1)rose tutorial

里面有大量的示例程序展示如何调用rose的接口,且在程序的编译目录下(注意,是编译目录,而不是最后的安装目录)有个tutorial文件夹,里面有这些示例程序的源代码。

2)rose user manual

和tutorial不同,user manual侧重于rose的实现介绍,对用户更加深入了解rose的实现有帮助。

在这里,对tutorial和user manual里面前7章的内容进行部分介绍,这也记录着我的学习历程。


3,AST(抽象语法树)的直观理解



以上两幅图是针对一个最简单的a[i][j]=1.0/i+j;的二重循环赋值程序,使用dotGenerator得到的。这个工具详见tutorial chapter3。

第一幅图,直观的认识是:一个程序,全局域里面包括两个定义,一个是main函数(右子树),一个是全局变量的定义(左子树)。

第二幅图,直观的认识是:对于for循环,包括四个子树,最左边的时变量i的初始化条件,第二个是变量i的终止条件,第三个是变量i的自增条件,第四个是for循环内部的程序(basic block)。

我们需要对语法树进行操作,某个语法树就和某个程序对应。最后我们的目标肯定是通过修改AST,达到生成优化过后的新程序的目的。

根据张立博师兄的说法,修改语法树肯定不是我们一个节点一个节点的改,而是通过ROSE提供的接口进行修改。做某些语法树修改如果一个节点一个节点的改肯定特别麻烦,而且容易出错。

ROSE的AST图结构帮助我们理解编译器是如何理解源程序的。

每个圈圈代表ROSE的IR(intermediate representation)节点,那串英文是这个结构名称,上面代表前序遍历的进出序列时间,下面表示有几个子节点。指针地址在最下面。每个节点都是一个C++类。


3)编译运行程序

在编译目录(非下载目录,非安装目录)的exampleTranslators/documentedExamples/simpleTranslatorExample目录下,有个exampleMakefile,这可以作为编译自己程序的样例makefile,很简单,40多行。但是有一个问题,里面的libtool是做什么的?这个下一次blog说明一下。(问题1)


4)Query操作

据userManual里的Chapter6,query分为三种类型:

1,query AST中的subTree。(且如果函数参数中给定NodeQuery::ChildrenOnly,则只遍历直接后继结点;否则遍历子树中的所有节点)

2,query AST中的node list

3,query memory pool

在tutorial chapter7中,有两个例子,一个是简单的querySubTree(tutorial/queryLibraryExample.C),一个是对querySubTree的结果进行简单的处理和query memory pool处理(tutorial/nestedQueryExample.C)。

第一个例子的核心程序如下:

 13   // Build a list of functions within the AST

 14      Rose_STL_Container<SgNode*> functionDeclarationList = NodeQuery::querySubTree (project,V_SgFunctionDeclaration);

 15   

 16      int counter =0;

 17      for (Rose_STL_Container<SgNode*>::iterator i = functionDeclarationList.begin(); i != functionDeclarationList.end(); i++)

 18         {                                                                            

 19        // Build a pointer to the current type so that we can call the get_name() member function.

 20           SgFunctionDeclaration* functionDeclaration = isSgFunctionDeclaration(*i);  

 21           ROSE_ASSERT(functionDeclaration !=NULL); 

 22 

 23        // DQ (3/5/2006): Only output the non-compiler generated IR nodes             

 24           if ( (*i)->get_file_info()->isCompilerGenerated() ==false)                

 25              {

 26             // output the function number and the name of the function

 27                printf ("Function #%2d name is%s at line %d \n",                     

 28                     counter++,functionDeclaration->get_name().str(),                 

 29                     functionDeclaration->get_file_info()->get_line());               

 30              }

 31             else

 32              { 

 33             // Output something about the compiler-generated builtin functions       

 34                printf ("Compiler-generated (builtin) function #%2d name is%s\n",   

 35                     counter++,functionDeclaration->get_name().str());                

 36              }

 37         } 

对一个简单的stecil计算程序(只有main函数),生成的结果惊人:

里面有420个builtin function,还有107个getw,putw, fseek之类的function,最后才是main function

为什么是这样呢?这个下一个blog解释。(问题2)


这里需要仔细介绍下各个数据结构:

#define Rose_STL_Container   std::vectornode query在user manual6.2.1里面是一个namespace, 在online doxgen里面查不到相关资料,但是有这个网站查阅起来资料却很多:

http://fossies.org/dox/rose-0.9.5a-without-EDG-20584/index.html

里面有各个类的描述,也有类图的描述,很不错!

v_sgfunctiondeclaration=382是enum variantT里定义,在cxx_grammar.h里面定义。

sgFunctionDeclaration是 doxgen里面可以查到的class定义,里面有get_file_info和get_name等定义。

queryMemoryPool意思可能和querySubTree(project,)类似。目前理解是这样。。


5)Traverse操作

这里面有5个Ast*Processing类,每个类里面都有三种不同的遍历函数:

traverse, traverseInputFiles, traverseWithinFile


a)第一个例子,也是最简单的例子,是tutorial/visitorTraversal.C

这个例子是重写了AstSimpleProcessing类里面的visit函数,判断当前signed是否是for循环。

但是如果添加一句,cout<<n->class_name()<<endl;并和dotGenerator得到的图进行比对发现:

打印的顺序就是第一次进入该节点的时间戳,同时,打印的点的class_name和dotGenerator一致。

这里就又出现类似问题2的问题,simpleProcessing里面为什么得到的点这么少,而dotGeneratorWholeASTGraph里面得到的点又是什么(问题3)。


b)prePostTraversal.c

preOrderVisit这个虚函数表示前序遍历到这个点进行的操作。PostOrderVisit这个虚函数表示后序遍历到这个节点进行的操作。

例子中,对于loop 结构,正好前序遍历作为enter loop操作,后序遍历作为leaving loop操作。


c)astTopDownProcessing(inheritedAttributeTraversal.C)

相当于在astSimpleProcessing里面的visit函数里多了个参数,叫InheritedAttribute。

这个类是自定义的,按照前序遍历没每访问一个点就调用这个evaluateInheritedAttribute函数,通过这个自定义类在遍历中传递参数。


d)astBottomUpProcessing(synthesizedAttributeTraversal.C)

需要实现的虚函数是evaluateSynthesizedAttribute(SgNode* astNode, synthesizedAttributesList synList)

需要注意的是第二个参数,它是子节点的synthesizedAttribute的vector,用一个iterator来进行遍历。

这样,每个节点就可以进行bottomup操作。理论上说,遍历顺序应该是从下往上,递归的进行遍历。但打印遍历顺序来看,后面几个的遍历很符合。

但遍历的总数特别大,不知道为什么。


e)astTopDownBottomUpProcessing()

这里面需要实现的函数是evaluateInheritedAttribute和evaluateSynthesizeAttribute两个,

根据Tutorial和User manual里面的两个例子,一般的用法是对于某个点sgNode*n,evaluateInheritedAttribute算出从上到下继承到的数据,

evaluateSynthesizeAttribute算出从下至上合成的数据;但最关键的是,前一个函数有两个参数而后一个函数有三个参数。

这也意味着后一个函数可以用前一个函数计算得到的结果(参数给定),而不能相反。


陆陆续续写了一周,对nodeQuery和ASTTraverse进行了比较全面的介绍。下一步就是进行AST的transformation了,当然下一个blog会回答这里面遗留的若干问题。

分了?!不觉得是这样但又好像已经是这样。。这周的思路乱的很,很难长时间静心学术,哎。。

也许这周末会有好结果,也许学术感情双丰收呢!加油!!求给力!!!

0 0
原创粉丝点击