проФорт

Форт и всё такое

Конечные автоматы и таблицы решений на SPF

,

Наработка выросла из необходимости быстро написать парсер для html (для дипломной работы и в образовательно-показательных целях задача стояла писать велосипеды и не брать готовое). А как известно, конечные автоматы — это самое оно для сканеров и прочих лексических анализаторов. В итоге всей годовой работы автоматы (дальше — КА) и написание (рисование) схем для анализа html-текстов были наиболее приятной и наиболее богатой на полезные последействия подзадачкой.

Наработка уже немножко выросла из коротких штанишек (хотя и не избавилась до конца от своих родовых, студенческих пятен — например, имён переменных и процедур на русском языке [sic!], только недавно, с месяц назад, задним числом были добавлены синонимы в латинице). Активно используется, например, в ygrek'овых регулярных выражениях на SPF (NFA-реализация) и конечно в моих программках на скорую руку (см. ссылки на примеры кода в конце).

Для тех, кому незнакомо что же есть такое "конечные автоматы", прошу обращаться в обзорные статьи: "От тьюрингова программирования к автоматному", раздел на SoftCraft.

Несмотря на то что конечные автоматы — немножко иной подход, никакими "революциями" по переписыванию всего кода он не метастазирует, не заставляет пересаживать мозги на новую колею, не постулирует нового и единственно правильного способа написания кода отныне и вовеки веков, а вполне себе тихо работает, быстро пишется и быстро работает там где он уместен (по крайней мере это так в рамках Форта, которому это вообще свойственно: "включение" новых, как это модно говорить, "парадигм" программирования подключением несколько килобайтовой библиотеки, и само собой что без отключения предыдущих "парадигм").

КА (конечные автоматы, finite-state machines) пусть и имеют за собой некую теоретическую базу (см. "страшную" статью на Wikipedia), на практике не представляют ничего такого сложного и академически высоколобого для освоения и использования. Уверять в этом не буду, а просто покажу это примерами на пальцах.

Таблицы решений (переходов) — по реализации стали частным случаем одного состояния автомата, хотя и приобрели в процессе работы некоторые собственные свойства. С них, простых и начнём.

Для начала работы нужно взять последнюю версию ~profit/lib/chartable.f и положить её в соответствующую папку в DEVEL.

Следующий код:

<span style='color:#000084; font-weight:bold; '>REQUIRE </span><span style='color:#000084; font-weight:bold; '>state-table </span><span style='color:#000084; '>~profit/lib/chartable.f</span>

<span style='color:#008c00; '>3</span> state-table one-two-three
<span style='color:#008c00; '>1</span> asc: <span style='color:#000084; font-weight:bold; '>." </span><span style='color:#0000ff; '>one</span><span style='color:#000084; font-weight:bold; '>"</span> ;
<span style='color:#008c00; '>2</span> asc: <span style='color:#000084; font-weight:bold; '>." </span><span style='color:#0000ff; '>two</span><span style='color:#000084; font-weight:bold; '>"</span> ;
<span style='color:#008c00; '>3</span> asc: <span style='color:#000084; font-weight:bold; '>." </span><span style='color:#0000ff; '>three</span><span style='color:#000084; font-weight:bold; '>"</span> ;

<span style='color:#008c00; '>1</span> one-two-three
<span style='color:#808080; '>\ вывод: one</span>
<span style='color:#008c00; '>3</span> one-two-three
<span style='color:#808080; '>\ вывод: three</span>


будет аналогичен функции one-two-three с одним параметром в языке С:

<span style='color:#000084; font-weight:bold; '>void</span> one_two_three(<span style='color:#000084; font-weight:bold; '>int</span> n){
<span style='color:#000084; font-weight:bold; '>switch</span>(n) {
<span style='color:#000084; font-weight:bold; '>case </span><span style='color:#008c00; font-weight:bold; '>1</span><span style='color:#800000; font-weight:bold; '>: </span><span style='color:#000084; font-weight:bold; '>printf</span>(<span style='color:#0000ff; '>"</span><span style='color:#0000ff; '>one</span><span style='color:#0000ff; '>"</span>); <span style='color:#000084; font-weight:bold; '>break</span>;
<span style='color:#000084; font-weight:bold; '>case </span><span style='color:#008c00; font-weight:bold; '>2</span><span style='color:#800000; font-weight:bold; '>: </span><span style='color:#000084; font-weight:bold; '>printf</span>(<span style='color:#0000ff; '>"</span><span style='color:#0000ff; '>two</span><span style='color:#0000ff; '>"</span>); <span style='color:#000084; font-weight:bold; '>break</span>;
<span style='color:#000084; font-weight:bold; '>case </span><span style='color:#008c00; font-weight:bold; '>3</span><span style='color:#800000; font-weight:bold; '>: </span><span style='color:#000084; font-weight:bold; '>printf</span>(<span style='color:#0000ff; '>"</span><span style='color:#0000ff; '>one</span><span style='color:#0000ff; '>"</span>); <span style='color:#000084; font-weight:bold; '>break</span>;
}}


