Flex和Bison给出了分段故障(核心转储)

时间:2017-02-27 13:08:01

标签: compiler-construction segmentation-fault bison flex-lexer

我正在尝试使用flex和bison来创建一个名为" FUNC"的简单语言的编译器。但它给了我一个分段错误,花了几个小时后,我仍然无法解决它。如果你们能提供帮助,我们真的很感激。谢谢!

Flex FIle" func.lex"

    %{
#include "tokens.h"
//#include "y.tab.h"
%}

DIGIT    [0-9]
IDENT   [a-zA-Z][A-Za-z0-9]*

%%

"function"  {return FUNCTION;}
"returns"   {return RETURNS;}
"begin" {return BEGIN;}
"end"  {return END;}
"read"  {return READ;}
"write" {return WRITE;}
"if"    {return IF;}
"then"  {return THEN;}
"else"  {return ELSE;}
"variables" {return VARIABLES;}
"while" {return WHILE;}
"loop"  {return LOOP;}
"Less"  {return LESS;}
"LessEq"    {return LESSEQ;}
"Eq"    {return EQ;}
"NEq"   {return NEQ;}
"("     {return LB;}
")"     {return RB;}
"Plus"  {return PLUS;}
"Times"  {return TIMES;}
"Minus"  {return MINUS;}
"Divide"  {return DIVIDE;} 
"," {return COMMA;}
":="    {return ASSIGN;}
";"  {return SEMI;}

{DIGIT}+ {return NUMBER;}
{IDENT}  {return NAME;}
<<EOF>> {return EOF;}

[ \t\n]+          /* eat up whitespace */


%%

int yywrap() { return EOF; }

Yacc文件&#34; func.y&#34;

%{
//#include "tokens.h"
#include <stdio.h>
#include <stdlib.h>
extern FILE * yyin;
extern char * yytext;
extern  int yylex(void);
extern  int yyparse();
void yyerror( const char *s);
int yylex(void);
int symb;
%}

/*****************bison declarations**********************/

%union               //defining all possible semantic data types (strings and digits)
{
  int       NUMBER; 
  char *    NAME;
  _Bool         COND;   //return value of conditional expressions. one of our $$ can have value 0 or 1
}

%start program

%type <NUMBER> NUMBER
%type <NAME> NAME

%token FUNCTION RETURNS VARIABLES BEGIN END COMMA SEMI ASSIGN
READ WRITE 
IF THEN ELSE
WHILE LOOP
LB RB
LESS LESSEQ EQ NEQ 
PLUS MINUS TIMES DIVIDE
NAME NUMBER      //same case as that used in "operations" below (same as FUNC syntax)

%%
//grammar rules

program: funcs
    ;                //<program> ::= <funcs>

funcs: func ";"                       //<funcs> ::= <func>; [<funcs>]
          |func ";" funcs
    ;

func: FUNCTION NAME "("")" BEGIN commands END FUNCTION           /*<func> ::= function <name>([<args>])[returns <name>] [variables <args>] begin <commands> end function*/
      |FUNCTION NAME "(" args ")" BEGIN commands END FUNCTION
      |FUNCTION NAME "(" args ")" RETURNS NAME BEGIN commands END FUNCTION
      |FUNCTION NAME "("")" RETURNS NAME BEGIN commands END FUNCTION
      |FUNCTION NAME "("")" BEGIN commands VARIABLES args END FUNCTION
      |FUNCTION NAME "(" args ")" BEGIN commands VARIABLES args END FUNCTION
      |FUNCTION NAME "("")" RETURNS NAME BEGIN commands VARIABLES args END FUNCTION
      |FUNCTION NAME "(" args ")" RETURNS NAME BEGIN commands VARIABLES args END FUNCTION
    ;

args: NAME                   //<args> ::= <name> [,<args>]
    |NAME "," args 
    ;

commands: command ";"           //<commands> ::= <command>; [<commands>]
          |command ";" commands
    ;

command: assign                            //<command> ::= <assign> | <if> | <while> | read <name> | write <expr>
         |if
         |while
         |read
         |write 
    ;

assign: NAME ":=" expr  {$<NAME>$=$1=$<NUMBER>3;}     //<assign> ::= <name> := <expr>
//assign: NAME ASSIGN expr  {$1=$3;}
    ;

if: IF condexpr THEN commands END IF                 //<if> ::= if <condexpr> then <commands> [else <commands>] end if
    |IF condexpr THEN commands ELSE commands END IF
    ;

while: WHILE condexpr LOOP commands END LOOP
    ;          //<for> ::= while <condexpr> loop <commands> end loop

read: READ NUMBER
|READ NAME 
    ;

write: WRITE expr
    ;

condexpr: bop "(" expr "," expr ")"
    ;                     //<condexpr> ::= <bop> ( <exprs> )

bop: LESS                    //<bop> ::= Less | LessEq | Eq | NEq
       |LESSEQ
       |EQ
       |NEQ
    ;


Less: LESS "(" NUMBER "," NUMBER ")"           {if($<NUMBER>3<$<NUMBER>5)$<COND>$=1;} ;

LessEq: LESSEQ "(" NUMBER "," NUMBER ")"     {if($<NUMBER>3<=$<NUMBER>5)$<COND>$=1;} ;

Eq: EQ "(" NUMBER "," NUMBER ")"             {if($<NUMBER>3=$<NUMBER>5)$<COND>$=1;} ;

