Реализация виртуальной машины на основе стека для подмножества C

Привет всем. В настоящее время я внедряю простой язык программирования для обучения, но мне нужен совет. В настоящее время я разрабатываю свой интерпретатор, и у меня возникла проблема.

Мой язык является подмножеством C, и у меня проблема с реализацией интерпретатора стека. На языке будет скомпилировано следующее:

somefunc ()
{
    1 + 2;
}

main ()
{
    somefunc ();
}

Теперь все в порядке, но когда вычисляется «1 + 2», результат помещается в стек, а затем функция возвращается, но в стеке все еще есть число, которого не должно быть. Как я могу обойти эту проблему?

Я думал о сохранении «состояния» стека перед вызовом функции и восстановлении «состояния» после вызова функции. Например, сохранение количества элементов в стеке, затем выполнение кода функции, возврат, а затем извлечение из стека, пока у нас не будет такое же количество элементов, как и раньше (или, может быть, +1, если функция что-то вернула).

Есть идеи? Спасибо за любые советы!


person Filip Jeremic    schedule 21.07.2010    source источник


Ответы (3)


Отличный вопрос! Одним из моих увлечений является написание компиляторов для игрушечных языков, так что спасибо за ваш отличный вкус в программировании.

оператор-выражение — это оператор, в котором код в операторе является просто выражением. Это означает что угодно в форме <expression> ;, включая такие вещи, как присваивания и вызовы функций, но не ifs, whiles или returns. Любой оператор выражения будет иметь остаточное значение в стеке в конце, которое вы должны отбросить.

1 + 2 — это оператор выражения, но таковы и эти:

  • x = 5;
    выражение присваивания оставляет значение 5 в стеке, поскольку результатом присваивания является значение левого операнда. После завершения оператора вы удаляете неиспользуемое значение 5.

  • printf("hello world!\n");
    printf() возвращает количество выводимых символов. У вас останется это значение в стеке, поэтому извлеките его, когда оператор завершится.

По сути, каждый оператор выражения оставляет значение в стеке, если тип выражения не равен void. В этом случае вы либо используете операторы void в особом случае и ничего не выталкиваете после этого, либо помещаете притворное «пустое» значение в стек, чтобы вы всегда могли вытолкнуть значение.

person John Kugelman    schedule 21.07.2010
comment
Забавно, что вы называете это, потому что в моем представлении AST у меня есть узел с именем ASTStmtExpr только для этого! Кажется, я начинаю что-то понимать... Вот в чем я не уверен: из-за ограничений этих ответов на комментарии я должен вставить фрагмент: void Compiler::visit (const ASTStmtExpr& expr_stmt, std:: shared_ptr‹Function› func) { expr_stmt.expr ()-›accept (*this, func); } Вы говорите, что после этого я должен добавить OP_POP, а для таких вещей, как присваивания, я буду помещать фиктивный объект Nil, чтобы он затем выталкивался? - person Filip Jeremic; 21.07.2010
comment
Для присваивания нет, вы не проталкиваете фиктивное значение, потому что у вас уже будет результат присваивания в стеке. Присваивание — это просто выражение с использованием оператора =, который ничем не отличается от + или -, за исключением того, что = имеет побочный эффект присваивания переменной. В противном случае он ведет себя так же, как и все другие операторы. - person John Kugelman; 21.07.2010
comment
Выражение void будет чем-то вроде вызова функции, которая возвращает void. Например: abort();. Но, черт возьми, это может быть просто академическое соображение. В вашем примере кода не перечислены типы возвращаемых функций, так что это может даже не быть проблемой для вас. - person John Kugelman; 21.07.2010
comment
Да, для меня это не проблема, так как в моем языке нет типов, даже примитивы являются объектами в моем языке, поэтому я не думаю, что это будет проблемой. Спасибо за ответ! - person Filip Jeremic; 21.07.2010

Вам понадобится более умный парсер. Когда вы видите выражение, значение которого не используется, вам нужно выдать POP.

person Hans Passant    schedule 21.07.2010
comment
Здравствуйте, спасибо за ответ. Я все еще нахожусь в начальной стадии компиляторов кодирования, и я думал о такой оптимизации, но не смог найти приемлемого решения :( Может быть, я попробую еще раз, еще раз спасибо !! - person Filip Jeremic; 21.07.2010

Это важная возможность по оптимизации обучения. у вас есть функция, которая выполняет числовые, но целочисленные математические вычисления, результат int math даже не используется каким-либо образом, в какой-либо форме или форме.

Если ваш компилятор оптимизирует функцию, это уменьшит количество генерируемого и выполняемого байт-кода впустую!

person Nergal    schedule 27.06.2017