Omnis Clocha Clochabilis in Clocherio Clochando Clochans Clochativo Clochare facit Clochabiliter Clochantes/refimpl
Jump to navigation
Jump to search
- Note: there may be errors in the reference implementation. It's still young.
#!/bin/python3
import sys, re, string, os.path as op
_regex = re.compile('[' + re.escape(string.punctuation) + ']')
bf2oc9 = {
'>': 'clochans',
'<': 'clochare',
'+': 'clochando',
'-': 'clocherio',
',': 'clochantes',
'.': 'clochativo',
'[': 'clochabilis',
']': 'clochabiliter',
}
oc92bf = {v: n for n, v in bf2oc9.items()}
class ClochaClochareClochansError(Exception): pass
usage_msg = '''Usage: {} PROG1 [ PROG2, ... ]
Executes one or more programs written in Omnis Clocha Clochabilis in Clocherio
Clochando Clochans Clochativo Clochare facit Clochabiliter Clochantes.
'''
def remove_punctuation(s):
return _regex.sub(' ', s).lower()
def brainfuck_to_OC9(bf):
'You have to add the `clocha` yourself.'
return ' '.join(bf2oc9[c] for c in bf if c in bf2oc9)
def OC9_to_brainfuck(oc9):
oc9 = remove_punctuation(oc9).split()
since_last_clocha = 0
ret = []
for s in oc9:
if not s: continue
since_last_clocha += 1
if s == 'clocha':
since_last_clocha = 0
elif s in oc92bf:
ret.append(oc92bf[s])
if since_last_clocha >= 10:
raise ClochaClochareClochansError('Needs more clocha!')
return ''.join(ret)
def _exec_bf(code, tape = None):
if tape is None: tape = {}
call_stack = []
head = 0
i = 0
while i < len(code):
c = code[i]
i += 1
if c == '>':
head += 1
elif c == '<':
head -= 1
elif c == '+':
tape[head] = tape.get(head, 0) + 1
elif c == '-':
tape[head] = tape.get(head, 0) - 1
elif c == ',':
tape[head] = ord(sys.stdin.read(1))
elif c == '.':
sys.stdout.write(chr(tape.get(head, 0)))
elif c == '[':
call_stack.append(i)
elif c == ']':
if tape.get(head, 0): i = call_stack[-1]
else: call_stack.pop()
def exec_file(path):
with open(path, 'r') as f:
code = f.read()
exec_code(code)
def exec_code(code):
try:
bf = OC9_to_brainfuck(code)
except ClochaClochareClochansError as e:
sys.stderr.write(e + '\n')
_exec_bf(bf)
def usage(prog_name):
sys.stdout.write(usage_msg.format(prog_name))
def main():
if len(sys.argv) <= 1 or '--help' in sys.argv:
usage(sys.argv[0])
return
for arg in sys.argv[1:]:
if op.exists(arg):
exec_file(arg)
else:
sys.stderr.write('File \'{}\' does not exist\n'.format(arg))
if __name__ == '__main__': main()