Compiler construction lex和yacc程序将中缀转换为前缀

Compiler construction lex和yacc程序将中缀转换为前缀,compiler-construction,yacc,lex,Compiler Construction,Yacc,Lex,我是lex和yacc程序的新手。我一直在尝试编写一个yacc程序,它以算术表达式作为输入,以前缀符号作为输出。 这是我的莱克斯密码 %{ #include<string.h> #include"pre.tab.h" %} %% "*"|"/"|"+"|"-"|"("|")" {return yytext[0];} [0-9]+ {yylval.name=(char*)malloc(yyleng+1); strcpy(yylval.name,yytext); return

我是lex和yacc程序的新手。我一直在尝试编写一个yacc程序,它以算术表达式作为输入,以前缀符号作为输出。 这是我的莱克斯密码

%{
#include<string.h>
#include"pre.tab.h"
%}
%%
"*"|"/"|"+"|"-"|"("|")" {return yytext[0];}
[0-9]+ {yylval.name=(char*)malloc(yyleng+1);
   strcpy(yylval.name,yytext);
   return NUM;}
\n {return(0);}
[a-zA-Z][a-zA-Z]* {yylval.name=(char*)malloc(yyleng+1);
      strcpy(yylval.name,yytext);
      return ID;}
. {}
%%
int yywrap()
{
return 1;
}
%{
#包括
#包括“预制表符h”
%}
%%
“*”|“/”|“+”|“-”|“(“|”)”{返回yytext[0];}
[0-9]+{yylval.name=(char*)malloc(yyleng+1);
strcpy(yylval.name,yytext);
返回NUM;}
\n{return(0);}
[a-zA-Z][a-zA-Z]*{yylval.name=(char*)malloc(yyleng+1);
strcpy(yylval.name,yytext);
返回ID;}
. {}
%%
int yywrap()
{
返回1;
}
这是我的YACC代码

%{
#include<stdio.h>
#include<string.h>
char buf[10];
%}

%union
{
  char *name;
}
%token<name>NUM ID
%type<name>E 
%left'+''-'
%left'*''/'
%nonassoc UMINUS
%%
S:E  {printf("\n%s",$1);}
;
E:E'*'E {buf[0]='\0';strcpy($$,strcat(strcpy(buf,"*"),strcat($1,$3)));}
|E'/'E {buf[0]='\0';strcpy($$,strcat(strcpy(buf,"/"),strcat($1,$3)));}
|E'+'E {buf[0]='\0';strcpy($$,strcat(strcpy(buf,"+"),strcat($1,$3)));}
|E'-'E {buf[0]='\0';strcpy($$,strcat(strcpy(buf,"-"),strcat($1,$3)));}
|ID
|NUM
|'('E')'{strcpy($$,$2);}
;
%%
main()
{
yyparse();
}
int yyerror(char *s) {fprintf(stderr,"%s\n",s);}
%{
#包括
#包括
char-buf[10];
%}
%联合
{
字符*名称;
}
%tokenNUM ID
%类型
%左'+''-'
%左'*''/'
%非寄生性耳鸣
%%
S:E{printf(“\n%S,$1);}
;
E:E'*'E{buf[0]='\0';strcpy($$,strcat(strcpy(buf,“*”),strcat($1,$3));}
|E'/'E{buf[0]='\0';strcpy($$,strcat(strcpy(buf,“/”),strcat($1,$3));}
|E'+'E{buf[0]='\0';strcpy($$,strcat(strcpy(buf,“+”),strcat($1,$3));}
|E'-'E{buf[0]='\0';strcpy($$,strcat(strcpy(buf,“-”),strcat($1,$3));}
|身份证
|NUM
|“('E')”{strcpy($$,$2);}
;
%%
main()
{
yyparse();
}
int yyerror(char*s){fprintf(stderr,“%s\n”,s);}

当我在论文中输入一个算术表达式时,我没有得到任何输出。例如:输入:1+(2*3)输出:+*23*23。我多次尝试更正代码,但都没有成功。

在C语言中,字符串不像在其他语言中那样神奇地扩展。(或者更好地说,实际上没有字符串对象。)除非已经确保字符数组
a
在NUL终止符后面有足够的空间来追加
b
,否则不能调用
strcat(a,b)

您不能对字符串文本执行
strcat
,因为不仅没有足够的空间,而且字符串文本可能位于只读内存中

而且,您不能将strcpy复制到未分配的变量,并期望自动分配足够的内存。(虽然
$
实际上不是未初始化的变量,因为它已初始化为
$1
的值)


因此,您的代码充满了缓冲区溢出,这是一种未定义的行为。

在C语言中,字符串不像在其他语言中那样神奇地扩展。(或者更好地说,实际上没有字符串对象。)除非已经确保字符数组
a
在NUL终止符后面有足够的空间来追加
b
,否则不能调用
strcat(a,b)

您不能对字符串文本执行
strcat
,因为不仅没有足够的空间,而且字符串文本可能位于只读内存中

而且,您不能将strcpy复制到未分配的变量,并期望自动分配足够的内存。(虽然
$
实际上不是未初始化的变量,因为它已初始化为
$1
的值)


因此,您的代码充满了缓冲区溢出,这是一种未定义的行为。

空格键断了吗?你有什么发现吗?语法错误?@EJP我没有得到任何输出。输入1+2时,命令提示中不显示任何内容。输入1+2检查半标准函数
strdup
asprintf
,在Linux、Windows、OSX、*BSD和大多数类似unix的系统上都可用,情况也是如此……空格键断了吗?你有什么发现吗?语法错误?@EJP我没有得到任何输出。输入1+2时,命令提示中不显示任何内容。当我输入1+2检查半标准函数
strdup
asprintf
,在Linux、Windows、OSX、*BSD和大多数类似unix的系统上可用时,情况也是如此……我更正了上面更新的代码,但现在出现了一个新错误。输入:1+(2*3)输出:+*23*23@user46663:当您编写strcpy($$,…)时,
$$
指向的缓冲区是什么?你分配了吗?你知道里面有多少空间吗?您确实需要了解如何在C中进行字符串操作,以便完成您想要做的事情。(请不要在回答问题后编辑它;这会使答案不正确甚至不相关。)我知道$$指向哪个缓冲区。也许你需要在评论之前温习一下你的Yacc技巧。如果您不知道答案,您不应该含糊其辞地回答。@user46663:因此在产品
'('E'){strcpy($$,$2);}
,例如,
$$
将在规则运行之前由
$$=$1
初始化,但
$1
指的是终端
。它甚至有与之相关联的语义值吗?它是否被初始化为任何东西?…所以不是“请为我编写代码”服务,我的回答旨在为您指出一个有用的方向。当然,您完全可以忽略它。@user46663:Oh,顺便说一句,如果您为某个op减少
E op E
,并且
$1
是减少
E:ID
E:NUM
的结果,
strcat的缓冲区($1,$3)
将由lexer使用
malloc(yyleng+1)
创建,因此它显然没有任何可用于附加的空间。我希望这对您足够具体。我更正了上面更新的代码,但现在出现了一个新错误。输入:1+(2*3)输出:+*23*23@user46663:当您编写strcpy($$,…)时,
$$
指向的缓冲区是什么?你分配了吗?你知道其中有多少可用空间吗?你真的需要了解如何在C中进行字符串操作才能完成你想做的事情。(回答问题后请不要编辑问题;这会使答案不正确甚至不相关。)我知道$$指向哪个缓冲区。也许你需要在评论之前复习一下你的Yacc技能。如果你不知道答案,你不应该含糊其辞地回答。@user46663:所以在产品中,
('E'){strcpy($$,$2);}
,例如,
$
将由
$=$1初始化<