
Быстрый поиск
Введите фрагмент названия статьи для поиска
Проверка баланса скобок на Ассемблере
28.01.2011 | Категория: Образ мышления: Assembler | Автор: ManHunter
Есть такая классическая задача по программированию: проверка правильности расстановки скобок в строке, или иначе проверка баланса скобок. Суть задачи заключается в том, что есть произвольное математическое выражение, записанное в строку, в этом выражении используется три вида скобок "( )", "[ ]" и "{ }", последовательность и вложенность может быть любая. Требуется проверить, все ли скобки закрыты, соответствует ли каждая закрывающая скобка открывающей и нет ли лишних закрывающих скобок. В разных интернетах есть решения на различных языках программирования, я решил добавить свое решение на Ассемблере, тем более, что он идеально подходит для реализации этого алгоритма.Решение заключается в том, что мы двигаемся по строке с самого начала, перебирая все символы по одному. Если символ является открывающей скобкой любого типа, то мы помещаем его в стек. Если символ является закрывающей скобкой, то берем из стека последнюю сохраненную открывающую скобку и проверяем на соответствие. Если не совпадают - ошибка несоответствия скобок, если стек пустой, то ошибка лишней закрывающей скобки. Если конец строки достигнут, но стек не пустой, то ошибка незакрытых скобок. Как видите, решение целиком построено на работе со стеком, а Ассемблер предоставляет для этого все возможности. Переходим к программированию.
Code (Assembler) : Убрать нумерацию
- ;------------------------------------------------------------------------
- ; Функция проверки правильности расстановки скобок в выражении
- ; На входе: указатель на строку ASCIIZ
- ; На выходе: EAX - результат проверки выражения
- ; 0 - скобки расставлены правильно
- ; 1 - ОШИБКА: скобки не совпадают
- ; 2 - ОШИБКА: закрывающая скобка без открывающей
- ; 3 - ОШИБКА: открывающая скобка без закрывающей
- ;------------------------------------------------------------------------
- proc CheckBrackets str:DWORD
- local res:DWORD ; Результат
- pusha ; Сохранить все регистры
- mov esi,[str] ; Указатель на строку
- cld
- xor ecx,ecx ; Глубина стека
- mov [res],0 ; Результат проверки
- .scan_expr:
- lodsb ; Прочитать символ из строки
- or al,al ; Конец строки достигнут?
- jz .finish
- ; Проверить открывающие скобки
- cmp al,'['
- je .push_bracket
- cmp al,'('
- je .push_bracket
- cmp al,'{'
- je .push_bracket
- ; Проверить закрывающие скобки
- cmp al,']'
- je .pop_bracket
- cmp al,')'
- je .pop_bracket
- cmp al,'}'
- je .pop_bracket
- jmp .scan_expr ; Следующий символ
- ; Занести скобку в стек
- .push_bracket:
- inc ecx ; Увеличить счетчик
- movzx eax,al ; Записать скобку в стек
- push eax
- jmp .scan_expr ; Следующий символ
- ; Извлечь скобку из стека
- .pop_bracket:
- or ecx,ecx ; В стеке ничего нет?
- jne @f
- ; ОШИБКА: закрывающая скобка без открывающей
- mov [res],2
- jmp .finish
- @@:
- dec ecx ; Уменьшить счетчик
- pop ebx ; Извлечь из стека скобку
- ; Проверить закрывающие скобки
- cmp bl,'['
- jne @f
- cmp al,']' ; Скобки совпадают?
- je .scan_expr ; Да, следующий символ
- @@:
- cmp bl,'('
- jne @f
- cmp al,')' ; Скобки совпадают?
- je .scan_expr ; Да, следующий символ
- @@:
- cmp bl,'{'
- jne @f
- cmp al,'}' ; Скобки совпадают?
- je .scan_expr ; Да, следующий символ
- @@:
- ; ОШИБКА: скобки не совпадают
- mov [res],1
- or ecx,ecx ; В стеке пусто?
- jz .exit ; Да, просто на выход
- jmp .clean_stack ; Надо почистить стек
- .finish:
- or ecx,ecx ; Все проверили и в стеке пусто?
- jz .exit ; Да, скобки расставлены правильно
- ; ОШИБКА: открывающая скобка без закрывающей
- mov [res],3
- ; Почистить стек от оставшихся скобок
- .clean_stack:
- pop eax
- loop .clean_stack
- .exit:
- popa ; Восстановить все регистры
- mov eax,[res]
- ret
- endp
Читать статью целиком »
Просмотров: 7616 | Комментариев: 4
Эффект плавного открытия окна
08.12.2010 | Категория: Образ мышления: Assembler | Автор: ManHunter
Разберем еще один красивый эффект для ваших приложений - плавное сворачивание и разворачивание окна. Для этого используются те же функции, что и для создания окон нестандартной формы, так как по сути это такая же работа с прямоугольными регионами, но только в цикле с заданными параметрами. Алгоритм простой: прямоугольный регион окна увеличивается от центра до полного размера или уменьшается со всех сторон до центра. Для этого надо сперва надо вычислить шаг, на который будет увеличиваться или уменьшаться горизонтальная и вертикальная координата.Code (Assembler) : Убрать нумерацию
- ; Обработчик инициализации окна
- ...
- ; Получить размер окна
- invoke GetClientRect,[hwnddlg],coord
- ; Вычислить размеры окна для создания основного региона
- mov eax,[coord.bottom]
- sub eax,[coord.top]
- mov [height],eax
- mov eax,[coord.right]
- sub eax,[coord.left]
- mov [width],eax
- SPEED = 4 ; Скорость анимации
- ; Вычислить коэффициент соотношения сторон в зависимости от
- ; размеров ширины и высоты окна
- cmp eax,[height]
- ja @f
- ; Высота/ширина
- xor edx,edx
- mov eax,[height]
- mov ecx,[width]
- div ecx
- shl eax,SPEED
- mov [delta_x],(1 shl SPEED) ; Шаг изменения ширины
- mov [delta_y],eax ; Шаг изменения высоты
- jmp @1
- @@:
- ; Ширина/высота
- xor edx,edx
- mov eax,[width]
- mov ecx,[height]
- div ecx
- shl eax,SPEED
- mov [delta_x],eax ; Шаг изменения ширины
- mov [delta_y],(1 shl SPEED) ; Шаг изменения высоты
- @1:
Читать статью целиком »
Просмотров: 6863 | Комментариев: 6
Расчет CRC16 на Ассемблере
30.11.2010 | Категория: Образ мышления: Assembler | Автор: ManHunter
CRC (Cyclic Redundancy Code - циклический избыточный код) - алгоритм расчета контрольной суммы для передаваемого сообщения, основанный на полиномиальной арифметике. Основная идея алгоритма CRC состоит в представлении сообщения в виде огромного двоичного числа, делении его на другое фиксированное двоичное число и использовании остатка от этого деления в качестве контрольной суммы. Получив сообщение, приемник должен выполнить аналогичное действие и сравнить полученный результат с принятой контрольной суммой. Сообщение считается достоверным, выполняется это равенство. Классический алгоритм CRC16 часто используется в архиваторах для контроля целостности данных служебных заголовков архивов, также его удобно использовать для сравнения строки с каким-либо значением, когда по соображениям безопасности сравниваемое значение не хранится в открытом виде. Для контроля целостности файлов функцию CRC16 лучше не использовать, так как из-за небольшой длины ее научились подделывать. Чтобы выполнить расчет CRC16 требуется сперва подготовить так называемую таблицу инициализации. В сегменте данных таблица резервируется как 256 слов, по одному word на каждый возможный байт:Code (Assembler) : Убрать нумерацию
- ; Сегмент данных
- section '.data' data readable writeable
- ; Таблица инициализации для расчета CRC16
- crc16table rw 256
Code (Assembler) : Убрать нумерацию
- ;-----------------------------------------------------------------------
- ; Функция создания таблицы инициализации для расчета CRC16
- ;-----------------------------------------------------------------------
- proc init_CRC16
- push eax ebx ecx edi
- ; Указатель на выделенную под таблицу память
- mov edi,crc16table
- ; Расчитать значения для всех 256 слов
- xor edx,edx
- CRC16_Polynom:
- mov eax,edx
- mov ecx,8
- CRC16_NL:
- shr ax,1
- jae CRC16_NoXOR
- ; Magic Number!
- xor ax,0a001h
- CRC16_NoXOR:
- loop CRC16_NL
- ; Записать значение в таблицу полиномов
- stosw
- inc edx ; Счетчик +1
- cmp edx,256 ; Всю таблицу сгенерировали?
- jne CRC16_Polynom ; Нет, работаем дальше
- ; Восстановить измененные регистры
- pop edi ecx ebx eax
- ret
- endp
Читать статью целиком »
Просмотров: 11790 | Комментариев: 2
Как запретить Windows переходить в спящий режим
26.10.2010 | Категория: Образ мышления: Assembler | Автор: ManHunter

