DSP编程技巧之7---揭开编译器神秘面纱之预处理与诊断
发布时间:2014-9-22 14:15
发布者:
看门狗
关键词:
DSP ,
编程 ,
CCS ,
解析器
作者:paradoxfx 来源:电子产品世界
在编程软件例如CCS中编程时,代码分析工具可以方便我们对代码进行分析,例如我们把鼠标指向一个函数名的时候,所指的地方就能出来一个实时菜单,使得我们可以直接定位到函数的声明、被调用的位置或者某个宏定义等等,非常方便。这种功能是如何实现的呢?在编译器的前端是一个语义解析器,它负责把源程序中的token找出来,然后解析器parser(也有的地方叫分析器)就可以解析这些token,并产生树状表,供编程环境使用;此外解析器还可以完成一部分的语法错误检查功能。如果希望了解关于解析器的更详细的信息,可以参考编译原理方面最著名的“龙书”,即《Compliers: Principles, Techniques, &Tools》;在K&RC语言文档的A12这一节中也对解析器的预处理功能进行了详细的叙述,它预处理的信息主要包括:
1. 宏定义和扩展,例如_INLINE;
2. #include引用的文件,包括<>和“”两种方法引用的头文件;
3. 条件编译指令,例如#if,#endif等等;
4. 其它的多种预处理指令,主要是#开头的一些指令,例如#error。
我们可以控制编译器的预处理选项,使得解析器根据我们的需求产生需要的预处理结果,方便我们对程序的开发调试;这些选项如表1所示。
表1 编译器中解析器的预处理选项
预处理选项 | 别名 | 控制效果 | --preproc_dependency[=filename | -ppd | 只执行预处理操作,并不输出预处理的解析结果,但是会并产生供make程序使用的列表文件,其中包含了被预处理的程序中存在的与头文件中的定义关联的行信息。 | make程序是编译器在编译时调用的编译程序。如果使用命令行的方法,可以不使用CCS而直接调用make程序进行编译。 | --preproc_includes[=filename] | -ppi | 只执行预处理操作,但是会把包含#include指令的文件列表写入列表文件。 | --preproc_macros[=filename] | -ppm | 只执行预处理操作,会生成其中包含了预定义的和用户自定义的宏的多个文件,这些文件和被预处理的文件的名字一样,只是其扩展名为.pp。 | 预定义的宏是TI预定义的,它在预处理结果中被用/* Predefined */标注出。 | --preproc_only | -ppo | 只执行预处理操作,并把解析的结果输出为名字与输入文件名一致、扩展名为.pp的文件。 | 在这种模式下,#include文件中的信息会被复制到.pp文件中,宏定义和其它的一些预处理指令信息都会被完全展开。 | --preproc_with_comment | -ppc | 只执行预处理操作,并把解析的结果输出为名字与输入文件名一致、扩展名为.pp的文件;与-ppo相比,输出的文件中保留了输入程序中的注释信息。 | --preproc_with_compile | -ppa | 在执行预处理之后,继续编译工作。对比可以看出,在预处理选项中,除了-ppa之外,其余的几个选项只完成预处理功能,并不进行接下来的编译工作。-ppa选项可以和其它的预处理选项一起使用,这样既可以输出预处理结果,又可以在预处理完成之后继续编译工作。 | --preproc_with_line | -ppl | 只执行预处理操作,并把包含行控制信息(#line指令)的解析结果输出为名字与输入文件名一致、扩展名为.pp的文件。 |
因为预处理器要使用到文件中的符号信息,所以相关的预定义信息一定要提供给预处理器,否则找不到符号信息就要报错了。符号选项比较简单,就是预定义与解除定义,如表2所示。
表2 预定义的符号选项
语言选项 | 别名 | 控制效果 | --define=name[=def] | -D | 预定义符号,使用方法是--define=name=""string def""。在编译器选项里使用-D,与在C程序里使用#define的效果是一样的。 | --undefine=name | -U | 解除对某个符号的定义,它会覆盖-D选项的效果。 |
在程序的处理过程中,我们可以控制编译器输出诊断信息选项,使得它输出我们期望的详细信息,更加容易定位和解决一些看起来难以捉摸的问题;这些选项如表3所示。需要注意的是,诊断信息相关的选项必须放在链接器选项--run_linker之前。
表3编译器的诊断信息选项
语言选项 | 别名 | 控制效果 | --compiler_revision |
| 在信息窗口中打印出编译器的版本号。这个用处不太大,因为从CCS的help的“关于”里面很容易看到。 | --diag_error=num | -pdse | 这里的num是诊断信息的标识符。不显示标识符的话,在编译出现错误时,会提示: | error: a break statement may only be used within a loop or switch | 启用的话,在有错误的时候,会提示: | error #77: this declaration has no storage class or type specifier xxxxx; | -pdse是把标识符num对应的语句标记为错误。 | --diag_remark=num | -pdsr | 把标识符num对应的语句标记为提示。 | --diag_suppress=num | -pds | 把标识符num对应的语句标记为不提示。 | --diag_warning=num | -pdsw | 把标识符num对应的语句标记为警告。 | --diag_wrap={on|off} |
| 默认为on,打包诊断信息。 | --display_error_number | -pden | 把诊断信息标识符和它对应的文本说明一起显示出来。 | --emit_warnings_as_errors | -pdew | 把警告信息作为错误处理。在这样的严格的模式下,必须消除所有的警告和错误,编译才能继续。 | --issue_remarks | -pdr | 提示所有的提醒信息(即非严重的警告信息)。 | --no_warnings | -pdw | 不显示警告信息,但是错误信息还是会提示的:毕竟有错误在的话编译无法完成。 | --quiet | -q | 安静模式,不显示编译过程中的诊断信息。 | --set_error_limit=num | -pdel | 这个选项设置编译过程中错误的上限,比如有10个源程序,设定错误上限为5,假如第3个文件时就已经有5个错误了,那么编译器就停止了编译,不再继续编译剩下的文件了。 | --super_quiet | -qq | “超级安静”模式。与-q相比,多了个q,足以看出它的级别。显然它的处理速度最快,但是给出的诊断信息那是一个也没有:最多告诉你程序有x个错误。如果确信程序完全无误,用这个选项编译倒是要快了不少。 | --tool_version | -version | 显示编译过程中调用的各个工具的版本信息。 | --verbose |
| 啰嗦模式:显示函数编译过程中的处理信息。 | --verbose_diagnostics | -pdv | 在啰嗦模式的基础上,把源程序中的对应部分也显示出来。 | --write_diagnostics_file | -pdf | 产生诊断信息文件。 |
|
网友评论