1

现在我得到了其他的东西。当我执行 a 时bison -d calc.y,我在控制台中获得了许多源代码(带有 many m4_define),但它不会生成任何文件。现在我的代码是这样的:

%{
#define YYSTYPE double
#include <math.h>
%}
%token NUM
%%
input:    /* empty */
        | input line
;

line:     '\n'
        | exp '\n'  { printf ("\t%.10g\n", $1); }
;

exp:      NUM             { $$ = $1;         }
        | exp exp '+'     { $$ = $1 + $2;    }
        | exp exp '-'     { $$ = $1 - $2;    }
        | exp exp '*'     { $$ = $1 * $2;    }
        | exp exp '/'     { $$ = $1 / $2;    }
      /* Exponentiation */
        | exp exp '^'     { $$ = pow ($1, $2); }
      /* Unary minus    */
        | exp 'n'         { $$ = -$1;        }
;
%%

/* Lexical analyzer returns a double floating point 
   number on the stack and the token NUM, or the ASCII
   character read if not a number.  Skips all blanks
   and tabs, returns 0 for EOF. */

#include <ctype.h>
#include <stdio.h>

yylex ()
{
  int c;

  /* skip white space  */
  while ((c = getchar ()) == ' ' || c == '\t')  
    ;
  /* process numbers   */
  if (c == '.' || isdigit (c))                
    {
      ungetc (c, stdin);
      scanf ("%lf", &yylval);
      return NUM;
    }
  /* return end-of-file  */
  if (c == EOF)                            
    return 0;
  /* return single chars */
  return c;                                
}

yyerror (s)  /* Called by yyparse on error */
     char *s;
{
  printf ("%s\n", s);
}

main ()
{
  yyparse ();
}

原始问题

我正在尝试创建自己的开发语言,但是很难开始,而且当我开始时,我遇到了很多错误,我不知道如何解决。这是我的代码:

#include <ctype.h>
#include <stdio.h>

yylex ()
{
  int c;

  /* skip white space  */
  while ((c = getchar ()) == ' ' || c == '\t')  
    ;
  /* process numbers   */
  if (c == '.' || isdigit (c))                
    {
      ungetc (c, stdin);
      scanf ("%lf", &yylval);
      return NUM;
    }
  /* return end-of-file  */
  if (c == EOF)                            
    return 0;
  /* return single chars */
  return c;                                
}

main ()
{
  yyparse ();
}

calc.y 源代码文件:

%token NUM
%%
input:
        | input line
;

line:     '\n'
        | exp '\n'  { printf ("\t%.10g\n", $1); }
;

exp:      NUM             { $$ = $1;         }
        | exp exp '+'     { $$ = $1 + $2;    }
        | exp exp '-'     { $$ = $1 - $2;    }
        | exp exp '*'     { $$ = $1 * $2;    }
        | exp exp '/'     { $$ = $1 / $2;    }
      /* Exponentiation */
        | exp exp '^'     { $$ = pow ($1, $2); }
      /* Unary minus    */
        | exp 'n'         { $$ = -$1;        }
;
%%

现在编译器日志:

C:\Documents and Settings\Nathan Campos\Desktop>gcc calc.tab.c -lm -o rpcalc
calc.tab.c: In function `yylex':
calc.tab.c:15: error: `yylval' undeclared (first use in this function)
calc.tab.c:15: error: (Each undeclared identifier is reported only once
calc.tab.c:15: error: for each function it appears in.)
calc.tab.c:16: error: `NUM' undeclared (first use in this function)

怎么了?

4

5 回答 5

6

修改后的答案

您提供的修改后的代码几乎可以干净地编译 - 您应该在使用#include <stdio.h>之前printf()声明它。(您还应该为函数使用原型 - 例如yyerror(const char *str),并且通常将代码拖入 21 世纪。)

它甚至可以正确响应“1 2 +”。

对于单个文件,您不需要使用“ bison -d”。

如果你看到垃圾,你需要检查你的构建命令和构建环境。


原始答案

从哪里开始?

建议:获取有关Lex 和 Yacc(来自图书馆)或Flex 和 Bison的 O'Reilly 书籍(2009 年 8 月更新/重写 - 可能还没有在图书馆中)。如果您需要更快的资源,那么我建议您使用Unix 版本 7手册或GNU Bison 手册- 两者都可以在线获得。特别是阅读关于 Lex 和 Yacc 的第 7 版文档;您并没有尝试做原始说明中未涵盖的事情(尽管那里的 C 代码比 C89 标准早了十年或更长时间)。

  • 您需要用于bison -d生成包含令牌编号的标头。对于源文件“zzz.y”,这将生成 C 代码“zzz.tab.c”和“zzz.tab.h”。
  • 您需要在主程序中包含“zzz.tab.h”。
  • 您需要使用 C99,因此应该在yylex()and上有一个返回类型main()
  • 您需要声明yylval. 幸运的是,Bison 'zzz.tab.h' 文件可以正确执行此操作;它并不像看起来那么简单。
  • 您可能希望在词法分析器中允许负数 (-3.1416)。您可能也希望允许显式正数 (+3.1416)。
  • 您可能需要确保 '$$' 和朋友是类型double而不是int( #define YYSTYPE double) 的默认类型。
于 2009-10-11T16:19:10.483 回答
2

IIRC,yylval 由 Bison 声明,但您必须提供类型。否则,编译器会感到困惑并可能会产生误导性错误。

您需要定义 YYSTYPE。在您的情况下,您可能会逃脱“#define YYSTYPE double”。在语法中,在靠近顶部的 %{ ... %} 块中执行此操作。

%union 也可用于将 YYSTYPE 声明为联合。

这看起来像 Bison 手动标准 rpcalc 示例,所以我假设您可以轻松查找“YYSTYPE”和“%union”。

于 2009-10-11T16:26:47.643 回答
1

在您的 .y 文件中添加以下行:

void yyerror(char *errorinfo);
int yylex(void);

您还需要定义 flex 生成的令牌类型:

%token NUM

等等。

编辑:Flex and Bison (O'Reilly) 是一个很好的资源。

于 2009-10-11T16:11:43.447 回答
0

您尚未在任何地方声明变量yylval

于 2009-10-11T16:09:43.340 回答
0

#define YYSTYPE 不是一个好主意。它当然不适用于我尝试过的 Bison。您应该做的是告诉 Bison 您使用的值是双精度值:

%union {
    double dval;
}

%type <dval> exp NUM

Bison 现在将为您生成适当的 YYSTYPE。

但我建议你看一个教程或其他东西。Thomas Niemann 的 Lex & Yacc 精简指南 是一本很好的指南,它提供了示例和逐步的解释。我教一门编译器课程,我的经验是 Bison 和语法可能会因过多的反复试验而难以入门。

于 2009-10-16T05:04:41.050 回答