最近在實踐中遇到一個需求:需要把一個C語言代碼文件中的註釋中的非空白字符全部替換爲空格(目的是讓新文件的長度和原來的一樣)..用flex鼓搗了兩個小時,得到了下面的代碼
%{
#include<iostream>
#include<sstream>
#include<fstream>
#include <iterator>
#include <vector>
#include <algorithm>
using namespace std;
ostringstream oss;
void replace();
%}
%start LINE_COMMENT BLOCK_COMMENT STRING
%%
%{
// 處理字符串常量,lex的註釋必須寫在%{和%}之內!!
%}
<INITIAL>\" { cout << yytext; BEGIN STRING;}
<STRING>[^\\]\" { cout << yytext; BEGIN 0; }
<STRING>. { cout << yytext;}
<INITIAL>"//" {cout << " ";BEGIN LINE_COMMENT;}
<LINE_COMMENT>"\n" {cout << endl; BEGIN 0; }
<LINE_COMMENT>"\r" {cout << yytext; }
<LINE_COMMENT>. { replace(); }
<INITIAL>"/*" {cout << " ";BEGIN BLOCK_COMMENT;}
<BLOCK_COMMENT>"*/" {cout << " ";BEGIN 0;}
<BLOCK_COMMENT>[\r\n] {cout<<yytext; }
<BLOCK_COMMENT>. { replace(); }
<INITIAL>[\r\n] {cout<<yytext; }
<INITIAL>. {cout<<yytext; }
%%
//將註釋裏的非空字符替換爲空格輸出
void replace(){
unsigned char c = yytext[0];
if (!isspace(c))
c =' ';
cout << c;
}
int yywrap(void)
{
return 1;
}
int main(int argc, char* argv[])
{
bool write_back_to_file = false;
string filename;
--argc;
++argv;
if(argc > 0){
write_back_to_file = true;
filename = argv[0];
yyin = fopen(argv[0],"r");
cout.rdbuf(oss.rdbuf()); //輸出重定向到字符串流裏,以便複製到文件中
}
else{
yyin = stdin;
}
yylex();
if (write_back_to_file){
//把輸出寫回文件
if(yyin != NULL)
fclose(yyin);
//把字符串流的內容拷貝到文件中
ofstream ofs(argv[0]);
const string & str = oss.str();
copy(str.begin(),str.end(),ostream_iterator<char>(ofs));//從字符串流讀取數據寫入輸出流
}
return 0;
}
然後在vs2017中編譯通過,
測試文件內容爲:
//行註釋測試
int main(){
const char* p ="//字符串裏的註釋" ;
/*
塊註釋
*/
return 0;
}
運行後文件的新內容爲
int main(){
const char* p ="//字符串裏的註釋" ;
return 0;
}
運行成功.
linux下的實驗過程爲:
sudo apt-get install flex #安裝flex包
sudo apt-get install bison #按照bison
flex demo.l #編譯剛纔寫的demo.l文件,會自動生成一個lex.yy.c文件
g++ -Wall -Wextra -o remove_comment lex.yy.c # 編譯之
./remove_comment test1.c #消除test1.c中的所有註釋
vs中如何使用flex 可以見這篇文章: