此代码的目的是读取以下txts(d.txt,e.txt,f.txt)并执行将字母顺序正确的字母放入output.txt所需的操作。代码假设工作,因为在output.txt我得到了正确的结果,但我使用printf进行的测试存在问题(它在newfile函数的末尾)。为了运行我输入d.txt和output.txt作为输入。 它应该打印
top->prev points to file :d
top->prev points to file :e
但是它会打印以下内容而我找不到原因
top->prev points to file :d
top->prev points to file :f
d.txt:
abc
#include e.txt
mno
e.txt:
def
#include f.txt
jkl
f.txt:
ghi
代码:
%{
#include <stdio.h>
#include <stdlib.h>
struct yyfilebuffer{
YY_BUFFER_STATE bs;
struct yyfilebuffer *prev;
FILE *f;
char *filename;
}*top;
int i;
char temporal[7];
void newfile(char *filename);
void popfile();
void create();
%}
%s INC
%option noyywrap
%%
"#include " {BEGIN INC;}
<INC>.*$ {for(i=1;i<strlen(yytext)-2;i++)
{
temporal[i-1]=yytext[i];
}
newfile(temporal);
BEGIN INITIAL;
}
<<EOF>> {popfile();
BEGIN INITIAL;
}
%%
void main(int argc,int **argv)
{
if ( argc < 3 )
{
printf("\nUsage yybuferstate <filenamein> <filenameout>");
exit(1);
}
else
{
create();
newfile(argv[1]);
yyout = fopen(argv[2], "w");
yylex();
}
system("pause");
}
void create()
{
top = NULL;
}
void newfile(char *filename)
{
struct yyfilebuffer *newptr;
if(top == NULL)
{
newptr = malloc(1*sizeof(struct yyfilebuffer));
newptr->prev = NULL;
newptr->filename = filename;
newptr->f = fopen(filename,"r");
newptr->bs = yy_create_buffer(newptr->f, YY_BUF_SIZE);
top = newptr;
yy_switch_to_buffer(top->bs);
}
else
{
newptr = malloc(1*sizeof(struct yyfilebuffer));
newptr->prev = top;
newptr->filename = filename;
newptr->f = fopen(filename,"r");
newptr->bs = yy_create_buffer(newptr->f, YY_BUF_SIZE);
top = newptr;
yy_switch_to_buffer(top->bs); //edw
}
if(top->prev != NULL)
{
printf("top->prev points to file : %s\n",top->prev->filename);
}
}
void popfile()
{
struct yyfilebuffer *temp;
temp = NULL;
if(top->prev == NULL)
{
printf("\n Error : Trying to pop from empty stack");
exit(1);
}
else
{
temp = top;
top = temp->prev;
yy_switch_to_buffer(top->bs);
system("pause");
}
}
答案 0 :(得分:2)
您需要考虑如何管理内存,记住C实际上没有像您可能习惯使用其他语言那样的字符串类型。
您定义了一个全局变量:
char temporal[7];
(它有一个奇怪的名字,因为全局变量不是临时的),然后在你的词法分析器中填入它的值:
for(i=1;i<strlen(yytext)-2;i++) {
temporal[i-1]=yytext[i];
}
上述代码至少有三个问题:
temporal
只有六个字符的文件名空间,但是你无处检查以确保yyleng
不大于6.如果是,你将覆盖随机内存。 (flex生成的扫描程序将yyleng
设置为起始地址为yytext
的令牌的长度。因此,您也可以使用该值而不是计算strlen(yytext)
,这涉及扫描文本。)
您永远不会终止temporal
。这是第一次,因为它具有静态生命周期,因此在程序初始化时将填充零。但是第二次和以后的时间你指望新的文件名不要比前一个短;否则,你最终会在新名称的末尾加上以前名字的一部分。
您可以更好地使用标准C库。虽然由于下面我将注意到的原因,但这并没有解决你观察到的问题,最好使用以下代替循环,检查后yyleng
不是太大:
memcpy(temporal, yytext + 1, yyleng - 2); /* Copy the filename */
temporal[yyleng - 2] = '\0'; /* NUL-terminate the copy */
在temporal
中复制后,您可以将其提交给newfile
:
newfile(temporal);
在newfile
中,我们看到的是:
newptr->filename = filename;
不会复制文件名。对newfile
的调用将temporal
的地址作为参数传递,因此在newfile
中,参数filename
的值是temporal
的地址。然后,您将该地址存储在newptr->filename
中,因此newptr->filename
也是temporal
的地址。
但是,如上所述,temporal
不是暂时的。它是一个全局变量,其生命周期是程序的整个生命周期。因此,下次您的词汇扫描程序遇到include
指令时,它会将其放入temporal
,覆盖以前的内容。那么filename
结构中的yyfilebuffer
成员会发生什么呢?答:没事。它仍然指向同一个地方temporal
,但该地方的内容已经改变。因此,当您稍后打印出filename
字段指向的字符串的内容时,您将获得与第一次创建{{1}时恰好位于temporal
的字符串不同的字符串。结构。
总的来说,如果yyfilebuffer
和newfile
“拥有”filebuffer堆栈中的内存,你会发现管理内存更容易。这意味着popfile
应该将其参数的副本复制到新分配的存储中,newfile
应该释放该存储,因为不再需要它。如果popfile
复制,则调用newfile
的词法扫描程序操作不需要复制;它只需要在调用newfile
时确保字符串正确地以NUL方式终止。
简而言之,代码可能如下所示:
newfile
既然/* Changed parameter to const, since we are not modifying its contents */
void newfile(const char *filename) {
/* Eliminated this check as obviously unnecessary: if(top == NULL) */
struct yyfilebuffer *newptr = malloc(sizeof(struct yyfilebuffer));
newptr->prev = top;
// Here we copy filename. Since I suspect that you are on Windows,
// I'll write it out in full. Normally, I'd use strdup.
newptr->filename = malloc(strlen(filename) + 1);
strcpy(newptr->filename, filename);
newptr->f = fopen(filename,"r");
newptr->bs = yy_create_buffer(newptr->f, YY_BUF_SIZE);
top = newptr;
yy_switch_to_buffer(top->bs); //edw
if(top->prev != NULL) {
printf("top->prev points to file : %s\n",top->prev->filename);
}
}
void popfile() {
if(top->prev == NULL) {
fprintf(stderr, "Error : Trying to pop from empty stack\n");
exit(1);
}
struct yyfilebuffer temp = top;
top = temp->prev;
/* Reclaim memory */
free(temp->filename);
free(temp);
yy_switch_to_buffer(top->bs);
system("pause");
}
取得了传递给它的字符串的所有权,我们就不再需要复制了。由于该操作清楚地表明您希望newfile
的参数类似于C #include
指令(由#include
或"..."
包围),因此最好明确指出:
<...>