2013-08-28 86 views
0

我在野牛(再次)上遇到了一些問題。 我試圖在我的語法文件中使用$$, 傳遞一個「遞歸規則」之間的字符串值,但是當我打印傳遞的值時,輸出看起來像是一個錯誤的引用(AU ),而不是我在輸入文件中寫入的值。在遞歸野牛規則中傳遞字符串值

line: tok1 tok2 
    | tok1 tok2 tok3 
    { 
     int len=0; 
    len = strlen($1) + strlen($3) + 3; 
    char out[len]; 
    strcpy(out,$1); 
    strcat(out," = "); 
     strcat(out,$3); 
     printf("out -> %s;\n",out); 
    $$ = out; 
    } 
    | line tok4 
    { 
     printf("line -> %s\n",$1); 
    } 

這裏我已經報道了代碼的簡化部分。 在輸入令牌tok1 tok2 tok3時,它應該爲$$ out變量賦值(使用printf我可以看到在規則的第一部分out變量具有正確的值)。 順序匹配tok4我在規則的遞歸部分。但是,當我打印$ 1的值(應該等於out,因爲我已經通過$ $$),我沒有正確的輸出。

回答

2

你不能設置:

$$ = out; 

因爲out指字符串就是要儘快成爲泡影,因爲在其被宣佈結束塊。

爲了擺脫這種情況,您需要爲malloc存儲新字符串。

此外,您需要strlen($1) + strlen($3) + 4;,因爲您需要爲NUL終止符留出空間。

重要的是要明白,C沒有真正的字符串。它有指向charchar*),但這些都是真正的指針。它有數組(char []),但不能將數組用作聚合。例如,在您的代碼中,out = $1將是非法的,因爲您無法分配給數組。 (也因爲$1是一個指針,而不是一個數組,但這並不重要,因爲任何引用到一個數組,除了在sizeof,有效地降低到指針。)

所以,當你說$$ = out,你這是$$指向由out表示的存儲,並且該存儲即將消失。所以這是行不通的。你可以說$$ = $1,因爲$1也是一個指向char的指針;這使得$$$1指向相同的字符。 (這是合法的,但這會使內存管理變得更加複雜,並且需要小心修改。)最後,您可以說strcpy($$, out),但依賴於$$已指向字符串,該字符串足夠長以容納out,這是不太可能的,因爲它意味着將out指向的存儲複製到$$指向的位置。如上所述,當你在C中使用「字符串」函數時,他們都堅持認爲它們的「字符串」參數指向的字符序列(即指向字符的參數)必須是以0字符(即,其代碼爲0的字符,而不是字符)終止。

如果你習慣用實際上有字符串數據類型的語言進行編程,所有這些看起來有點奇怪。實踐使得完美。

底線是,你需要做的是創建存儲大到足以容納你的字符串的一個新的區域,像這樣(我刪除out,因爲它不是必需的):

$$ = malloc(len + 1); // room for NUL 
strcpy($$, $1); 
strcat($$, " = "); 
strcat($$, $3); 
// You could replace the strcpy/strcat/strcat with: 
// sprintf($$, "%s = %s", $1, $3) 

注意在解析器堆棧中存儲mallocd數據(包括strdupasprintf的結果)(也就是$$)也意味着當你完成它時需要free;否則,你有內存泄漏。

+0

我不明白你的答案。變量out很難消失,這就是爲什麼我將它存儲到$ $$這個默認變量來存儲非終端(或遞歸)野牛規則之間的數據。通過這種方式,我可以在下一條規則中使用out值(存儲在$$中)。 –

+0

@Simone:out實際上是一個指向堆棧中存儲的char數組的指針。因此'$$ = out'使'$$'指向堆棧上的數據。恐怕,這就是C的工作方式。 – rici

+0

那麼爲什麼如果我將'$$ = out'換成'$$ = $ 1'(其中$ 1是一個字符串),我在輸出中在規則的遞歸部分中輸出了$ 1表示的正確字符串? –

0

我已經解決了它改變$$ = out;行到strcpy($$,out);現在它工作正常。

+0

這幾乎可以肯定是未定義的行爲。我會編輯我的答案。 (但你需要更好地理解如何在C中使用字符串。) – rici

+0

感謝您的編輯。現在我明白你的觀點了! –