C 为什么我在flex和bison中的程序不是';不行吗?正反函数计算器

C 为什么我在flex和bison中的程序不是';不行吗?正反函数计算器,c,bison,flex-lexer,C,Bison,Flex Lexer,我有这个程序,但不起作用,谁能帮我?当我输入2+3并输入时,.exe文件突然关闭。我不知道出了什么问题,但我需要尽快解决这个问题,希望你能帮助我。这是lexico.l: /* Ejemplo para una pequeña calculadora que permite trabajar con las funciones trigonometricas como el seno y el coseno */ #include <stdio.h> #include <stdl

我有这个程序,但不起作用,谁能帮我?当我输入2+3并输入时,.exe文件突然关闭。我不知道出了什么问题,但我需要尽快解决这个问题,希望你能帮助我。这是lexico.l:

/* Ejemplo para una pequeña calculadora que permite trabajar
con las funciones trigonometricas como el seno y el coseno */
#include <stdio.h>
#include <stdlib.h>
#include "sintactico.tab.h"
int nlines=0;
%}
DIGITO [0-9]
ID [a-zA-Z][a-zA-Z0-9_]*
%%
{DIGITO}+("."{DIGITO}+)? {//printf("Encontrado TKN_NUM: %f\n",atof(yytext));
 yylval.real=atof(yytext);
return(TKN_NUM);}
"=" {//printf("Encontrado TKN_ASIGN: %s\n",yytext);
 return(TKN_ASIGN);}
"(" {//printf("Encontrado TKN_PAA: %s\n",yytext);
 return(TKN_PAA);}
")" {//printf("Encontrado TKN_PAC: %s\n",yytext);
 return(TKN_PAC);}
"cos" {//printf("Encontrado TKN_COS: %s\n",yytext);
 return(TKN_COS);}
"sen" {//printf("Encontrado TKN_SEN: %s\n",yytext);
 return(TKN_SEN);}
{ID} {//printf("Encontrado TKN_ID: %s\n",yytext);
 return(TKN_ID);}
"\n" {nlines++;}
.
%%