То есть вроде бы это как конструкция case, только разница в том что one-two-three, при вызове, не делает никаких сравнений аргумента, а только сразу переходит к заданной заранее реакции номер которой и будет аргумент (то есть это один косвенный переход вместо нескольких сравнений). Поэтому при создании таблицы нужно сразу указывать кол-во реакций в ней. То есть при создании создаются ячейки которые будут гнёздами для хранения действий-реакций на вызов функции с определённым значением.

Можно задавать действия для нескольких реакций сразу:

<span style='color:#000084; font-weight:bold; '>REQUIRE </span><span style='color:#000084; font-weight:bold; '>state-table </span><span style='color:#000084; '>~profit/lib/chartable.f</span>

<span style='color:#008c00; '>3</span> state-table one-two-three
<span style='color:#008c00; '>1 </span><span style='color:#008c00; '>2</span> range: <span style='color:#000084; font-weight:bold; '>." </span><span style='color:#0000ff; '>onetwo</span><span style='color:#000084; font-weight:bold; '>"</span> ;
<span style='color:#008c00; '>3</span> asc: <span style='color:#000084; font-weight:bold; '>." </span><span style='color:#0000ff; '>three</span><span style='color:#000084; font-weight:bold; '>"</span> ;

<span style='color:#008c00; '>1</span> one-two-three
<span style='color:#808080; '>\ вывод: onetwo</span>
<span style='color:#008c00; '>3</span> one-two-three
<span style='color:#808080; '>\ вывод: three</span>


Можно разом поставить действие для всех реакций через слово all:. Само собой, что последующие установки затирают действие заданное им:

<span style='color:#000084; font-weight:bold; '>REQUIRE </span><span style='color:#000084; font-weight:bold; '>state-table </span><span style='color:#000084; '>~profit/lib/chartable.f</span>

<span style='color:#008c00; '>9</span> state-table nine
all: <span style='color:#000084; font-weight:bold; '>." </span><span style='color:#0000ff; '>IV-IX</span><span style='color:#000084; font-weight:bold; '>"</span> ;
<span style='color:#008c00; '>1</span> asc: <span style='color:#000084; font-weight:bold; '>." </span><span style='color:#0000ff; '>I</span><span style='color:#000084; font-weight:bold; '>"</span> ;
<span style='color:#008c00; '>2</span> asc: <span style='color:#000084; font-weight:bold; '>." </span><span style='color:#0000ff; '>II</span><span style='color:#000084; font-weight:bold; '>"</span> ;
<span style='color:#008c00; '>3</span> asc: <span style='color:#000084; font-weight:bold; '>." </span><span style='color:#0000ff; '>III</span><span style='color:#000084; font-weight:bold; '>"</span> ;

<span style='color:#008c00; '>2</span> nine <span style='color:#000084; font-weight:bold; '>.</span>
<span style='color:#808080; '>\ вывод: II</span>

<span style='color:#008c00; '>7</span> nine <span style='color:#000084; font-weight:bold; '>.</span>
<span style='color:#808080; '>\ вывод: IV-IX</span>

<span style='color:#008c00; '>100</span> nine <span style='color:#000084; font-weight:bold; '>.</span>
<span style='color:#808080; '>\ вывод: IV-IX</span>


Обратите внимание что в последнем примере при задании некорректного номера реакции выполняется действие "по-умолчанию".

Также я для себя определял "синтаксически-сахарные" слова задающие реакции для групп символов как-то:
  • пробел: — задаёт действие на поступивший пробел (код 32)
  • перевод-строки: — задаёт действие на поступивший перевод строки (код 10, код 13 игнорируется)
  • разделители: — задаёт действие для кодов от 0-я до 32-х включительно, то есть реакции для пробельных символов
  • цифры: — задаёт действие для поступающих цифр
  • латинские-буквы: — задаёт действие для поступающих латинских букв
  • символ: — задаёт действие для символа который записан сразу после символ:
  • символы: — задаёт действие для символов которые заданы строкой после слова