Как запретить Windows переходить в спящий режим
В некоторых случаях требуется, чтобы на время работы вашего приложения компьютер постоянно оставался в активном состоянии, то есть не включался скринсейвер, не отключался монитор, система не переходила в спящий режим. Для этого надо "убедить" Windows, что за клавиатурой сидит реальный пользователь и проявляет какую-то активность, в этом случае все счетчики времени бездействия будут сбрасываться. Для программной имитации действий пользователя используются две функции: mouse_event для симуляции работы с мышкой мышки и, соответственно, keybd_event для клавиатуры. Также можно использовать более универсальную функцию SendInput, она позволяет симулировать не только мышку и клавиатуру, но и хардварные события. Есть еще более суровые варианты, связанные с ковырянием в реестре, изменением профилей электропитания, но их я рассматривать не буду.
Читать статью целиком »
Просмотров: 13403 | Комментариев: 25
Экранная лупа на Ассемблере
15.10.2010 | Категория: Образ мышления: Assembler | Автор: ManHunter
Алгоритм реализации экранной лупы достаточно простой. Надо получить часть изображения рабочего стола и скопировать его с масштабированием в нужную область вашего приложения. Сделать это можно при помощи функции StretchBlt. Если посмотрите описание, то увидите, что для работы этой функции требуются следующие параметры: размеры результирующей области, размеры исходной области и контексты устройств (окон), в которых находятся области. А поскольку мы сейчас разрабатываем лупу, значит она должна увеличивать, то есть размеры исходного окна должны быть пропорционально меньше результирующего. Коэффициент пропорциональности и есть коэффициент увеличения лупы. При инициализации окна выполним предварительные расчеты:Code (Assembler) : Убрать нумерацию
- ...
- ; Получить контекст окна лупы
- invoke GetDlgItem,[hwnddlg],ID_ZOOM
- mov ebx,eax
- invoke GetDC,eax
- mov [wDC],eax
- ; Получить размеры окна лупы
- invoke GetClientRect,ebx,coord
- mov eax,[coord.right]
- sub eax,[coord.left]
- mov [dWidth],eax
- mov eax,[coord.bottom]
- sub eax,[coord.top]
- mov [dHeight],eax
- ; Получить контекст десктопа
- invoke GetDesktopWindow
- mov [hDesktop],eax
- invoke GetDC,eax
- mov [dDC],eax
- ...
Читать статью целиком »
Просмотров: 6541 | Комментариев: 6


