Skip to content

Instantly share code, notes, and snippets.

@leegao
Created November 10, 2016 23:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leegao/5f8f1ecea6a9f551a2e63cb904a9f157 to your computer and use it in GitHub Desktop.
Save leegao/5f8f1ecea6a9f551a2e63cb904a9f157 to your computer and use it in GitHub Desktop.
Ahead-of-time compiled RPN for /r/DailyProgrammer
import ctypes, mmap, struct
DEBUG = True
try:
VirtualAlloc = ctypes.windll.kernel32.VirtualAlloc
raise Exception("Windows not supported.")
except(AttributeError):
libc = ctypes.CDLL("libc.so.6")
libc.valloc.restype = ctypes.c_void_p
def valloc(size):
addr = libc.valloc(size)
if not addr or libc.mprotect(addr, size, 0x07):
raise RuntimeError("Cannot allocate RWX memory")
return addr
def pack_number(term):
number = float(term)
return struct.pack('f', number)
def compile(rpn_code):
size = mmap.PAGESIZE
page = valloc(size)
# cdecl header, compatible with python ctype
buffer = ''.join((
"\x55", # push rbp
"\x48\x89\xe5", # mov rbp, rsp
))
sp = 0
for term in rpn_code.split():
try:
number = pack_number(term)
buffer += "\x68" + str(number) # mov rax, number
sp += 1
except(ValueError):
binary_prelude = ''.join((
"\xD9\x44\x24\x00", # fld [rsp]
"\x59", # pop rsp
"\xD9\x44\x24\x00", # fld [rsp]
"%s",
"\xD9\x54\x24\x00", # fst [rsp]
))
dictionary = {
"+" : binary_prelude % "\xd8\xc1",
"-" : binary_prelude % "\xd8\xe1",
"*" : binary_prelude % "\xd8\xc9",
"/" : binary_prelude % "\xd8\xf1",
"//": binary_prelude % "\xd8\xf1\xD9\xFC",
"%" : binary_prelude % "\xd9\xf8",
"^" : binary_prelude % "\xD9\xF1\xDB\x14\x24\xDB\x04\x24\xDE\xE9\xD9\xF0\xD9\xE8\xDE\xC1\xDB\x04\x24\xD9\xC9\xD9\xFD",
}
sp -= 1
buffer += dictionary[term]
pass
for _ in range(sp): buffer += "\x58" # pop rax to clear the stack
buffer += ''.join((
"\x48\x89\xec", # mov rsp, rbp
"\x5d", # pop rbp
"\xc3", # ret
))
if not ctypes.memmove(page, buffer, min(len(buffer), size)):
raise RuntimeError("Input cannot not fit into memory.")
if DEBUG: print(''.join(map(lambda x: '%02x' % ord(x), buffer)))
return ctypes.CFUNCTYPE(ctypes.c_int)(page)
def rpn(code):
f = compile(code)
return struct.unpack('f', struct.pack('i', f()))[0]
if __name__ == '__main__':
import sys
DEBUG = True if len(sys.argv) > 2 and sys.argv[2] == '--debug' else False
print(rpn(sys.argv[1] if len(sys.argv) > 1 else "2 0.5 ^"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment