Автор |
Сообщение |
|
|
Заголовок сообщения: |
Re: Реализация стеков в СПФ |
|
|
Может, кому интересно будет... Я тут пытался кое-что наваять на gforth с использованием их OOP библиотечки, и мне понадобились стеки для объектов. Причем стеков нужно много, и начальный их размер маленький, но теоретически в любой стек в процессе может понадобиться засунуть количество объектов, стремящееся к бесконечности, поэтому стеки должны автоматически менять размер, желательно в любую сторону. Четыре операции: засунуть в стек, высунуть из стека, посмотреть, что лежит на стеке на заданной глубине, и ROLL. Проще сделать стеки, растущие вверх, по-моему, где-то в папке devel у SP-Forth есть исходник, реализующий это. Но из-за ROLL я решил не париться в коде с перетаскиванием туда-сюда содержимого памяти, а сделать стек, растущий вниз, и использовать обычный ROLL, меняя указатель стека данных. Оно вроде бы работает. Там в коде есть вывод сообщений о изменении размера и вывод содержимого памяти, это для наглядности тестового примера, при реальном использовании это, естественно, лучше убрать. Код: #! /opt/local/bin/gforth
S" objects.fs" required
15 CONSTANT DEFAULT_STACK_SIZE DEFAULT_STACK_SIZE VALUE StackSize StackSize VALUE StackResizingTerm 0 VALUE OriginalStackPointer
object class cell% inst-var __stack_heap_address cell% inst-var __stack_size cell% inst-var __stack_pointer
selector __destroy_stack selector __get_stack_heap_address selector __get_stack_size selector __get_stack_pointer selector __get_stack_available_cells selector __get_stack_depth selector __resize_stack selector __increase_stack_if_needed selector __decrease_stack_if_needed selector __push_object_on_stack selector __pop_object_from_stack selector __roll_object_on_stack selector __inspect_object_on_stack
m: ( stack_addr -- ) StackSize CELLS ALLOCATE DROP __stack_heap_address ! StackSize __stack_size ! __stack_heap_address @ __stack_size @ 1- CELLS + __stack_pointer ! ;m overrides construct
m: ( stack_addr -- ) __stack_heap_address @ free DROP ;m overrides __destroy_stack
m: ( stack_addr -- u ) __stack_heap_address @ ;m overrides __get_stack_heap_address
m: ( stack_addr -- u ) __stack_size @ ;m overrides __get_stack_size
m: ( stack_addr -- u ) __stack_pointer @ ;m overrides __get_stack_pointer
m: ( stack_addr -- u ) __stack_pointer @ __stack_heap_address @ - CELL / ;m overrides __get_stack_available_cells
m: ( stack_addr -- u ) __stack_heap_address @ __stack_size @ CELLS + __stack_pointer @ - CELL / ;m overrides __get_stack_depth
m: ( n stack_addr -- ) this __get_stack_depth 0 0 0 { ResizingTerm StackDepth NewStackSize NewStackPointer NewStackHeapAddress -- } __stack_size @ ResizingTerm + TO NewStackSize NewStackSize CELLS ALLOCATE DROP TO NewStackHeapAddress NewStackHeapAddress NewStackSize CELLS + StackDepth CELLS - TO NewStackPointer __stack_pointer @ NewStackPointer StackDepth 1- CELLS CMOVE NewStackSize __stack_size ! NewStackPointer __stack_pointer ! __stack_heap_address @ free DROP NewStackHeapAddress __stack_heap_address ! ;m overrides __resize_stack
m: ( stack_addr -- ) this __get_stack_available_cells 0= IF StackResizingTerm this __resize_stack S" ( Resizing + ) " TYPE THEN ;m overrides __increase_stack_if_needed
m: ( stack_addr -- ) this __get_stack_available_cells StackResizingTerm - 0= IF StackResizingTerm NEGATE this __resize_stack S" ( Resizing - ) " TYPE THEN ;m overrides __decrease_stack_if_needed
m: ( object_addr stack_addr -- ) { ObjectAddress -- } this __increase_stack_if_needed ObjectAddress __stack_pointer @ ! __stack_pointer @ CELL - __stack_pointer ! ;m overrides __push_object_on_stack
m: ( stack_addr -- ) __stack_pointer @ CELL + __stack_pointer ! __stack_pointer @ @ this __decrease_stack_if_needed ;m overrides __pop_object_from_stack
m: ( u stack_addr -- ) { RollingObject -- } this __increase_stack_if_needed SP@ TO OriginalStackPointer __stack_pointer @ CELL + SP! RollingObject ROLL OriginalStackPointer SP! this __decrease_stack_if_needed __stack_heap_address @ __stack_size @ CELLS DUMP ;m overrides __roll_object_on_stack
m: ( u stack_addr -- object_addr ) 1+ { ObjectToInspect -- } __stack_pointer @ ObjectToInspect CELLS + @ ;m overrides __inspect_object_on_stack
end-class stack_object
0 VALUE MyStack : test_stacks stack_object heap-new TO MyStack
CR CR 100 0 DO i MyStack __push_object_on_stack i . LOOP CR S" Current stack size: " TYPE MyStack __get_stack_size . CR MyStack __get_stack_heap_address MyStack __get_stack_size CELLS dump CR 0 99 DO i . S" = " TYPE MyStack __pop_object_from_stack . CR -1 +LOOP
CR CR 14 0 DO i MyStack __push_object_on_stack LOOP 14 0 DO i MyStack __inspect_object_on_stack . LOOP CR 14 0 DO 13 MyStack __roll_object_on_stack LOOP 14 0 DO MyStack __pop_object_from_stack . LOOP MyStack __destroy_stack MyStack free ;
Может, кому интересно будет...
Я тут пытался кое-что наваять на gforth с использованием их OOP библиотечки, и мне понадобились стеки для объектов. Причем стеков нужно много, и начальный их размер маленький, но теоретически в любой стек в процессе может понадобиться засунуть количество объектов, стремящееся к бесконечности, поэтому стеки должны автоматически менять размер, желательно в любую сторону. Четыре операции: засунуть в стек, высунуть из стека, посмотреть, что лежит на стеке на заданной глубине, и ROLL. Проще сделать стеки, растущие вверх, по-моему, где-то в папке devel у SP-Forth есть исходник, реализующий это. Но из-за ROLL я решил не париться в коде с перетаскиванием туда-сюда содержимого памяти, а сделать стек, растущий вниз, и использовать обычный ROLL, меняя указатель стека данных.
Оно вроде бы работает. Там в коде есть вывод сообщений о изменении размера и вывод содержимого памяти, это для наглядности тестового примера, при реальном использовании это, естественно, лучше убрать.
[code]#! /opt/local/bin/gforth
S" objects.fs" required
15 CONSTANT DEFAULT_STACK_SIZE DEFAULT_STACK_SIZE VALUE StackSize StackSize VALUE StackResizingTerm 0 VALUE OriginalStackPointer
object class cell% inst-var __stack_heap_address cell% inst-var __stack_size cell% inst-var __stack_pointer
selector __destroy_stack selector __get_stack_heap_address selector __get_stack_size selector __get_stack_pointer selector __get_stack_available_cells selector __get_stack_depth selector __resize_stack selector __increase_stack_if_needed selector __decrease_stack_if_needed selector __push_object_on_stack selector __pop_object_from_stack selector __roll_object_on_stack selector __inspect_object_on_stack
m: ( stack_addr -- ) StackSize CELLS ALLOCATE DROP __stack_heap_address ! StackSize __stack_size ! __stack_heap_address @ __stack_size @ 1- CELLS + __stack_pointer ! ;m overrides construct
m: ( stack_addr -- ) __stack_heap_address @ free DROP ;m overrides __destroy_stack
m: ( stack_addr -- u ) __stack_heap_address @ ;m overrides __get_stack_heap_address
m: ( stack_addr -- u ) __stack_size @ ;m overrides __get_stack_size
m: ( stack_addr -- u ) __stack_pointer @ ;m overrides __get_stack_pointer
m: ( stack_addr -- u ) __stack_pointer @ __stack_heap_address @ - CELL / ;m overrides __get_stack_available_cells
m: ( stack_addr -- u ) __stack_heap_address @ __stack_size @ CELLS + __stack_pointer @ - CELL / ;m overrides __get_stack_depth
m: ( n stack_addr -- ) this __get_stack_depth 0 0 0 { ResizingTerm StackDepth NewStackSize NewStackPointer NewStackHeapAddress -- } __stack_size @ ResizingTerm + TO NewStackSize NewStackSize CELLS ALLOCATE DROP TO NewStackHeapAddress NewStackHeapAddress NewStackSize CELLS + StackDepth CELLS - TO NewStackPointer __stack_pointer @ NewStackPointer StackDepth 1- CELLS CMOVE NewStackSize __stack_size ! NewStackPointer __stack_pointer ! __stack_heap_address @ free DROP NewStackHeapAddress __stack_heap_address ! ;m overrides __resize_stack
m: ( stack_addr -- ) this __get_stack_available_cells 0= IF StackResizingTerm this __resize_stack S" ( Resizing + ) " TYPE THEN ;m overrides __increase_stack_if_needed
m: ( stack_addr -- ) this __get_stack_available_cells StackResizingTerm - 0= IF StackResizingTerm NEGATE this __resize_stack S" ( Resizing - ) " TYPE THEN ;m overrides __decrease_stack_if_needed
m: ( object_addr stack_addr -- ) { ObjectAddress -- } this __increase_stack_if_needed ObjectAddress __stack_pointer @ ! __stack_pointer @ CELL - __stack_pointer ! ;m overrides __push_object_on_stack
m: ( stack_addr -- ) __stack_pointer @ CELL + __stack_pointer ! __stack_pointer @ @ this __decrease_stack_if_needed ;m overrides __pop_object_from_stack
m: ( u stack_addr -- ) { RollingObject -- } this __increase_stack_if_needed SP@ TO OriginalStackPointer __stack_pointer @ CELL + SP! RollingObject ROLL OriginalStackPointer SP! this __decrease_stack_if_needed __stack_heap_address @ __stack_size @ CELLS DUMP ;m overrides __roll_object_on_stack
m: ( u stack_addr -- object_addr ) 1+ { ObjectToInspect -- } __stack_pointer @ ObjectToInspect CELLS + @ ;m overrides __inspect_object_on_stack
end-class stack_object
0 VALUE MyStack : test_stacks stack_object heap-new TO MyStack
CR CR 100 0 DO i MyStack __push_object_on_stack i . LOOP CR S" Current stack size: " TYPE MyStack __get_stack_size . CR MyStack __get_stack_heap_address MyStack __get_stack_size CELLS dump CR 0 99 DO i . S" = " TYPE MyStack __pop_object_from_stack . CR -1 +LOOP
CR CR 14 0 DO i MyStack __push_object_on_stack LOOP 14 0 DO i MyStack __inspect_object_on_stack . LOOP CR 14 0 DO 13 MyStack __roll_object_on_stack LOOP 14 0 DO MyStack __pop_object_from_stack . LOOP MyStack __destroy_stack MyStack free ;[/code]
|
|
|
|
Добавлено: Вс апр 10, 2011 14:10 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
rvm писал(а): Но, стек данных можно легко безболезненно переставить на блок памяти необходимого размера.
Да, точно, например так:
Код: USER-CREATE UP-SP 4096 CELLS USER-ALLOT \ выделяем блок данных под стек параметров UP-SP 4096 CELLS + DUP S0 ! \ записываем в переменную S0 новый адрес дна стека параметров SP! \ устанавливаем указатель стека на дно
\ проверка стека параметров на переполнение STARTLOG : S1 10000 0 DO I CELL +LOOP ; S1
ЛОГ Ok ( [2500].. 9980 9984 9988 9992 9996 ) переполнения нет
[quote="rvm"]Но, стек данных можно легко безболезненно переставить на блок памяти необходимого размера.[/quote]
Да, точно, например так:
[code]USER-CREATE UP-SP 4096 CELLS USER-ALLOT \ выделяем блок данных под стек параметров UP-SP 4096 CELLS + DUP S0 ! \ записываем в переменную S0 новый адрес дна стека параметров SP! \ устанавливаем указатель стека на дно
\ проверка стека параметров на переполнение STARTLOG : S1 10000 0 DO I CELL +LOOP ; S1
ЛОГ Ok ( [2500].. 9980 9984 9988 9992 9996 ) переполнения нет[/code]
|
|
|
|
Добавлено: Ср янв 16, 2008 18:29 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
Да, это жестко заданно в _WNDPROC-CODE. Но, стек данных можно легко безболезненно переставить на блок памяти необходимого размера.
Да, это жестко заданно в _WNDPROC-CODE. Но, стек данных можно легко безболезненно переставить на блок памяти необходимого размера.
|
|
|
|
Добавлено: Ср янв 16, 2008 13:05 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
Mihail писал(а): В СПФ используется аппаратный стеки возвратов и растет он, как положено, в минус.
Поправил картинку.
Из рисунка можно получить максимальный размер стека параметров.
Код: : MAX-DEPTH R0 @ S0 @ - NEGATE 4 U/ ; MAX-DEPTH CR . Получается всего 1008 ячеек.
[quote="Mihail"]В СПФ используется аппаратный стеки возвратов и растет он, как положено, в минус.[/quote]
Поправил картинку.
Из рисунка можно получить максимальный размер стека параметров.
[code]: MAX-DEPTH R0 @ S0 @ - NEGATE 4 U/ ; MAX-DEPTH CR .[/code]Получается всего 1008 ячеек.
|
|
|
|
Добавлено: Ср янв 16, 2008 12:13 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
chess писал(а): Начинающим фортерам будет полезно узнать как устроены в СПФ стеки возвратов В СПФ используется аппаратный стеки возвратов и растет он, как положено, в минус. вопрос писал(а): Возник вопрос: существует ли потенциальная возможность изменения адреса дна стека параметров и как ... (т.е. в коде как бы это выглядело?)
Слова SP@ SP! - просто чтение и запись в соответствующий регистр
смотри src\spf_forthproc.f
ЗЫ: В Форте возможно все, на то но и Форт. Ограничение накладывает только среда базирования.
[quote="chess"]Начинающим фортерам будет полезно узнать как устроены в СПФ стеки возвратов [/quote]
В СПФ используется аппаратный стеки возвратов и растет он, как положено, в минус.
[quote="вопрос"]Возник вопрос: существует ли потенциальная возможность изменения адреса дна стека параметров и как ... (т.е. в коде как бы это выглядело?)[/quote]
Слова SP@ SP! - просто чтение и запись в соответствующий регистр
смотри src\spf_forthproc.f
ЗЫ: В Форте возможно все, на то но и Форт. Ограничение накладывает только среда базирования.
|
|
|
|
Добавлено: Вт янв 15, 2008 20:09 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
Возник вопрос: существует ли потенциальная возможность изменения адреса дна стека параметров и как ... (т.е. в коде как бы это выглядело?)
Возник вопрос: существует ли потенциальная возможность изменения адреса дна стека параметров и как ... (т.е. в коде как бы это выглядело?)
|
|
|
|
Добавлено: Вт янв 15, 2008 19:47 |
|
|
|
|
|
Заголовок сообщения: |
Реализация стеков в СПФ |
|
|
Начинающим фортерам будет полезно узнать как устроены в СПФ стеки возвратов и параметров.
PS. Адреса USER переменных S0 и R0 зависят от версии СПФ, но сути это не меняет.
Начинающим фортерам будет полезно узнать как устроены в СПФ стеки возвратов и параметров.
[img]http://i038.radikal.ru/0801/0a/ac3e9382a90d.jpg[/img]
PS. Адреса USER переменных S0 и R0 зависят от версии СПФ, но сути это не меняет.
|
|
|
|
Добавлено: Вт янв 15, 2008 17:50 |
|
|
|
|