2010-02-24 22 views
1

我想在使用C作爲輸出語言的C++項目中使用ANTLR v3.2生成的分析器。理論上,生成的解析器可以編譯爲C++,但是在處理解析器操作中的C++類型時遇到問題。下面是一個C++頭文件中定義了幾個類型的,我想在解析器使用方法:在ANTLR生成的C語法分析器中使用C++類型

/* expr.h */ 
enum Kind { 
    PLUS, 
    MINUS 
}; 

class Expr { // stub 
}; 

class ExprFactory { 
public: 
    Expr mkExpr(Kind kind, Expr op1, Expr op2); 
    Expr mkInt(std::string n); 
}; 

而且這裏有一個簡單的分析器定義:

/* Expr.g */ 
grammar Expr; 

options { 
    language = 'C'; 
} 

@parser::includes { 
    #include "expr.h" 
} 

@members { 
    ExprFactory *exprFactory; 
} 

start returns [Expr expr] 
    : e = expression EOF { $expr = e; } 
    ; 

expression returns [Expr e] 
    : TOK_LPAREN k=builtinOp op1=expression op2=expression TOK_RPAREN 
    { e = exprFactory->mkExpr(k,op1,op2); } 
    | INTEGER { e = exprFactory->mkInt((char*)$INTEGER.text->chars); } 
    ; 

builtinOp returns [Kind kind] 
    : TOK_PLUS { kind = PLUS; } 
    | TOK_MINUS { kind = MINUS; } 
    ; 

TOK_PLUS : '+'; 
TOK_MINUS : '-'; 
TOK_LPAREN : '('; 
TOK_RPAREN : ')'; 
INTEGER : ('0'..'9')+; 

語法通過ANTLR運行良好。當我嘗試編譯ExprParser.c,我得到這樣的錯誤

  1. conversion from ‘long int’ to non-scalar type ‘Expr’ requested
  2. no match for ‘operator=’ in ‘e = 0l’
  3. invalid conversion from ‘long int’ to ‘Kind’

在每種情況下,語句爲ExprKind值來初始化NULL

我可以通過將所有內容更改爲Expr*來解決Expr的問題。這是可行的,雖然很不理想。但是傳遞一個簡單枚舉類似Kind的指針似乎很荒謬。我發現的一個醜陋的解決方法是創建第二個返回值,該值將Kind值推入結構中,並將初始化設置爲NULL。即,builtinOp成爲

builtinOp returns [Kind kind, bool dummy] 
    : TOK_PLUS { $kind = PLUS; } 
    | TOK_MINUS { $kind = MINUS; } 
    ; 

和第一expression替代成爲

TOK_LPAREN k=builtinOp op1=expression op2=expression TOK_RPAREN 
    { e = exprFactory->mkExpr(k.kind,*op1,*op2); } 

必須有一個更好的方式來做事?我錯過了C語言後端的配置選項嗎?有沒有另一種方法來安排我的語法來避免這種尷尬?是否有我可以使用的純C++後端?

+0

對於那些正在計劃回答的人,您可以首先查看http://www.antlr.org/pipermail/antlr-interest/2010-February/037764.html,看它是否已經提交給Chris。 – 2010-02-24 21:42:50

+0

我相信我不知道爲什麼在另一個論壇上要求得到一個讚譽。我很樂意在此提出/接受任何有用的答案。 – 2010-02-24 23:50:19

+0

我會這樣說,如果它是我的。雖然我曾經考慮過低調,但我沒有提出你的問題,因爲你的問題是非常好的:細節層次高,問題明確等。但是,我*明白downvote:在多個論壇中提問**而不提這個在其中任何一個**是國際海事組織不好的做法。我的意思是,爲什麼不直接在這裏發佈一個鏈接到ANTLR郵件列表上的帖子?這樣,其他人就可以看到已經回答了什麼,並且不用花時間複製在這裏已經在其他地方建議的(精心製作的)答案。 – 2010-02-25 06:51:23

回答

3

下面是我發現這個問題的解決方案。問題的關鍵是ANTLR想要初始化所有的返回值和屬性。對於非原始類型,ANTLR只是假定它可以用NULL進行初始化。因此,舉例來說,上面的expression規則將被翻譯成類似

static Expr 
expression(pExprParser ctx) 
{ 
    Expr e = NULL; // Declare and init return value 
    Kind k; // declare attributes 
    Expr op1, op2; 
    k = NULL; // init attributes 
    op1 = NULL; 
    op2 = NULL; 
    ... 
} 

的選擇,因爲我看到他們,是這些:

  1. 給的值的基本類型,可以合法地進行初始化到NULL。例如,使用Expr*Kind*而不是ExprKind

  2. 如上所述,使用「虛擬」技巧將值推入不會被初始化的結構中。

  3. 使用參考參數代替返回值。例如,

    builtinOp[Kind& kind] 
        : TOK_PLUS { kind = PLUS; } 
        | TOK_MINUS { kind = MINUS; } 
        ; 
    
  4. 增廣作爲值類型的操作,使上述聲明和初始化法律類。即,爲Expr返回值,你需要一個構造函數,可以採取NULL

    Expr(long int n); 
    

    對於Expr屬性,你需要一個無參數的構造和operator=,可以採取NULL

    Expr(); 
    Expr operator=(long int n); 
    

我知道這很哈克,但我暫時與#4一起去。恰巧我的Expr類對這些操作有相當自然的定義。

P.S. On the ANTLR list,C後端的維護者提示說這個問題可能在未來的版本中得到解決。