2011-10-10 39 views
0

让我们定义一个语言:如何编写解析这种语言的flex和bison文件?

VAR := [0-9A-Za-z_]+ 
Exp := VAR 
    | VAR,'=',VAR 
    | '(', Exp, ')' 
    | Exp, '&', Exp 
    | Exp ,'|', Exp  

如: “(A = B)&(C |(d = E))” 是法律

我读过云南省社会科学院&莱克斯手册,但我完全困惑,我只是想要解析这种语言的编译器
你能告诉我如何编写这种语言的flex & bison配置文件吗?

我迄今所做的:

文件人:

%{ 

#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); 
} 

文件唉

%{ 
#include <stdio.h> 
%} 

%token AND OR EQ VAR LB RB LN 

%left AND OR 
%left EQ 

%% 

line : 
     | exp LN{ printf("LN: %s",$1);} 
; 

exp: VAR    { printf("var:%s",$1);} 
    | VAR EQ VAR  { printf("var=:%s %s %s",$1,$2,$3);} 
    | exp AND exp  { printf("and :%s %s %s",$1,$2,$3);} 
    | exp OR exp  { printf("or :%s %s %s",$1,$2,$3);} 
    | LB exp RB  { printf("abstract :%s %s %s",$1,$2,$3);}  

    ; 

现在我编辑过的文件作为多德引导,似乎要好得多(至少lex工作正常),但我得到这样的输出:

disk_path>myprogram 
a=b 
var=:(null) (null) (null)LN: (null)ab=b 
Error 

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

+2

向我们展示你的尝试。我会在回复中给出一些提示,但你真的应该先显示你尝试的第一个 –

回答

1

首先写的lex文件来标记输入(并打印出它认为)

您要为大家介绍的终端:

  • [0-9A-Za-z_]+ --> VAR
  • (--> LPAREN) --> RPAREN
  • & --> AND
  • | --> OR
  • = --> EQUAL

只是打印出每个字。对于你的例子

(a = b) & (c | (d=e)) --> LPAREN VAR EQUAL VAR RPAREN AND LPAREN VAR OR LPAREN VAR EQUAL VAR RPAREN RPAREN 

这是纯粹的法律可行。当你这样做,更新您回应,我们可以谈论下一步

+0

谢谢,我已经完成了,如何编写yacc文件? –

1

你的lex规则("[0-9A-Za-z_]+")会(只)匹配的文本字符串[0-9A-Za-z_]+ - 摆脱"人物有它是匹配任何一个模式标识符或编号。

你的yacc代码不匹配标点符号你的代码法 - 该法码&返回AND而YACC代码期待一个& - 所以要么改法代码返回'&'或改变YACC代码使用代币AND,以及类似的|,()。您可能还想忽略lex代码中的空格(而不是将它们视为错误)。即使您在yacc语法中使用该规则,也没有lex规则来匹配并返回'\n'

你的yacc代码,否则正确的,但不明确,从而给你转移/减少冲突。这是因为你的语法不明确 - 像a&b|c这样的输入可以被解析为(a&b)|ca&(b|c)。您需要决定如何解决歧义问题,并在语法中反映 - 通过使用更多的非终端,或者通过使用yacc的内置优先级支持来解决这种模糊性。如果你坚持的声明:

%left '|' 
%left '&' 
在YACC文件的顶部

,这将有两个工作&|左结合,并&优先级高于|,这将是正常的解释化解歧义。

编辑

你现在的问题是,你永远不会在你的.Y文件中定义YYSTYPE(直接或工会%)与您从未设置的yylval在.L文件。第一个问题意味着$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 

添加到YACC文件的顶部。然后改变所有的lex规则是这样的

([A-Za-z0-9_]+) { yylval.name = strdup(yytext); return VAR;} 

最后,您还需要改变野牛行动expr的设置$$,如:

| LB exp RB  { asprintf(&$$, "%s %s %s",$1,$2,$3); printf("abstract: %s\n", $$); } 

这将至少工作,虽然它会泄漏分配的字符串的大量内存。

你的最后一个问题是,您line规则只匹配单个行,所以输入的第二行导致错误。你需要一个递归规则,如:

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

谢谢你,我按照你的说法编辑了.l和.y文件,但是新的问题出现了,请看上面的描述 –