在 lex 和 yacc 代码中 printf 在 yacc 文件中不起作用

in lex and yacc code printf not working in yacc file

您好,我正在尝试 运行 来自 R. Levine 的 lex 和 yacc 书中的 John 代码,我已经使用命令

在 linux 中编译了 lex 和 yacc 程序
lex example.l
yacc example.y
gcc -o example y.tab.c
./example

程序要求用户以

格式输入动词、名词、介词 e.t.c
verb accept,admire,reject
noun jam,pillow,knee

然后运行s yacc中的语法检查是单句还是复合句 但是当我输入 jam reject knee

它在屏幕上显示了应该在 parsing.The 上显示行 "Parsed a simple sentence." 的注释,代码如下

yacc文件

%{
#include <stdio.h>
/* we found the following required for some yacc implementations. */
/* #define YYSTYPE int */
%}

%token NOUN PRONOUN VERB ADVERB ADJECTIVE PREPOSITION CONJUNCTION

%%

sentence: simple_sentence   { printf("Parsed a simple sentence.\n"); }
    | compound_sentence { printf("Parsed a compound sentence.\n"); }
    ; 

simple_sentence: subject verb object
    |   subject verb object prep_phrase
    ;

compound_sentence: simple_sentence CONJUNCTION simple_sentence
    |   compound_sentence CONJUNCTION simple_sentence
    ;

subject:    NOUN
    |   PRONOUN
    |   ADJECTIVE subject
    ;

verb:       VERB
    |   ADVERB VERB
    |   verb VERB
    ;

object:     NOUN
    |   ADJECTIVE object
    ;

prep_phrase:    PREPOSITION NOUN
    ;

%%

extern FILE *yyin;

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

yyerror(s)
char *s;
{
    fprintf(stderr, "%s\n", s);
}

lex 文件

%{
/*
 * We now build a lexical analyzer to be used by a higher-level parser.
 */

#include "ch1-06y.h"    /* token codes from the parser */

#define LOOKUP 0 /* default - not a defined word type. */

int state; 

%}

%%

\n  { state = LOOKUP; }

\.\n    {   state = LOOKUP;
        return 0; /* end of sentence */
    }

^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 recognize\n", yytext);
          /* don't return, just ignore it */
        }
            }
          }

.   ; 

%%
/* define a linked list of words and types */
struct word {
    char *word_name;
    int word_type;
    struct word *next;
};

struct word *word_list; /* first element in word list */

extern void *malloc();

int
add_word(int type, char *word)
{
    struct word *wp;    

    if(lookup_word(word) != LOOKUP) {
        printf("!!! warning: word %s already defined \n", word);
        return 0;
    }

    /* word not there, allocate a new entry and link it on the list */

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

    wp->next = word_list;

    /* have to copy the word itself as well */

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

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

    /* search down the list looking for the word */
    for(; wp; wp = wp->next) {
        if(strcmp(wp->word_name, word) == 0)
            return wp->word_type;
    }

    return LOOKUP;  /* not found */
}

头文件

# define NOUN 257
# define PRONOUN 258
# define VERB 259
# define ADVERB 260
# define ADJECTIVE 261
# define PREPOSITION 262
# define CONJUNCTION 263

你有几个问题:

  1. 您描述的构建细节不遵循通常的模式,事实上 它们对您提供的代码不起作用

  2. 弄清了如何构建程序后,它根本不起作用,而是在读取任何输入之前出现段错误。

  3. 解决了那个问题后,您对给定输入的程序行为的预期至少在两个方面是不正确的。

关于构建:

  • yacc 为解析器构建 C 源代码,并可选择 header 包含相应标记定义的文件。通常使用选项来获取定义,并在词法分析器的源文件中 #include 它们的 header (#include 'y.tab.h'):

    yacc -d example.y

  • lex 为词法分析器构建 C 源代码。这可以在 yacc 之前或之后完成,因为 lex 不直接依赖于标记定义:

    lex example.l

  • 两个生成的 C 源文件必须一起编译和 linked,可能还有其他源,可能还有库。特别是,在 libl 中 link 通常很方便(或者 libfl 如果你的 lex 真的是 GNU flex)。我 link 编辑后者以获得默认值 yywrap():

    gcc -o example lex.yy.c y.tab.c -lfl

关于段错误:

您生成的程序是围绕此构建的:

extern FILE *yyin;

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

首先,您应该阅读Why is “while ( !feof (file) )” always wrong?。考虑到这一点可能会让您免于犯下更根本的错误:在设置 yyin 之前对其进行评估。尽管 yyin 确实会被设置为 stdin 如果您不将其设置为其他内容,那不会在程序初始化时发生,因为 stdin 不是 compile-time 常量.因此,当控制首先到达循环控制表达式时,yyin 的值仍然为 NULL,并导致段错误。

yyparse() returns.

之后测试文件结尾是安全且更有意义的

关于行为期望

您抱怨输入

verb accept,admire,reject
noun jam,pillow,knee
jam reject knee

不会从程序中引出任何输出,但事实并非如此。当以交互方式输入时,该输入不会从程序 引出输出,之后不发送 end-of-file 信号 (即通过在行首键入 control-D ).

在那种情况下,解析器还没有检测到 end-of-file(并且根本不注意换行符,因为你的词法分析器只有在它们紧跟句点时才会通知它),它没有理由尝试将其令牌堆栈减少到起始符号。可能是您将继续使用 object 来扩展简单句,并且不能确定接下来不会看到连词。它不打印任何东西,因为它正在等待更多输入。如果你用句号结束​​句子或之后发送 control-D 那么它实际上会打印 "Parsed a simple sentence."