2011-10-10 41 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文件,但是新的問題出現了,請看上面的描述 –