我們在先前的範例中,程式在讀取完單一檔案便結束了。如果要讀取多份檔案的話,程式就要不斷的呼叫 Parser。然而,這樣會造成前面的文件資訊被直接清除。如果要連續的輸入文件,其實可以好好利用之前提到的 yywrap function。這個function在 yylex 結束前被呼叫,若是回傳 1 ,代表文件讀取完畢,而回傳 0 則代表尚有文件沒有讀取。因此,我們可以利用這個特性,來製作一個可以連續讀取多份文件的程式。
請實作一份可以連續讀取多份文件的文字計數器,並顯示每份文件的行數、字數與字元數。最後,顯示總計的行數、字數與字元數。輸入的文件寫在執行檔後,範例如下:
./main.exe file1.txt file2.txt ...
int ncharTotal = 0;
int nwordTotal = 0;
int nlineTotal = 0;
char **fileList;
int currentFile = 0;
int nFiles;
int main(int argc, char **argv) {
FILE *file;
fileList = argv + 1;
nFiles = argc - 1;
if (argc == 1) {
printf("No input files!\n");
return -1;
}
if (argc == 2) {
currentFile = 1;
file = fopen(argv[1], "r");
if (!file) {
fprintf(stderr,"could not open %s\n",argv[1]);
return -1;
}
yyin = file;
}
if (argc > 2) yywrap();
yylex();
if (argc > 2) {
printf("%s result: line %d, word %d, char %d\n", fileList[currentFile - 1], nline, nword, nchar);
ncharTotal += nchar;
nwordTotal += nword;
nlineTotal += nline;
printf("total: line %d, word %d, char %d\n", nlineTotal, nwordTotal, ncharTotal);
} else {
printf("A result: line %d, word %d, char %d\n", nline, nword, nchar);
}
return 0;
}
int yywrap() {
FILE *file = NULL;
if ((currentFile != 0) && (nFiles > 1) && (currentFile < nFiles)) {
printf("%s result: line %d, word %d, char %d\n", fileList[currentFile - 1], nline, nword, nchar);
ncharTotal += nchar;
nwordTotal += nword;
nlineTotal += nline;
nchar = nword = nline = 0;
fclose (yyin);
}
while (fileList[currentFile] != nullptr) {
file = fopen(fileList[currentFile++], "r");
if (file != NULL) {
yyin = file;
break;
}
fprintf(stderr, "could not open %s\n", fileList[currentFile - 1]);
}
return (file ? 0 : 1);
}
%{
int yylex(void);
int nchar, nword, nline;
%}
word [^ \t\n]+
eol \n
%%
{eol} { nline++; nchar++; }
{word} { nword++, nchar += yyleng; }
. { nchar++; }
%%
int ncharTotal = 0;
int nwordTotal = 0;
int nlineTotal = 0;
char **fileList;
int currentFile = 0;
int nFiles;
int main(int argc, char **argv) {
FILE *file;
fileList = argv + 1;
nFiles = argc - 1;
if (argc == 1) {
printf("No input files!\n");
return -1;
}
if (argc == 2) {
currentFile = 1;
file = fopen(argv[1], "r");
if (!file) {
fprintf(stderr,"could not open %s\n",argv[1]);
return -1;
}
yyin = file;
}
if (argc > 2) yywrap();
yylex();
if (argc > 2) {
printf("%s result: line %d, word %d, char %d\n", fileList[currentFile - 1], nline, nword, nchar);
ncharTotal += nchar;
nwordTotal += nword;
nlineTotal += nline;
printf("total: line %d, word %d, char %d\n", nlineTotal, nwordTotal, ncharTotal);
} else {
printf("A result: line %d, word %d, char %d\n", nline, nword, nchar);
}
return 0;
}
int yywrap() {
FILE *file = NULL;
if ((currentFile != 0) && (nFiles > 1) && (currentFile < nFiles)) {
printf("%s result: line %d, word %d, char %d\n", fileList[currentFile - 1], nline, nword, nchar);
ncharTotal += nchar;
nwordTotal += nword;
nlineTotal += nline;
nchar = nword = nline = 0;
fclose (yyin);
}
while (fileList[currentFile] != nullptr) {
file = fopen(fileList[currentFile++], "r");
if (file != NULL) {
yyin = file;
break;
}
fprintf(stderr, "could not open %s\n", fileList[currentFile - 1]);
}
return (file ? 0 : 1);
}
Hello, World!
I am a software engineer.
I like lex and yacc.
Hello, BarleyTea!
My name is BlackTea.
I am also a software engineer.
I am learning lex and yacc.
file.txt result: line 3, word 12, char 60
file2.txt result: line 4, word 18, char 97
total: line 7, word 30, char 157
雖然看起來有點複雜,但只要掌握yywrap的基本原則,就可以連續讀取多個檔案囉~