【问题标题】:Run GCC preprocessor non-C files运行 GCC 预处理器非 C 文件
【发布时间】:2013-08-27 18:37:15
【问题描述】:

我正在使用一个专有的开发环境来编译用 C 以及 IEC 61131 语言编写的代码。对于 C 编译,它使用具有以下构建选项的 GCC 4.1.2:

-fPIC -O0 -g -nostartfiles -Wall -trigraphs -fno-asm

编译是由运行在使用 Cygwin 的 Windows 上的程序完成的。

我的问题是,IEC 语言预处理器不是很有用(根本不支持#define),我想使用宏!我不明白为什么 GCC 预处理器会真正关心它正在处理的语言(我的目标语言是结构化文本),所以我想看看是否有人知道如何让它处理不同文件类型的文件然后不会进一步编译(我只是在文件通过 IEC 编译器运行之前寻找宏扩展)。我对编译器选项和环境一无所知,因为我从来不需要处理它们,我只是编写 C 代码,它会神奇地编译并转移到我的目标系统运行。

我唯一能做的就是添加构建选项并在执行任何操作之前执行一个批处理文件。我认为我最大的希望在于使用批处理文件来处理某个扩展名的所有文件,但我什至不知道要使用 gnuinst 文件夹中的哪个可执行文件,更不用说使用什么标志来运行文件了。

【问题讨论】:

  • GCC preprocessor 的可能重复项 - 谈论 C,但这大多无关紧要。只需在您想要的任何源文本上使用-E 标志。
  • 我试过gcc -E TestIn.txt -o TestOut.txt 并得到消息:链接器输入文件未使用,因为链接未完成。 TestIn.txt 的内容是:#define ADDTHEM(x,y) ((x)+(y)) Test= ADDTHEM(2,3);。我正在尝试获取包含以下内容的输出文件:Test= ((2)+(3));
  • GCC 有有趣的启发式方法,可以根据扩展名确定您要输入的文件类型,显然.txt 是链接器指令...只要告诉它是 C:gcc -xc -E TestIn.txt。跨度>
  • 嗯,这给出了_spawnvp: no such file or directory,但我认为这是因为我是在 Windows 命令提示符下执行此操作的,而编译器不在我的 PATH 中。
  • @Mat: 或gcc -E - < TestOut.txt

标签: c batch-file gcc cygwin c-preprocessor


【解决方案1】:

几乎任何 C 预处理器,包括 gcc 的 cpp,都会假设其输入是有效的 C 代码。它必须按照 C(或 C++ 或 Objective-C)规则对输入进行标记,因为它必须将其输入解析为标记(更准确地说是预处理标记)。高于令牌级别的构造应该不是问题。

您当然可以使用cppgcc -E 来预处理不是C 源代码的文本,但是某些输入结构会导致问题。

以cmets为例:

$ cat foo.txt
#define ADDTHEM(x, y) ((x) + (y))
ADDTHEM(2, 3)
$ gcc -E - < foo.txt
# 1 "<stdin>"
# 1 "<command-line>"
# 1 "<stdin>"

((2) + (3))

请注意,我必须使用gcc -E - &lt; foo.txt 而不是gcc -E foo.txt,因为gcc 默认将.txt 文件视为链接器输入文件。

但是,如果您向 foo.txt 添加一些不包含有效 C 预处理器令牌的内容,您可能会遇到问题:

$ cat foo.txt 
#define ADDTHEM(x, y) ((x) + (y))
ADDTHEM(2, 3)
ADDTHEM('c, "s)
$ gcc -E - < foo.txt
# 1 "<stdin>"
# 1 "<command-line>"
# 1 "<stdin>"

((2) + (3))
<stdin>:3:9: warning: missing terminating ' character [enabled by default]
<stdin>:3:0: error: unterminated argument list invoking macro "ADDTHEM"
ADDTHEM

(尝试将 Ada 源代码提供给 C 预处理器时遇到了此类问题,因为 Ada 使用孤立的撇号 ' 字符作为其属性语法。)

所以你可以这样做如果输入语言不使用不是有效的 C 预处理器标记的东西。

有关预处理令牌的更多信息,请参阅 C 标准的 the N1570 draft 第 6.4 节。

我实际上是在查看GNU cpp manual之前写了上面的内容,上面写着:

C 预处理器仅适用于 C、C++ 和 Objective-C 源代码。过去曾被滥用为将军 文本处理器。它会阻塞不遵守 C 词法的输入 规则。例如,撇号将被解释为 字符常量,并导致错误。此外,你不能依赖它 保留对输入不重要的特征 C 族语言。如果对 Makefile 进行了预处理,则所有硬标签 将被删除,Makefile 将不起作用。

话虽如此,您通常可以在事情上使用 cpp 不是 C。其他类似 Algol 的编程语言通常是安全的 (Pascal、Ada 等)组装也是如此,谨慎行事。 `-传统-cpp' 模式保留更多的空白,否则更宽容。许多 可以通过编写 C 或 C++ 样式的 cmets 来避免这些问题 而不是母语 cmet,并保持宏简单。

您应该尽可能使用适合于 您正在编写的语言。现代版本的 GNU 汇编器具有 宏观设施。大多数高级编程语言都有自己的 条件编译和包含机制。如果一切都失败了, 试试真正的通用文本处理器,比如 GNU M4。

(该手册的作者显然忽略了 Ada 属性语法的问题。)

【讨论】:

  • 您会推荐什么来替代 cpp?我可以使用 PHP,但它似乎有点矫枉过正。
  • 是否可以选择让预处理器不在开头添加那些以# 开头的行?
  • @BennyJobigan:我不这么认为。自己过滤它们很容易。
  • @KeithThompson 实际上我发现了一个可以做到这一点的标志。 -P Inhibit generation of linemarkers in the output from the preprocessor. This might be useful when running the preprocessor on something that is not C code, and will be sent to a program which might be confused by the linemarkers.
猜你喜欢
  • 2011-02-06
  • 2011-06-16
  • 1970-01-01
  • 2014-09-13
  • 2011-04-24
  • 1970-01-01
  • 1970-01-01
  • 2017-06-02
  • 2014-06-14
相关资源
最近更新 更多