373 lines
7.4 KiB
Python
373 lines
7.4 KiB
Python
import os
|
|
import sys
|
|
|
|
def eq(a, b):
|
|
return a == b
|
|
|
|
def lt(a, b):
|
|
return a[0] < b[0]
|
|
|
|
def addstringchar(a, b):
|
|
return a + b[0]
|
|
|
|
def emit(string):
|
|
sys.stdout.write(string)
|
|
|
|
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
|
|
|
|
def skip():
|
|
global LINE
|
|
global PEEK
|
|
if eol == PEEK:
|
|
LINE += 1
|
|
PEEK = None
|
|
|
|
def skipchar(char):
|
|
global LINE
|
|
assert char == peek(), (LINE, char, peek())
|
|
skip()
|
|
|
|
def increaseindent(indent):
|
|
indent = addstringchar(indent, " ")
|
|
indent = addstringchar(indent, " ")
|
|
indent = addstringchar(indent, " ")
|
|
indent = addstringchar(indent, " ")
|
|
return indent
|
|
|
|
def lexident():
|
|
word = ""
|
|
while True:
|
|
char = peek()
|
|
isbeforea = lt(char, "a")
|
|
if isbeforea:
|
|
break
|
|
isafterz = lt("z", char)
|
|
if isafterz:
|
|
break
|
|
word = addstringchar(word, char)
|
|
skip()
|
|
return word
|
|
|
|
def parseconststring():
|
|
skipchar(quote)
|
|
emit(quote)
|
|
while True:
|
|
char = peek()
|
|
iseof = eq(char, eof)
|
|
if iseof:
|
|
break
|
|
isquote = eq(char, quote)
|
|
if isquote:
|
|
break
|
|
emit(char)
|
|
skip()
|
|
skipchar(quote)
|
|
emit(quote)
|
|
|
|
def parseexprvarref():
|
|
varname = lexident()
|
|
emit("var_")
|
|
emit(varname)
|
|
|
|
def parseexprcall():
|
|
funcname = lexident()
|
|
emit(funcname)
|
|
emit("(")
|
|
first = "1"
|
|
while True:
|
|
char = peek()
|
|
isspace = eq(char, " ")
|
|
isnotspace = not(isspace)
|
|
if isnotspace:
|
|
break
|
|
skip()
|
|
isfirst = eq(first, "1")
|
|
isnotfirst = not(isfirst)
|
|
if isnotfirst:
|
|
emit(", ")
|
|
char = peek()
|
|
isquote = eq(char, quote)
|
|
isnotquote = not(isquote)
|
|
if isquote:
|
|
parseconststring()
|
|
if isnotquote:
|
|
parseexprvarref()
|
|
first = "0"
|
|
emit(")")
|
|
|
|
def parsestatset(indent):
|
|
skipchar(" ")
|
|
var = lexident()
|
|
skipchar(" ")
|
|
emit(indent)
|
|
emit("char * var_")
|
|
emit(var)
|
|
emit(" = ")
|
|
parseconststring()
|
|
emit(";")
|
|
emit(eol)
|
|
skipchar(eol)
|
|
|
|
def parsestatcalc(indent):
|
|
skipchar(" ")
|
|
var = lexident()
|
|
skipchar(" ")
|
|
emit(indent)
|
|
emit("char * var_")
|
|
emit(var)
|
|
emit(" = ")
|
|
parseexprcall()
|
|
emit(";")
|
|
emit(eol)
|
|
skipchar(eol)
|
|
|
|
def parsestatif(indent):
|
|
skipchar(" ")
|
|
emit(indent)
|
|
emit("if (")
|
|
parseexprvarref()
|
|
emit(")\n")
|
|
emit(indent)
|
|
emit("{\n")
|
|
skipchar(eol)
|
|
indentt = increaseindent(indent)
|
|
parseblock(indentt)
|
|
emit(indent)
|
|
emit("}\n")
|
|
|
|
def parsestatforever(indent):
|
|
emit(indent)
|
|
emit("while (1)\n")
|
|
emit(indent)
|
|
emit("{\n")
|
|
skipchar(eol)
|
|
indentt = increaseindent(indent)
|
|
parseblock(indentt)
|
|
emit(indent)
|
|
emit("}\n")
|
|
|
|
def parsestatbreak(indent):
|
|
emit(indent)
|
|
emit("break;\n")
|
|
skipchar(eol)
|
|
|
|
def parsestatreturn(indent):
|
|
emit(indent)
|
|
emit("return ")
|
|
char = peek()
|
|
isspace = eq(char, " ")
|
|
if isspace:
|
|
skip()
|
|
parseexprvarref()
|
|
emit(";")
|
|
emit(eol)
|
|
skipchar(eol)
|
|
|
|
def parsestatemit(indent):
|
|
emit(indent)
|
|
emit("emit(")
|
|
skipchar(" ")
|
|
char = peek()
|
|
isquote = eq(char, quote)
|
|
isnotquote = not(isquote)
|
|
if isquote:
|
|
parseconststring()
|
|
if isnotquote:
|
|
parseexprvarref()
|
|
emit(");\n")
|
|
skipchar(eol)
|
|
|
|
def parsestattrace(indent):
|
|
emit(indent)
|
|
emit("trace(")
|
|
emit(quote)
|
|
skipchar(" ")
|
|
varname = lexident()
|
|
emit(varname)
|
|
emit(quote)
|
|
emit(", ")
|
|
emit(varname)
|
|
emit(")\n")
|
|
skipchar(eol)
|
|
|
|
def parsestatskipchar(indent):
|
|
skipchar(" ")
|
|
emit(indent)
|
|
emit("skipchar(")
|
|
char = peek()
|
|
isquote = eq(char, quote)
|
|
isnotquote = not(isquote)
|
|
if isquote:
|
|
parseconststring()
|
|
if isnotquote:
|
|
parseexprvarref()
|
|
emit(");\n")
|
|
skipchar(eol)
|
|
|
|
def parsestat(indent):
|
|
call = lexident()
|
|
trace("call", call)
|
|
isset = eq(call, "set")
|
|
if isset:
|
|
parsestatset(indent)
|
|
return
|
|
iscalc = eq(call, "calc")
|
|
if iscalc:
|
|
parsestatcalc(indent)
|
|
return
|
|
isif = eq(call, "if")
|
|
if isif:
|
|
parsestatif(indent)
|
|
return
|
|
isforever = eq(call, "forever")
|
|
if isforever:
|
|
parsestatforever(indent)
|
|
return
|
|
isbreak = eq(call, "break")
|
|
if isbreak:
|
|
parsestatbreak(indent)
|
|
return
|
|
isreturn = eq(call, "return")
|
|
if isreturn:
|
|
parsestatreturn(indent)
|
|
return
|
|
isemit = eq(call, "emit")
|
|
if isemit:
|
|
parsestatemit(indent)
|
|
return
|
|
istrace = eq(call, "trace")
|
|
if istrace:
|
|
parsestattrace(indent)
|
|
return
|
|
isskipchar = eq(call, "skipchar")
|
|
if isskipchar:
|
|
parsestatskipchar(indent)
|
|
return
|
|
emit(indent)
|
|
emit(call)
|
|
emit("(")
|
|
first = "1"
|
|
while True:
|
|
char = peek()
|
|
isspace = eq(char, " ")
|
|
isnotspace = not(isspace)
|
|
if isnotspace:
|
|
break
|
|
skip()
|
|
char = peek()
|
|
isquote = eq(char, quote)
|
|
isnotquote = not(isquote)
|
|
if isquote:
|
|
parseconststring()
|
|
if isnotquote:
|
|
parseexprvarref()
|
|
isfirst = eq(first, "1")
|
|
isnotfirst = not(isfirst)
|
|
if isnotfirst:
|
|
emit(", ")
|
|
first = "0"
|
|
skipchar(eol)
|
|
emit(");\n")
|
|
|
|
def parseblock(indent):
|
|
while True:
|
|
while True:
|
|
char = peek()
|
|
iseol = eq(char, eol)
|
|
isnoteol = not(iseol)
|
|
if isnoteol:
|
|
break
|
|
skip()
|
|
copy = " "
|
|
while True:
|
|
isdone = eq(copy, indent)
|
|
if isdone:
|
|
break
|
|
skipchar("\t")
|
|
copy = increaseindent(copy)
|
|
char = peek()
|
|
iseoblock = eq(char, "/")
|
|
if iseoblock:
|
|
skip()
|
|
skipchar(eol)
|
|
break
|
|
skipchar("\t")
|
|
parsestat(indent)
|
|
|
|
def parsefunc():
|
|
funcname = lexident()
|
|
trace("funcname", funcname)
|
|
emit("void ")
|
|
emit(funcname)
|
|
emit("(")
|
|
first = "1"
|
|
while True:
|
|
char = peek()
|
|
isspace = eq(char, " ")
|
|
isnotspace = not(isspace)
|
|
if isnotspace:
|
|
break
|
|
skip()
|
|
var = lexident()
|
|
isfirst = eq(first, "1")
|
|
isnotfirst = not(isfirst)
|
|
if isnotfirst:
|
|
emit(", ")
|
|
emit("char * var_")
|
|
emit(var)
|
|
first = "0"
|
|
skipchar(":")
|
|
skipchar(eol)
|
|
emit(")\n{\n")
|
|
parseblock(" ")
|
|
emit("}\n\n")
|
|
|
|
def emitheader():
|
|
emit("char * addstringchar(char * str, char * chr)\n")
|
|
emit("{\n")
|
|
emit("}\n")
|
|
emit("\n")
|
|
emit("\n")
|
|
|
|
def emitfooter():
|
|
emit("")
|
|
|
|
def main():
|
|
emitheader()
|
|
while True:
|
|
char = peek()
|
|
iseof = eq(char, eof)
|
|
if iseof:
|
|
break
|
|
while True:
|
|
char = peek()
|
|
iseol = eq(char, eol)
|
|
isnoteol = not(iseol)
|
|
if isnoteol:
|
|
break
|
|
skip()
|
|
parsefunc()
|
|
emitfooter()
|
|
|
|
if __name__ == '__main__':
|
|
main()
|