[转帖] Scala 文法词法分析---分析C++类的声明_Android, Python及开发编程讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  Android, Python及开发编程讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 3337 | 回复: 0   主题: [转帖] Scala 文法词法分析---分析C++类的声明        下一篇 
周逸涵
注册用户
等级:少校
经验:871
发帖:83
精华:0
注册:2013-7-8
状态:离线
发送短消息息给周逸涵 加好友    发送短消息息给周逸涵 发消息
发表于: IP:您无权察看 2013-7-9 9:52:33 | [全部帖] [楼主帖] 楼主

  1. 想要写个C++类的词法文法分析由来已久。一直找不到好的方法,之前尝试使用正则表达式来解析,但是有点受限,正则表达式过于复杂,而且一般是按行分析的。之所以要分析提取C++类的信息,主要还是为了解放劳动力,提高生产效率。我的目标是,以后写代码一般情况下只写类的基础框架,包含类名称,基类及其相关的类成员变量。其它的所有方法接口,都使用分析工具分析后自动生成。当然生成后的代码有些需要小改动后才可使用,有些则直接使用。开发软件时,就可以集中关注业务流程。  


  1. 最近一直在学习Scala语言,偶然发现其Parser模块功能强大,乃为BNF而设计。啥是BNF,读大学的时候在课本上见过,那时候只觉得这个东西太深奥。没想到所有的计算机语言都是基于BNF而定义的一套规范。词法,语法,词法,语法。。。下面看看解析C++类声明的一个简单例子吧。 


  1. class CPlusPlusParser extends StandardTokenParsers{  
  2.   //分隔符,用于repsep,和其它显示的地方  
  3.   lexical.delimiters += (":","::","<",">","(",")","&","{","}",";",",","~")  
  4.   //关键字集合,所有在解析方法中,以字符串形式出现的单词,都必须加入保留字集合,保留字大部分属于关键字  
  5.   lexical.reserved   += ("class","public","private","protected","operator","const","mutable","static")  
  6.   // 注意: 词法分析过程中,会自动删除空白,注释等不必要的内容。  
  7.   /** 
  8.   * 解析类,包含7个部分,解析的时候是按照顺序严格的匹配。 
  9.   *1. class 关键字 
  10.   *2. ident 标识符 被解析为类的名称 
  11.   *3. opt(parserBaseClasses) 可选的基类集合 
  12.   *4. {  类定义开始 
  13.   *5.opt(parserClassBody) 可选的类内容,如果没有,就是一个空类了。 
  14.   *6. } 和 ; 类定于的结束标记. 
  15.   * */  
  16.   def parserClass : Parser[Any] = {  
  17.     "class"~ident~opt(parserBaseClasses)~"{"~opt(parserClassBody)~"}"~";"  
  18.   }  
  19.   /** 
  20.    * 解析基类集合 
  21.    * 1. :  分隔符,用于分割类名称和基类集合,如果没有改分隔符则表明该类没有基类。 
  22.    * 2. repsep(parserOneBaseClass,",") 解析一个或者多个基类,C++支持多继承,每个继承以逗号(,)分割 
  23.    */  
  24.   def parserBaseClasses : Parser[Any] ={  
  25.     ":"~repsep(parserOneBaseClass,",")  
  26.   }  
  27.   /** 
  28.    * 解析单一继承 
  29.    *1.opt("public"|"private"|"protected") 没有包含范围修饰符时,C++默认为private继承 
  30.    *2.parserType 基类名称 
  31.    */  
  32.   def parserOneBaseClass : Parser[Any] ={  
  33.     opt("public"|"private"|"protected")~parserType  
  34.   }  
  35.   /** 
  36.    * 解析类型 
  37.    * 1.rep(parserTypeNamespace) 可选的名称前缀,例如std::string,std::tr1::shared_ptr,包含了名称前缀 
  38.    * 2.ident 类型名称 
  39.    * 4.opt("<"~repsep(parserType,",")~">") 模板类型,及其嵌套解析,在此属于递归解析 
  40.    * 
  41.    * 次类型没有考虑解析“unsigned” 数据类型 
  42.    */  
  43.   def parserType : Parser[Any] ={  
  44.     rep(parserTypeNamespace)~ident~opt("<"~repsep(parserType,",")~">")  
  45.   }  
  46.   /* 
  47.   * 解析单一名称空间*/  
  48.   def parserTypeNamespace : Parser[Any] ={  
  49.     ident~"::"  
  50.   }  
  51.   /* 
  52.   * 解析类的内容,类的成员,如果没有public,private,protected等修饰符,则为默认private 
  53.   * 1.rep(parserFun|parserField) 解析可能包含的默认的private范围的方法和字段 
  54.   * 2.rep(parserSection) 后续可能包含其他public,private,protected修饰的字段。 
  55.   * 
  56.   * 例如一个类可以包含public:private: 等多个不同的范围修饰段 
  57.   * */  
  58.   def parserClassBody : Parser[Any] = {  
  59.     rep(parserFun|parserField)~rep(parserSection)  
  60.   }  
  61.   /** 
  62.    * 解析每一个具体的范围访问段。可能是public、private或者protected,并且包含一些列的方法和字段 
  63.    */  
  64.   def parserSection : Parser[Any] = {  
  65.     ("public"|"private"|"protected")~":" ~rep(parserFun|parserField)  
  66.   }  
  67.   /* 
  68.   * 解析方法的声明,在此没有解析方法的定义,比较复杂。 
  69.   * 1. opt(opt("virtual")~(parserReturnValue|"~")) 方法的返回值,之所以使用opt,是因为构造函数没有返回值,~用于析构函数的解析 
  70.   * 2. ident  方法名称,在此没有解析操作符重载方法,如果需要,需要另外单独定义, 
  71.   * 3. "("~repsep(parserFunParam,",")~")" 解析参数列表,不支持 (void) 模式的参数,请使用()替代(void) 
  72.   * 4. opt("const") 可选的const修饰符 
  73.   * 5.; 函数声明结束 
  74.   * 
  75.   * 没有包含静态方法(static),很容易根据此模板写出来 
  76.   * */  
  77.   def parserFun : Parser[Any] ={  
  78.     opt(opt("virtual")~(parserReturnValue|"~"))~ident~"("~repsep(parserFunParam,",")~")"~opt("const")~";"  
  79.   }  
  80.   /** 
  81.    * 解析返回值 
  82.    * 1.包含可选的const修饰符 
  83.    * 2.返回值的具体类型 
  84.    * 3.包含可选的引用 
  85.    */  
  86.   def parserReturnValue : Parser[Any] ={  
  87.     opt("const")~parserType~opt("&")  
  88.   }  
  89.   /** 
  90.    * 解析一个函数参数,数据类型与 parserReturnValue,不过多了参数名称和可选的默认值 
  91.    */  
  92.   def parserFunParam : Parser[Any] = {  
  93.     opt("const")~parserType~opt("&")~ident~opt("="~(numericLit|stringLit|ident)) // 默认参数支持false,true,数字,字符串  
  94.   }  
  95.   /* 
  96.   * 解析字段定义 
  97.   * 1.可选的字段修饰符 
  98.   * 2.字段数据类型,不支持unsigned,相对容易。在此不给出 
  99.   * 3.ident 字段名称 
  100.   * 4.; 字段定义结束*/  
  101.   def parserField : Parser[Any] ={  
  102.     opt("const"|"mutable"|"static") ~parserType~ident~";"  
  103.   }  
  104.   def parserAll[T]( p : Parser[T], input :String) = {  
  105.     phrase(p)( new lexical.Scanner(input))  
  106.   }  
  107. }  
  108. object CPlusPlusParser {  
  109.   def main( args : Array[String]) {  
  110.     val c = new CPlusPlusParser  
  111.     val r = c.parserAll(c.parserClass,  
  112.       """  
  113.         |class MyClass : public A, public N {  
  114.         |int a;  
  115.         |void SetA( int v );  
  116.         |int GetA()const;  
  117.         |public :  
  118.         |int a;  
  119.         |void SetA( int v );  
  120.         |int GetA()const;  
  121.         |};  
  122.       """.stripMargin)  
  123.     println(r)  
  124.     /* 测试输出 
  125.     [11.11] parsed: ((((((class~MyClass)~Some((:~List((Some(public)~((List()~A)~None)), (Some(public)~((List()~N)~None))))))~{)~Some((List((((None~((List()~int)~None))~a)~;), ((((((Some((None~((None~((List()~void)~None))~None)))~SetA)~()~List(((((None~((List()~int)~None))~None)~v)~None)))~))~None)~;), ((((((Some((None~((None~((List()~int)~None))~None)))~GetA)~()~List())~))~Some(const))~;))~List(((public~:)~List((((None~((List()~int)~None))~a)~;), ((((((Some((None~((None~((List()~void)~None))~None)))~SetA)~()~List(((((None~((List()~int)~None))~None)~v)~None)))~))~None)~;), ((((((Some((None~((None~((List()~int)~None))~None)))~GetA)~()~List())~))~Some(const))~;)))))))~})~;) 
  126. Process finished with exit code 0 
  127.      */  
  128.   }  
  129. }  

后续目标是分析头文件,提前所有类和枚举的定义。自动转换为protobuf接口,并且自动生成protobuf消息和类之间进行编解码的接口。还可以以类为蓝本生成其它语言的对象及其与protobuf消息之间的编解码。这样以后在涉及到客户机和服务器通信的时候,大部分的业务数据对象都只要写一次,其它自动生成,并小改动。




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论