Теперь вернёмся к КА. Теоретически автомат — это такой ящик, могущий находится в разных состояниях. В зависимости от своего состояния он будет делать разные действия в ответ на подаваемые на вход данные, в том числе — и переключение себя в другое состояние. В реализации же на SPF автомат представляют из себя группу слов-состояний, в чём-то похожих, в чём-то отличающихся от таблиц решений.

Отличия примерно такие: тогда как таблица решений является по своему эффекту просто поименованной конструкцией case и стоит как бы сама по себе, то для налаживания работы автомата уже нужно строить инфраструктуру: несколько состояний; связи между ними; курсор; обработка специальных реакций состояний автомата, которых нет у таблиц решений (событие о включении состояния, событие об окончании входного потока) и прочее. И самое видное отличие: когда запускаешь состояние (точнее говоря слово созданное через слово state) не делается вызов реакции, вызов слова-состояния только переключает переменную current-state. Реакции состояния вызывает т.н. запускающее слово (о нём — позже) которое будет вызывать реакции текущего состояния подставляя поочерёдно на вход состояний символы из данной заранее строки (хотя технически и можно вызывать реакции текущего состояния "вручную" словом execute-one).

Возьмём для следующего примера задачу подсчёта скобок, при уравновешенном количестве левых и правых скобок выдавать TRUE, при неравном — FALSE:

<span style='color:#000084; font-weight:bold; '>REQUIRE </span><span style='color:#000084; font-weight:bold; '>state-table </span><span style='color:#000084; '>~profit/lib/chartable.f</span>

<span style='color:#000084; font-weight:bold; '>VARIABLE </span><span style='color:#000084; font-weight:bold; '>parens</span><span style='color:#808080; '> \ переменная, счётчик скобок</span>


<span style='color:#808080; '>\ Начало описания автомата</span>
<span style='color:#000084; font-weight:bold; '>state</span> count-parens         <span style='color:#808080; '> \ задаём состояние</span>
<span style='color:#808080; '>\ кол-во реакций задавать не надо, их всегда 256 реакций на символы + 3 специальных</span>

on-enter:      parens  <span style='color:#000084; font-weight:bold; '>0!</span> ; <span style='color:#808080; '> \ действие при входе в состояние</span>
<span style='color:#000084; font-weight:bold; '>CHAR </span><span style='color:#0000ff; '>(</span> asc:    parens 1+! ; <span style='color:#808080; '> \ открывающая круглая скобка</span>
<span style='color:#000084; font-weight:bold; '>CHAR </span><span style='color:#0000ff; '>)</span> asc: <span style='color:#008c00; '>-1</span> parens  <span style='color:#000084; font-weight:bold; '>+!</span> ; <span style='color:#808080; '> \ закрывающая круглая скобка</span>
end-input: parens <span style='color:#000084; font-weight:bold; '>@ </span><span style='color:#000084; font-weight:bold; '>0=</span> ;    <span style='color:#808080; '> \ когда кончилась обрабатываемая строка</span>
<span style='color:#808080; '>\ Конец описания автомата, всего лишь одно состояние</span>


<span style='color:#808080; '>\ на входе строка со скобками, на выходе — лог. значение указывающее равно ли их кол-во</span>
<span style='color:#000084; font-weight:bold; '>: </span><span style='color:#000084; font-weight:bold; '>подсчитать-скобки</span><span style='color:#808080; '> ( addr u — f )</span>
<span style='color:#008c00; '>1</span><span style='color:#800000; '> </span><span style='color:#000084; font-weight:bold; '>TO</span> размер-символа  <span style='color:#808080; '> \ указываем обработчику что символы — однобайтные</span>
<span style='color:#000084; font-weight:bold; '>SWAP</span> поставить-курсор<span style='color:#808080; '> \ устанавливаем курсор на начало строки</span>
count-parens         <span style='color:#808080; '> \ ставим начальное состояние автомата</span>
-символов-обработать <span style='color:#808080; '> \ пускаем автомат, на входе — кол-во символов которые нужно </span>
<span style='color:#808080; '>\ обработать начиная с текущего местоположения курсора</span>
<span style='color:#000084; font-weight:bold; '>;</span>

