【问题标题】:Reflections for C language?C语言的反思?
【发布时间】:2011-09-08 00:37:19
【问题描述】:

在断章取义时,问题标题可能会产生误导。让我先解释一下我要构建的内容。

我正在构建一个脚本,它将包含我的学生编写的 100 多个非常简单的 C 程序,并检查一些非常基本的属性,例如。

  1. 他们是否声明了一个名为“x”的变量,它的类型是否为“int”等等。
  2. 变量“z”的值是多少?

如果这是某种脚本编程语言,这可能会容易得多。我本可以简单地使用 include 或 eval 然后进行检查。

但是当谈到 C 编程时,我会说这非常困难。我该怎么做 ?

【问题讨论】:

  • 我希望我的教授当时给我单元测试代码来编写代码!为什么不提供一个简单的单元测试模块供学生编写代码?
  • 我想建立一个门户,学生可以在业余时间来这里,在浏览器中针对列出的目标提交一些代码,他们将为每个成功的目标获得积分。
  • 好吧,你可以告诉他们从标准输入中获取输入,然后将输出提供给标准输出。这样,在服务器端,您可以尝试编译代码,如果它编译通过标准流提供输入和接收输出。
  • 你的编译器写作技巧如何?您可以使用这些LexYacc 语法来解析C 代码。或者,使用像 LLVM 这样的 IR。无论哪种方式,只需遍历 AST 来验证您想要的属性。
  • @chisaycock:如果你有足够的时间来构建一个完整的 C 解析器,那么你可以获得这样的答案。我们大多数人的生命有限,都想做点别的事情。

标签: c parsing reflection verification abstract-syntax-tree


【解决方案1】:

您可以使用 ANTLR 来执行此操作。已经有一个 C 语法可以与 ANTLR 一起使用,所以主要你所要做的就是将代码传递给 antlr,然后遍历语法树以查找各种属性....

您可以使用多种语言的 ANTLR。虽然一开始可能看起来令人生畏。它实际上非常容易使用。

【讨论】:

    【解决方案2】:

    我看到了一个为 GCC 构建的树创建 XML 转储器的倡议,称为 gcc-xml。所以你给它一个文件example1.cxx,比如:

    struct EmptyClass {};
    
    int a_function(float f, EmptyClass e)
    {
    }
    
    int main(void)
    {
        return 0;
    }
    

    你会回来的:

    <?xml version="1.0"?>
    <GCC_XML>
      <Namespace id="_1" name="::" members="_2 _3 _4 "/>
      <Function id="_2" name="main" returns="_5" context="_1" location="f0:8"/>
      <Function id="_3" name="a_function" returns="_5" context="_1" location="f0:4">
        <Argument name="f" type="_6"/>
        <Argument name="e" type="_4"/>
      </Function>
      <Struct id="_4" name="EmptyClass" context="_1" location="f0:1" members="_7 _8 " bases=""/>
      <FundamentalType id="_5" name="int"/>
      <FundamentalType id="_6" name="float"/>
      <Constructor id="_7" name="EmptyClass" context="_4" location="f0:1">
        <Argument name="_ctor_arg" type="_9"/>
      </Constructor>
      <Constructor id="_8" name="EmptyClass" context="_4" location="f0:1"/>
      <ReferenceType id="_9" type="_4c"/>
      <File id="f0" name="example1.cxx"/>
    </GCC_XML>
    

    需要注意的是它只有works with the subset of C compatible with C++,官方项目不支持函数体的转储。不知道非官方的努力进步了多少:

    http://www.djlauk.de/index.php/Projects/GccXmlFunctionBodies

    【讨论】:

    【解决方案3】:

    一个重要的区别是您所说的“检查”这些程序。我假设您并不是指在运行时实际编译/运行它们(这就是反射对我的意义),因为您无法从已编译的程序中检查它们的程序结构。

    这意味着您将对源文件进行文本处理,虽然这在几乎所有脚本语言中都容易得多,但在 C 语言中并没有那么糟糕:

    1. 弄清楚如何获取所有要处理的文件的列表。将所有文件名放在索引文件中,然后遍历该文件,或者使用 readdir 或最好是库 (Boost) 来获取文件列表。

    2. 对于每个文件,打开它并读取每一行(谷歌,这很简单)

    3. 对于每一行,对照您的规则进行检查,并收集必要的结果。

    4. 将结果存储在数组中,或将其写入文件等。

    编辑-如果您想检查学生的程序是否运行(也就是在运行时编译/运行它们),您可能必须 execve 关闭一些 gcc 调用(如果您想编译),然后再次运行程序。但是,execve 只会告诉您命令是否失败。从其他程序获取输出意味着使用popen 打开管道。如果您发现自己已经准备好这样做,请回头,您已经走得太远了。

    【讨论】:

      【解决方案4】:

      语言内部的反射总是受到语言设计者的限制(C 的设计者根本不允许这样做)。如果您使用的工具可以从语言之外检查语言的任何部分,那么您就不会受到语言设计者想象的限制的问题。 (当前所有具有反射功能的语言都限制了您可以通过用该语言编写代码来学习的内容。在我看来,这似乎是一个愚蠢的约束。)

      分析程序的方法是让代理从外部理解编程语言,并且没有任何此类限制。请参阅我们的DMS Software Reengineering Toolkit,了解可以提供终极程序检查的系统。使用它的C Front End,您可以以可靠的方式提出任何关于 C 源代码的精心设计的问题。

      DMS 及其 C 前端可以轻松回答您提出的具体问题(关于 Z 值的问题可能很难;您正在推理图灵机)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-10-30
        • 2022-01-12
        • 2020-08-07
        • 2016-12-03
        • 2011-09-02
        • 1970-01-01
        • 1970-01-01
        • 2011-01-14
        相关资源
        最近更新 更多