Victor__v писал(а):
Как понимаю, Вы закидываете часть переменных выше вершины стека.
Но как происходит контроль измерения глубины?
При изменении этого самого стека?
Ничего никуда не закидывается. В начале манипулятора просто отмечается с каким количеством верхних параметров на стеке будет работать данный манипулятор. Вот на стеке находятся 4 параметра: a b c d. Нам нужно оставить на стеке параметр а, а с параметрами
b c d поработать. Мы пишем определение
Код:
: proba /[312M3m'1 ;
что эквивалентно
Код:
: proba { b c d } b c MAX d MIN ;
После исполнения слова proba на стеке останется два параметра
Код:
a
и результат от
Код:
b c MAX d MIN
Для управления стеком при компиляции используются стековые эффекты входящих в определение через двоеточие слов.
Это технологический прием. Каждое слово форта имеет стековый эффект - величина на которую слово меняет глубину стека.
Зная исходное состояние стека и стековые эффекты последовательно выполняемых слов, можно вычислять положение ячеек стека
во время компиляции кода определения.
Сложности при компиляции возникают для ветвлений, циклов, слов типа EXECUTE, LAMBDA{ и тому подобных.
Для циклов я ввел правило - стековый эффект внутри цикла должен быть нулевым(аналогия со стеком возвратов).
Для ветвлений ввел массив трасс ветвления, в который вписываются вычисляемые стековые эффекты каждой трассы.
Для EXECUTE нужно менять структуру словарной статьи - вводить туда значение стекового эффекта
(сейчас я привязку слов к их стековым эффектам реализовал в обход словарей). Пока такие слова ( типа EXECUTE) не использую.
Немного оптимизировал код определений через двоеточие в части сокращения числа перестановок указателя стека.
Убрал слово DUP как лишнее, так как вместо него можно просто написать номер верхней ячейки.
С DROP такое не проходит, хотя запись, например ]3, означает, что если в стеке было 4 параметра,
останется 3 нижних, верхнее удалится. Таким образом DROP тоже можно исключить.
Вот еще некоторые соображения на примере:
Код:
\ площадь треугольника по Герону
: S3 { a b c \ p }
a b + c + 2 / TO p p a - p b - * p c - * p * sqrt ; SEE S3
: s3 /[312+3+(2)/41-42-*43-*4*q'1 ; SEE s3
: TST 100 0 DO 3 4 5 S3 DROP LOOP ; TIME
: tst 100 0 DO 3 4 5 s3 DROP LOOP ; time
CODE S3
621623 8945FC MOV FC [EBP] , EAX
621626 B80C000000 MOV EAX , # C
62162B 8D6DFC LEA EBP , FC [EBP]
62162E E8B11AF3FF CALL 5530E4 ( DRMOVE )
621633 8945FC MOV FC [EBP] , EAX
621636 B801000000 MOV EAX , # 1
62163B 8D6DFC LEA EBP , FC [EBP]
62163E E8DD1BF3FF CALL 553220 ( (RALLOT) )
621643 6810000000 PUSH , # 10
621648 6868325500 PUSH , # 553268
62164D 8945FC MOV FC [EBP] , EAX
621650 8B442414 MOV EAX , 14 [ESP]
621654 03442410 ADD EAX , 10 [ESP]
621658 0344240C ADD EAX , C [ESP]
62165C B902000000 MOV ECX , # 2
621661 99 CDQ
621662 F7F9 IDIV ECX
621664 89442408 MOV 8 [ESP] , EAX
621668 2B442414 SUB EAX , 14 [ESP]
62166C 8945F8 MOV F8 [EBP] , EAX
62166F 8B442408 MOV EAX , 8 [ESP]
621673 2B442410 SUB EAX , 10 [ESP]
621677 F76DF8 IMUL F8 [EBP]
62167A 8945F8 MOV F8 [EBP] , EAX
62167D 8B442408 MOV EAX , 8 [ESP]
621681 2B44240C SUB EAX , C [ESP]
621685 F76DF8 IMUL F8 [EBP]
621688 8945F8 MOV F8 [EBP] , EAX
62168B 8B442408 MOV EAX , 8 [ESP]
62168F F76DF8 IMUL F8 [EBP]
621692 8D6DFC LEA EBP , FC [EBP]
621695 E88D57FFFF CALL 616E27 ( sqrt )
62169A C3 RET NEAR
END-CODE
( 120 bytes, 33 instructions )
CODE s3
6216AB 8945FC MOV FC [EBP] , EAX
6216AE 8B4504 MOV EAX , 4 [EBP]
6216B1 034500 ADD EAX , 0 [EBP]
6216B4 0345FC ADD EAX , FC [EBP]
6216B7 8945F8 MOV F8 [EBP] , EAX
6216BA B802000000 MOV EAX , # 2
6216BF 8BC8 MOV ECX , EAX
6216C1 8B45F8 MOV EAX , F8 [EBP]
6216C4 99 CDQ
6216C5 F7F9 IDIV ECX
6216C7 8945F8 MOV F8 [EBP] , EAX
6216CA 2B4504 SUB EAX , 4 [EBP]
6216CD 8945F4 MOV F4 [EBP] , EAX
6216D0 8B45F8 MOV EAX , F8 [EBP]
6216D3 2B4500 SUB EAX , 0 [EBP]
6216D6 F76DF4 IMUL F4 [EBP]
6216D9 8945F4 MOV F4 [EBP] , EAX
6216DC 8B45F8 MOV EAX , F8 [EBP]
6216DF 2B45FC SUB EAX , FC [EBP]
6216E2 F76DF4 IMUL F4 [EBP]
6216E5 F76DF8 IMUL F8 [EBP]
6216E8 8D6DF8 LEA EBP , F8 [EBP]
6216EB E83757FFFF CALL 616E27 ( sqrt )
6216F0 8D6D10 LEA EBP , 10 [EBP]
6216F3 C3 RET NEAR
END-CODE
( 73 bytes, 25 instructions )
2836 ns ( время TST)
1274 ns ( время tst)
Вычисление на стеке в итоге помещает результат в конкретную ячейку, в качестве
имени которой в дальнейших вычислениях используется номер этой ячейки.
Необходимости в явном присвоении (как для локальных переменных в SPF - см. пример выше ) нет,
что дополнительно повышает эффективность кода.
Еще кое-что:
Использование номеров ячеек в качестве имен локальных переменных вполне годится, потому, что
внутри определения локальных переменных немного и наделять их каким особым смыслом нет необходимости.
PS. С Новым Годом!