如何使用Bison打印解析树



我已经实现了一个解析器,但它不打印任何内容。如果给定的输入在语法上是错误的,它不会打印"错误",尽管我将其包含在yyerror()例程中。此外,如果输入正确,则不会打印解析树。可能的原因是什么?我已将我的main()放在.lex文件中,而不是放在.y文件中。这可能是原因吗?这是主要的方法:

int main( argc, argv )
int argc;
char **argv;
{
    ++argv, --argc; 
    if ( argc > 0 )
    yyin = fopen( argv[0], "r" );
    else
    yyin = stdin;     
    yyparse();
}

语法文件为:

%{
#include "parser.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
%}
%union {
  char* a_variable;
  tree* a_tree;
}
%start file
%token <a_variable> TOKID TOKSEMICOLON TOLCOLON TOKCOMMA TOKUNRECOG TOKDOT TOKMINUS TOKCOLON
%type <a_tree> field file obj ID
%right TOKMINUS
%%
file      :     /*empty*/ { return NULL; }
      |     field file { printtree($1, 1);  }
  ;
field     : ID TOKCOLON field {$$ = make_op($1, ':', $3); }
  | ID TOKCOMMA field {$$ = make_op($1, ',', $3); }
  | obj { $$ = $1; }
  ;
obj       :     ID TOKSEMICOLON { $$ = make_op($1, ';', NULL); }
      ;
ID        :     TOKID { $$ = $1; }
%%
#include <stdio.h>
yyerror(char *str)
{
  fprintf(stderr,"error FAIL: %sn",str);
}
int yywrap()
{
  return 1;
}

这就是我的.lex文件的样子:

%{
/* need this for the call to atof() below */
#include <math.h>
#include "parser.h"
#include "idf.tab.h"
%}
DIGIT    [0-9]
ID       [a-zA-Z]*
%option noyywrap
%% 

{ID} |  
-?{DIGIT}+"."{DIGIT}* |    
-?{DIGIT}+      { yylval.a_variable = findname(yytext); return TOKID; }
";"           return TOKSEMICOLON;
":"           return TOKCOLON;
","           return TOKCOMMA;
"."           return TOKDOT;
"-"           return TOKMINUS; 
.           return TOKUNRECOG;
%%
int main( int argc, char** argv )
{
++argv, --argc; 
if ( argc > 0 )
yyin = fopen( argv[0], "r" );
else
yyin = stdin;
yyparse();
}

我不太确定你能不能把多个规则组合成一个这样的规则:

{ID} |  -?{DIGIT}+"."{DIGIT}* |    -?{DIGIT}+      return TOKID;

lex对空格敏感;我认为应该是这样的:

{ID} |
-?{DIGIT}+"."{DIGIT}* |
-?{DIGIT}+      return TOKID;

|字符被解释为一种特殊的动作,意思是"与下一行的动作相同"。在模式中,|表示正则表达式分支。但你有所有这些空间。

你的评论匹配器看起来是假的:

"{"[^{}}n]*"}"     /* eat up one-line comments */   

我想你想要一个否定的字符类,但你在^字符上放了一个转义符,这只会导致^包含在字符类中。

这有什么意义:

"!"+"-"[n] return TOKCOMMENT;

后面跟着-和换行符的!序列是某种注释,您不会忽略它,而是作为标记返回,wha?

这个解析规则无法正常工作,因为lexer:中的行为已损坏

ID        :     TOKID { $$ = $1; }

表达式$1想要访问yystack[<whatever>].a_variable,因为您将TOKID定义为具有a_variable语义类型。但是生成TOKID的lex规则不会向a_variable中放入任何内容。它只执行return TOKID;,让指针包含垃圾。lexer规则必须分配给yylval.a_variable

Lex和Yacc远没有你想象的那么自动化。

函数yylex()是词法扫描器,而不是语法分析器;解析器是CCD_ 20。因此,更新您的程序以调用yyparse()而不是yylex(),让yyparse()在需要新令牌时调用yylex()
while (yyparse() != 0)
    ;

您可以打印解析树来代替空循环体,也可以在从语法本身的开始规则调用的函数中打印。

顺便说一句,我想不出有什么好的理由使用K&main()的R声明。始终使用int main(int argc, char **argv)。如果你使用K&R表示法,则必须从main()返回一个值,通常成功时为零,失败时为零。尽管C99允许您省略main()的最终返回(在main()的唯一非常特殊的情况下,这相当于return 0;),但我建议将其包括在内


后期注释

这是一个好主意,让人们更容易测试你寻求帮助的内容。提供足够的资源使其可编译。删除足够的源代码以最大限度地减少编译工作量。

中和语法中的各种动作功能并不难。parser.h文件需要包含类似typedef struct tree tree;的内容。语法需要是idf.y,这样bison -d idf.y就会生成idf.tab.hidf.tab.c

我对词法分析器做的第一件事是确保它打印出它正在做的事情。所以,我修改了规则,做了一些事情,比如:

{ID} |  
-?{DIGIT}+"."{DIGIT}* |    
-?{DIGIT}+      { printf("ID or number: %sn", yytext); /*yylval.a_variable = findname(yytext);*/ return TOKID; }
";"           { printf("Semi-colonn"); return TOKSEMICOLON;}
":"           { printf("Colonn"); return TOKCOLON;}

这很快就向我表明,你不会很优雅地处理空格或换行符。你可能需要规则来做到这一点(而这些规则可能不会回到语法中)。

[ t]         { printf("White spacen"); }

当然,这需要出现在"吞噬点"规则之前。

有了这些,我就可以运行程序并获得词法输出:

$ ./idf
abc ;
ID or number: abc
White space
Semi-colon
$

我在上面输入了abc ;,它确定了那些OK。由于语法在操作中没有代码,所以语法本身没有输出。可能值得使用-DYYDEBUG进行编译,并在main()函数中设置yydebug = 1;—您可能需要在词法分析器源文件中添加extern int yydebug;,因为main()已经存在。

$ flex scanner.l
$ bison -d idf.y
$ gcc -DYYDEBUG -o idf idf.tab.c lex.yy.c
$ ./idf
Starting parse
Entering state 0
Reading a token: abc ;
ID or number: abc
Next token is token TOKID ()
Shifting token TOKID ()
Entering state 1
Reducing stack by rule 7 (line 32):
   $1 = token TOKID ()
-> $$ = nterm ID ()
Stack now 0
Entering state 5
Reading a token: White space
Semi-colon
Next token is token TOKSEMICOLON ()
Shifting token TOKSEMICOLON ()
Entering state 8
Reducing stack by rule 6 (line 29):
   $1 = nterm ID ()
   $2 = token TOKSEMICOLON ()
-> $$ = nterm obj ()
Stack now 0
Entering state 4
Reducing stack by rule 5 (line 26):
   $1 = nterm obj ()
-> $$ = nterm field ()
Stack now 0
Entering state 3
Reading a token: 
Now at end of input.
Reducing stack by rule 1 (line 20):
$

现在,您的问题出现在尚未显示的函数中。这些都是你要解决的。

相关内容

  • 没有找到相关文章

最新更新