Загрузка...

Как организовать игрушечную память своего языка?

Тема в разделе C# создана пользователем Host1 23 мар 2024. 192 просмотра

  1. Host1
    Host1 Автор темы 23 мар 2024 Лучше бы раньше, но раньше уже закончилось 64 8 авг 2017
    Делаю свой домашний проект - виртуальную машину наподобие jvm. Есть текстовый файл с опкодами по типу:
    Код
    store 200 0 i //кладет в ячейку памяти 0 значение 200 и помечает ячейку как integer
    store string 1 s //кладет в ячейку памяти 1 значение string и помечает ячейку как string
    store a 2 c //кладет в ячейку памяти 2 значение c и помечает ячейку как char
    store 300 3 i //кладет в ячейку памяти 3 значение 300 и помечает ячейку как integer
    load 0 //загружает из ячейки памяти 0 значение в стек, тип стека задается типом первого загружаемого значение, в данном случае int
    load 3 //загружает из ячейки памяти 3 значение в стек
    add //складывает значения в стеке
    store 4 //результат который остался от сложения берет из стека и кладет в ячейку 4
    И я столкнулся с проблемой как хранить эти ячейки памяти.
    Если создавать ячейки через дженерики < T >, то такие ячейки будут разными и хранить их в одном массиве не получится. Если бы так работало, то можно было бы получать доступ к ячейке просто по индексу и вызывать в ней метод get который возвращал тот тип данных который хранит ячейка.

    Потом я подумал хранить ячейки в массиве object, но это плохая идея так как все равно придется приводить к типу ячейки, приведение типов не безопасно. Да и конвертация в object и обратно занимает время просто так, неэффективно.

    Далее я подумал сделать ячейку универсальной и дать ей поля всех нужных типов данных: int float char string bool, но тогда получается когда в ячейку помещается значение оно хранится в одном из 5 полей, остальные 4 поля пустые и неинициализированные, что не есть хорошо.

    Еще была идея создать 5 массивов, каждый для своего типа ячеек, например массив MemArrInt[] хранит ячейки MemCellInt которые имеют поле int для хранения данных, но мне эта идея показалась неправильной и костыльной и что будто есть нормальный путь сделать задуманное.

    Если тут есть хорошо разбирающиеся в C# и в целом архитектуре языков программирования, подскажите пожалуйста идею как это все можно было бы реализовать по вашему. Или если вы знаете источники где это хорошо описано прошу поделиться. Заранее спасибо. Если есть какие либо идеи или предложения и вам удобнее показать/рассказать это в тг, то пожалуйста, буду ждать вас там.
     
    23 мар 2024 Изменено
    1. Посмотреть предыдущие комментарии (9)
    2. vtlstolyarov
      Host1, Обращайся :)
    3. Host1 Автор темы
      vtlstolyarov, Пишу с еще одним вопросом который долго гуглил, но так и не нашел решение. Я использовал концепцию которую вы подсказали - с байтами. Теперь у меня другая дилемма.

      Опишу что у меня уже есть: Есть бинарный файл у него есть 2 секции [переменные и константы] и [команды], разделяются они специальным байтом который обрабатывает вм. Если байт разделяющий секции еще не прочитан, то она читает переменные и записывает в память (массив байт в классе VicrtualMachine). Переменные устроены как вы раньше и говорили: 1 байт определяющий тип, байты самой переменной.

      Получается что далее просто цикл: прочитать байт типа переменной -> прочитать столько байт сколько имеет тип переменной -> все это [байт типа и байты переменной] скопировать в массив байт памяти в классе. Далее читается байт-разделитель секций и начинается другая логика. Тут уже читается байт инструкции, и ее аргумент.

      Так как я примерно поглядывал на jvm и ее устройство, я оттуда взял то что все происходит в стеке. Например у меня инструкция load 0 то есть загрузить в стек переменную 0. То как она загружается опустим, это не сложно. А вот сам стек стал для меня проблемой. Так как типов данных может быть больше одного: int float bool char то и стек должен поддерживать хранение всех этих типов.

      Сначала я думал использовать много стеков каждый для своего типа данных, но мне показалось что это совсем не правильно городить столько разных полей в классе просто так.

      Далее я спросил все это у chatgpt и других нейросетей, там мне предложило использовать стек object. Но мне почему-то кажется что это тоже не совсем верно и удобно. Во первых придется приводить типы, а как нас учил преподаватель по с++, это небезопасное действие. Поэтому я всячески стараюсь избегать приведения типов там мне совсем позарез не нужно. Да и тогда встает вопрос как понимать что именно находится в стеке если все внутри него это object, ведь для каждого типа нужно иметь разные методы.

      Потом я подумал использовать стек из моих структур данных которые будут хранить: тип и байты переменной чтобы потом когда нужно будет что-то с ней сделать, то перемести из байт в нужный тип, сделать что-то, получить результат, перемести его обратно в байты и записать в вершину стека, ну и далее если будет такая инструкция то записать в память.

      Тут хотел бы спросить вашего мнения, мне почему-то кажется что байтовое представление это больше про память и когда переменная попадает в стек, то она уже не должна быть в байтах, хотя может это тоже не совсем правильно или вообще есть еще какой-то вариант реализовать это все по правильному и не изобретать архитектуру-кривой велосипед,

      Заранее спасибо!
    4. vtlstolyarov
      Host1,

      Это правильный подход - стэк это тоже память, просто выделеный кусок памяти скорость работы с которым чуть быстрее потому что не надо рыскать по всей оперативе, а всё что нужно находится на вершине стэка. Из нюансов я бы рекомендовал сначала на стэк писать блок данных, потом блок заголовка типа и потом иденификатор типа - в таком порядке их потом проще снимать со стэка - сначала ты снимешь байт типа, потом байты заголовка, и потом байты данных - если порядок будет другим то тебе будет сложнее найти с какого байта начинается значение на вершине стэка.
      29 мар 2024 Изменено
    5. Посмотреть следующие комментарии (7)
Загрузка...
Top