如何编写flex和bison文件来解析这种语言?

如何编写flex和bison文件来解析这种语言?,bison,yacc,lex,Bison,Yacc,Lex,让我们定义一种语言: VAR := [0-9A-Za-z_]+ Exp := VAR | VAR,'=',VAR | '(', Exp, ')' | Exp, '&', Exp | Exp ,'|', Exp 例如:“(a=b)和(c|(d=e))是合法的 我已经阅读了YASS&Lex手册,但我完全搞不懂,我只想要能够解析这种语言的编译器 你能告诉我如何为这种语言编写flex&bison配置文件吗 到目前为止,我已经做到了: 文件a.l: %

让我们定义一种语言:

VAR := [0-9A-Za-z_]+
Exp := VAR 
   | VAR,'=',VAR 
   | '(', Exp, ')'
   | Exp, '&', Exp 
   | Exp ,'|', Exp       
例如:“(a=b)和(c|(d=e))是合法的

我已经阅读了YASS&Lex手册,但我完全搞不懂,我只想要能够解析这种语言的编译器
你能告诉我如何为这种语言编写flex&bison配置文件吗

到目前为止,我已经做到了:

文件a.l:

%{

#include <string.h>
#include "stdlib.h"
#include "stdio.h"
#include "y.tab.h"

%}

%%

("&"|"and"|"AND")   { return AND; }
("|"|"or"|"OR")   { return OR; }
("="|"eq"|"EQ")   { return EQ; }
([A-Za-z0-9_]+)   { return VAR;}
("(")   { return LB ;}
(")")   { return RB ;}
("\n")   { return LN ;}



%%

int main(void)
{
 yyparse();
 return 0;
}

int yywrap(void)
{
 return 0;
}

int yyerror(void)
{
  printf("Error\n");
  exit(1);
}

那么,为什么函数printf输出为null?输入第二个后,它会提示出错并退出程序?

首先编写一个lex文件来标记输入(并打印出它看到的内容)

您想介绍以下终端:

  • [0-9A-Za-zè]+-->VAR
  • (->LPAREN
    )-->RPAREN
  • &-->和
  • |-->或
  • =-->EQUAL
只需为每个人打印一个单词。以你为例

( a = b ) & ( c | (d=e) ) --> LPAREN VAR EQUAL VAR RPAREN AND LPAREN VAR OR LPAREN VAR EQUAL VAR RPAREN RPAREN
这在纯莱克斯是可行的。当您这样做时,更新您的响应,我们就可以讨论下一步了。

您的lex规则
(“[0-9A-Za-z+”)
将匹配(仅)文本字符串
[0-9A-Za-z+
——去掉
字符,使其成为匹配任何标识符或数字的模式

您的yacc代码与标点符号的lex代码不匹配——lex代码返回
,而yacc代码预期的是
——因此,要么将lex代码更改为返回
,要么将yacc代码更改为使用标记
,同样,对于
,和
。您可能还希望忽略lex代码中的空格(而不是将其视为错误)。您也没有lex规则可匹配并返回
“\n”
,即使您在yacc语法中使用了该规则

你的yacc代码在其他方面是正确的,但是是不明确的,因此会使你移位/减少冲突。这是因为你的语法是不明确的,
a&b|c
这样的输入可以被解析为
(a&b)| c
a&(b | c)
。您需要决定如何解决这种歧义,并在语法中反映出来——或者使用更多的非终结符,或者使用yacc内置的优先级支持来解决这种歧义。如果坚持声明:

%left '|'
%left '&'
在yacc文件的顶部,这将通过使
&
左关联和
&
高于
的优先级来解决歧义,这将是正常的解释

编辑

现在的问题是,您从未在.y文件中定义YYSTYPE(直接或使用%union),也从未在.l文件中设置yylval。第一个问题意味着
$1
等只是
int
s,而不是指针(因此,尝试使用
%s
打印它们是没有意义的——您应该从C编译器那里得到一个警告)。第二个问题意味着它们无论如何都没有值,所以它始终是未初始化全局变量的默认0值

最简单的修复方法是添加

%union {
    const char *name;
}
%token <name> VAR LB RB LN
%left <name> AND OR
%left <name> EQ
%type <name> expr
最后,您还需要将expr的bison操作更改为设置
$$
,例如:

|  LB exp RB      { asprintf(&$$, "%s %s %s",$1,$2,$3);  printf("abstract: %s\n", $$); }
这至少会起作用,尽管它会为分配的字符串泄漏大量内存

最后一个问题是,您的
规则只匹配一行,因此第二行输入会导致错误。您需要一个递归规则,如:

line: /* empty */
    | line exp LN { printf....

向我们展示您尝试过的内容。我会在回复中给出一些提示,但您确实应该先展示您尝试过的内容谢谢您,正如您所说,我编辑了.l和.y文件,但是出现了新问题,请参见上面的描述
([A-Za-z0-9_]+)   { yylval.name = strdup(yytext); return VAR;}
|  LB exp RB      { asprintf(&$$, "%s %s %s",$1,$2,$3);  printf("abstract: %s\n", $$); }
line: /* empty */
    | line exp LN { printf....