#c #compiler-construction #symbol-table #semantic-analysis
#c #компилятор-конструкция #таблица символов #семантический анализ
Вопрос:
У меня есть довольно элементарная таблица символов для сопоставления идентификатора с символом, хранения VariableSymbols, MethodSymbols, BuiltInTypeSymbols и т.д. Это отлично работало для моего простого интерпретатора. Однако теперь я хочу реализовать более продвинутые типы символов, такие как кортежи (скажем, — TupleSymbol ), в которых хранится массив встроенных типов.
Я могу легко реализовать TupleSymbol и сохранить его в таблице, но я понял, что продолжение использования моего текущего подхода «сопоставление с символом» для хранения типов в конечном итоге приведет к появлению множества неоднозначных типов символов при поиске в таблице символов. Например, если я хочу присвоить кортеж переменной кортежа с именем «test», в рамках операции присваивания мне нужно будет проверить, является ли символ, хранящийся в таблице для идентификатора «test», символом TupleSymbol или BuiltInTypeSymbol, и мне нужно будет сделать то же самое для значения, которое яхотите присвоить ему.
Есть ли лучший способ реализации таблицы символов? Например, лучше ли иметь несколько областей в области таблицы символов, хранящих каждый тип символа отдельно, т.Е. std::map<std::string, MethodSymbol> для методов и std::map<std::string, VarSymbol> для переменных?
Редактировать
Вот некоторый код, который поможет визуализировать мой текущий дизайн. Обратите внимание, как карта таблицы символов symbolTable
использует базовый класс символов.
class BuiltInTypeSymbol;
class Symbol {
public:
BuiltInTypeSymbol* type;
std::string name;
Symbol(std::string inname, BuiltInTypeSymbol* intype) : name(inname), type(intype){}
};
class BuiltInTypeSymbol : public Symbol {
public:
BuiltInTypeSymbol(std::string inname) : Symbol(inname, this) {}
}
class VarSymbol : public Symbol {
public:
VarSymbol(std::string inname, BuiltInTypeSymbol* typesymbol) : Symbol(inname, typesymbol) {}
}
BuiltInTypeSymbol* intType = new BuiltInTypeSymbol("int");
BuiltInTypeSymbol* floatType = new BuiltInTypeSymbol("float");
std::map<std::string, Symbol*> symbolTable = {
{intType->name, intType}, // registering int type
{floatType->name, floatType}, // registering float type
{"a", new VarSymbol("a", intType)} // registering test variable "a" of type int
};
Комментарии:
1. Как это должно использоваться? Почему вы так часто используете указатели? Что такое
int->name
?2. @super. Исправлена опечатка, она должна была быть IntType->name . Код не так важен, просто иллюстрация того, как представлена моя текущая таблица символов. В первую очередь я ищу совет относительно наилучшего способа создания символа для сопоставления идентификаторов с символами разных типов, например VarSymbol, BuiltInTypeSymbol, MethodSymbol и т. Д.
3. Почему? Конечно, вы можете добиться полипорфизма с вашими различными
Symbol
типами?
Ответ №1:
Если вы разрешаете повторяющиеся имена символов для разных типов, как допускает большинство языков, например, одно и то же имя для переменной и функции, вам нужно использовать разные map
s для каждого типа.
Также вам, вероятно, потребуется выполнить итерацию по какому-либо типу символов, например встроенным символам — неплохо также создать для них карту.