Я и мой друг думаем о написании нашего собственного языка программирования, используя своевременную компиляцию. Мы договорились о сборке, которую будем использовать, но в одном мы не совсем уверены, как хранить переменные. То, о чем мы договорились, это их структура.
Переменные будут заменены ключами (во время компиляции). Каждый ключ представляет собой 2-байтовое целое число в диапазоне от 1 до 65535. Когда у вас есть, например, переменная внутри пространства имен, ключ будет существовать из первого 2-байтового целого числа, содержащего ключ пространства имен, и чем 2-байтовое целое число, содержащее ключ фактической переменной.
Например, если у меня есть пространство имен foo и у меня есть переменная test, и мы говорим, что пространству имен foo будет назначен ключ 1, а переменной test внутри 1 будет назначен ключ 1-> 1. (Первая переменная в первом пространстве имен). В самой сборке мы завершаем эти ключи нулевым байтом. (Имейте в виду, что это компилированная сборка, а не реальный код перед компиляцией)
GETV 1 1 0 SET 5 RET
Эта сборка получит переменную test из пространства имен foo и установит ее на 5. Затем она вернет эту переменную.
GETV 1 2 1 0 SETV 1 1 0 RET
Эта сборка может соответствовать следующему (вымышленному) коду:
foo::testClass::test = foo::test;
return foo::test;
Предоставляется следующая структура.
namespace foo { // 1 First Global Variable
byte test = 1; // 1 1 - First Variable Inside First Global Variable
class testClass { // 1 2 - Second Variable Inside First Global Variable
static byte test = 0; // 1 2 1 - First Variable Inside Second Variable Inside First Global Variable
}
}
Как мне получить доступ к этим переменным? Мой текущий план состоял в том, чтобы хранить их внутри хэш-карты, используя ключ в качестве строки в качестве хеш-кода. Я не имею ни малейшего представления о том, как это сделать, как узнать, как переменная какого типа хранится в текущем ключе, как долго это происходит и как выполнять вычисления с ним. Я понимаю, что предотвращение безумных вычислений, таких как добавление беззнаковых целых к подписанным, может быть обработано компилятором, но это все еще оставляет нас с проблемой, какова длина этой переменной и как ее обрабатывать. (Добавление 2-х чисел будет обрабатываться иначе, чем добавление 2-х целых чисел, верно?)
Наилучшим подходом здесь является не сохранение каких-то странных идентификаторов для ваших переменных, а использование прямых указателей. После того, как программа скомпилирована, вам больше не понадобятся ориентированные на человека имена.
Что более важно, вам нужно подумать о структуре ваших переменных. В зависимости от синтаксиса вашего языка, помимо памяти, в которой хранятся значения ваших переменных, вам также могут потребоваться некоторые метаданные для хранения — например, тип переменной. Эта информация необходима, только если вы хотите поддерживать автоматическое приведение типов. Если ваш язык строго типизирован, вы сможете разрешить все конфликты типов во время компиляции, и тогда вам не понадобится информация о типах во время выполнения.
Кроме того, в зависимости от синтаксиса вам может потребоваться сохранить индекс, чтобы сопоставить понятные человеку имена переменных с реальными адресами. Этот индекс необходим, только если ваш язык имеет функции, подобные:
var_by_name(s:string):pointer
Других решений пока нет …