Forth http://fforum.winglion.ru/ |
|
Локальные слова http://fforum.winglion.ru/viewtopic.php?f=2&t=2557 |
Страница 1 из 7 |
Автор: | chess [ Вт мар 30, 2010 15:08 ] |
Заголовок сообщения: | Локальные слова |
Локальные имена слов(чтобы не загромождать словарь "разовыми именами" и сильно не задумываться над их названиями). В качестве таковых можно использовать, например, имена лок. переменных. Простейшая реализация: Код: : x{ HERE BRANCH, >MARK 2 HERE \ формируем безусловный переход вперед 0x5E C, \ POP ESI - убираем адрес возврата со стека возврата, чтобы корректно работать с локальными переменными ; IMMEDIATE : }x 0x56 C, \ PUSH ESI - возвращаем адрес возврата на стек возврата, чтобы корректно работал EXECUTE >R RET, POSTPONE THEN R> LIT, \ разрешаем переход вперед, формируем ret в конце кода и оставляем нач. адрес кода (xt) ; IMMEDIATE \ EOF : S1 { a b \ c c+8 sum } 2 TO c x{ c 8 + TO c }x TO c+8 x{ a b + }x TO sum c+8 EXECUTE sum EXECUTE c * ; Код: 1 2 S1 лог. Код: Ok ( 30 )
пс. 1.Сохранять адрес возврата надо в USER-переменной. Вместо связок name EXECUTE можно использовать суффикс ~ (name~). 2. Можно начинать локальное определение например так: NAME{ и заканчивать } При этом в куче сформировать простейший список типа: n1 name1 0 xt1 n name2 0 xt2 ... после формирования определения список удалить. Вариантов как всегда много. |
Автор: | chess [ Пт апр 16, 2010 20:09 ] |
Заголовок сообщения: | |
chess писал(а): Вариантов как всегда много.
Реализация без лок. переменных: Код: 1000 CONSTANT LVOC \ глубина лок. словаря USER DPVOC \ указатель в лок. словаре на первый своб. байт \ формирование локального имени в буфере PAD : NAME, ( a u -- axt ) 2>R 2R@ DPVOC @ SWAP MOVE 2R> NIP DPVOC @ + DUP DPVOC ! ; \ опознаем начало локального имени кода, формируем имя кода в буфере, \ кладем на стек адрес буфера, в котором будет находиться адрес кода внутреннего определения, \ формируем код для перехода вперед : NOTFOUND ( a u -- axt here 2 xt ) 2>R 2R@ + 1- C@ [CHAR] ( <> IF 2R> NOTFOUND EXIT THEN DPVOC @ 0= IF PAD LVOC ERASE PAD DPVOC ! THEN 2R> 1- NAME, HERE BRANCH, >MARK 2 HERE ; \ окончание формирования определения с локальным имененм : ) ( axt here 2 xt -- ) >R RET, POSTPONE THEN R> SWAP ! DPVOC @ CELL+ DPVOC ! ; IMMEDIATE \ префикс для исполнения локальных имен(включен примитивный поиск) : ~ ( "name" -- ) PAD LVOC NextWord DUP >R SEARCH IF DROP R> + @ LIT, POSTPONE EXECUTE ELSE DROP R> TYPE ." NOT" THEN ; IMMEDIATE \ выход с "обнулением" признака заполненности буфера : ; 0 DPVOC ! POSTPONE ; ; IMMEDIATE \ пример для демонстрации : s ( a b -- a^2 + b^3 ) square( DUP * ) cub( DUP DUP * * ) f1( ~ cub SWAP ~ square + ) ~ f1 ; SEE s 2 3 s log Код: CODE s 5AE9D7 E907000000 JMP 5AE9E3 ( s+C ) __ 5AE9DC 8945FC MOV FC [EBP] , EAX xt1 | 5AE9DF F76DFC IMUL FC [EBP] | 5AE9E2 C3 RET NEAR __| 5AE9E3 E90D000000 JMP 5AE9F5 ( s+1E ) __ 5AE9E8 8945FC MOV FC [EBP] , EAX xt2 | 5AE9EB 8945F8 MOV F8 [EBP] , EAX | 5AE9EE F76DF8 IMUL F8 [EBP] | 5AE9F1 F76DFC IMUL FC [EBP] | 5AE9F4 C3 RET NEAR ___| 5AE9F5 E92D000000 JMP 5AEA27 ( s+50 ) ___ 5AE9FA 8945FC MOV FC [EBP] , EAX xt3 | 5AE9FD B8E8E95A00 MOV EAX , # 5AE9E8 | 5AEA02 8BD0 MOV EDX , EAX | 5AEA04 8B45FC MOV EAX , FC [EBP] | 5AEA07 FFD2 CALL EDX | 5AEA09 8B5500 MOV EDX , 0 [EBP] | 5AEA0C 894500 MOV 0 [EBP] , EAX | 5AEA0F 8BC2 MOV EAX , EDX | 5AEA11 8945FC MOV FC [EBP] , EAX | 5AEA14 B8DCE95A00 MOV EAX , # 5AE9DC | 5AEA19 8BD0 MOV EDX , EAX | 5AEA1B 8B45FC MOV EAX , FC [EBP] | 5AEA1E FFD2 CALL EDX | 5AEA20 034500 ADD EAX , 0 [EBP] | 5AEA23 8D6D04 LEA EBP , 4 [EBP] | 5AEA26 C3 RET NEAR ____| 5AEA27 8945FC MOV FC [EBP] , EAX 5AEA2A B8FAE95A00 MOV EAX , # 5AE9FA 5AEA2F 8BD0 MOV EDX , EAX 5AEA31 8B45FC MOV EAX , FC [EBP] 5AEA34 FFD2 CALL EDX 5AEA36 C3 RET NEAR END-CODE ( 96 bytes, 33 instructions ) Ok ( 31 ) ПС. - поиск в лок. словаре примитивный, реально нужно чуть сложнее для надежности идентификации имен - слова читающие из входного потока лучше не использовать(надежнее через вход в NOTFOUND сделать) ( слово ~ использовано только из-за простоты реализации - для демонстрации ) у таких слов есть недостатки, например: Код: TO VAL1 \ так работает
TO \ так VAL1 \ не работает в макросах их нельзя использовать и тп ... |
Автор: | вопрос [ Пт апр 16, 2010 21:26 ] |
Заголовок сообщения: | |
Цитата: chess писал(а): есть соображения - каков оптимальнй?
Вариантов как всегда много. видимо - нет ... |
Автор: | chess [ Сб апр 17, 2010 10:47 ] |
Заголовок сообщения: | |
вопрос писал(а): есть соображения - каков оптимальнй?
видимо - нет ... Соображения всегда есть. Оптимальный вариант на все случаи жизни и со всех точек зрения врд-ли существует. В части повышения эффективности труда программиста оптимальным видится вариант, сочетающий локальные переменные и локальные слова в любых комбинациях. Что-то вроде такого: Код: : name { a b c \ d e -- }
c b sname1 ... lname1( a b sname1 ... to d ) a c d sname2 d lname1 ... lname2( a b lname1 ... to e ) sname3 lname2 .. ... ; |
Автор: | mOleg [ Сб апр 17, 2010 11:07 ] |
Заголовок сообщения: | |
все замечательно, только не понятно, зачем их вообще надо делать? т.е. зачем нужны временные определения в момент создания статического определения? |
Автор: | chess [ Сб апр 17, 2010 12:22 ] |
Заголовок сообщения: | |
mOleg писал(а): все замечательно, только не понятно, зачем их вообще надо делать?
т.е. зачем нужны временные определения в момент создания статического определения? Вы не поняли. Тут нет никаких временных определений. Весь код определения без исключения попадает в словарь. Тут только вводятся временные имена кусочкам кода, чтобы потом формировать вызовы на эти временно именованные куски кода внутри определения. Не надо особо заботиться о временных именах - их не будет в словаре системы. Более компактный код определения получается за счет повторного использования кода. |
Автор: | вопрос [ Сб апр 17, 2010 13:52 ] |
Заголовок сообщения: | |
chess писал(а): mOleg писал(а): все замечательно, только не понятно, зачем их вообще надо делать? т.е. зачем нужны временные определения в момент создания статического определения? Вы не поняли. Тут нет никаких временных определений. Весь код определения без исключения попадает в словарь. Тут только вводятся временные имена кусочкам кода, чтобы потом формировать вызовы на эти временно именованные куски кода внутри определения. Не надо особо заботиться о временных именах - их не будет в словаре системы. Более компактный код определения получается за счет повторного использования кода. типа label или goto |
Автор: | chess [ Сб апр 17, 2010 19:16 ] |
Заголовок сообщения: | Re: |
вопрос писал(а): типа label или goto Нет это совсем не label и тем более не goto. Поле кода в таких определениях выглядит сл. образом: Код: код Во время исполнения код1 и код2 обходятся jmp-амиjmp a код1 ret a: код jmp b код2 ret b: код .... ret Сами коды типа код1 выполняются посредством xt1(код1) execute. Вообщем смотрите ассемблерный код примера. |
Автор: | chess [ Ср апр 21, 2010 16:51 ] |
Заголовок сообщения: | Re: Локальные слова |
Теперь доступ к именам внутренних процедур упрощен, а вместо связки адрес execute просто Call адрес, поиск в лок. словаре стал надежным. Код: \ область и указатель для лок. словаря
0x200 CONSTANT larr USER ldp USER-CREATE arr larr USER-ALLOT : lvoc ( -- a len ) arr larr ; 0 ldp ! \ формирование локального имени (после последнего символа имени идет нулевой байт) : lname, \ a u -- axt 2>R 2R@ ldp @ SWAP MOVE 0 2R> NIP ldp @ + TUCK C! 1+ DUP ldp ! ; \ опознаем начало локального имени кода, формируем имя кода в лок. области, \ кладем на стек адрес в лок. области, в котором будет находиться адрес начала кода внутреннего определения, \ формируем код для перехода вперед : NOTFOUND ( a u -- axt here 2 xt ) 2>R 2R@ + 1- C@ [CHAR] ( <> IF 2R> NOTFOUND EXIT THEN ldp @ 0= IF lvoc ERASE lvoc DROP ldp ! THEN 2R> 1- lname, HERE BRANCH, >MARK 2 HERE ; \ окончание формирования кода с локальным имененм : ) \ axt here 2 xt -- >R RET, POSTPONE THEN R> SWAP ! ldp @ CELL+ ldp ! ; IMMEDIATE \ процедура поиска имени в лок. словаре : lsearch { a u a1 u1 \ a2 u2 fl -- a u 0|1 } 0 TO fl BEGIN a u a1 u1 SEARCH >R TO u2 TO a2 R> a2 u1 + C@ 0= AND IF 1 TO fl a2 u2 TRUE ELSE a2 u1 + 1+ TO a u2 u1 - 1- TO u u u1 < IF 1 TO fl a u FALSE THEN THEN fl UNTIL ; \ компиляция кода с именами в лок. словаре : NOTFOUND \ a u -- 2>R lvoc 2R@ DUP >R lsearch 0= ldp @ 0= OR IF RDROP 2DROP 2R> NOTFOUND EXIT THEN DROP R> + 1+ @ >CS :@, RDROP RDROP ; \ окончание компиляции определения с "обнулением" признака заполненности лок. словаря : ; 0 ldp ! POSTPONE ; ; IMMEDIATE \ примеры для демонстрации принципа STARTLOG : s1 \ a b -- a^2 + b^2 ^2( DUP * ) ^2 SWAP ^2 + ; SEE s1 10 11 s1 : s2 { a b c -- a^2+a^3+a^4 b^2+b^3+b^4 c^2+c^3+c^4 } ^2( DUP * ) ^3( DUP ^2 * ) \ с использованием уже определенных ^4( ^2 ^2 ) ++( + + ) a ^2 a ^3 a ^4 ++ b ^2 b ^3 b ^4 ++ c ^2 c ^3 c ^4 ++ ; 10 11 12 s2 lvoc DROP 30 DUMP CR LOG CODE s1 5AEBBF E907000000 JMP 5AEBCB ( s1+C ) 5AEBC4 8945FC MOV FC [EBP] , EAX 5AEBC7 F76DFC IMUL FC [EBP] 5AEBCA C3 RET NEAR 5AEBCB E8F4FFFFFF CALL 5AEBC4 ( s1+5 ) 5AEBD0 8B5500 MOV EDX , 0 [EBP] 5AEBD3 894500 MOV 0 [EBP] , EAX 5AEBD6 8BC2 MOV EAX , EDX 5AEBD8 E8E7FFFFFF CALL 5AEBC4 ( s1+5 ) 5AEBDD 034500 ADD EAX , 0 [EBP] 5AEBE0 8D6D04 LEA EBP , 4 [EBP] 5AEBE3 C3 RET NEAR END-CODE ( 37 bytes, 12 instructions ) 333E3C 5E 32 00 12 EC 5A 00 5E 33 00 1E EC 5A 00 5E 34 ^2..мZ.^3..мZ.^4 333E4C 00 35 EC 5A 00 2B 2B 00 45 EC 5A 00 00 00 00 00 .5мZ.++.EмZ..... Ok ( 221 11100 16093 22608 ) |
Автор: | chess [ Чт апр 22, 2010 09:33 ] |
Заголовок сообщения: | Re: |
chess писал(а): В части повышения эффективности труда программиста оптимальным видится вариант, сочетающий локальные переменные и локальные слова в любых комбинациях. Подумал как можно вводить вместо традиционных локальных переменных локально-именованные переменные в самом теле кода определения. В качестве примера привожу решение по римским числам. Код: : rome. smd( S" " DROP ) \ так вводим локально именованный байт sym.( smd C@ S" IVXLCDM" DROP + + C@ EMIT ) dig.( smd C! 5 /MOD OVER 4 = \ dig sm -- IF 0 sym. IF 2 sym. ELSE 1 sym. THEN DROP ELSE IF 1 sym. THEN 0 ?DO 0 sym. LOOP THEN ) 1000 /MOD 6 dig. 100 /MOD 4 dig. 10 /MOD 2 dig. 0 dig. ; log Код: 3949 rome. MMMCMXLIX Ok пс. лок. переменные таким образом(в виде строк) можно вводить произвольной разрядности. Но код DROP надо бы убрать. |
Автор: | вопрос [ Чт апр 22, 2010 10:46 ] |
Заголовок сообщения: | Re: Локальные слова |
Да. это хорошая полезная подвижка в деле организации forth-кода |
Автор: | chess [ Пт апр 23, 2010 09:28 ] |
Заголовок сообщения: | Re: Re: |
chess писал(а): пс. лок. переменные таким образом(в виде строк) можно вводить произвольной разрядности. Но код DROP надо бы убрать. Показалось наиболее простым так ввести ячейку для переменной: Код: : SS v( DUP A=RS ret ) \ на встроенном ассме определим ячейку для переменной ( DUP POP EAX RET ) a( v ) b( v ) \ вводим две ячейки с именами a и b 123 a ! 456 b ! a @ b @ + ; SS log Код: Ok ( 579 )
|
Автор: | chess [ Пт апр 23, 2010 16:02 ] |
Заголовок сообщения: | Re: Re: |
chess писал(а): Показалось наиболее простым так ввести ячейку для переменной Вот именно что показалось. Вариант некорректный по причине затирания кода данными. Да и за счет переписывания кэша из-за близости в адресном пространстве кода и данных - вариант медленный. Более быстрым будет вариант с использованием отдельного user-массива данных удаленного от кода. Например: Код: USER-CREATE data 200 USER-ALLOT
: SS v( data + ) a( 0 v ) b( 4 v ) 1 a ! 2 b ! a @ b @ + ; |
Автор: | chess [ Пн апр 26, 2010 16:21 ] |
Заголовок сообщения: | Re: Re: |
Еще один способ введения локально-именуемых стат. переменных внутрь кода определений. Если связку >CS :@, (формирует код CALL addr без участия оптимизатора СПФ) заменить на эквивалент ( COMPILE, ) Код: \ компиляция кода с именами в лок. словаре : NOTFOUND \ a u -- 2>R lvoc 2R@ DUP >R lsearch 0= ldp @ 0= OR IF RDROP 2DROP 2R> NOTFOUND EXIT THEN DROP R> + 1+ @ COMPILE, RDROP RDROP ; то при компиляции подключится оптимизатор СПФ, и в частности начнет работать механизм инлайн-подстановок. При этом появляется нетривиальная возможность вводить статические локально-именуемые переменные внутри кода определения. Код: : v S" [ HERE ] LITERAL" EVALUATE ; IMMEDIATE \ или, что эквивалентно, через макрос: M: v [ HERE ] LITERAL ; И хотя код определения вроде-бы становится самомодифицируемым в ходе его исполнения (перезапись данных в адреса переменных, которые находятся внутри кода определения), но на самом деле будет модифицироваться лишь та часть кода определения, которая не будет работать в качестве исполняемого кода. Такие переменные могут использоваться как байтовые, двухбайтовые, обычные или двойные в любых сочетаниях. \EOF Код: : s1 a( v ) b( v ) 1 a ! a @ 2 a C! a C@ 4. a 2! 2. b 2! a 2@ b 2@ D+ ; s1 log Код: ( 1 2 6 0 )
Ok |
Автор: | chess [ Пт апр 30, 2010 16:16 ] |
Заголовок сообщения: | Re: Re: |
Реализация XT для локально-именованного кода: Код: USER lxt 0 lxt ! : l' TRUE lxt ! ; IMMEDIATE \ компиляция кода с именами в лок. словаре(чуть переделано) : NOTFOUND \ a u -- 2>R lvoc 2R@ DUP >R lsearch 0= lhere @ 0= OR IF RDROP 2DROP 2R> NOTFOUND EXIT THEN DROP R> + 1+ @ lxt @ 0= IF COMPILE, ELSE 0 lxt ! LIT, THEN RDROP RDROP ; Многократное исполнение локально-именованного кода: Код: \ чтобы не городить новую структуру управления(в дальнейшем вряд-ли часто используемую) \ проще по случаю написать ее на ассме: : lrep \ N -- 1- lvoc NextWord DUP >R lsearch 2DROP R> + 1+ @ 2>R L2: R@ EXECUTE $ 4 @X-- L1 J0= L2 JMP L1: $ 8 Xa ; \ примеры использования : S1 dup( DUP ) 3 lrep dup l' dup ; SEE S1 22 S1 \ Напечать N чисел Фибоначчи : fibo. \ n -- step-fibo( TUCK + DUP CR . ) >R 1 1 R> lrep step-fibo 2DROP ; 10 fibo. HEX CR . DECIMAL log Код: CODE S1 5AECC3 E907000000 JMP 5AECCF ( S1+C ) 5AECC8 8945FC MOV FC [EBP] , EAX 5AECCB 8D6DFC LEA EBP , FC [EBP] 5AECCE C3 RET NEAR 5AECCF 8945FC MOV FC [EBP] , EAX 5AECD2 B803000000 MOV EAX , # 3 5AECD7 8D6DFC LEA EBP , FC [EBP] 5AECDA E888FFFFFF CALL 5AEC67 ( lrep ) 5AECDF 8945FC MOV FC [EBP] , EAX 5AECE2 8945F8 MOV F8 [EBP] , EAX 5AECE5 B8C8EC5A00 MOV EAX , # 5AECC8 5AECEA 8D6DF8 LEA EBP , F8 [EBP] 5AECED C3 RET NEAR END-CODE ( 43 bytes, 13 instructions ) 2 3 5 8 13 21 34 55 89 144 5AECC8 Ok ( 22 22 22 22 ) пс. Вывод- локально-именованный код доступен внешним словам через XT(не через имена). |
Страница 1 из 7 | Часовой пояс: UTC + 3 часа [ Летнее время ] |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |