Задачка о разбиении на строки (оптимизация по размеру)

Тема в разделе "WASM.A&O", создана пользователем Black_mirror, 10 июн 2008.

  1. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    Есть текстовый буфер, который заканчивается символом с кодом 0. В буфере находятся строки, друг от друга они могут отделяться символом с кодом 10, символом с кодом 13, последовательностью 10,13 или последовательностью 13,10. После последней строки этих символов может и не быть. Необходимо написать функцию GetLine, которая получив указатель на начало буфера, найдёт конец первой строки, заменит символ 10 или 13 на 0 (если там два символа, то можно заменить оба), и вернёт указатель на начало следующей строки. Функция должна быть STDCALL, то есть параметр получает через стёк, результат в eax, регистры ebx,esi,edi,ebp разрушать нельзя.

    Если текст имеет следующий вид
    Код (Text):
    1. s0 db 'a',10
    2. s1 db 'bb',10,13
    3. s2 db 10,13
    4. s3 db 'cccc',13
    5. s4 db 13,10
    6. ;s5 db 'ddd',13   [add]<- закомментрирую чтобы не исправлять остальное[/add]
    7. s5 db 'end'    
    8. s6 db 0
    то GetLine(s0) должно вернуть s1, GetLine(s1) должно вернуть s2, ..., GetLine(s5) должно вернуть s6, а GetLine(s6) должно вернуть s6. При этим символы 10 или 13 в конце строк замениться на 0 (там где их по 2, обязательно должен быть заменён первый символ, второй по желанию).
     
  2. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    GetLine proc astr
    mov eax,astr
    test eax,eax
    jz short glStrScanLoop_e
    mov ch,1
    mov dx,0a0dh
    jmp short glStrScanLoop_entry
    glStrScanLoop_b:
    mov ch,0
    mov [eax],ch
    glStrScanLoop_loop:
    inc eax
    glStrScanLoop_entry:
    mov cl,[eax]
    test cl,cl
    jz short glErrExit
    cmp cl,dl
    jz short glStrScanLoop_b
    cmp cl,dh
    jz short glStrScanLoop_b
    test ch,ch
    jnz short glStrScanLoop_loop
    glStrScanLoop_e:
    ret
    glErrExit:
    xor eax,eax
    ret
    GetLine endp
     
  3. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    _basmp_
    xor eax,eax
    Imho противоречит условиям задачи.

    Black_mirror
    Уточни задание.
    Имеют ли преимущество пары (13, 10) и (10,13) перед отдельными 13 и 10. Например
    Код (Text):
    1. 0000    'a'
    2. 0001    'b'
    3. 0002    'c'
    4. 0003    'd'
    5. 0004    13
    6. 0005    10
    7. 0006    13
    8. 0007    'e'
    9. ...
    первая строка начинается по смещению 0, а вторая 5 или 6?
     
  4. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    q_q
    Чем? еах==0 на выходе означает конец перебора. А как без этого?
     
  5. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    _basmp_
    Чем?
    Black_mirror > "GetLine(s6) должно вернуть s6."
     
  6. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    q_q
    Ну тогда вместо
    xor eax,eax
    пишем
    mov eax,astr
    или пушаем в начале и попаем перед рет-ами. Нехорошо - лишнее обращение к памяти. Хорошо - сохраняет 2 байта.
     
  7. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    _basmp_
    test eax,eax/jz short glStrScanLoop_e делать не нужно, можно считать что указатель всегда передаётся правильный, но он может указывать на строку 0й длины, в этом случае именно его и нужно вернуть. Если мы передаём указатель на 13,13,13,... (или 10,10,10,...) то каждый из этих символов расценивается как конец строки, и после первого вызова последовательность должна иметь вид 0,13,13,..., и eax должно указывать на следующий за 0м символ. А у вас все символы 10 и 13 будут пропущены за один вызов.

    q_q
    Имеют, вторая строка начинается по смещению 6, а треться по смещению 7. А если текст имеет вид 'abcd',13,13,10,'e', то вторая строка будет начинаться по смещению 5, но третья по смещению 7 как и в прошлом случае.
     
  8. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    Black_mirror
    Недопонял

    GetLine proc astr
    mov eax,astr
    mov ch,0
    mov dx,0a0dh
    jmp short glStrScanLoop_entry
    glStrScanLoop_b:
    and cl,3
    test ch,cl
    jnz short glStrScanLoop_e
    or ch,cl
    mov byte ptr [eax],0 ; или mov cl,0; mov [eax],cl
    glStrScanLoop_loop:
    inc eax
    glStrScanLoop_entry:
    mov cl,[eax]
    test cl,cl
    jz short glLastExit
    cmp cl,dl
    jz short glStrScanLoop_b
    cmp cl,dh
    jz short glStrScanLoop_b
    test ch,ch
    jz short glStrScanLoop_loop
    glStrScanLoop_e:
    ret
    glLastExit:
    mov eax,astr
    ret
    GetLine endp
     
  9. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
  10. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
  11. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
  12. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
  13. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    Black_mirror
    Код (Text):
    1. option prologue : none
    2. option epilogue : none
    3.  
    4. GetLine proc    Src : ptr byte
    5.  
    6.     mov eax,Src
    7.     dec eax
    8.  
    9. next_char:
    10.     inc eax
    11.     mov cl,[eax]
    12.     or  cl,cl
    13.     jz  short eob_found
    14.  
    15.     cmp cl,0Dh
    16.     jz  short first_eol_char_found
    17.     cmp cl,0Ah
    18.     jnz short next_char
    19.  
    20. first_eol_char_found:
    21.     mov byte ptr [eax],0
    22.  
    23.     inc eax
    24.     mov ch,[eax]
    25.     or  ch,ch
    26.     jz  short eob_found
    27.  
    28. ;;
    29. ;; проверка на пары (0Dh,0Dh) или (0Ah,0Ah)
    30. ;;
    31.     cmp ch,cl
    32.     jz  short double_eol_char_found
    33.  
    34. ;;
    35. ;; удвоения нет, но возможно есть (0Dh,0Ah) или (0Ah,0Dh),
    36. ;; тогда надо пропустить второй символ конца строки
    37. ;;
    38.     inc eax     ;; пока пропускаю
    39.  
    40.     cmp ch,0Dh
    41.     jz  short second_eol_char_found
    42.     cmp ch,0Ah
    43.     jz  short second_eol_char_found
    44.  
    45.     dec eax     ;; второго символа нет, вернуть пропуск
    46.  
    47. eob_found:
    48. double_eol_char_found:
    49. second_eol_char_found:
    50.     retn    4h
    51.  
    52. GetLine endp
    53.  
    54. option prologue : prologuedef
    55. option epilogue : epiloguedef
     
  14. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    _basmp_
    Теперь почти работает, только от минимума пока далеко. Код после glLastExit- лишний, переходить нужно на glStrScanLoop_e. Когда в строке 10 или 13 отсутствуют, то вернуть нужно указатель на завершающий 0.

    q_q
    Работает, но тоже далеко до оптимального варианта. Я думаю что у этой задачи существует решение не длинее 32х байт :)

    All
    В дальшейшем просьба указывать сколько байт занимает код, начиная от proc и заканчивая endp. А еще лучше дизассемблированный текст приводить с кодами команд.
     
  15. NoResponse

    NoResponse New Member

    Публикаций:
    0
    Регистрация:
    28 дек 2005
    Сообщения:
    89
    Код (Text):
    1. 00401000  /$  55            PUSH EBP
    2. 00401001  |.  8BEC          MOV EBP,ESP
    3. 00401003  |.  8B75 08       MOV ESI,[ARG.1]                          ;  _.<ModuleEntryPoint>
    4. 00401006  |.  8BCE          MOV ECX,ESI
    5. 00401008  |.  33C0          XOR EAX,EAX
    6. 0040100A  |.  33DB          XOR EBX,EBX
    7. 0040100C  |.  EB 0A         /JMP SHORT _.00401018
    8. 0040100E  |>  C646 FF 00    |/MOV BYTE PTR DS:[ESI-1],0
    9. 00401012  |.  4B            ||DEC EBX
    10. 00401013  |.  80FB FE       ||CMP BL,0FE
    11. 00401016  |.  74 19         ||JE SHORT _.00401031
    12. 00401018  |>  8AE0          | MOV AH,AL
    13. 0040101A  |.  AC            ||LODS BYTE PTR DS:[ESI]
    14. 0040101B  |.  38E0          ||CMP AL,AH
    15. 0040101D  |.  74 11         ||JE SHORT _.00401030
    16. 0040101F  |.  3C 00         ||CMP AL,0
    17. 00401021  |.  74 0E         ||JE SHORT _.00401031
    18. 00401023  |.  3C 0D         ||CMP AL,0D
    19. 00401025  |.^ 74 E7         ||JE SHORT _.0040100E
    20. 00401027  |.  3C 0A         ||CMP AL,0A
    21. 00401029  |.^ 74 E3         |\JE SHORT _.0040100E
    22. 0040102B  |.  80FB 00       |CMP BL,0
    23. 0040102E  |.^ 74 E8         \JE SHORT _.00401018
    24. 00401030  |>  4E            DEC ESI
    25. 00401031  |>  8D4433 FF     LEA EAX,DWORD PTR DS:[EBX+ESI-1]
    26. 00401035  |.  2BC1          SUB EAX,ECX
    27. 00401037  |.  C9            LEAVE
    28. 00401038  \.  C2 0400       RETN 4
    29. 0040103B      3B            DB 3B                                    ;  CHAR ';'
    3Bh = 59 если не ошибаюсь
    если длина строки не нужна, то выкидываем:
    Код (Text):
    1. 00401031  |>  8D4433 FF     LEA EAX,DWORD PTR DS:[EBX+ESI-1]
    2. 00401035  |.  2BC1          SUB EAX,ECX
    без них 53
     
  16. KeSqueer

    KeSqueer Сергей

    Публикаций:
    0
    Регистрация:
    19 июл 2007
    Сообщения:
    1.183
    Адрес:
    Москва
    Код (Text):
    1. 00401000    58              POP EAX
    2. 00401001    59              POP ECX
    3. 00401002    50              PUSH EAX
    4. 00401003    49              DEC ECX
    5. 00401004    41              INC ECX
    6. 00401005    8A01            MOV AL,BYTE PTR DS:[ECX]
    7. 00401007    84C0            TEST AL,AL
    8. 00401009    74 12           JE SHORT 0040101D
    9. 0040100B    3C 0D           CMP AL,0D
    10. 0040100D    74 04           JE SHORT 00401013
    11. 0040100F    3C 0A           CMP AL,0A
    12. 00401011  ^ 75 F1           JNE SHORT 00401004
    13. 00401013    3001            XOR BYTE PTR DS:[ECX],AL
    14. 00401015    41              INC ECX
    15. 00401016    34 07           XOR AL,07
    16. 00401018    3801            CMP BYTE PTR DS:[ECX],AL
    17. 0040101A    75 01           JNE SHORT 0040101D
    18. 0040101C    41              INC EСX    ; [b]исправлено[/b]
    19. 0040101D    91              XCHG EAX,ECX
    20. 0040101E    C3              RETN
    31 байт
     
  17. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    NoResponse
    Black_mirror > "регистры ebx,esi ... разрушать нельзя"

    Black_mirror
    Я думаю что у этой задачи существует решение не длинее 32х байт
    Можешь доказать?
     
  18. KeSqueer

    KeSqueer Сергей

    Публикаций:
    0
    Регистрация:
    19 июл 2007
    Сообщения:
    1.183
    Адрес:
    Москва
    и сам код:
    Код (Text):
    1. get_str:
    2.         pop     eax
    3.         pop     ecx
    4.         push    eax
    5.         dec     ecx
    6.     .loop:
    7.         inc     ecx
    8.         mov     al, [ecx]
    9.         test    al, al
    10.         je      .end
    11.         cmp     al, 0x0D
    12.         je      .crlf_found
    13.         cmp     al, 0x0A
    14.         jne     .loop
    15.     .crlf_found:
    16.         xor     [ecx], al
    17.         inc     ecx
    18.         xor     al, 0x0D xor 0x0A
    19.         cmp     [ecx], al
    20.         jne     .end
    21.         inc     eсx
    22.     .end:
    23.         xchg    eax, ecx
    24.         retn
     
  19. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    KeSqueer
    0040101C 40 INC EAX
    Может быть ECX?
     
  20. KeSqueer

    KeSqueer Сергей

    Публикаций:
    0
    Регистрация:
    19 июл 2007
    Сообщения:
    1.183
    Адрес:
    Москва
    q_q
    да, спасибо. поправил.