import os import sys def emit(string): sys.stdout.write(string) sys.stdout.flush() def trace(header, value): if os.environ.get('TRACE'): sys.stderr.write(f'{header}={value!r}\n') eof = chr(0) eol = chr(10) quote = chr(34) PEEK = None LINE = 1 def peek(): global PEEK if PEEK is None: char = sys.stdin.read(1) trace('char', char) if not char: PEEK = eof else: PEEK = char return PEEK peek() def skip(): global LINE global PEEK if eol == PEEK: LINE += 1 PEEK = None def emitln(data): emit(data) emit(eol) def lexident(): word = '' while True: char = peek() if char < 'a' or char > 'z': break word += char skip() return word def skipchar(char): global LINE assert char == peek(), (LINE, char, peek()) skip() def parseconststring(): skipchar(quote) emit(quote) escaped = False while True: char = peek() if char == eof: break if char == quote: break emit(char) skip() skipchar(quote) emit(quote) def parseexprvarref(): var = lexident() emit(var) def parseexprcall(): funcname = lexident() emit(funcname) emit('(') first = True while ' ' == peek(): skip() if not first: emit(', ') if quote == peek(): parseconststring() else: parseexprvarref() first = False emit(')') def parsestatdeclare(indent): skipchar(' ') var = lexident() skipchar(eol) def parsestatset(indent): skipchar(' ') var = lexident() skipchar(' ') emit(' ' * indent) emit(var) emit(' = ') parseconststring() emit(eol) skipchar(eol) def parsestatcalc(indent): skipchar(' ') var = lexident() skipchar(' ') emit(' ' * indent) emit(var) emit(' = ') parseexprcall() emit(eol) skipchar(eol) def parsestatif(indent): skipchar(' ') emit(' ' * indent) emit('if ') parseexprvarref() emitln(':') skipchar(eol) parseblock(indent + 1) def parsestatforever(indent): emit(' ' * indent) emitln('while True:') skipchar(eol) parseblock(indent + 1) def parsestatbreak(indent): emit(' ' * indent) emitln('break') skipchar(eol) def parsestatreturn(indent): emit(' ' * indent) emit('return ') if ' ' == peek(): skip() if quote == peek(): parseconststring() else: parseexprvarref() emit(eol) skipchar(eol) def parsestatcheck(indent): skipchar(' ') emit(' ' * indent) emit('assert ') func_name = lexident() emit(func_name) emit('(') notfirst = False while True: skipchar(' ') if ':' == peek(): break if notfirst: emit(', ') if quote == peek(): parseconststring() else: parseexprvarref() notfirst = True skipchar(':') emit('), (') notfirst = False while True: skipchar(' ') if notfirst: emit(', ') if quote == peek(): parseconststring() else: parseexprvarref() if eol == peek(): break notfirst = True emitln(')') def parsestattrace(indent): skipchar(' ') emit(' ' * indent) emit('trace("') var_name = lexident() skipchar(eol) emit(var_name) emit('", ') emit(var_name) emitln(')') def parsestat(indent): call = lexident() trace('call', call) if call == "declare": parsestatdeclare(indent) return if call == "set": parsestatset(indent) return if call == "calc": parsestatcalc(indent) return if call == "if": parsestatif(indent) return if call == "forever": parsestatforever(indent) return if call == "break": parsestatbreak(indent) return if call == "return": parsestatreturn(indent) return if call == "check": parsestatcheck(indent) return if call == "trace": parsestattrace(indent) return emit(' ' * indent) emit(call) emit('(') first = True while ' ' == peek(): skip() if not first: emit(", ") if '"' == peek(): parseconststring() else: parseexprvarref() first = False skipchar(eol) emitln(')') def parseblock(indent): while True: while eol == peek(): skip() for _ in range(indent - 1): skipchar('\t') if '/' == peek(): skip() skipchar(eol) break skipchar('\t') parsestat(indent) def parsefunc(): funcname = lexident() trace('funcname', funcname) emit('def ') emit(funcname) emit('(') first = True while ' ' == peek(): skip() var = lexident() if not first: emit(", ") emit(var) first = False if '/' == peek(): # Ahead declaration skipchar('/') skipchar(eol) emitln("):") emitln(" pass # ahead declaration") emit(eol) return skipchar(':') skipchar(eol) emitln('):') parseblock(1) emit(eol) def emitheader(): emitln("import os") emitln("import sys") emitln("") emitln("def eq(a, b):") emitln(" return a == b") emitln("") emitln("def lt(a, b):") emitln(" return a[0] < b[0]") emitln("") emitln("def addstringchar(a, b):") emitln(" return a + b[0]") emitln("") emitln("def emit(string):") emitln(" sys.stdout.write(string)") emitln(" sys.stdout.flush()") emitln("") emitln("def trace(header, value):") emitln(" if os.environ.get('TRACE'):") emitln(" sys.stderr.write(f'{header}={value!r}\\n')") emitln("") emitln("eof = chr(0)") emitln("eol = chr(10)") emitln("quote = chr(34)") emitln("") emitln("STDINCOLNO = 0") emitln("STDINLINENO = 1") emitln("STDINPEEK = None") emitln("") emitln("def _readchar():") emitln(" char = sys.stdin.read(1)") emitln(" trace('char', char)") emitln(" if not char:") emitln(" return eof") emitln(" return char") emitln("") emitln("def peek():") emitln(" return STDINPEEK") emitln("") emitln("def skip():") emitln(" global STDINCOLNO") emitln(" global STDINLINENO") emitln(" global STDINPEEK") emitln(" if eol == STDINPEEK:") emitln(" STDINLINENO += 1") emitln(" STDINCOLNO = 0") emitln(" STDINCOLNO += 1") emitln(" STDINPEEK = _readchar()") emitln("") emitln("def stdinlineno():") emitln(" global STDINLINENO") emitln(" return str(STDINLINENO)") emitln("") emitln("def stdincolno():") emitln(" global STDINCOLNO") emitln(" return str(STDINCOLNO)") emitln("") emitln("skip()") emitln("") def emitfooter(): emit("if __name__ == '__main__':\n") emit(" main()\n") def main(): emitheader() while True: if eof == peek(): break while eol == peek(): skip() parsefunc() emitfooter() if __name__ == '__main__': main()