Hex, 550 bytes
This specifically targets x86_64 systems running Linux.
7f454c4602010100000000000000000002003e0001000000780040000000000040000000000000000000000000000000000000004000380001004000000000000100000005000000000000000000000000004000000000000000400000000000130100000000000013010000000000000000200000000000e81700000085c07c0b31ff01c7e879000000ebec31c089c7b03c0f05e84c0000004885c07c203c2178f2741b89c7e825000000c0e00450e83100000089c7e8150000005900c8c3e8210000003c0d7ff774ca3c0a75f1ebc489f831c93c400f9cc148ffc980e12780c13028c8c36a004889e631c089c2fec289c70f0531c985c0580f95c148ffc94809c8c3574889e631c0fec089c289c70f0558c3
In this language, source code consists of bytes represented as two lowercase hexadecimal digits, [0-9a-f][0-9a-f]
. These bytes may have any amount of surrounding whitespace, but nothing may occur between the digits that form a single byte. Further, '!'
is a line-comment character: it is ignored, as well as everything between it and the next '\n'
character.
If you understand x86 assembly, here's a much more readable version of the source code:
! ELF Header !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
7f 45 4c 46 !e_ident[EI_MAG0] (0x7F "ELF")
02 !e_ident[EI_CLASS] (64-bit)
01 !e_ident[EI_DATA] (little-endian)
01 !e_ident[EI_VERSION] (ELF v1)
00 !e_ident[EI_OSABI] (System V ABI)
00 !e_ident[EI_ABIVERSION] (version 0)
00 00 00 00 00 00 00 !e_ident [EI_PAD]
02 00 !e_type (executable)
3e 00 !e_machine (x86_64)
01 00 00 00 !e_version (ELF v1)
78 00 40 00 00 00 00 00 !e_entry (0x40078)
40 00 00 00 00 00 00 00 !e_phoff (0x 40)
00 00 00 00 00 00 00 00 !e_shoff (0x 0)
00 00 00 00 !e_flags
40 00 !e_ehsize (ELF header size = 64 bytes)
38 00 !e_phentsize (Program headers = 56 bytes)
01 00 !e_phnum (1 program header)
40 00 !e_shentsize (Section headers = 64 bytes)
00 00 !e_shnum (no section headers)
00 00 !e_shstrndx (section names, not useful here)
! Program Headers !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
01 00 00 00 !p_type (LOAD)
05 00 00 00 !p_flags (R+E)
00 00 00 00 00 00 00 00 !p_offset (file-loc 0)
00 00 40 00 00 00 00 00 !p_vaddr (vmem-loc 0x40000)
00 00 40 00 00 00 00 00 !p_paddr (pmem-loc 0x40000)
13 01 00 00 00 00 00 00 !p_filesz (length 0x113 bytes)
13 01 00 00 00 00 00 00 !p_memsz (allocate 0x113 bytes)
00 00 20 00 00 00 00 00 !p_align (align pages in 0x20000 increments)
! Program Code !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! _start: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
e8 17 00 00 00 ! callq _gethx
85 c0 ! test %eax,%eax
7c 0b ! jl .+11
31 ff ! xor %edi,%edi
01 c7 ! add %eax,%eax
e8 79 00 00 00 ! callq _putch
eb ec ! jmp .-20
31 c0 ! xor %eax,%eax
89 c7 ! mov %eax,%edi
b0 3c ! mov $0x3c,%al
0f 05 ! syscall
!! _gethx: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
e8 4c 00 00 00 ! callq _getch
48 85 c0 ! test %rax,%rax
7c 20 ! jl _gethx+42
3c 21 ! cmp $0x21,al
78 f2 ! js _gethx
74 1b ! je _gethx+43
89 c7 ! mov %eax,%edi
e8 25 00 00 00 ! callq _h2d
c0 e0 04 ! sal $4,%al
50 ! push %rax
e8 31 00 00 00 ! callq _getch
89 c7 ! mov %eax,%edi
e8 15 00 00 00 ! callq _h2d
59 ! pop %rcx
00 c8 ! add %cl,%al
c3 ! retq
e8 21 00 00 00 ! callq _getch
3c 0d ! cmp $0xd,%al
7f f7 ! jg _gethx+43
74 ca ! je _gethx
3c 0a ! cmp $0xa,%al
75 f1 ! jne _gethx+43
eb c4 ! jmp _gethx
!! _h2d: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
89 f8 ! mov %edi,%eax
31 c9 ! xor %ecx,%ecx
3c 40 ! cmp $0x40,%al
0f 9c c1 ! setl %cl
48 ff c9 ! dec %rcx
80 e1 27 ! and $0x27,%cl
80 c1 30 ! add $0x30,%cl
28 c8 ! sub %cl,%al
c3 ! retq
!! _getch: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
6a 00 ! push $0
48 89 e6 ! mov %rsp,%rsi
31 c0 ! xor %eax,%eax
89 c2 ! mov %eax,%edx
fe c2 ! inc %dl
89 c7 ! mov %eax,%edi
0f 05 ! syscall
31 c9 ! xor %ecx,%ecx
85 c0 ! test %eax,%eax
58 ! pop %rax
0f 95 c1 ! setne %cl
48 ff c9 ! dec %rcx
48 09 c8 ! or %rcx,%rax
c3 ! retq
!! _putch: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
57 ! push %rdi
48 89 e6 ! mov %rsp,%rsi
31 c0 ! xor %eax,%eax
fe c0 ! inc %al
89 c2 ! mov %eax,%edx
89 c7 ! mov %eax,%edi
0f 05 ! syscall
58 ! pop %rax
c3 ! retq
If you extract the assembly language from the comments below ! Program Code
, you can assemble and run the Hex compiler. Input and output use stdin and stdout.