NEq: NEQ "(" NUMBER "," NUMBER ")"          {if($<NUMBER>3!=$<NUMBER>5)$<COND>$=1;} ;




exprs: expr                   //<expr> [,<exprs>]
           |expr "," exprs 
    ;


expr: NAME
     |NUMBER
         |NAME "(" exprs ")"               //<name>[( <exprs> )]   |   <number> 
    ;

/***************idk if we need this. dunno which file to describe these operations in ***********************/

Plus: PLUS "(" NUMBER "," NUMBER ")"       {$<NUMBER>$=$3+$5; } ;        //S1=plus  $2=(  $3=expr  $4=   $5=expr   $6=)
Minus: MINUS "(" NUMBER "," NUMBER ")"   {$<NUMBER>$=$3-$5; } ;
Times: TIMES "(" NUMBER "," NUMBER ")"   {$<NUMBER>$=$3*$5; } ;
Divide: DIVIDE "(" NUMBER "," NUMBER ")" {$<NUMBER>$=$3/$5; } ;

%%

//c code

/*
int main(int c, char * * argv) {

        if ((yyin = fopen(argv[1], "r")) == NULL) {

                printf("can't open %s\n", argv[1]);

                exit(0);

        }
        symb = yylex();
        yyparse();
       // program(1);

        fclose(yyin);

}
*/
int main (char * * argv)
{
  if ((yyin = fopen(argv[1], "r")) == NULL) {

                printf("can't open %s\n", argv[1]);

                exit(0);
}
 yylex();
}

void yyerror(const char *s)
{
  extern int yylineno;  // defined and maintained in lex.c
  extern char *yytext;  // defined and maintained in lex.c

  /*std::cerr << "ERROR: " << s << " at symbol \"" << yytext;
  std::cerr << "\" on line " << yylineno << std::endl;
  exit(1);*/
printf("parse error  Message: ", s);
fflush(1);
exit(-1);
}

/*int yyerror(char *s)
{
  return yyerror(string(s));
}*/

1 个答案:

答案 0 :(得分:1)

你的词汇定义有各种错误;由于缺乏有关问题的详细信息,我不知道他们中任何一个人在多大程度上对您的问题做出了贡献,所以我只会列出它们:

  1. 使用野牛头文件;不要替换你自己的。

    %{
    #include "tokens.h"
    //#include "y.tab.h"
    %}
    

    bison生成的头文件包含YYSTYPE的定义,解析器和扫描器必须同意此定义。它还包含各种标记的正确定义,在两个文件中也必须相同。你没有显示token.h的内容,但它的使用没有任何信心;如果你这样做是为了掩盖其他一些问题,修复另一个问题,然后继续。

  2. 不要替换非标准的EOF处理

    <<EOF>> {return EOF;}
    

    词法分析器和扫描器之间的协议是词法分析器将返回令牌ID 0以表示输入结束。 EOF的值通常为-1,这不是有效的标记号(标记号是非负整数,并且生成的解析器将无法正确处理。默认情况下, (f)lex插入一个适当的默认文件结束规则,它做了正确的事情,你应该依赖这种行为。

  3. 如果你不需要yywrap,请告诉flex不要依赖它。

    一个好习惯是将以下定义放在(f)lex定义的序言中:

    %option noyywrap noinput nounput nodefault
    

    (除非您需要其中一个功能,并且您应该知道需要哪些功能。)noyywrap选项会从生成的词法分析器中删除调用yywrap的代码,以便词法分析器立即返回当它从输入流遇到EOF时输入指示的结束。 noinputnounput删除了input()unput()函数的定义,如果您的词法分析器操作未使用它们,则会导致编译器警告。 (顺便说一句,你编译时启用了编译器警告,对吧?不启用编译器警告是一种很好的方法,可以忽略你自己在脚下射击的事实。)

    nodefault选项为无法识别的输入字符删除(f)lex生成的默认规则,并警告您是否可能无法识别某些输入字符。 (这不会影响默认的<<EOF>>操作。无法识别的输入上的默认flex操作是ECHO,这意味着无法识别的字符将被简单地发送到标准输出而不会生成任何类型的错误消息。 (几乎)从来不是你想要的,也可以用来掩盖真正的错误。

    如果您使用yywrap,则表示输入结束的常规返回值为1(&#34; true&#34;),而不是EOF,尽管{{1}将会有效。

  4. 如果解析器需要语义值,则需要提供一个。

    在您的解析器中,您声称EOF令牌的语义值类型为NAME。 (重复使用令牌名称作为标记名非常不明智;您应该修复它。)但是,返回NAME令牌的flex操作不会填充语义值。最可能的结果是解析器在期望有效NAME时会收到NULL,这肯定会导致段错误。

  5. 您的解析器定义也存在一些问题,应予以纠正。首先是我在上面提到的char*声明中的标记名。其次,您不需要在解析器代码中%union,因为它的内容已经插入。

    解析器代码中最令人困惑的部分是在整个语法中使用命名类型语法#include "y.tab.h"不要这样做。您应该正确地声明所有令牌和非终端的正确类型:

    $<tag>1

    (假设有一组更标准的标记名。)如果提供显式标记名,生成的解析器将使用该标记名,从而绕过类型安全检查。 (而且,显然,如果你绕过类型安全检查,在规则中使用错误的工会成员会更容易,导致谁知道后果是什么)