Реализация post / pre приращения / декремента при переводе на Lua

Я пишу LSL переводчику Lua, и у меня возникают всевозможные проблемы с реализацией увеличивающихся и уменьшающихся операторов. В LSL есть такие вещи, в которых используется обычный синтаксис C (x++, x--, ++x, --x), а Lua - нет. Просто для того, чтобы избежать массового набора текста, я называю эти виды операторов "созданиями". В приведенном ниже коде я буду использовать "..." для представления других частей выражения.

... x += 1 ...

Не будет работать, потому что Луа имеет только простое назначение.

... x = x + 1 ...

Не сработает, потому что это утверждение, и Lua не может использовать выражения в выражениях. LSL может использовать творения в выражениях.

function preIncrement(x)  x = x + 1;  return x;  end
... preIncrement(x) ...

Хотя оно и обеспечивает правильное значение в выражении, Lua передается по значению для чисел, поэтому исходная переменная не изменяется. Если бы я мог заставить это действительно изменить переменную, тогда все хорошо. Взаимодействие с окружающей средой может быть не очень хорошей идеей, не знаю, что такое область действия x. Я думаю, что я исследую это дальше. Переводчик может выводить детали области видимости.

Предполагая, что вышеуказанная функция существует -

... x = preIncrement(x) ...

Не будет работать по причине "это утверждение".

Другие решения начинают становиться действительно грязными.

x = preIncrement(x)
... x ...

Работает нормально, кроме случаев, когда оригинальный код LSL выглядит примерно так:

while (doOneThing(x++))
{
  doOtherThing(x);
}

Который становится целой банкой червей. Использование таблиц в функции -

function preIncrement(x)  x[1] = x[1] + 1;  return x[1];  end
temp = {x}
... preincrement(temp) ...
x = temp[1]

Это даже грязнее, и имеет те же проблемы.

Начав с того, что мне, возможно, придется анализировать окружающий код вместо того, чтобы просто делать простые переводы, чтобы разобраться, каким будет правильный способ реализации любого данного элемента. У кого-нибудь есть простые идеи?

5 ответов

Решение

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

Для глобалов -

function preIncrement(x)
  _G[x] = _G[x] + 1
  return _G[x]
end
... preIncrement("x") ...

Для локальных и функциональных параметров (которые являются локальными для), я знаю, что во время синтаксического анализа инструмента, он является локальным, я могу сохранить четыре флага, чтобы сообщить мне, какой из четырех инструментов используется в структуре переменных AST. Затем, когда придет время вывести определение переменных, я могу вывести что-то вроде этого:

local x;
function preIncrement_x() x = x + 1;  return x;  end
function postDecrement_x() local y = x;  x = x - 1;  return y;  end
... preIncrement_x() ...

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

Обратите внимание, что, по крайней мере, в C вы можете отложить пост-инкременты / декременты до следующей "точки последовательности" и поставить пре-инкременты / декременты перед предыдущей точкой последовательности; Точки последовательности расположены только в нескольких местах: между операторами, у "операторов короткого замыкания" (&& а также ||) и т. д. (подробнее здесь)

Так что нормально заменить x = *y++ + z * f (); с { x = *y + z * f(); y = y + 1; }- пользователь не может предполагать, что y будет увеличиваться перед чем-либо еще в операторе, только то значение, которое используется в *y будет y прежде чем он увеличивается. Так же, x = *--y + z * f(); можно заменить на { y = y - 1; x = *y + z * f (); }

Lua разработан, чтобы быть в значительной степени невосприимчивым к реализациям такого рода вещей. Это может быть сделано как проблема компилятора / интерпретатора, поскольку интерпретатор может знать, что переменные изменяются только при выполнении оператора.

Нет способа реализовать подобные вещи в Lua. Не в общем случае. Вы можете сделать это для глобальных переменных, передав строку в функцию приращения. Но очевидно, что это не будет работать для локальных пользователей или для переменных, которые находятся в таблице, которая сама является глобальной.

Луа не хочет, чтобы ты это делал; Лучше всего найти способ работать в рамках ограничения. А это означает анализ кода.

Предлагаемое вами решение будет работать только тогда, когда все переменные Lua являются глобальными. Если только это не то, что делает LSL, у вас возникнут проблемы с переводом программ LSL, которые используют переменные, называемые одинаково в разных местах.

Lua может изменять только одно lvalue на оператор - таблицы, передаваемые в функции, являются единственным исключением из этого правила. Вы можете использовать локальную таблицу для хранения всех местных жителей, и это поможет вам с предварительными...;-; они могут быть оценены до выражения, в котором они содержатся. Но пост -...- инструменты должны быть оценены позже, что просто невозможно в lua - по крайней мере, без какого-то уродливого кода, включающего анонимные функции.

Таким образом, у вас есть один вариант: вы должны принять, что некоторые операторы LSL будут переведены в несколько операторов Lua.

Допустим, у вас есть оператор LSL с такими приращениями:

f(integer x) {
  integer y = x + x++;
  return (y + ++y)
}

Вы можете перевести это в утверждение Lua следующим образом:

function f(x) {
  local post_incremented_x = x + 1 -- extra statement 1 for post increment
  local y = x + post_incremented_x
  x = post_incremented_x -- extra statement 2 for post increment

  local pre_incremented_y = y + 1
  return y + pre_incremented_y
  y = pre_incremented_y -- this line will never be executed
}

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

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

В большинстве ваших оценок настраиваемость к коду. Вы пытаетесь жестко передать типы данных из одного в другой. И назовите это "переводчиком". И во всем этом вы упускаете регулярные выражения и другие возможности сопоставления с образцом. Которые гораздо больше присутствуют в LUA, чем в LSL. И так как код LSL передается в LUA. Попробуйте использовать их вместе с другими функциями. Который определил бы работу больше как переводчик, чем как сложный пас.

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

Другие вопросы по тегам