Команды изменения потока управления. Команды условных переходов. Реализация конечных автоматов. Регулярные выражения

 

Если команда перехода и точка перехода находятся в одном сегменте – то для перехода процессору достаточно изменить значение в IP– это и будет близкий переход. Если же точка перехода находится в другом сегменте чем команда перехода – процессору, для осуществления перехода, понадобится изменить значение как CSтак и IP– это уже будет дальний переход. Короткий переход аналогичен близкому, за тем исключением, что для процессора 8086 он может осуществляться только в пределах –128…+127 байт от операции, следующей за командой перехода.

Безусловный переход изменяет адрес следующей исполняемой команды. Если процессор выполняет безусловный переход, то следующей обязательно будет выполняться команда, на которую указывает этот переход. При безусловных переходах в регистр IP (близкий переход) или CS:IP (дальний переход) загружаются значения новых адресов. Вместе CS:IP определяют адрес следующей исполняемой команды. Безусловный переход осуществляется командой ассемблера jmp. Ниже приведен синтаксис данной команды:

jmp shortTarget jmp short @@5 Короткий – на локальную метку@@5
jmp nearTarget jmp finish Близкий – на метку finish
jmp farTarget jmp far count Дальний – метка count в другом сегменте
jmp regW/memDW jmp bx, jmp [word si] Близкий – адрес перехода в bx, адрес перехода в ячейке, адресуемой содержимым si
jmp memDD jmp [dword di] Дальний – адрес в двойном слове, адресуемом содержимым di

Условные переходы осуществляют переход по целевому адресу в случае выполнения определенного условия, задаваемого состоянием флагов процессора.

Переходы для беззнаковых данных:
мнемоника описание флаги
je/jz переход, если равно/нуль ZF
jne/jnz переход, если не равно/нуль ZF
ja/jnbe переход, если больше/не меньше или равно ZF, CF
jae/jnb переход, если больше или равно/не меньше CF
jb/jnae переход, если меньше/не больше или равно CF
jbe/jna переход, если меньше или равно/не больше CF, AF

 

Переходы для знаковых данных:
мнемоника описание флаги
je/jz переход, если равно/нуль ZF
jne/jnz переход, если не равно/нуль ZF
jg/jnle переход, если больше/не меньше или равно ZF, SF, OF
jge/jnl переход, если больше или равно/не меньше SF, OF
jlb/jnge переход, если меньше/не больше или равно SF, OF
jle/jng переход, если меньше или равно/не больше ZF, SF, OF
Дополнительные арифметические проверки:
мнемоника описание флаги
js/jns переход, если отрицательно/положительно SF
jc/jnc переход, если перенос/нет переноса CF
jo/jno переход, если переполнение/нет п. OF
jp/jnp переход, если четный/нечетный PF

Условные переходы требуют целевого адреса – метки, обозначающей место в программе, с которого она продолжит исполняться в случае выполнения заданного условия. Метка должна находиться в пределах –128…+127 байт от адреса следующей инструкции. В случае нарушения данного условия ассемблер, во время компиляции, сообщит о соответствующей ошибке.

Конечный автомат — абстрактный автомат без выходного потока, число возможных состояний которого конечно. Результат работы автомата определяется по его конечному состоянию.

 

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

Q — конечное множество состояний автомата;

q0 — начальное состояние автомата ();

F — множество заключительных (или допускающих) состояний, таких что ;

Σ — допустимый входной алфавит (конечное множество допустимых входных символов), из которого формируются строки, считываемые автоматом;

δ — заданное отображение множества во множество подмножеств Q:

 

(иногда δ называют функцией переходов автомата).

 


#include <stdio.h>

int c;

 

int

main()

{

goto s1;

 

s2: c = getchar();

 

switch(c)

{

case EOF:

exit(0);

default :

putchar(c);

goto s2;

}

s1: c = getchar();

switch (c)

{

case EOF:

exit(0);

case '1':

putchar('0');

goto s1;

case '0':

putchar('1');

goto s2;

}

 

}

#include <stdio.h>

 

int char_to_id (int c) {

switch (c) {

case '0': return 0;

case '1': return 1;

case EOF: return 2;

default: return 2;

}

}

 

typedef struct table_item_s {

int state;

int out_char;

 

} table_item_t;

 

#define END_STATE 2

table_item_t

T[2][3] = {

{ {1, '1'}, {0, '0'} , {END_STATE, '\n'}},

{ {1, '0'}, {1, '1'} , {END_STATE, '\n'}}

};

 

 

int main() {

int c, c_id;

int state = 0;

while(!feof(stdin)) {

c = getchar();

c_id = char_to_id(c);

putchar(T[state][c_id].out_char);

state = T[state][c_id].state;

if(state == END_STATE)

return 0;

}

}


Регуля́рные выраже́ния (англ. regular expressions, сокр. RegExp, RegEx, жарг. регэ́кспы или ре́гексы) — это формальный язык поиска и осуществления манипуляций с подстроками в тексте, основанный на использовании метасимволов (символов-джокеров, англ. wildcard characters). По сути это строка-образец (англ. pattern, по-русски её часто называют «шаблоном», «маской»), состоящая из символов и метасимволов и задающая правило поиска.

Регулярные выражения используются некоторыми текстовыми редакторами и утилитами для поиска и подстановки текста. Например, при помощи регулярных выражений можно задать шаблоны, позволяющие: найти все последовательности символов «кот» в любом контексте, как то: «кот», «котлета», «терракотовый»;

найти отдельно стоящее слово «кот» и заменить его на «кошка»;

найти слово «кот», которому предшествует слово «персидский» или «чеширский»;

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

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

Команды работы со стеком. Процедуры. Передача параметров. Стековые фреймы. Рекурсия. Создание функций с переменным числом параметров. Локальные и глобальные переменные. Модели памяти. Интерфейс с языками высокого уровня. Встроенный ассемблерный код.