<span style='color:#000084; font-weight:bold; '>S" </span><span style='color:#0000ff; '>(1+(2-3))</span><span style='color:#000084; font-weight:bold; '>"</span> подсчитать-скобки <span style='color:#000084; font-weight:bold; '>.</span>
<span style='color:#808080; '>\ вывод: -1 (TRUE)</span>
<span style='color:#000084; font-weight:bold; '>S" </span><span style='color:#0000ff; '>(</span><span style='color:#000084; font-weight:bold; '>"</span> подсчитать-скобки <span style='color:#000084; font-weight:bold; '>.</span>
<span style='color:#808080; '>\ вывод: 0</span>


Главное запускающее слово автомата (в нашем примере — подсчитать-скобки), нужно формировать вручную, но поможет тут то что запускающее слово в примере имеет некую "каноническую" форму которой должно хватать для большинства нужд. В следующий раз можно спокойно копировать "шаблон" и просто менять имя первичного состояния на то, что в вашем автомате.

NB. Да, то что нужно задавать переменную размер-символа означает в том числе и то что эта реализация автоматов работает и в Unicode, и в UTF-8 (в упомянутом дипломном проекте).

Этот простенький автомат в виде графа выглядит так:



Пока написанное является просто обёрткой анализа строки, где в лексиконе chartable.f спрятан цикл прохода по строке и вызова соответсвующих реакций для каждого символа строчки. Да и всего одно состояние.

Тогда теперь наложим проверки на наше арифметическое выражение с цифрами, скобками и операциями, которые будут срабатывать на неверных комбинациях вида: "(+)" и "(11)11". Возьмём корректное выражение:

(<span style='color:#008c00; '>1</span>+(<span style='color:#008c00; '>2</span>-<span style='color:#008c00; '>3</span>))


и прикинув какие символы в каждый момент последовательной обработки будут правильными, а какие — ведущими к ошибке, выводим три проверочных состояния:

  • ожидание открывающей скобки или цифры — нулевая позиция и позиции после плюса и минуса,
  • ожидание цифры — позиции после каждой открывающей скобки,
  • ожидание операции ('+', '-', '*', '/') или закрывающей скобки.


Всякий другой символ кроме определённых в состоянии будет вызывать ошибку и останавливать автомат. При желании можно даже оформить вывод осмысленных сообщений об ошибке в позиции где автомат ждал получить на входе то-то, а получил другое.

Пишем код для описанного автомата:

<span style='color:#000084; font-weight:bold; '>REQUIRE </span><span style='color:#000084; font-weight:bold; '>state-table </span><span style='color:#000084; '>~profit/lib/chartable.f</span>

<span style='color:#000084; font-weight:bold; '>VARIABLE </span><span style='color:#000084; font-weight:bold; '>parens </span><span style='color:#808080; '> \ переменная, счётчик скобок</span>

<span style='color:#000084; font-weight:bold; '>state</span> count-parens        <span style='color:#808080; '> \ состояние подсчёта скобок</span>
<span style='color:#000084; font-weight:bold; '>state</span> wait-for-digit      <span style='color:#808080; '> \ состояние ждать-цифры</span>
<span style='color:#000084; font-weight:bold; '>state</span> wait-for-digit-or-( <span style='color:#808080; '> \ состояние ждать-цифры-или-скобки</span>
<span style='color:#000084; font-weight:bold; '>state</span> wait-for-ops-or-)   <span style='color:#808080; '> \ состояние ждать-действия-или-скобки</span>


<span style='color:#000084; font-weight:bold; '>: </span><span style='color:#000084; font-weight:bold; '>err</span>             <span style='color:#808080; '> \ слово обработчик ошибки</span>
<span style='color:#008c00; '>-1</span> parens <span style='color:#000084; font-weight:bold; '>!</span>       <span style='color:#808080; '> \ поставить в счётчик заведомо неверное значение</span>
остановить-автомат<span style='color:#000084; font-weight:bold; '> ;</span>

count-parens<span style='color:#808080; '> \ начинаем задавать реакции для count-parens</span>
all: err ;<span style='color:#808080; '> \ на все символы, кроме заданных явно ниже, реагировать ошибкой</span>
цифры: ;<span style='color:#808080; '> \ цифры игнорировать и пропускать мимо</span>
символы: +-*/  wait-for-digit-or-( ;<span style='color:#808080; '> \ после операции</span>
<span style='color:#000084; font-weight:bold; '>CHAR </span><span style='color:#0000ff; '>(</span> asc:    parens 1+! wait-for-digit ;
<span style='color:#000084; font-weight:bold; '>CHAR </span><span style='color:#0000ff; '>)</span> asc: <span style='color:#008c00; '>-1</span> parens  <span style='color:#000084; font-weight:bold; '>+!</span> wait-for-ops-or-) ;

