2012-06-26 64 views
2

我一直在努力尋找無處不在的例子,但它是徒勞的。野牛的語義類型檢查分析

我想寫一個基本的Ruby解釋器。爲此,我編寫了一個包含令牌識別語句的flex詞法文件和一個語法文件。

我希望我的語法包含語義類型檢查。

我的語法文件包含,例如:

arg : arg '+' arg 

這應該是整數和浮點數的有效規則。

據我讀過,我可以爲一個非終端如精氨酸指定類型,就像這樣:

%type <intval> arg 

其中「INTVAL」是在類型工會和對應於INT C類。

但是,這只是整數,我不知道如何使規則有效,例如,浮動。 我想到了有兩個不同的規則,一個是整數,一個用於花車,如:

argint : argint '+' argint 
argfloat : argfloat '+' argfloat 

,但我相信有這樣做的很多很多更好的辦法,因爲這種暴行需要我有規則允許在浮動和整數之間添加。

我發現的所有例子都只有一種類型(通常是類似計算器的例子中的整數)。

我該如何實現指定像添加這樣的規則可以有整數和浮點數作爲參數?

非常感謝。

+0

你誤解%類型的目的。它可以控制你自己的語法終端和非終端的類型,在YYUNION中使用,所以你不必爲你的$$,$ 1等編寫類型轉換:不允許你控制語義類型在你解析的程序中。 – EJP

回答

4

這不是你希望的答案。我認爲你沒有看到你想要的例子的原因是在語法文件(.y)中強制輸入規則是不切實際的;相反,開發人員在程序化的.c或.cpp代碼中完成此操作。一般來說,無論如何你都要對分析過的輸入進行一些分析,所以這樣做是強制執行語義規則的副產品。

另外,由於您在問題中重現的語法片段,我不太瞭解如何解析表達式。

這就是爲什麼我聲稱這是不切實際的。 (1)你的類型信息必須滲透到語法的非終端。 (2)更糟的是,它必須反映在變量名稱中。

考慮這個玩具的解析簡單賦值語句的例子,它可以使用標識符,數字常量和四個桌面計算器操作符。 NUMBER標記可以是像42這樣的整數或像3.14這樣的浮點數。假設一個IDENTIFIER是一個字母,A-Z。

%token IDENTIFIER NUMBER 

%% 

stmt : IDENTIFIER '=' expr 
    ; 

expr : expr '+' term 
    | expr '-' term 
    | term 
    ; 

term : term '*' factor 
    | term '/' factor 
    | factor 
    ; 

factor : '(' expr ')' 
     | '-' factor 
     | NUMBER 
     | IDENTIFIER 
     ; 

現在讓我們試着介紹打字規則。我們將NUMBER標記分隔爲FLT_NUMBER和INT_NUMBER。我們exprtermfactor非終端分成兩個還有:

%token IDENTIFIER FLT_NUMBER INT_NUMBER 

stmt : IDENTIFIER '=' int_expr 
    | IDENTIFIER '=' flt_expr 
    ; 

int_expr : int_expr '+' int_term 
     | int_expr '-' int_term 
     | int_term 
     ; 

flt_expr : flt_expr '+' flt_term 
     | flt_expr '-' flt_term 
     | flt_term 
     ; 

int_term : int_term '*' int_factor 
     | int_term '/' int_factor 
     | int_factor 
     ; 

flt_term : flt_term '*' flt_factor 
     | flt_term '/' flt_factor 
     | flt_factor 
     ; 

int_factor : '(' int_expr ')' 
      | '-' int_factor 
      | INT_NUMBER 
      | int_identifier 
      ; 

flt_factor : '(' flt_expr ')' 
      | '-' flt_factor 
      | FLT_NUMBER 
      | flt_identifier 
      ; 

int_identifier : IDENTIFIER ; 

flt_identifier : IDENTIFIER ; 

由於我們的語法矗立在這一點上,有一個矛盾:解析器無法分辨是否承認一個標識符作爲int_identifier或一個flt_identifier。所以它不知道是否減少A = BIDENTIFIER = int_exprIDENTIFIER = flt_expr

(這裏就是我的紅寶石的理解是有點軟:)紅寶石(最喜歡的語言)並沒有提供在詞彙層面的方式確定數值類型的標識符。將這與BASIC老派對比,其中A表示數字,A $表示字符串。換句話說,如果你發明了一種語言,比如說A#表示一個整數,A @表示一個浮點數,那麼你就可以完成這項工作。

如果你想允許有限的混合類型表達式,像int_term '*' flt_factor,那麼你的語法會得到更加複雜。

可能會有方法來解決這些問題。用yacc/bison以外的技術構建的解析器可能會使它更容易。至少,也許我的素描會給你一些想法來進一步追求。

+0

很好的答案。在語法中構建類型語義的想法在Algol-68項目中得到了全面的推廣,當時是在20世紀60年代。現在普遍認爲這是不可行的。 – EJP

+0

是的,這就是我最後做,到了最後,我還沒有決定如何檢查返回函數的類型,但是這基本上是我的結論,謝謝! –

+0

這是[Wadler定律(http://www.haskell.org/haskellwiki/Wadlers_Law)......但是,即使直到今天,只有一種語言的語法代碼正式它仍然是一個有點難過(通過BNF)而不是語義(通過vWG)。 – NevilleDNZ