Автор |
Сообщение |
|
|
Заголовок сообщения: |
|
|
|
Ну все, получили самый маленький язык программирования, теперь можно на этом рисовать программки.
Для удобства надо еще добавить многозадачность (хотя бы параллельное выполенние нескольких нитей -- адресное пространство кода и данных одно и то же, но для каждой нити отдельные стеки).
Так вот при запуске таких нитей нам нужно будет для команды ( cfa-addr ) thread ( pid ) указывать адрес слова, с которого будет стартовать потом нить командой ( pid ) start ( -- ) .
Для этого нам в ЦК нужно слово ['] которое будет каким-то образом лезть внутрь CREATE-DOES {слова} и вытаскивать из него адрес, который это {слово} использует при компиляции call {слово-addr}.
Самым простым мне показалось сначала дать этому {слову} отработать, то есть скомпилить call, а потом пропатчить этот call заменив на lit. Чтобы сохранить традиционный префиксный синтаксис ['] , используется поиск имени {слова} по словарю и запуск еще через EXECUTE, хотя более красивым и простым было бы использование постфиксной формы.
Код: : ['] BL WORD FIND IF EXECUTE ELSE ABORT THEN \ лезем в поток SOURCE выцепляя имя, делаем поиск и запуск (или аборт) 0x05 ( lit-op) THERE _cell - ( call-op-addr ) b! \ патчим опкод call на опкод lit ;
Ну все, получили самый маленький язык программирования, теперь можно на этом рисовать программки.
Для удобства надо еще добавить многозадачность (хотя бы параллельное выполенние нескольких нитей -- адресное пространство кода и данных одно и то же, но для каждой нити отдельные стеки).
Так вот при запуске таких нитей нам нужно будет для команды [b]( cfa-addr ) thread ( pid )[/b] указывать адрес слова, с которого будет стартовать потом нить командой [b]( pid ) start ( -- )[/b] .
Для этого нам в ЦК нужно слово [b]['][/b] которое будет каким-то образом лезть внутрь CREATE-DOES [b]{слова}[/b] и вытаскивать из него адрес, который это [b]{слово}[/b] использует при компиляции [b]call {слово-addr}[/b].
Самым простым мне показалось сначала дать этому {слову} отработать, то есть скомпилить call, а потом пропатчить этот call заменив на lit. Чтобы сохранить традиционный префиксный синтаксис ['] , используется поиск имени {слова} по словарю и запуск еще через EXECUTE, хотя более красивым и простым было бы использование постфиксной формы.
[code]: ['] BL WORD FIND IF EXECUTE ELSE ABORT THEN \ лезем в поток SOURCE выцепляя имя, делаем поиск и запуск (или аборт) 0x05 ( lit-op) THERE _cell - ( call-op-addr ) b! \ патчим опкод call на опкод lit ;[/code]
|
|
|
|
Добавлено: Вс июн 03, 2007 11:48 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
буфер
Код: : buffer ( n ) CREATE THERE , ( n ) 0 DO 0 b, LOOP DOES> @ lit ; запоминаем адрес (текущее значение THERE), компилим n нулевых байт, при упоминании имени буфера компилим литерал адрес буфера Код: 512 buffer FLOPPY_SECTOR ... z1 ... FLOPPY_SECTOR ... z2 ... компилится в Код: ... @FLOPPY_SECTOR: db 0 times 512 ... z1 ... lit @FLOPPY_SECTOR ... z2 ...
буфер
[code]: buffer ( n ) CREATE THERE , ( n ) 0 DO 0 b, LOOP DOES> @ lit ;[/code]запоминаем адрес (текущее значение THERE), компилим n нулевых байт, при упоминании имени буфера компилим литерал адрес буфера [code]512 buffer FLOPPY_SECTOR ... z1 ... FLOPPY_SECTOR ... z2 ...[/code]компилится в [code]... @FLOPPY_SECTOR: db 0 times 512 ... z1 ... lit @FLOPPY_SECTOR ... z2 ...[/code]
|
|
|
|
Добавлено: Вс июн 03, 2007 11:36 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
переменные -- компилируем в байт-код начальное значение, его адрес запоминаем через CREATE-DOES,
Код: : var ( n ) CREATE THERE , ( n ) cell, DOES> @ lit ; при упоминании имени переменной в коде Код: 0x1234 var SDKJSDJ
.... z1 ... SDKJSDJ @ ... z2 ... компилируем запомненный адрес переменной литералом: Код: ... @SDKJSDJ: dcell 0x1234 ... z1 ... lit @SDKJSDJ @ ... z2 ...
переменные -- компилируем в байт-код начальное значение, его адрес запоминаем через CREATE-DOES,
[code]: var ( n ) CREATE THERE , ( n ) cell, DOES> @ lit ;[/code]при упоминании имени переменной в коде [code]0x1234 var SDKJSDJ
.... z1 ... SDKJSDJ @ ... z2 ...[/code] компилируем запомненный адрес переменной литералом: [code]... @SDKJSDJ: dcell 0x1234 ... z1 ... lit @SDKJSDJ @ ... z2 ...[/code]
|
|
|
|
Добавлено: Вс июн 03, 2007 11:31 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
ну и структуры управления.
если словарную структуру не создаем, то делаем просто:
константы реализуем как CREATE-DOES слова, в целевой код компилируем литералом inline:
Код: : const ( n ) CREATE ( n ) , DOES> @ lit ; код Код: 0x1234 const KDSKSDKJ
.... z1 ... KDSKSDKJ ... z2 ... компилится Код: .... z1 .... lit 0x1234 ... z2 ...
ну и структуры управления.
если словарную структуру не создаем, то делаем просто:
константы реализуем как CREATE-DOES слова, в целевой код компилируем литералом inline:
[code]: const ( n ) CREATE ( n ) , DOES> @ lit ; [/code] код [code]0x1234 const KDSKSDKJ
.... z1 ... KDSKSDKJ ... z2 ...[/code]компилится [code].... z1 .... lit 0x1234 ... z2 ...[/code]
|
|
|
|
Добавлено: Вс июн 03, 2007 11:27 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
и наконец аналогично
Код: .... z1 begin z2 ( flag ) until z3 ... компилится в Код: ... z1 @BEGIN: z2 ( flag ) @UNTIL: ?jmp @BEGIN z3 ... как и с begin/again никаких фиктивных jmpов, компилим Код: ?jmp @BEGIN и все
и наконец аналогично
[code].... z1 begin z2 ( flag ) until z3 ...[/code]компилится в [code] ... z1 @BEGIN: z2 ( flag ) @UNTIL: ?jmp @BEGIN z3 ...[/code] как и с begin/again никаких фиктивных jmpов, компилим [code]?jmp @BEGIN[/code] и все
|
|
|
|
Добавлено: Вс июн 03, 2007 11:24 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
Код: ... z1 begin z2 ( flag ) while z3 repeat z4 ... компилится в Код: ... z1 @BEGIN: \ begin положил адрес z2 ( flag ) @WHILE: ?jmp 0xFFFF --patched--> @REPEAT \ while положил адрес и скомпилил фиктивный ?jmp z3 jmp @WHILE \ это @REPEAT: \ и это скомпилил repeat используя со стека адреса положенные begin и while z4 ...
[code]... z1 begin z2 ( flag ) while z3 repeat z4 ...[/code]компилится в [code] ... z1 @BEGIN: \ begin положил адрес z2 ( flag ) @WHILE: ?jmp 0xFFFF --patched--> @REPEAT \ while положил адрес и скомпилил фиктивный ?jmp z3 jmp @WHILE \ это @REPEAT: \ и это скомпилил repeat используя со стека адреса положенные begin и while z4 ...[/code]
|
|
|
|
Добавлено: Вс июн 03, 2007 11:19 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
совсем просто реализуются циклы do/loop:
Код: .... z1 ( n1 n2 ) do z2 i z3 loop z4 ... компилится используя спец.команды для таких циклов, которые используют собственный стек Код: ... z1 ( n1 n2 ) do z2 i z3 loop z4 ...
совсем просто реализуются циклы do/loop:
[code].... z1 ( n1 n2 ) do z2 i z3 loop z4 ...[/code]
компилится используя спец.команды для таких циклов, которые используют собственный стек
[code] ... z1 ( n1 n2 ) do z2 i z3 loop z4 ...[/code]
|
|
|
|
Добавлено: Вс июн 03, 2007 11:16 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
Код: .... z1 begin z2 again z3 ... проще всего: Код: ... z1 @BEGIN: z2 @AGAIN: jmp @BEGIN z3 ...
никакого геморроя -- тупо взяли адрес, положенный begin, и скомпилили на него jmp
[code].... z1 begin z2 again z3 ...[/code]проще всего: [code] ... z1 @BEGIN: z2 @AGAIN: jmp @BEGIN z3 ...[/code]
никакого геморроя -- тупо взяли адрес, положенный begin, и скомпилили на него [b]jmp[/b]
|
|
|
|
Добавлено: Вс июн 03, 2007 11:14 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
код
Код: ... z1 if z2 else z3 endif z4 ... компилится более сложно: Код: ... z1 @IF: ?jmp 0xFFFF --patched--> @ELSE \ скомпилилось ifом z2 jmp 0xFFFF --patched--> @ENDIF \ это @ELSE: \ и это скомпилилось elseом, на стеке данных была подмена адресов для endifа z3 @ENDIF: \ отработал endif но пропатчил не ifный ?jmp а elseный jmp (адреса параметров на стеке были подменены elseом) z4 ...
код
[code]... z1 if z2 else z3 endif z4 ...[/code] компилится более сложно: [code] ... z1 @IF: ?jmp 0xFFFF --patched--> @ELSE \ скомпилилось ifом z2 jmp 0xFFFF --patched--> @ENDIF \ это @ELSE: \ и это скомпилилось elseом, на стеке данных была подмена адресов для endifа z3 @ENDIF: \ отработал endif но пропатчил не ifный ?jmp а elseный jmp (адреса параметров на стеке были подменены elseом) z4 ...[/code]
|
|
|
|
Добавлено: Вс июн 03, 2007 11:09 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
код
Код: ... z1 ( n1 n2 n3 flag ) if z2 endif z3 ... скомпилируется в байт-код Код: ... z1 ( n1 n2 n3 flag ) @IF: ?jmp 0xFFFF --patched--> label@ENDIF \ здесь работало слово if компилируя фиктивный jmp z2 label@ENDIF: \ здесь работало слово endif которое взяло THERE=label@ENDIF и пропатчило фиктивный jmp z3 ...
код
[code]... z1 ( n1 n2 n3 flag ) if z2 endif z3 ...[/code] скомпилируется в байт-код [code] ... z1 ( n1 n2 n3 flag ) @IF: ?jmp 0xFFFF --patched--> label@ENDIF \ здесь работало слово if компилируя фиктивный jmp z2 label@ENDIF: \ здесь работало слово endif которое взяло THERE=label@ENDIF и пропатчило фиктивный jmp z3 ... [/code]
|
|
|
|
Добавлено: Вс июн 03, 2007 11:02 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
чтобы врубиться в работу слов типа if else begin while ... имхо лучше всего посмотреть в какой код компилируются эти конструкции, и попытаться реализовать их самостоятельно (в итоге получится практически тот же самый код что и у меня
чтобы врубиться в работу слов типа [b]if else begin while ...[/b] имхо лучше всего посмотреть в какой код компилируются эти конструкции, и попытаться реализовать их самостоятельно (в итоге получится практически тот же самый код что и у меня 8-)
|
|
|
|
Добавлено: Вс июн 03, 2007 10:59 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
С реализацией конструкций типа if/else/endif все очень запутанно. Если кратко, то используется принцип -- в местах где нам нужно скомпилировать безусловный или условный переход, компилируем фиктивный (?)jmp 0xFFFF(FFFF) , запоминая в стеке данных адрес параметра этого (?)jmpа. Далее в процессе работы ЦК мы выясняем необходимые реальные значения этого параметра, и патчим параметры ранее скомпилированных jmpов (так называемая методика backpatching, используется практически во всех однопроходных компиляторах).
С реализацией конструкций типа [b]if/else/endif[/b] все очень запутанно. Если кратко, то используется принцип -- в местах где нам нужно скомпилировать безусловный или условный переход, компилируем фиктивный [b](?)jmp 0xFFFF(FFFF)[/b] , запоминая в стеке данных адрес параметра этого [b](?)jmp[/b]а. Далее в процессе работы ЦК мы выясняем необходимые реальные значения этого параметра, и патчим параметры ранее скомпилированных jmpов (так называемая методика backpatching, используется практически во всех однопроходных компиляторах).
|
|
|
|
Добавлено: Вс июн 03, 2007 10:57 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
совсем по-простому: словом { NEWWORD мы добавляем в ЦК слово NEWWORD компилирующее call на значение THERE в момент своего создания,
} вообще тупо компилирует ret.
совсем по-простому: словом { NEWWORD мы добавляем в ЦК слово NEWWORD компилирующее call на значение THERE в момент своего создания,
} вообще тупо компилирует ret.
|
|
|
|
Добавлено: Вс июн 03, 2007 10:50 |
|
|
|
|
|
Заголовок сообщения: |
Re: [BF] структуры управления в старом ЦК |
|
|
forth@km.ru писал(а): Код: : { THERE _entry cell! CREATE THERE , DOES> @ call ; : } ret ;
Эти два слова используются для определения слов (процедур) в целевом коде (vs макросы определенные как обычно через : ; и компилирующиеся в целевой код inline). Код: THERE _entry cell! берет текущее значение указателя ЦК, и патчит параметрт стартого jmpа в стартовом коде (см. самый конец исходника цк), устанавливая точку входа программы на определяемое через { } слово. Учтите что словарная структура в целевом коде не создается, так что это значение фактически является CFA нового слова. Если все же понадобится создание словарной структуры, слово HEADER, компилирующее заголовок словарной статьи, должно выполняться до этого кода. Код: CREATE THERE , DOES> @ call в словаре инструментальной форт-системы (в нашем случае это SPF) создается CREATE-DOESнутое слово с именем слова, которое мы сейчас определяем через { }. Это слово при своем выполнении будет компилировать команду call на запомненное текущее значение THERE.
Таким образом, когда при работе ЦК мы выполняем (в режиме интерпретации) слово { NEWWORD. оно добавляет в ЦК слово NEWWORD, которое уже в свою очередь будет компилировать call на текущий адрес.
[quote="forth@km.ru"][code] : { THERE _entry cell! CREATE THERE , DOES> @ call ; : } ret ; [/code][/quote]
Эти два слова используются для определения слов (процедур) в целевом коде (vs макросы определенные как обычно через : ; и компилирующиеся в целевой код inline).
[code]THERE _entry cell![/code] берет текущее значение указателя ЦК, и патчит параметрт стартого jmpа в стартовом коде (см. самый конец исходника цк), устанавливая точку входа программы на определяемое через { } слово. Учтите что словарная структура в целевом коде не создается, так что это значение фактически является CFA нового слова. Если все же понадобится создание словарной структуры, слово HEADER, компилирующее заголовок словарной статьи, должно выполняться до этого кода.
[code]CREATE THERE , DOES> @ call[/code] в словаре инструментальной форт-системы (в нашем случае это SPF) создается CREATE-DOESнутое слово с именем слова, которое мы сейчас определяем через { }. Это слово при своем выполнении будет компилировать команду call на запомненное текущее значение THERE.
Таким образом, когда при работе ЦК мы выполняем (в режиме интерпретации) слово { NEWWORD. оно добавляет в ЦК слово NEWWORD, которое уже в свою очередь будет компилировать call на текущий адрес.
|
|
|
|
Добавлено: Вс июн 03, 2007 10:48 |
|
|
|
|
|
Заголовок сообщения: |
[BF] структуры управления в старом ЦК |
|
|
Код: \ структуры управления
: { THERE _entry cell! CREATE THERE , DOES> @ call ; : } ret ;
: if -1 ?jmp THERE _cell - ; : endif THERE SWAP cell! ; : else -1 jmp THERE _cell - SWAP endif ;
: begin THERE ; : again jmp ; : until ?jmp ; : while if ; : repeat SWAP jmp THERE SWAP cell! ;
: const ( n ) CREATE ( n ) , DOES> @ lit ; : var ( n ) CREATE THERE , ( n ) cell, DOES> @ lit ; : buffer ( n ) CREATE THERE , ( n ) 0 DO 0 b, LOOP DOES> @ lit ;
[code] \ структуры управления
: { THERE _entry cell! CREATE THERE , DOES> @ call ; : } ret ;
: if -1 ?jmp THERE _cell - ; : endif THERE SWAP cell! ; : else -1 jmp THERE _cell - SWAP endif ;
: begin THERE ; : again jmp ; : until ?jmp ; : while if ; : repeat SWAP jmp THERE SWAP cell! ;
: const ( n ) CREATE ( n ) , DOES> @ lit ; : var ( n ) CREATE THERE , ( n ) cell, DOES> @ lit ; : buffer ( n ) CREATE THERE , ( n ) 0 DO 0 b, LOOP DOES> @ lit ;[/code]
|
|
|
|
Добавлено: Вс июн 03, 2007 10:38 |
|
|
|
|