wait-for-digit
all: err ;
<span style='color:#000084; font-weight:bold; '>CHAR </span><span style='color:#0000ff; '>0 </span><span style='color:#000084; font-weight:bold; '>CHAR </span><span style='color:#0000ff; '>9</span> range: rollback1 count-parens ;

wait-for-digit-or-(
all: err ;
цифры: rollback1 count-parens ;
<span style='color:#000084; font-weight:bold; '>CHAR </span><span style='color:#0000ff; '>(</span> asc: тоже-самое ;

wait-for-ops-or-)
all: err ;
символы: +-*/  rollback1 count-parens ;
<span style='color:#000084; font-weight:bold; '>CHAR </span><span style='color:#0000ff; '>)</span> asc: тоже-самое ;

<span style='color:#000084; font-weight:bold; '>: </span><span style='color:#000084; font-weight:bold; '>подсчитать-скобки</span><span style='color:#808080; '> ( addr u — f )</span>
<span style='color:#808080; '>\ на входе — строка с арифм. выражением, на выходе — корректность</span>
<span style='color:#008c00; '>1</span><span style='color:#800000; '> </span><span style='color:#000084; font-weight:bold; '>TO</span> размер-символа <span style='color:#000084; font-weight:bold; '>SWAP</span> поставить-курсор
parens <span style='color:#000084; font-weight:bold; '>0!</span>
 wait-for-digit-or-( -символов-обработать
parens <span style='color:#000084; font-weight:bold; '>@ </span><span style='color:#000084; font-weight:bold; '>0=</span><span style='color:#000084; font-weight:bold; '> ;</span>

<span style='color:#808080; '>\ включить-отладку-автомата</span>
<span style='color:#000084; font-weight:bold; '>S" </span><span style='color:#0000ff; '>(1+(2-3))</span><span style='color:#000084; font-weight:bold; '>"</span> подсчитать-скобки <span style='color:#000084; font-weight:bold; '>.</span>
<span style='color:#808080; '>\ вывод: -1 (TRUE)</span>
<span style='color:#000084; font-weight:bold; '>S" </span><span style='color:#0000ff; '>(</span><span style='color:#000084; font-weight:bold; '>"</span> подсчитать-скобки <span style='color:#000084; font-weight:bold; '>.</span>
<span style='color:#808080; '>\ вывод: 0</span>


И смотрим диаграмму переходов автомата:



То что автомат можно соптимизировать и убрать состояние count-parens здесь неважно. Так было сделано для того чтобы оставлять действия по изменению переменной parens в одном месте, а не разносить по трём состояниям. Поэтому также после проверки на корректность очередного поступившего символа и перед переключением автомата в "главное" состояние count-parens, надо "возвращать" символ назад, чтобы главное подсчитывающее состояние могло проанализировать поступивший символ (слово rollback1 в коде реакций проверочных состояний и обозначение "вернуть" на предыдущей картинке).

Желающие самостоятельно продолжить тему применения КА в анализе текстов могут сравнить например коды автоматного сканера (парсера) XML на Pascal'е и на SPF (+ диаграмма).

Примеры кода на chartable.f:


Ссылки по теме "КА и Форт":

Распечатка стека возвратовПростой сканер портов - 3

Comments

garbler Friday, July 27, 2007 5:42:55 AM

а вот интересно, как изменится схема, если перейти на unicode ?
или, говоря иначе, что делать при увеличении числа состояний/переходов?

КА ведь вещь достаточно "рыхлая".... памяти ест много....

Azamadt SmaguloffprofiT Friday, July 27, 2007 6:19:10 AM

Originally posted by garbler:

а вот интересно, как изменится схема, если перейти на unicode ?


Конкретно реализация HTML-обработчика в дипломке не требовала от меня анализа не-ASCII символов (русских букв и прочего), поэтому все символы с кодами выше 256-и обрабатываются "на общих основаниях", то есть реакцией задавемой через all:.

Originally posted by garbler:

КА ведь вещь достаточно "рыхлая".... памяти ест много....


Хм. Текущая реализация с простым массивом реакций требует 4 байт * (256 реакций на ASCII-символы + 3 спец. сигнала) = ~1Кб на одно состояние автомата. Даже если мы потребуется анализировать все Unicode-множества, то пусть и получится многовато для отдельных применений, но всё равно достаточно по-божески: 4 байт *(65 536 реакций на каждый U-символ+3) = ~64Кб на одно состояние (при UTF-16).

Буде возникнет особая нужда в этом, можно и перевести внутреннюю механику КА на хранение сигналов и реакций на них в виде хэшей…

Пока не нужно было.

exs Friday, July 27, 2007 5:40:53 PM

Хочется отметить то как такое расширение синтаксиса языка органично встраивается отдельной либой не требуя никаких переделок ядра или ограничений на другие возможности..

garbler Saturday, July 28, 2007 10:50:20 AM

хм, вообще-то не 64кб, а 256, что уже существенно больше.
а вот с хэшами уже интереснее..... я к тому, что было-бы
интересно подумать о механизме глобальной оптимизации/упаковки
всего автомата. в хаскеле вот для этой цели механизм монад
расширили (дополнительным параметром, по которому и производят
оптимизацию), новый тип называется Arrow.... в общем, тут есть
поле для экспериментов.

> Хочется отметить то как такое расширение синтаксиса языка органично
> встраивается отдельной либой не требуя никаких переделок ядра или
> ограничений на другие возможности..

а о синтаксисе/расширяемости никто и не спорит, я знаю,
что в этом вопросе форт так проектировался изначально и
остальные языки уже заимствовали из форта (ридер-макросы
в лиспе и т.п.). вопросы становления хорошо в статье из
HOPL2 от основателей описаны.

собственно, я даже предполагаю, что на использовании лексикона
расширение алфавита может не отразиться, но сам вопрос
остаётся, что делать в ситуациях, когда ввод не ascii.

более того, этот вопрос остаётся для абсолютно любого
языка программирования :-) и форт тут совершенно не при чём....

