#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <list>
#include <set>
#include <stack>
#include <string>
#include <iostream>
using namespace std;
/*
* size of the buffer for a line limits to 8KB
* if a line is longger than 8KB, it will be interrupted.
*/
#define BUFSIZE 1024*8
/*
* let set the macro bigger than 255 to avoid ascii chars.
* and, make it can adapt bit or/and operate.
*/
#define DEFINE 256
#define ELIF 512
#define ELSE 1024
#define ENDIF 2048
#define IF 4096
#define IFDEF 8192
#define IFNDEF 16384
#define NORMAL 32768
#define UNDEF 65536
#define OTHERS 131072
#define EQUAL 300
#define NEQUAL 301
#define ENDS 302
#define PASS_SPACE2(buf,i) while( ++i<buf.length() && isspace( buf[i]) );
/*
* yytext is the value for some token.
* there are two global variables.
*/
string yytext; /* save the result of lex analyze. */
int lineno = 1; /* current line number. */
int comment_flag = 0; /* whether to delete or comment the undefined parts. */
/*
* function eatword
* push every char which construct the word into yytext.
* this function only push strings into yytext, never clear it.
*/
int eatword(string& buf, unsigned int& i){
/* first pass spaces. */
if ( isspace(buf[i]) ) {
PASS_SPACE2(buf,i);
}
/* check if it is a word or a char. */
/* if it's word */
if ( isalpha(buf[i]) || buf[i] == '_' ) {
yytext.push_back( buf[i] );
i++;
while ( i<buf.length() && ( isalnum(buf[i]) || buf[i] == '_' ) ) {
yytext.push_back( buf[i] );
i++;
}
/* check if keyword. */
if ( yytext.compare("if") == 0 ) {
return IF;
}else if( yytext.compare( "define" ) == 0 ){
return DEFINE;
}else if( yytext.compare( "elif" ) == 0 ){
return ELIF;
}else if( yytext.compare( "else" ) == 0 ){
return ELSE;
}else if( yytext.compare( "endif" ) == 0 ){
return ENDIF;
}else if( yytext.compare( "ifdef" ) == 0 ){
return IFDEF;
}else if( yytext.compare( "ifndef" ) == 0 ){
return IFNDEF;
}else if( yytext.compare( "undef" ) == 0 ){
return UNDEF;
}else {
return OTHERS;
}
}else if( buf[i] == '=' || buf[i] == '!' ){
yytext.push_back( buf[i] );
if ( buf[++i] == '=' ) {
yytext.push_back( '=' );
i++;
return (buf[i-2] == '=') ? EQUAL : NEQUAL;
}else {
return buf[i-1];
}
}else if( i == buf.length() ){
return ENDS;
}else { /* it's a char */
yytext.push_back( buf[i] );
/*
* important: this function has the responsibility to modify the i to next position
* because i is the reference type.
* we make the contract that we only modified i in this function.
*/
i++;
return buf[i-1];
}
}
/*
* analyze a whole line.
* important:
* yytext is cleared here, and in function lex,it only push chars into it.
*
* this function returns an int or a char.
*/
int parse_line( string& buf, set<string>& env ){
yytext.clear();
/* var i can modified only by function lex !!!!!!! */
unsigned int i = 0;
int first_word = eatword( buf, i );
/* check if it start with # */
if ( first_word != '#' ) {
return NORMAL;
}else {
yytext.clear();
/* i++; */
first_word = eatword( buf, i );
}
switch( first_word ){
case DEFINE:
yytext.clear();
/* get next word into yytext. */
eatword( buf, i );
/*
* this section reserved for next develop of macro launching.
*/
#if 0
/* look forward for a char */
if ( buf[i] == '(' ) {
stack<int> s;
s.push( 1 );
yytext.push_back( '(' );
i++;
while ( !s.empty( ) ) {
int tmp = eatword( buf, i );
if ( tmp == ')' ) {
s.pop( );
}else if( tmp == '(' ){
s.push(1);
}
}
}
#endif
return DEFINE;
case ELIF:
case IF:
yytext.clear();
eatword( buf, i );
if ( yytext.compare( "defined" ) == 0 ) {
yytext.clear();
eatword( buf, i );
return first_word == IF ? IFDEF : ELIF|IFDEF;
}else if( yytext[0] == '!' ){
eatword( buf, i );
if ( yytext.compare( "!defined" ) == 0 ){
yytext.clear();
eatword( buf, i );
return first_word == IF ? IFNDEF : ELIF|IFNDEF;
}else {
return first_word;
}
}else {
int x1 = (env.find( yytext )!=env.end()) ? 1 : 0;
yytext.clear();
int oper = eatword( buf, i );
if ( oper != EQUAL && oper != NEQUAL && oper != ENDS ) {
printf( "error: lack of != or == at line %d\n",lineno );
cout<<buf<<endl;
exit(1);
}else if( oper == ENDS ){
(x1 != 0)? yytext.push_back('1') : yytext.push_back('0');
return first_word;
}
yytext.clear();
eatword( buf, i );
int x2 = (env.find( yytext ) != env.end()) ? 1 : 0;
int comp_res = (oper == EQUAL) ? (x1 == x2) : (x1 != x2);
yytext.clear();
(comp_res != 0) ? yytext.push_back('1') : yytext.push_back('0');
return first_word;
}
case IFDEF:
case IFNDEF:
yytext.clear();
eatword( buf, i );
return first_word;
case UNDEF:
yytext.clear();
eatword( buf, i );
return UNDEF;
default:
return first_word; /* other preprocess command. */
}
}
void killpp4( list<string>& l, set<string>& env ){
/*
* top of status stack is the latest saved elif_flag.
*/
stack<int> status;
list<string>::iterator iter;
/*
* this var is used for if...elif...elif...end.
* because in these sections only one section could be execute,
* if one section in if...elif...elif...end structure has
* ever executed, let's mark it.
* init it to 0
*/
int ever_true = 0;
/*
* this var is used for determine the current status is defined or
* not defined, the former the line reserved, and the latter the line ignored.
*/
int elif_flag = 1;
lineno = 1;
for( iter = l.begin(); iter != l.end(); ++lineno ){
int result = parse_line( *iter, env );
switch( result ){
case IF:
status.push( elif_flag );
if( yytext[0] == '0' )
elif_flag = 0;
else
elif_flag = 1;
if( elif_flag != 0 )
ever_true = 1;
elif_flag &= status.top();
break;
case IFDEF:
status.push( elif_flag );
elif_flag = env.find( yytext ) != env.end();
if( elif_flag != 0 )
ever_true = 1;
elif_flag &= status.top();
break;
case IFNDEF:
status.push( elif_flag );
elif_flag = env.find( yytext ) == env.end();
if( elif_flag != 0 )
ever_true = 1;
elif_flag &= status.top();
break;
case ENDIF:
if( !status.empty() ){
elif_flag = status.top();
status.pop();
/* when a select structure ends, reset ever_true to 0 */
ever_true = 0;
}else {
printf("syntax error at line %d\n",lineno);
cout<<*iter<<endl;
exit(1);
}
break;
case ELSE:
elif_flag = !elif_flag;
elif_flag &= !ever_true;
if( status.top() == 0 )
elif_flag = 0;
break;
case ELIF:
if( elif_flag != 0 )
elif_flag = 0;
else if ( yytext[0] != '0' ) {
elif_flag = 1;
}
elif_flag &= !ever_true;
if( elif_flag != 0 )
ever_true = 1;
if( status.top() == 0 )
elif_flag = 0;
break;
case ELIF|IFDEF:
if ( elif_flag != 0 ) {
elif_flag = 0;
}else if( env.find( yytext ) != env.end() ){
elif_flag = 1;
}
elif_flag &= !ever_true;
if( elif_flag != 0 )
ever_true = 1;
if( status.top() == 0 )
elif_flag = 0;
break;
case ELIF|IFNDEF:
if ( elif_flag != 0 ) {
elif_flag = 0;
}else if( env.find( yytext ) == env.end() ){
elif_flag = 1;
}
elif_flag &= !ever_true;
if( elif_flag != 0 )
ever_true = 1;
if( status.top() == 0 )
elif_flag = 0;
break;
}
if ( elif_flag ) {
switch( result ){
case DEFINE:
env.insert( yytext );
break;
case UNDEF:
if ( env.find( yytext ) != env.end() ) {
env.erase( yytext );
}
break;
}
}else {
if ( comment_flag ) {
(*iter).insert(0,"/* ");
(*iter).append(" */");
iter++;
}else {
l.erase( iter++ );
}
continue;
}
/*
没有合适的资源?快使用搜索试试~ 我知道了~
清除c/c++代码中条件编译部分的程序,帮助阅读源代码,生成好的tags
3星 · 超过75%的资源 需积分: 9 66 下载量 62 浏览量
2009-11-24
12:36:49
上传
评论 1
收藏 4KB GZ 举报
温馨提示
共1个文件
cpp:1个
网上众多的开源C/C++代码,因为跨平台的需要,参杂了许多的条件编译语句,对阅读源代码造成了不方便,而且用ctags等工具生成源代码的tags文件时会有些妨碍,本工具就是用来预处理这些条件编译的,将未定义的区域自动删除或者注释,但保留诸如 #include, #define, #undef ,#pragma 等和条件编译无关的预处理语句,留下干净的代码以供阅读。 源代码使用了stl,在任何平台下编译应该都没有问题,使用的都是标准库中的函数。 该程序编译后生成的程序在命令行或终端中运行 选项介绍: -h 帮助 -n 打印行号 -c 注释掉未定义行,而不是清除掉 -Dmacro 预定义宏 -Umacro 预取消宏 usage: killpp filename -Dmacro ... 如果没有指定文件,将从标准输入中读取 默认输出到标准输出。
资源推荐
资源详情
资源评论
收起资源包目录
killpp4.cpp.tar.gz (1个子文件)
killpp4.cpp 11KB
共 1 条
- 1
资源评论
- xuzhouweihao2014-07-25Linux下是可以使用的,但是使用C++来写这个功能是不是比较累赘? 使用shell应该会更好点吧, 另外对于if 0 这个是删除不了的。 总体来时还是可以的
- suyong_yq2013-01-29好像不能用
- mloik2014-06-09好像是不能用
- danxia2hao2015-05-28对于类似于 #if VERSION == V1_1 这样的条件是无效的。 处理方式有参考价值。
- brkang112012-03-08VC 6.0编译无法通过
qianlongwydh
- 粉丝: 25
- 资源: 11
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功