我正在撰寫一個玩具編譯器,它將類似 ac/c 的語言編譯為 c 。我正在使用野牛,但是當變數超出范圍時,在這種結構中很難處理。
在整個主函式的源語言中,只能有一個同名變數,這很好,但是有一個我無法解決的問題。
我不能像這樣制作 c 代碼,因為 c 編譯器會拋出語意錯誤:“var”未在此范圍內宣告。
int main()
{
if (true)
{
int var = 4;
}
if (true)
{
var = 5;
}
}
源語言有 while、if 和 if/else 陳述句。如果宣告的變數超出范圍,我必須拋出語意錯誤。例如:
這應該是語意錯誤,所以我無法生成此代碼:
int main()
{
while(0)
{
int var = 1;
}
if (1)
{
var = 2;
}
}
這也必須是語意錯誤:
int main()
{
if (0)
{
int var = 1;
}
else
{
if (1)
{
var = 5;
}
}
}
這是允許的,我可以生成以下代碼:
int main()
{
if (0)
{
}
else
{
int var = 1;
if (1)
{
while (0)
{
while (0)
{
var = 2;
}
}
}
}
}
我嘗試了很多東西,但是當有嵌套的 if、if/else 或 while 時,我無法解決。
I read tons of tutorials about symbol table, but none of them can explain properly how to manage a variable if it is become out of scope.
If you familiar with this topic and with bison, please do not just give me hints, like "use stack, and mark a variable if it become out of scope". I found lot of article about it. Instead of please give me pseudocode or concrate implementation sketch.
I think it cannot be so much difficult, because in the whole main function there can be one variable with the same name as I wrote.
Symbol table:
struct SymbolType
{
int lineNumber;
std::string identifier;
int identifierValue;
Type type;
int functionArgumentNumber;
Type functionReturnType;
Type markType;
bool outOfScope;
};
class Symbol
{
public:
void AddVariable(int _lineNumber, std::string _identifier, int _identifierValue, Type _type, int _functionArgumentNumber, Type _functionReturnType, Type _markType, bool _outOfScope);
void AddMarker(int _lineNumber, std::string _scopeName, Type _markType);
bool FindVariable(std::string _identifier);
int FindVariableValue(std::string _identifier);
void Remove();
void Print();
std::vector<SymbolType> symbolTable;
private:
int lineNumber;
std::string identifier;
int identifierValue;
Type type;
int functionArgumentNumber;
Type functionReturnType;
Type markType;
bool outOfScope;
};
uj5u.com熱心網友回復:
現在讓我們假設以下情況:當您在嵌套范圍內時,您不能將變數添加到父范圍。因此,我們可以使用類似堆疊的結構(僅在最后推送/彈出就足夠了,但可以讀取所有條目 - 后者要求取消資格std::stack,因此我們將std::vector改為使用 eg on)。
- 遇到新變數的宣告:
運行整個堆疊以查看該變數是否已經存在。如果是這樣,發出一個錯誤('duplicate declaration/definition')。 - 遇到訪問變數:向上運行整個堆疊,查看該變數是否存在;如果不是,則發出錯誤('未宣告/定義' - 我不會區分從未定義過的變數或已離開范圍)。
- 在離開范圍時,向上運行堆疊并洗掉駐留在該范圍內的任何變數。
為了能夠做到 3. 你有(至少)兩個選擇:
- 每個堆疊條目都為各自的范圍提供一個識別符號,可以是簡單的計數器。然后洗掉所有具有相同計數器值的變數。如果您擔心計數器可能溢位,那么也將其減少 1(那么它始終代表當前范圍深度)。
- 有一個哨兵型別——在打開一個新范圍時將其推入堆疊,與任何變數名比較不相等,并且在離開一個范圍時,你將洗掉所有變數,直到遇到哨兵——以及哨兵本身。
此處理使您的outOfScope成員過時。
順便說一句,你的addVariable函式接受了太多引數——為什么變數需要回傳型別,例如???
我建議為您的語言可能提供的每種特定語意型別添加多個函式(addVariable, addFunction, ...)。每個函式都接受實際需要配置的內容,并將其余的設定為適當的默認值(例如,設定Type為Functionwithin addFunction)。
編輯 - 處理您評論中的示例:
while(condition)
{ // opens a new scope:
// either place a sentinel or increment the counter (scope depth)
int var = 1; // push an entry onto the stack
// (with current counter value, if not using sentinels)
if (true)
{ // again a new scope, see above
var = 2; // finds 'var' on the stack, so fine
} // closes a scope:
// either you find immediately the sentinel, pop it from the stack
// and are done
//
// or you discover 'var' having a counter value less than current
// counter so you are done as well
} // closing next scope:
// either you find 'var', pop it from the stack, then the sentinel,
// pop it as well and are done
//
// or you discover 'var' having same counter value as current one,
// so pop it, then next variable has lower counter value again or the
// stack is empty, thus you decrement the counter and are done again
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/448841.html
標籤:c c 11 scope symbol-table
