Почему этот код не работает?
TIB 10 ACCEPT
TIB SP@ 1 cells - 10 cmove
В этом коде я попытался ввести строку и сохранить ее в буфере ввода терминала, а затем сохранить ее в стеке параметров.
А вот с .S вижу, что не работает.
Почему этот код не работает?
TIB 10 ACCEPT
TIB SP@ 1 cells - 10 cmove
В этом коде я попытался ввести строку и сохранить ее в буфере ввода терминала, а затем сохранить ее в стеке параметров.
А вот с .S вижу, что не работает.
Основная проблема с примером кода заключается в том, что стек параметров растет в сторону нехватки памяти. Таким образом, отправной точкой для назначения копии должен быть более высокий адрес памяти (внутри существующего/определенного стека параметров). Итак, вместо
TIB SP@ 1 cells - 10 cmove
так должно быть:
TIB SP@ 1 cells + 10 cmove
Следующая проблема заключается в том, что для строки в стеке параметров недостаточно места. ACCEPT оставил более одной ячейки (четыре байта в 32-битной системе), фактическое количество символов. С образцом ввода «user10181» (9 символов),
TIB 10 ACCEPT
приводит к:
.S <1> 9 ok
Забыв на время о том лишнем элементе1, для целей этой проработки мы выделяем четыре ячейки в стеке параметров (фактическое значение, например, 235, не имеет значения), 16 байт на 32-битная система:
235 DUP DUP DUP
Тогда результатом TIB SP@ 1 cells + 10 cmove
будет:
.S <5> 9 235 8241 541085779 541215060 ok
Мы видим, что три из четырех ячеек (каждая по четыре байта) были перезаписаны cmove
(как и ожидалось).
К сожалению, наши скопированные байты не такие, как ожидалось. Декодирование вывода для трех измененных ячеек (в десятичном формате), сначала из
8241 541085779 541215060
в шестнадцатеричный:
2031 20405053 20424954
А затем декодировать как ASCII:
20 31 20 40 50 53 20 42 49 54
1 @ P S B I T
И реверсирование (сначала у нас была старшая память, а тестовая платформа - little endian) :
"TIB SP@ 1 "
Это первые десять символов нашей второй строки, TIB SP@ 1 cells + 10 cmove
. Таким образом, становится ясно, что терминальный входной буфер (TIB) слишком временный, чтобы его можно было использовать в данном случае.
Решение третьей проблемы состоит в том, чтобы весь код был скомпилирован до того, как мы запросим ввод данных пользователем. Например, поместите его в слово inputOnStack
:
: inputOnStack TIB 10 ACCEPT 235 DUP DUP DUP TIB SP@ 1 cells + 10 cmove ;
Тогда результат:
inputOnStack user10181 ok
.S <5> 9 235 24881 942747697 1919251317 ok
Это соответствует «user10181», а десятый символ — «a» (скорее всего, из «a» в inputOnStack
).
Тестовая платформа:
sudo apt-get update; sudo apt-get install gforth
)1. Более продвинутая версия кода может использовать фактическое количество символов. В любом случае, он должен быть DROP так или иначе, чтобы сбалансировать стек, если этот код будет интегрирован в другой код.
Внимательно рассмотрите, что происходит со стеком после каждого слова. Я воспроизвел ваш код ниже и аннотировал его с глубиной стека в каждой точке.
( 0 ) TIB ( 1 ) 10 ( 2 ) ACCEPT ( 1 )
( 1 ) TIB ( 2 ) SP@ ( 3 ) 1 ( 4 ) cells ( 4 ) - ( 3 ) 10 ( 4 ) cmove ( 1 )
Таким образом, когда выполняется SP@
, он возвращает указатель на элемент стека 2. Затем указатель уменьшается на одну ячейку, в результате чего получается указатель на элемент стека 3 (поскольку стек растет вниз). cmove
затем перезаписывает 10 байтов, то есть 2 элемента стека (при условии, что вы используете 64-битную версию). Таким образом, элементы стека 3 и 2 меняются. Наконец, cmove
извлекает из стека три элемента, оставляя только один. Что без изменений.
MU!
В основном то, что вы здесь делаете, это копирует CMOVE в область стека на Форте, где определен SP@ (это не стандартное слово). Так вы уничтожите стек. Ответ таков: такой код не должен работать.
Вопрос не должен быть "почему это не работает?" но "при каких обстоятельствах это имеет ожидаемый эффект?"
Предположим:
этот Форт имеет адресуемый и доступный для записи стек (если вы думаете, что это то же самое, прочитайте об дескрипторах сегментов Intel и особенностях инструкций POP и MOV)
SP@ указывает на вершину стека в момент вызова.
стек растет. (если он растет вниз, ситуация совершенно иная)
в начале вызова стек был пуст.
TIB и ACCEPT являются отвлекающими маневрами и будут игнорироваться.
1 cells - \ The pointer to the stack is changed opening up one cell
100 cmove \ you overwrite one cell below the stack,
\ then the (32-bit) cell place where the result of SP@ resides *and*
\ then TIB and then a couple of more bytes
Предполагая защищенный Форт, последние байты находятся за пределами стека и приводят к ошибке сегментации.
Таким образом, вы должны перенастроить свое мышление на более низкий уровень, если хотите использовать Форт. Думайте о памяти как о стопке почтовых ящиков и начните оттуда.
-1 U.
- person Peter Mortensen   schedule 11.01.2015-1 U.
вернул 4294967295 на Raspberry Pi (32-разрядная система). В той же системе1 cells .
вернул 4 (4 байта на слово — слово является отдельным элементом в стеке данных (или стеке параметров)). - person Peter Mortensen   schedule 11.01.2015