Сборник по задачам и примерам Assembler

Создание односвязного списка переходов для состояния конечного автомата



Создание односвязного списка переходов для состояния конечного автомата

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

item_l1st_cross struc ;элемент списка переходов

simbol db 0 :входной символ, при котором автомат переходит

:в состояние ниже (поля id_state_cross и nextjtem) id_state_crossdb 0 идентификатор состояния в списке состояний,

:в которое производится переход

point_state dd 0 ;адрес элемента состояния, в которое производится переход next_item dd 0 :адрес следующего элемента в списке переходов для этого состояния

create_item_cross macro sim:REQ.state:REQ.descr:REQ.head:REQ. Hand_Head:REQ

local ml,@@cycl.exit_m

:создание элемента списка переходов для определенного состояния

:вход:

;регистр ЕВХ - адрес предыдущего (для поля descr.nextjtern),

.-Для первого должен быть равен нулю



:sim - символ ASCII, при поступлении которого производится переход в состояние state

:descr - имя структуры-элемента списка переходов

:state - номер состояния, в которое производится переход

;(если двузначное, то в скобках <>)

:head - имя переменной для хранения указателя на конец списка состояний

;Hand_Head - дескриптор кучи процесса по умолчанию

: выход:

регистр ЕВХ - адрес созданного элемента списка переходов

:флаг cf=l - ошибка: нет такого состояния

сохраняем регистры

push eax

:запрашиваем и инициализируем блок памяти из кучи: :LPVOID HeapAlloc(HANDLE hHeap. DWORD dwFlags. DWORD dwBytes); push type descr ;размер структуры push 0 -.флаги не задаем

push Hand_Head ;описатель кучи call HeapAlloc

mov [eax].next_item.ebx :адрес предыдущего movebx.eax запоминаем адрес текущего


mov [eax].simbol,"&sim" инициализируем поле simbol текущего элемента mov [eax].id_state_cross.state ;номер состояния в поле descr.id_state_cross :теперь нужно определить адрес элемента в списке состояний state для выполнения дальнейших переходов и инициализации поля point_state push ebx mov ebx.head clc

(a@cycl :cmp [ebx].id_state_state,state je ml jc exit_m

mov ebx,[ebx].prev_state ;адрес предыдущего состояния в списке состояний cmpebx.O :последний элемент?

jne @@cycl stc

jmp @@cycl ml: :нашли!

mov [eax].poi nt_state,ebx exitjn: восстанавливаем регистры pop ebx pop eax endm

Далее приведена вспомогательная макрокоманда, которая по номеру состоя-ия определяет адрес соответствующего элемента в списке состояний. def_point_item_state macro N_state:REQ,head:REQ local @(acy,@@ml сохраняем регистры :вход:

:N_state - номер состояния

:head - имя ячейки, где хранится указатель на список состояний :выход: регистр ЕВХ - адрес элемента в списке состояний

mov eax.head

@@су: cmp [eax].id_state_state,N_state :ищем ... je @@ml ;нашли?

moveax,[eax].prev_state ;адрес следующего состояния cmp eax. О последний элемент? jne @@cy

stc ;cf=l если состояния с таким номером не существует

jmp @@су

@@ml: :нашли!

endm

Собственно программа prg02_ll.asm, выполняющая построение и инициализацию конечного автомата для распознавания лексемы вещественного числа в директивах dd, dq и dt, достаточно велика.

 

Содержание раздела