Azamadt SmaguloffprofiT Saturday, July 28, 2007 7:20:24 PM

Originally posted by garbler:

хм, вообще-то не 64кб, а 256...


Мда, звиняюсь… Никогда не был силён в арифметике — потому и стал программистом.

Originally posted by garbler:

я к тому, что было-бы интересно подумать о механизме глобальной оптимизации/упаковки всего автомата.


Может быть и интересно, не знаю… Только оптимизировать максимум 20 состояний с не больше чем пятью-семью веточками у каждого (это самый сложный автомат что под рукой) — это как-то пушковоробьино.

Ну, если есть у людей такая задача -- то было бы интересно посмотреть… Хотя вот ygrek давно выцыганивает у меня сбор статистики о работе автомата (фактически — профилирование).

Azamadt SmaguloffprofiT Tuesday, July 31, 2007 1:23:53 PM

Достойно упоминания то что дизассемблер SPF (lib/ext/disasm.f) изначально написанный Эндрю МакКюэном в 94-м, работает на двух таблицах переходов по 256 событий: для основной и расширенной систем команд.

А фича тут в том, что можно временно в run-time переопределив отдельные реакции из таблицы переходов получить другое поведение, например, перенос кода на другой адрес вместо дизассемблирования.

garbler Thursday, August 2, 2007 7:53:01 AM

разбор систем команд процессоров - это отдельный разговор :-)
здесь своя специфика, но, даже для этого примера -
только у интела "гранулярность" байтовой будет,
для других процессоров это не так:
например
это фрагмент дизассемблера для NEC V850
idpcmrec.pp порождает iddv850e.ipp который используется
в iddv850e.cpp

у V850 базовой единицей при разборе команды будет 32 бита
(архитектурно - типичный risc)

в общем, не пойми меня превратно, я никого ни за что не
агитирую. мне нравится твой код, просто с моей стороны
это был комментарий к интересной статье.

Azamadt SmaguloffprofiT Thursday, August 2, 2007 1:07:41 PM

Да какие проблемы.

Просто частное решение частной задачи на частной архитектуре.

Anonymous Thursday, April 24, 2008 7:21:35 AM

Anonymous writes: поведение, например, перенос кода на другой адрес вместо дизассемблирования. http://fforum.winglion.ru/viewtopic.php?p=9361#9361 В топике нет информации по переносу кода на другой адрес.

Azamadt SmaguloffprofiT Thursday, April 24, 2008 1:23:05 PM

Правильная ссылка (это не более чем набросок):
~profit/misc/movecode2.f.

Anonymous Friday, October 31, 2008 10:34:46 PM

hl67qh writes: вообщето у Ахо в Книге Дракона было про сжатие таблиц DFA. довольно интересный алгоритм. вродебы он используется в flex

How to use Quote function:

  1. Select some text
  2. Click on the Quote link

Write a comment

Comment
(BBcode and HTML is turned off for anonymous user comments.)

If you can't read the words, press the small reload icon.


Smilies