在 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
你有几个问题:
您描述的构建细节不遵循通常的模式,事实上 它们对您提供的代码不起作用。
弄清了如何构建程序后,它根本不起作用,而是在读取任何输入之前出现段错误。
解决了那个问题后,您对给定输入的程序行为的预期至少在两个方面是不正确的。
关于构建:
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."
您好,我正在尝试 运行 来自 R. Levine 的 lex 和 yacc 书中的 John 代码,我已经使用命令
在 linux 中编译了 lex 和 yacc 程序lex example.l
yacc example.y
gcc -o example y.tab.c
./example
程序要求用户以
格式输入动词、名词、介词 e.t.cverb 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
你有几个问题:
您描述的构建细节不遵循通常的模式,事实上 它们对您提供的代码不起作用。
弄清了如何构建程序后,它根本不起作用,而是在读取任何输入之前出现段错误。
解决了那个问题后,您对给定输入的程序行为的预期至少在两个方面是不正确的。
关于构建:
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
真的是 GNUflex
)。我 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."