我如何实现类似于ANSI C中的Objective-C @encode()编译器指令的东西?

@encode指令返回一个const char *,它是传入的数据类型的各种元素的编码类型描述符。示例如下:

struct test { int ti ; char tc ; } ; printf( "%s", @encode(struct test) ) ; // returns "{test=ic}" 

我可以看到使用sizeof()来确定原始类型 – 如果它是一个完整的对象,我可以使用类方法进行内省。

但是,它如何确定不透明结构的每个元素?

@Lothars的回答可能是“愤世嫉俗”,但不幸的是,它非常接近标记。 为了实现像@encode()这样的东西,你需要一个完整的解析器来提取类型信息。 好吧,至少除了“琐碎的” @encode()语句之外的任何东西(即@encode(char *) )。 现代编译器通常有两个或三个主要组件:

  • 前端。
  • 中间端(对于某些编译器)。
  • 后端。

前端必须解析所有源代码,并基本上将源代码文本转换为内部的“机器可用”forms。

后端将内部的“机器可用”表单转换为可执行代码。

具有“中间端”的编译器通常会因为某些需要而这样做:它们支持多个“前端”,可能由完全不同的语言组成。 另一个原因是简化优化:所有优化过程都在相同的中间表示上工作。 gcc编译器套件是“三阶段”编译器的一个例子。 llvm可以被认为是“中间和后端”阶段编译器:“低级虚拟机”是中间表示,并且所有优化都以这种forms发生。 llvm也能够将它保持在这个中间表示中直到最后一秒 – 这允许“链接时间优化”。 clang编译器实际上是一个“前端”,它(有效地)输出llvm中间表示。

因此,如果您想将@encode()function添加到“现有”编译器中,您可能必须将其作为“源到源”“编译器/预处理器”。 这就是原始的Objective-C和C ++编译器的编写方式 – 他们解析了输入源文本并将其转换为“plain C”,然后将其输入到标准C编译器中。 有几种方法可以做到这一点:

滚动你自己

  • 使用yacclex将ANSI-C解析器组合在一起。 你需要一个语法 – ANSI C语法(Yacc)是一个好的开始。 实际上,要明确的是,当我说yacc ,我的意思是野牛和flex 。 另外,松散地,其他各种yacclex就像基于C的工具: 柠檬 , dparser等……
  • 使用带有Yapp或EYapp的 perl ,它们是perl中的伪yacc克隆。 与基于C的yacclex相比,可能更快速地对一个想法进行原型设计 – 毕竟它是perl :正则表达式,关联数组,无内存管理等。
  • 使用Antlr构建解析器。 我对这个工具链没有任何经验,但它是另一个“编译器编译器”工具(似乎)更适合Java开发人员。 似乎有免费提供的C和Objective-C语法。

破解另一个工具

注意:我没有使用任何这些工具做任何事情的个人经验,比如添加@encode() ,但我怀疑它们会有很大的帮助。

  • CIL – 没有使用此工具的个人经验,但设计用于解析C源代码,然后用它“做事”。 从我可以从文档中收集到的内容,此工具应该允许您提取您需要的类型信息。
  • 稀疏 – 值得看,但不确定。
  • 铿锵 – 没有用它来达到这个目的,但据称其中一个目标就是让这种东西“容易被黑客攻击”。 特别是(再次,没有个人经验)在做所有解析的“繁重”,让你专注于“有趣”部分,在这种情况下将提取上下文和语法敏感类型信息,然后转换为到一个普通的C字符串。
  • gcc插件 – 插件是gcc 4.5(这是编译器的当前alpha / beta版本)function,“可能”允许您轻松地连接到编译器以提取您需要的类型信息。 不知道插件架构是否允许这种事情。

其他

  • Coccinelle – 最近将此书加入“后来看”。 这“可能”能够做你想做的事情,并且“可能”能够付出很多努力。
  • MetaC – 最近也为此书添加了书签。 不知道这会有多大用处。
  • mygcc – “可能”做你想做的事。 这是一个有趣的想法,但它并不直接适用于你想要的东西。 从网页:“Mygcc允许程序员添加自己的检查,考虑语法,控制流和数据流信息。”

链接。

  • CocoaDev Objective-C解析 – 值得关注。 有一些词法和词法的链接。

编辑#1,奖金链接。

@Lothar在他的评论中提出了一个很好的观点。 我实际上打算包括lcc ,但看起来它在途中迷路了。

  • lcc – lcc C编译器。 这是一个特别小的C编译器,至少在源代码大小方面。 它还有一本书 ,我强烈推荐。
  • tcc – tcc C编译器。 不像lcc那样教学,但绝对值得一看。
  • poc – poc Objective-C编译器。 这是一个“源到源”Objective-C编译器。 它解析Objective-C源代码并发出C源代码,然后传递给gcc (好吧,通常是gcc )。 有许多在gcc中没有的Objective-C扩展/function。 绝对值得一看。

您可以通过首先实现ANSI C编译器然后向其添加一些特定于实现的编译指示和函数来实现它。

是的,我知道这是愤世嫉俗的答案,我接受了downvotes。

一种方法是编写一个预处理器,它读取类型定义的源代码,并用相应的字符串文字替换@encode ….

如果你的程序是用-g编译的,另一种方法是编写一个函数,在运行时从程序的调试信息中读取类型定义,或者使用gdb或其他程序为你读取它,然后根据需要重新格式化它。 gdb ptype命令可用于打印特定类型的定义(如果不足,则还有maint print type ,这肯定会打印出比您可能想要的更多的信息)。

如果您使用的是支持插件的编译器(例如GCC 4.5),也可以为此编写一个编译器插件。 然后,您的插件可以利用编译器已经解析的类型信息。 显然,这种方法非常适合编译器。