2012-12-01 57 views
4

我正在使用C/C++編寫一個簡單的計算器Bison & Flex(該邏輯在Bison中完成,C/C++部分負責數據結構,例如STL等)。在Bison中爲&&和||啓動短路規則操作

我有以下問題:

在我的計算器美元符號$意味着我++和++我(前綴和後綴),例如:

int y = 3; 
-> $y = 4 
-> y$ = 4 

當用戶點擊:int_expression1 && int_expression2,如果int_expression1進行評估,以0(即假),那麼我不wan't野牛評估int_expression2

例如:

int a = 0 ; 
int x = 2 ; 

和用戶點擊:int z = a&&x$ ...

因此,可變a評估爲0,因此,我不想評價x,但它仍以1增加到......這裏是野牛的代碼/ C++:

%union 
{ 
    int int_value; 
    double double_value; 
    char* string_value; 
} 

%type <int_value> int_expr 
%type <double_value> double_expr 
%type <double_value> cmp_expr 

int_expr: 

    | int_expr '&&' int_expr { /* And operation between two integers */ 
         if ($1 == 0) 
         $$ = 0; 
         else // calc 
         $$ = $1 && $3;   
        } 

我怎麼能告訴野牛不評估第二個表達式,如果第一個表達式已經被評估爲假(即, 0)?

+0

我不明白最後的codelines句子可以將它們翻譯成C嗎? –

+0

@AlbertoBonsanto:它們在'Bison'中,意思是'$$'是整條線的結果。'$ 1'代表左邊的'int_expr','$ 3'代表右邊的'int_expr' ... – ron

+0

我重複了這個;因爲它與Adobe/Apache框架無關。 gnu-flex和/或lex通常用於詞法分析器。 – JeffryHouser

回答

2

轉換廣泛評論爲一個答案:

我怎麼能告訴野牛不計算第二個表達式,如果第一個是已經評估,以虛假的?

這是你的代碼,而不是評估,而不是Bison;把'責任'放在它所屬的地方。

您需要在RHS評估之前檢測到您正在處理&&規則。如果第一個int_expr的計算結果爲0,您可能需要在&&之後插入一些代碼,第二個int_expr暫停評估。您還需要修改所有其他評估代碼,以檢查並遵守「不要評估'旗幟。

或者,你有野牛做解析,並創建一個程序,當解析完成時執行,而不是當你解析時進行評估。這是一組更大的變化。

你確定要在第二個int_expr之前加入一些代碼嗎?我似乎無法找到一個合理的方法來做到這一點。這是一個很好的訣竅,但我找不到一種方法可以告訴Bison不要評估第二個int_expr,而不會破壞整個評估。

你必須編寫你的代碼,以便它不會評估它不應該評估的時間。野牛語法是:

| int_expr '&&' {...code 1...} int_expr {...code 2...} 

「代碼1」將檢查$1並安排停止評估(設置一個全局變量或類似的東西)。 '代碼2'將有條件地評估$4(4因爲'代碼1'現在是3美元)。所有評估代碼必須遵守'代碼1'的規定 - 它不能評估'代碼1'是否表示'不評估'。或者你可以做我建議的和asellesuggested;分別解析和評估。

我是第二個關於The UNIX Programming Environment的建議。關於開發一款計算器(他們稱之爲高階計算器的hoc)有一整章,值得一讀。不過請注意,這本書是在1984年出版的,並在C標準之前做了一個很好的預測。 C代碼中沒有原型,並且(按照現代標準)它需要一些自由度。我有hoc6(他們描述的hoc的最後一個版本;也有1-3版本),如果你想要的話(請參閱我的個人資料)。

這就是問題所在:我不能停止在規則的中間評價,因爲我不能使用return(我可以,但沒有用的,它會導致程序退出)。 | intExpr '&&' { if ($1 == 0) {/* turn off a flag */ } } intExpr { /* code */}我退出$3後,$4正在自動評估。

您可以在規則中間停止評估,但必須對錶達式評估代碼塊進行編碼以考慮可能性。當我說'停止評估'時,我的意思是'停止計算',而不是'停止解析器'。解析必須繼續;您的計算值的代碼只能在評估需要時評估,而不需要評估。這可能是一個(呃!)全局標誌,或者你可能有其他一些機制。

最好將解析器轉換爲代碼生成器,並在解析完代碼後執行代碼。這種複雜性就是爲什麼這是一個好策略。

@JonathanLeffler:你確實是國王!這應該是一個答案!

現在它是一個答案。

1

你幾乎可以肯定地想要在你的計算器評估之前生成一些其他表示。解析樹或ast是經典的方法,但是一個簡單的堆棧機也很流行。有很多很好的例子,但我最喜歡的是 http://www.amazon.com/Unix-Programming-Environment-Prentice-Hall-Software/dp/013937681X 這說明了如何使用一個簡單的直接評估工具,就像你在yacc(老bison)中所做的一樣,並且一直使用一種編程語言幾乎和BASIC一樣強大。所有內容都非常少。這本書很古老,但值得一讀。

你也可以看看SeExpr http://www.disneyanimation.com/technology/seexpr.html 這是一個簡單的表達式語言計算器的標量和3個向量。如果你看一下https://github.com/wdas/SeExpr/blob/master/src/SeExpr/SeExprNode.cpp 行313你會看到& &實現他的eval()函數:

void 
SeExprAndNode::eval(SeVec3d& result) const 
{ 
    // operands and result must be scalar 
    SeVec3d a, b; 
    child(0)->eval(a); 
    if (!a[0]) { 
    result[0] = 0; 
    } else { 
    child(1)->eval(b); 
    result[0] = (b[0] != 0.0); 
    } 
} 

該文件包含了解析樹表示操作的所有對象。這些對象是在解析代碼時生成的(這些是yacc中的操作)。希望這可以幫助。