Сеть
Создание односвязного списка переходов для состояния конечного автомата
Также опишем структуру элемента списка переходов и макрокоманду для создания этого элемента. Особенность в том, что в отличие от списка состояний макрокоманда строит не весь список, а только один его элемент. Другая особенность в том, что указатель на полученный односвязный список является ссылкой на последний выделенный элемент списка и именно к этому элементу осуществляется привязка элемента состояния к своему списку переходов, что на самом деле особого значения не имеет.
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, достаточно велика.