2013-10-11 128 views
0

我正在使用lex來實現掃描程序。我想在解析時建立一個符號表。我有兩個結構,SymbolEntry和SymbolTable(如下)。大多數情況下,當我調用插入符號的函數(registerID,也在下面)時,我擁有該條目的所有信息。但是,當我有一個常數時,我也想知道它的價值,但是當我第一次創建條目時,這並不是立即可用的。當我在代碼中稍後嘗試更改條目值時,我使該條目使用的整個內存塊無效,並且名稱和值正在打印垃圾。更改結構字符串

這裏有兩種結構:

typedef struct{ 
    char* type; 
    char* name; 
    char* value; 
} SymbolEntry; 
typedef struct{ 
    SymbolEntry *entries; 
    size_t size; 
    size_t capacity; 
} SymbolTable; 

這是registerID功能,當{id}匹配調用。 yytext包含該ID。

int registerID(char* type){ 
    //create a new symbol entry with the specified type and name and a default value 
    SymbolEntry e; 
    e.type = type; 
    e.name = (char *)calloc(yyleng+1, sizeof(char)); 
    strcpy(e.name, yytext); 
    e.value = ""; 
    prevSym = insertSymbol(&table, e); 
    return prevSym; 
} 

這是insertSymbol(SymbolTable* st, SymbolEntry entry)相關代碼。 pos始終是插入時數組中的最後一個元素(否則該條目不是唯一的,並且只返回pos)。

st->entries[pos].name = (char *)calloc(strlen(entry.name)+1, sizeof(char)); 
st->entries[pos].type = (char *)calloc(strlen(entry.type)+1, sizeof(char)); 
st->entries[pos].value = (char *)calloc(strlen(entry.value)+1, sizeof(char)); 
strcpy(st->entries[pos].name, entry.name); 
strcpy(st->entries[pos].type, entry.type); 
strcpy(st->entries[pos].value, entry.value); 

後來,法框架匹配緊跟一個常量名值之後,該代碼執行(直接在規則<CONSTANT_VAL>{number}

table.entries[prevSym].value = (char *)calloc(yyleng+1, sizeof(char)); 
strcpy(table.entries[prevSym].value, yytext); 

爲什麼會出現這種無效的SymbolEntry在陣列中的這個位置,以及如何安全地更改value的內容?

編輯: 它不僅與常量發生。前兩個SymbolEntry s總是垃圾。我假設這可能意味着他們都是,但其他人只是沒有被覆蓋。

此外,似乎後續調用registerID正在導致數據損壞。只有9個符號,只有前兩個是垃圾,其中34個是前7個。添加更多的文本解析沒有變量不會導致任何問題。

已解決 事實證明,我只是不小心刪除了某處沿途的某條線,這就是導致該錯誤的原因。我意外地刪除了我的電話initSymbolTable。感謝chux詢問我是如何初始化表格的。對於那個很抱歉。

+0

你是如何分配ST->項[POS]一種可能性是你寫過你分配的內存。 – KayakDave

+0

我開始它的大小爲16,但如果有'size == capacity'那麼我重新分配兩倍的大小。該檢查在每次插入操作後完成。 – Jaws212

+0

另外,我試過將SymbolEntry數組分配給1024,但它仍然無效。 – Jaws212

回答

1

2潛在的問題。

1 - 比較

// Fields set with non-malloc'ed memory 
e.type = type; 
e.value = ""; 
// Fields set with malloc'ed memory 
st->entries[pos].type = (char *)calloc(strlen(entry.type)+1, sizeof(char)); 
st->entries[pos].value = (char *)calloc(strlen(entry.value)+1, sizeof(char)); 
strcpy(st->entries[pos].type, entry.type); 
strcpy(st->entries[pos].value, entry.value); 

這兩個設置中的字段,以有效存儲和在第二種情況下,動態地填充存儲器。關注的是後續使用。 OP如何知道free()realloc()第二種而不是第一種。進一步的擔憂:在registerID(char* type)的情況下,我們如何知道當通過type字段使用該指針時,傳遞給type的值在以後仍然有效。建議:

e.type = strdup(type); // or the usual strlen()+1, malloc() and copy 
e.value = strdup(""); 

2 - yyleng的類型和設置未顯示。可能它與strlen(e.name)等相比還不夠大?

[編輯]經過審查,我真的認爲e.type = type;是問題所在。 e.type需要它自己的副本type

輔修:考慮

// st->entries[pos].type = (char *)calloc(strlen(entry.type)+1, sizeof(char)); 
// strcpy(st->entries[pos].type, entry.type); 
size_t Length = strlen(entry.type) + 1; 
st->entries[pos].type = malloc(Length); 
memcpy(st->entries[pos].type, entry.type, Length); 
+0

我改變了所有的'strdup()'調用。 'yyleng'由lex定義,是'yytext'的長度。每個記錄中的每個字段只能創建一次,「type == CONSTANT」的「value」除外。然後它只在兩個特定地點中的一個地方變化。此時(即使沒有輸入文件中的常量),前3/32的SymbolEntries已損壞。我不明白,如果在每一步使用'strdup()',情況會如何。最壞的情況下,我應該處理內存溢出。 – Jaws212

+0

嗯。爲了調試目的,考慮'e.name = strdup(yytext)'和'table.entries [prevSym] .value = strdup(yytext)' - 也許你已經做好了所有準備。如果這不能解決問題,則問題必須在未發佈的代碼中。 – chux

+0

@ Jaws212分配給「st」的內存如何? – chux