2016-11-25 16 views
3

Я работал над этой программой, где мне нужно ввести строку, а затем отобразить распределение символов в этой строке.Поиск находок в строке в сборке x86

Например:
если вход «minecode» вывод должен быть

С - 1
О - 1
Д - 1
Е - 2
I - 1
M - 1
N - 1

Вот что я пытался сделать, но я действительно не знаю, как пройти цикл и проверить аналогичный символ, а затем увеличить счетчик. Ассемблером является MASM 615, работающий на 32-битной машине.

.686 
.MODEL flat, stdcall 
.STACK 
INCLUDE Irvine32.inc 
.DATA 
    msg0 BYTE "Enter a string of characters: ",0 
    msg1 BYTE "Character Distribution: ",0 
    MainArray dword 10000 dup (?) 
    UniqueChar dword 10000 dup (?) 
    CharCount dword 10000 dup (?) 
.CODE 
MAIN PROC 
    lea edx, msg0 
    call WriteString 
    call dumpregs  ; 1 
    call ReadString 
    mov MainArray, eax 
    call dumpregs  ; 2 
    mov MainArray, ebx 
    call dumpregs  ; 3 
    call CRLF 
    lea edx, msg1 
    call WriteString 
    call CharDist  ; Calls the procedure 
    call dumpregs  ; 5 
    exit 
MAIN ENDP 
CharDist PROC 
    mov ecx, lengthof MainArray 
    mov esi, OFFSET MainArray 
    L1: 
; what to do here?? 
Loop L1: 
CharDist ENDP 
END MAIN 
+4

'Loop L1:' является синтаксической ошибкой. Вы используете только конечный ':', когда вы определяете метку, а не когда ссылаетесь на нее из другого места. (И не используйте LOOP в первую очередь, [он медленный и не делает ничего, что вы не можете сделать так же легко с более распространенными инструкциями] (http://stackoverflow.com/questions/35742570/why-is). –

ответ

5

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

Вы никогда не говорите, является ли это строкой, завершаемой байтом 0 (C-style), которому предшествует его длина (стиль Паскаля) или одна, длина которой передается как второй параметр, но это определит когда вы завершаете цикл. Если вы ищете нулевое завершение, проверьте только что прочитанный байт, и если вы подсчитываете определенное количество байтов, продолжайте подсчет байтов в ecx и проверьте это. (Есть специальные инструкции по отрасли условно, если ecx не равен нуль, если вы чувствуете, как использовать их.)

Если вы держите свой указатель на строку в esi, вы можете загрузить следующие байты в al с lodsb инструкции. Кроме того, вы можете mov от [esi], а затем inc esi. Если вы обнулите eax перед сохранением каждого байта в al, это даст вам индекс в eax, который вы можете использовать с массивом счетчиков.

+1

Yup, только 256 ящиков достаточно малы, чтобы стандартный подход к гистограмме хорошо работал с простым массивом, а не хеш-таблицей или другая структура данных карты. –

+5

Однако ваше предложение использовать инструкцию LOOP для реализации цикла не очень хорошо. На большинстве процессоров [это настолько медленно, что вы можете забыть и его существование) (http://stackoverflow.com/questions/35742570/why-is-the-loop-instruction-slow-couldnt-intel-have-implemented- это эффективно), если не оптимизировать размер кода. Другая вещь, которую я предлагаю, заключается в использовании 'movzx eax, byte [esi]'/'inc [table + eax]' внутри цикла. Это может быть проще, чем обнулить eax за пределами цикла, а затем просто изменить младший байт внутри цикла (например, с помощью LODSB). Оба способа работают. –

+1

Я бы определенно посоветовал OP получить простой подход, прежде чем пытаться реализовать хеш-таблицу на ассемблере. – Davislor

3

Другой возможный подход:

Должно быть легче понять и на самом деле это очень «человек» просто (например, как бы вы это делаете на бумаге с карандашом), так что я удивляюсь, как вы не придумали этот ... вы должны не только попытаться понять, как это работает, но и попытаться выяснить, почему вы его не видели, что вас путает/блокирует.

for all letters of alphabet [A-Z] as "letter" { 
    counter = 0; 
    for all characters in input string as "char" { 
     if (letter ignore_case_equals char) ++counter; 
    } 
    if (0 < counter) { 
     display "letter - counter" and new line. 
    } 
} 

Это может быть действительно быстрее для английского алфавита и короткой строки, например, 3-5 букв (содержащих только буквы); чем предложенный тип сортировки, так как алфавит составляет 26 символов, а таблица счетчика - 256 байт, поэтому 256/26 = ~ 9. Но таблица счетчика будет показывать количество для любого символа, включая не-алфавитные, а также будет меньше останавливаться на ветвлении.


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

Я начал с почти-английского описания алгоритма.Потому что мне все равно, что я знаю, чтобы писать в Assembly (я уже знаю, что почти что угодно :)), сначала я хочу быть уверенным, что знаю, что я хочу, чтобы код сделал для меня и какие данные я хочу обрабатывать. Затем я попрошу CPU сделать это, завершая план структур данных и разделяя эти английские заметки на более простые и простые шаги, пока они не начнут напоминать инструкции, затем я пополняю инструкции между комментариями.

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

+3

В зависимости от того, как вы реализуете часть count-matches, эта часть может быть разветвленной (CMP/'sete al' /' add ecx, eax'). В версии гистограммы также присутствует ветвь '0

+0

Если бы вы могли гарантировать, что будут только буквы, вы также можете оптимизировать массив ведер, чтобы быть быстрее! Но это также работает, и хорошо попробовать более одного подхода. – Davislor