This is a follow up on A progression of quines.
Based on the reviews I got, I have reworked my first and fifth programs.
The nice quine
The answer I received from ecm made me realize that my nice quine wasn't all that nice. More than 900 characters on a single line is just too much! Like she wrote in her "q.asm", I too give each source line its own db
now.
QN. Nicer
This program executes a subroutine twice. The first time it is call
-ed and the second time the code just falls through. I could do this because at the end a simple ret
is enough to exit to DOS.
In the appended source text the asterisk (*) is used as an end of line marker. That's why I had to avoid using the asterisk in my actual code.
I've also avoided the use of embedded single quote characters (') because they would throw off the FASM parser.
org 256
mov ah, 02h ; DOS.PrintChar
xor bx, bx ; 1st pass BX=0
call job
inc bx ; 2nd pass BX=1
job: mov cx, 36 ; Number of lines/pass
mov si, text
more: test bx, bx ; In 2nd pass we prefix with ...
jz first
mov dl, 100 ; d
int 21h
mov dl, 98 ; b
int 21h
mov dl, 32 ; space
int 21h
mov dl, 39 ; quote
int 21h
first: lodsb ; No asterisk-only strings
next: mov dl, al
int 21h
lodsb
cmp al, 42 ; Terminating asterisk
jne next
test bx, bx ; In 2nd pass we suffix with ...
jz crlf
mov dl, al ; asterisk
int 21h
mov dl, 39 ; quote
int 21h
crlf: mov dl, 13 ; newline
int 21h
mov dl, 10
int 21h
loop more
ret ; Exits to DOS on 2nd pass!
text:
db ' org 256*'
db ' mov ah, 02h ; DOS.PrintChar*'
db ' xor bx, bx ; 1st pass BX=0*'
db ' call job*'
db ' inc bx ; 2nd pass BX=1*'
db 'job: mov cx, 36 ; Number of lines/pass*'
db ' mov si, text*'
db 'more: test bx, bx ; In 2nd pass we prefix with ...*'
db ' jz first*'
db ' mov dl, 100 ; d*'
db ' int 21h*'
db ' mov dl, 98 ; b*'
db ' int 21h*'
db ' mov dl, 32 ; space*'
db ' int 21h*'
db ' mov dl, 39 ; quote*'
db ' int 21h*'
db 'first: lodsb ; No asterisk-only strings*'
db 'next: mov dl, al*'
db ' int 21h*'
db ' lodsb*'
db ' cmp al, 42 ; Terminating asterisk*'
db ' jne next*'
db ' test bx, bx ; In 2nd pass we suffix with ...*'
db ' jz crlf*'
db ' mov dl, al ; asterisk*'
db ' int 21h*'
db ' mov dl, 39 ; quote*'
db ' int 21h*'
db 'crlf: mov dl, 13 ; newline*'
db ' int 21h*'
db ' mov dl, 10*'
db ' int 21h*'
db ' loop more*'
db ' ret ; Exits to DOS on 2nd pass!*'
db 'text:*'
The short quine
Reworking the shortest quine was much harder. Some good ideas didn't stand the test of the numbers. The Norton Editor doesn't allow using the character codes 0, 1, 26, or 255 and DOS just eats the character codes 7, 8, 9, 10, 13, or 26. Avoiding all of those tiny numbers in a very small program is itself a challenge!
Since this one line program uses the DOS.PrintString function 09h, it cannot have embedded dollar characters ($) and the FASM parser would be thrown off by embedded quotation marks (").
Q5. Shorter by 5
Here the big gain came from building the next AX
through xor
-ing it with some mask value.
6264h ; db
xor 4044h
----
2220h ; "
xor 0602h
----
2422h ; "$
I've also included the first tip by Fifoernik to use cwd
as a shortcut for xor dx, dx
.
db "¸db™²ü‰×«5D@«5##‰E#Àì#Í!Ã"
The character codes involved:
B8 64 62 99 B2 FC 89 D7 AB 35 44 40 AB 35 02 06 89 45 19 C0 EC 02 CD 21 C3
The equivalent program:
mov ax, "db"
cwd
mov dl, 252
mov di, dx
stosw
xor ax, 4044h
stosw
xor ax, 0602h
mov [di+25], ax
shr ah, 2
int 21h
ret
Q6. Shorter by 7
Following the second tip by Fifoernik - I will have to investigate this a bit further - I could use the pre-existing value 09h in the high byte of the BP
register and shave off another 2 bytes, replacing shr ah, 2
by xchg ax, bp
.
db "¸db™²ü‰×«5D@«5##‰E#•Í!Ã"
The character codes involved:
B8 64 62 99 B2 FC 89 D7 AB 35 44 40 AB 35 02 06 89 45 17 95 CD 21 C3
The equivalent program:
mov ax, "db"
cwd
mov dl, 252
mov di, dx
stosw
xor ax, 4044h
stosw
xor ax, 0602h
mov [di+23], ax
xchg ax, bp
int 21h
ret
New summary
Next table shows how the quines' sourcefiles gradually became smaller.
QN Q0 Q1 Q2 Q3 Q4 Q5 Q6
-------------------------------------------
.ASM 2640 1837 319 294 178 35 30 28
.COM 1243 960 186 42 44 30 25 23
Every program was tested using FASM in MS-DOS 6.20
C:\FASM>fasm q6.asm q6.com
flat assembler version 1.70 (2086464 kilobytes memory)
1 passes, 23 bytes.C:\FASM>q6 > q6_.asm
C:\FASM>fc q6.asm q6_.asm
Comparaison des fichiers en cours : Q6.ASM et Q6_.ASM
FC: aucune différence trouvée
Conclusion
I fear it will be very hard to shorten that last 23-bytes program, but you never know...
As before, I leave it up to you to decide if 'a smaller quine' should refer to a smaller source file or to a smaller executable file.