在lex和yacc代码printf无法在yacc文件中工作

时间:2017-05-10 18:53:26

标签: c bison yacc lex lexical-analysis

您好我正试图运行Lex和yacc的John代码由R. Levine运行我已经使用命令在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

然后在yacc中运行语法以检查它是简单句还是复合句 但是当我打字的时候 jam reject knee

它显示在屏幕上注明它应该显示的行"解析一个简单的句子。"解析。代码如下:

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 个答案:

答案 0 :(得分:1)

您有几个问题:

  1. 您描述的构建详细信息不遵循通常的模式,实际上它们不能用于您提供的代码

  2. 完成了如何构建程序后,根本不起作用,而是在读取任何输入之前进行segfaulting。

  3. 解决了 问题之后,您对该程序在给定输入中的行为的期望至少有两种方式不正确。

  4. 关于构建:

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

      yacc -d example.y

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

      lex example.l

    • 必须将两个生成的C源文件编译并链接在一起,也可能与其他源一起编译,也可能与库一起使用。特别是,如果您的libl确实是GNU libfl,则lex(或flex)链接通常很方便。我将后者链接到默认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是正确的,但在程序初始化时不会发生这种情况,因为yyin不是编译时常量。因此,当控件首次到达循环控制表达式时,yyparse()的值仍然为NULL,并且会产生段错误。

    verb accept,admire,reject noun jam,pillow,knee jam reject knee 返回后测试文件结尾会更安全,更有意义。

    关于行为期望

    你抱怨输入

      constructor(private symbolSearchService: SymbolSearchService) {
        this.symbolSearchForm = new FormControl();
      }
    
      ngOnInit() {
        this.symbolSearchForm.valueChanges.subscribe(
          val => {
            this.symbolSearchService.symbolLookup(val).subscribe(
              val => console.log('val', val)
            )
          }
        )
      }
    

    不会从程序中获得任何输出,但这并不完全正确。当交互式输入时,该输入不会从程序中获得输出,而不会随后发送文件结束信号(即通过在行的开头键入control-D)。

    在这种情况下,解析器还没有检测到文件结束(并且根本没有注意到换行符,因为你的词法分析器只在它们紧跟一段时间后通知它们),它没有理由尝试将其令牌堆栈减少到起始符号。可能是你将继续使用一个对象来扩展简单的句子,并且它不能确定它不会看到下一个CONJUNCTION,eithger。它没有打印任何东西,因为它正在等待更多的输入。如果你用句号结束​​句子或者之后发送一个控制-D那么它实际上会打印出#34;解析一个简单的句子。&#34;