在以下 lex/yacc 个文件中收到分段错误(核心已转储)。他们怎么了?

Receiving Segmentation fault (core dumped) in the following lex/yacc files. What is wrong with them?

我遇到以下代码的分段错误(核心已转储):

lex文件如下, test.l :

    %{

    #include "y.tab.h"

    #define LOOKUP 0

    int state;

    int add_word(int type, char *word);
    int lookup_word(char *word);
    %}

    %%

    \n {state = LOOKUP;}
    \.\n {state = LOOKUP;
            return 0;
        }

    ^verb {state = VERB;}
    ^adj {state = ADJECTIVE;}
    ^adv {state = ADVERB;}
    ^noun {state = NOUN;}
    ^prep {state = PREPOSITION;}
    ^pron {state = PRONOUN;}
    ^conj {state = CONJUNCTION;}

    [a-zA-Z]+ {
                if(state != LOOKUP){
                    add_word(state, yytext);
                }else{
                    switch(lookup_word(yytext)){
                        case VERB: return(VERB);
                        case ADJECTIVE: return(ADJECTIVE);
                        case ADVERB: return(ADVERB);
                        case NOUN: return(NOUN);
                        case PREPOSITION: return(PREPOSITION);
                        case PRONOUN: return(PRONOUN);
                        case CONJUNCTION: return(CONJUNCTION);
                        default:
                            printf("%s: don't recog\n",yytext);
                    }
                }
                }
    . ;

    %%
    struct word{
        char *word_name;
        int word_type;
        struct word *next;
    };

    struct word *word_list;

    extern void *malloc();

    int add_word(int type, char *word){
        struct word *wp;
        if(lookup_word(word) != LOOKUP){
            printf("word %s already defined\n", word);
            return 0;
        }

        wp = (struct word *) malloc(sizeof(struct word));

        wp-> next = word_list;

        wp-> word_name = (char*) malloc(strlen(word)+1);
        strcpy(wp->word_name, word);
        wp->word_type = type;
        word_list = wp;
        return 1;
    }

    int lookup_word(char *word){
        struct word *wp = word_list;

        for(; wp; wp = wp->next){
        if(strcmp(wp->word_name, word) == 0)
            return wp->word_type;
        }
        return LOOKUP;
    }

yacc文件如下,

test.y:

%{

#include <stdio.h>

%}

%token NOUN PRONOUN VERB ADVERB ADJECTIVE PREPOSITION CONJUNCTION

%%
sentence: subject VERB object {printf("sentence is valid\n");}
        ;

subject: NOUN
        | PRONOUN
        ;
object: NOUN
        ;

%%

extern FILE *yyin;

main(){ 
    while(!feof(yyin)){
        yyparse();
    }
}

yyerror(s)
{
    fprintf(stderr, "some error\n");
}

我已经尝试了几个小时来找出问题所在。我对这些完全陌生,并且正在阅读这本书 "O'reilly - Lex and Yacc"。

(f)lex生成的扫描器,负责执行输入的组件,将yyinyyout分别初始化为stdinstdout ,在其初始化功能期间。在此之前,由于C的静态初始化规则(即全局指针变量被初始化为NULL),它们都是NULL指针。

第一次调用时调用初始化函数yylex。 (它设置了一个标志,以便下一次调用 yylex 不会再次进行初始化。这是初始化库系统的一种非常典型的方法;大多数 malloc 实现和 C stdio 函数做同样的事情。)

yylexyyparse 重复调用,所以第一次调用 yyparse 隐式初始化 yylex。但是当你写:

main(){ 
  while(!feof(yyin)){
    yyparse();
  }
}

yyin 的首次使用发生在它被初始化之前。因此,第一次评估 while 条件时,yyin 仍然是 NULL,因此没有第二次;由此产生的段错误是致命的。

您可以通过自己初始化 yyin 来解决这个问题,但是由于 while (!feof(file)) 总是错误的 (sm),所以将在循环的 end 处进行 EOF 测试:

int main(){ 
  do yyparse(); while (!feof(yyin));
}

参见this very helpful SO answer问题为什么“while ( !feof (file) )”总是错误的?进行详细分析。