/*ejempo para una pequeña calculadora que permite trabajar
三角函数的con las functiones como el seno y el coseno*/
#包括
#包括
#包括“sintactico.tab.h”
int-nlines=0;
%}
DIGITO[0-9]
识别号[a-zA-Z][a-zA-Z0-9]*
%%
{DIGITO}+(“{DIGITO}+)?{//printf(“Encontrado TKN_NUM:%f\n”,atof(yytext));
yylval.real=atof(yytext);
返回值(TKN_NUM);}
“=”{//printf(“密码:%s\n”,yytext);
返回(TKN_ASIGN);}
“({//printf(“Encontrado TKN_PAA:%s\n”,yytext);
返回(TKN_PAA);}
“”{//printf(“Encontrado TKN_PAC:%s\n”,yytext);
返回(TKN_PAC);}
“cos”{//printf(“Encontrado TKN_cos:%s\n”,yytext);
返回(TKN_COS);}
“sen”{//printf(“Encontrado TKN_sen:%s\n”,yytext);
返回(TKN_SEN);}
{ID}{//printf(“Encontrado TKN_ID:%s\n”,yytext);
返回(TKN_ID);}
“\n”{nlines++;}
.
%%
和sintactico.y文件:

%{
/* Ejemplo para una pequeña calculadora que permite trabajar
con funciones trigonometricas como el seno y el coseno */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
extern int yylex(void);
extern char *yytext;
extern int nlines;
extern FILE *yyin;
void yyerror(char *s);
%}
%union
{
 float real;
}
%start Calculadora
%token <real> TKN_NUM
%token TKN_ASIGN
%token TKN_PAA
%token TKN_PAC
%token TKN_COS
%token TKN_SEN
%token <real> TKN_ID
%type Calculadora
%type <real> Expresion
%left TKN_MAS TKN_MENOS
%left TKN_MULT TKN_DIV
%%
Calculadora : TKN_ID { printf("El valor de %s es: ", yytext);}
Expresion : TKN_NUM {$$=$1;}|
 TKN_PAA Expresion TKN_PAC {$$=$2;}|
 TKN_COS TKN_PAA Expresion TKN_PAC {$$=cos($3);}|
 TKN_SEN TKN_PAA Expresion TKN_PAC {$$=sin($3);};
%%
void yyerror(char *s)
{
printf("Error %s",s);
}
int main(int argc,char **argv)
{
if (argc>1)
 yyin=fopen(argv[1],"rt");

else
 yyin=stdin;
yyparse();
printf("FIN del Analisis. Entrada CORRECTA\n");
printf("Numero lineas analizadas: %d\n", nlines);
return 0;
}

%{
/*在计算过程中,必须考虑到许可证的性质
三角函数como el seno y el coseno*/
#包括
#包括
#包括
外部内部yylex(无效);
外部字符*文本;
外联线;
外部文件*yyin;
无效错误(字符*s);
%}
%联合
{
浮动真实;
}
%从加尔各拉多拉开始
%令牌TKN_NUM
%令牌TKN\u ASIGN
%代币TKN_PAA
%令牌TKN_PAC
%代币
%代币
%令牌TKN_ID
%加尔各拉多拉型
%类型扩展
%左TKN_MAS TKN_MENOS
%左TKN_MULT TKN_DIV
%%
Calculadora:TKN_ID{printf(“El valor de%s:,yytext);}
表达式:TKN_NUM{$$=$1;}|
TKN_PAA表达式TKN_PAC{$$=$2;}|
TKN_COS TKN_PAA expression TKN_PAC{$$=COS($3);}|
这是一种表达形式{$$=sin($3);};
%%
无效错误(字符*s)
{
printf(“错误%s”,s);
}
int main(int argc,字符**argv)
{
如果(argc>1)
yyin=fopen(argv[1],“rt”);
其他的
yyin=stdin;
yyparse();
printf(“FIN del Analisis.Entrada CORRECTA\n”);
printf(“分析的数字线:%d\n”,nlines);
返回0;
}
怎么了?我对Flex和Bison是新手,很难理解错误

当我输入2+3并输入时,.exe文件突然关闭

这里发生了几件事:

  • “2+3”不是程序的有效输入。您的语法的开始符号是
    Calculadora
    ,它的唯一产物是一个
    TKN\u ID
    标记。lexer为给定输入返回的第一个标记将是与
    2
    对应的
    TKN\u NUM
    。将导致分析错误,
    yyparse()
    将返回,程序将很快终止

  • 按照您启动程序的方式,程序一旦终止,Windows将关闭运行程序的窗口。您应该能够通过打开命令窗口,并通过命令行在中启动程序来避免这种情况

  • 还请注意:

  • 即使您的开始符号是
    Expresion
    ,“2+3”仍然不是有效的输入。
    TKN_NUM
    仍然是第一个令牌。
    +
    将仅由lexer的通配符模式匹配,该模式具有空操作,因此将打印它,但不会生成令牌。然后会有另一个
    TKN_NUM
    ,但语法没有规则可以应用于两个连续的
    TKN_NUM
    标记

  • 看起来您想要使用变量名,然后需要在lexer中读入一个字符串值,并在bison文件中使用它

    您的%联合可能如下所示:

    %union
    {
        char* str;
        float real;
    }
    
    {DIGITO}+("."{DIGITO}+)? { yylval.real=atof(yytext); return(TKN_NUM); }
    =       { return TKN_ASIGN; }
    \(      { return TKN_PAA; }
    \)      { return TKN_PAC; }
    cos     { return TKN_COS; }
    sen     { return TKN_SEN; }
    {ID}    { yylval.str = strdup(yytext); return TKN_ID; }
    \+      { return TKN_MAS; }
    \-      { return TKN_MENOS; }
    \n      { nlines++; return '\n'; }
    .
    
    Calculadora: { $$ = 0; }
        | Calculadora Expresion '\n' { printf("%f\n", $2); }
        | Calculadora '\n'
        ;
    
    同样,您的TNK_ID应该是:

    %token <str> TKN_ID
    
    还请注意,现在有+和-以及\n的定义。变量名存储在yylval.str中

    Calculadora宁愿这样:

    %union
    {
        char* str;
        float real;
    }
    
    {DIGITO}+("."{DIGITO}+)? { yylval.real=atof(yytext); return(TKN_NUM); }
    =       { return TKN_ASIGN; }
    \(      { return TKN_PAA; }
    \)      { return TKN_PAC; }
    cos     { return TKN_COS; }
    sen     { return TKN_SEN; }
    {ID}    { yylval.str = strdup(yytext); return TKN_ID; }
    \+      { return TKN_MAS; }
    \-      { return TKN_MENOS; }
    \n      { nlines++; return '\n'; }
    .
    
    Calculadora: { $$ = 0; }
        | Calculadora Expresion '\n' { printf("%f\n", $2); }
        | Calculadora '\n'
        ;
    
    对于
    Expresion
    而言,应添加ID、赋值以及加减运算的处理,例如:

    Expresion: TKN_NUM { $$=$1; }
        | TKN_ID { $$ = get_symbol($1)->value; }
        | TKN_ID TKN_ASIGN Expresion { put_symbol($1, $3); $$ = $3; }
        | Expresion TKN_MENOS Expresion { $$ = $1 - $3; }
        | Expresion TKN_MAS Expresion { $$ = $1 + $3; }
        | TKN_PAA Expresion TKN_PAC { $$ = $2; }
        | TKN_COS TKN_PAA Expresion TKN_PAC { $$ = cos($3); }
        | TKN_SEN TKN_PAA Expresion TKN_PAC { $$ = sin($3); }
        ;
    
    因为您似乎想要为变量名赋值,所以需要一种符号表。您可以提供
    void put\u symbol(char*name,float value)
    struct symbol\u entry*get\u symbol(char*name)
    的实现。符号条目可以定义为:

    struct symbol_entry {
        char name[50];
        float value;
    };
    
    测试

    快速测试-一行输入后是计算器的一行输出:

    5 + 3
    8.000000
    a = 5 + 3
    8.000000
    a = 0.5
    0.500000
    a
    0.500000
    b = cos(a)
    0.877583
    c = b + a        
    1.377583
    c
    1.377583
    

    这就是您要找的吗?

    它打印了行数吗?没有,应用程序刚刚关闭。@Megasaw:我强烈建议您阅读野牛手册中的内容,其中有详细的解释,以便您能够看到正在发生的事情。(不幸的是,仅用英语,但我认为它并不太复杂。)这些示例构建了一个包含函数和变量的完整计算器,但它们一开始很简单,值得花时间来遵循顺序。从长远来看,这将为您节省大量的痛苦。即使我把cos(2)放进去,程序也会突然终止:(而且我不知道如何修复它,我对它是新手,这个程序快把我逼疯了。@megasaw,“cos(2)”对您的程序来说也是无效的输入。同样,您的开始符号是
    Calculadora
    ,唯一可以匹配的令牌序列是一个
    TKN\u ID
    。因此,我必须将#start Calculadora by#start Expresion?@megasaw更改,如果您将开始符号更改为
    Expresion
    ,则我希望输入“cos(2)”但是,语法无法解析除此之外的其他输入,因此我希望
    yyparse()
    返回,让您回到我的观点(2)。此外,
    Expresion
    中没有任何内容打印表达式的值。这在
    Calculadora
    中,但是
    Calculadora
    的主体与
    Expresion
    不匹配。非常感谢!