First version

This commit is contained in:
Johan B.W. de Vries 2025-01-05 16:41:11 +01:00
parent 49662a9a78
commit 98166bfa2e
4 changed files with 794 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/it0-out0.diff
/it1-out*

17
Makefile Normal file
View File

@ -0,0 +1,17 @@
TEE :=
run:
cat it1-in.lang0 | python3 it0-out.py $(if $(TEE),| tee,> ) it1-out0.py
cat it1-in.lang0 | python3 it1-out0.py $(if $(TEE),| tee,> ) it1-out1.py
diff it1-out0.py it1-out1.py > it1-out1.diff
cat it1-in.lang0 | python3 it1-out1.py $(if $(TEE),| tee,> ) it1-out2.py
diff it1-out1.py it1-out2.py > it1-out2.diff
cat it1-in.lang0 | python3 it1-out2.py $(if $(TEE),| tee,> ) it1-out3.py
diff it1-out2.py it1-out3.py > it1-out3.diff
# See how much our hand written code differs from resulting code
-diff it0-out.py it1-out0.py > it0-out0.diff
clean:
-rm it1-out*

362
it0-out.py Normal file
View File

@ -0,0 +1,362 @@
import os
import sys
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 lexident():
word = ''
while True:
char = peek()
if char < 'a' or char > 'z':
break
word += char
skip()
return word
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 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()
emit(':\n')
skipchar(eol)
parseblock(indent + 1)
def parsestatforever(indent):
emit(' ' * indent)
emit('while True:\n')
skipchar(eol)
parseblock(indent + 1)
def parsestatbreak(indent):
emit(' ' * indent)
emit('break\n')
skipchar(eol)
def parsestatreturn(indent):
emit(' ' * indent)
emit('return ')
if ' ' == peek():
skip()
parseexprvarref()
emit(eol)
skipchar(eol)
def parsestatemit(indent):
skipchar(' ')
emit(' ' * indent)
emit('emit(')
if quote == peek():
parseconststring()
else:
parseexprvarref()
skipchar(eol)
emit(')\n')
def parsestattrace(indent):
skipchar(' ')
emit(' ' * indent)
emit('trace("')
var_name = lexident()
skipchar(eol)
emit(var_name)
emit('", ')
emit(var_name)
emit(')\n')
def parsestatskipchar(indent):
skipchar(' ')
emit(' ' * indent)
emit('skipchar(')
if quote == peek():
parseconststring()
else:
parseexprvarref()
emit(')\n')
skipchar(eol)
def parsestat(indent):
call = lexident()
trace('call', call)
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 == "emit":
parsestatemit(indent)
return
if call == "trace":
parsestattrace(indent)
return
if call == "skipchar":
parsestatskipchar(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)
emit(')\n')
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
skipchar(':')
skipchar(eol)
emit('):\n')
parseblock(1)
emit("\n")
def emitheader():
emit("import os\n")
emit("import sys\n")
emit("\n")
emit("def eq(a, b):\n")
emit(" return a == b\n")
emit("\n")
emit("def lt(a, b):\n")
emit(" return a < b\n")
emit("\n")
emit("def addstringchar(a, b):\n")
emit(" return a + b\n")
emit("\n")
emit("def emit(string):\n")
emit(" sys.stdout.write(string)\n")
emit("\n")
emit("def trace(header, value):\n")
emit(" if os.environ.get('TRACE'):\n")
emit(" sys.stderr.write(f'{header}={value!r}\\n')\n")
emit("\n")
emit("eof = chr(0)\n")
emit("eol = chr(10)\n")
emit("quote = chr(34)\n")
emit("PEEK = None\n")
emit("LINE = 1\n")
emit("\n")
emit("def peek():\n")
emit(" global PEEK\n")
emit(" if PEEK is None:\n")
emit(" char = sys.stdin.read(1)\n")
emit(" trace('char', char)\n")
emit(" if not char:\n")
emit(" PEEK = eof\n")
emit(" else:\n")
emit(" PEEK = char\n")
emit(" return PEEK\n")
emit("\n")
emit("def skip():\n")
emit(" global LINE\n")
emit(" global PEEK\n")
emit(" if eol == PEEK:\n")
emit(" LINE += 1\n")
emit(" PEEK = None\n")
emit("\n")
emit("def skipchar(char):\n")
emit(" global LINE\n")
emit(" assert char == peek(), (LINE, char, peek())\n")
emit(" skip()\n")
emit("\n")
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()

413
it1-in.lang0 Normal file
View File

@ -0,0 +1,413 @@
increaseindent indent:
calc indent addstringchar indent " "
calc indent addstringchar indent " "
calc indent addstringchar indent " "
calc indent addstringchar indent " "
return indent
/
lexident:
set word ""
forever
calc char peek
calc isbeforea lt char "a"
if isbeforea
break
/
calc isafterz lt "z" char
if isafterz
break
/
calc word addstringchar word char
skip
/
return word
/
parseconststring:
skipchar quote
emit quote
forever
calc char peek
calc iseof eq char eof
if iseof
break
/
calc isquote eq char quote
if isquote
break
/
emit char
skip
/
skipchar quote
emit quote
/
parseexprvarref:
calc varname lexident
emit varname
/
parseexprcall:
calc funcname lexident
emit funcname
emit "("
set first "1"
forever
calc char peek
calc isspace eq char " "
calc isnotspace not isspace
if isnotspace
break
/
skip
calc isfirst eq first "1"
calc isnotfirst not isfirst
if isnotfirst
emit ", "
/
calc char peek
calc isquote eq char quote
calc isnotquote not isquote
if isquote
parseconststring
/
if isnotquote
parseexprvarref
/
set first "0"
/
emit ")"
/
parsestatset indent:
skipchar " "
calc var lexident
skipchar " "
emit indent
emit var
emit " = "
parseconststring
emit eol
skipchar eol
/
parsestatcalc indent:
skipchar " "
calc var lexident
skipchar " "
emit indent
emit var
emit " = "
parseexprcall
emit eol
skipchar eol
/
parsestatif indent:
skipchar " "
emit indent
emit "if "
parseexprvarref
emit ":\n"
skipchar eol
calc indent increaseindent indent
parseblock indent
/
parsestatforever indent:
emit indent
emit "while True:\n"
skipchar eol
calc indent increaseindent indent
parseblock indent
/
parsestatbreak indent:
emit indent
emit "break\n"
skipchar eol
/
parsestatreturn indent:
emit indent
emit "return "
calc char peek
calc isspace eq char " "
if isspace
skip
parseexprvarref
/
emit eol
skipchar eol
/
parsestatemit indent:
emit indent
emit "emit("
skipchar " "
calc char peek
calc isquote eq char quote
calc isnotquote not isquote
if isquote
parseconststring
/
if isnotquote
parseexprvarref
/
emit ")\n"
skipchar eol
/
parsestattrace indent:
emit indent
emit "trace("
emit quote
skipchar " "
calc varname lexident
emit varname
emit quote
emit ", "
emit varname
emit ")\n"
skipchar eol
/
parsestatskipchar indent:
skipchar " "
emit indent
emit "skipchar("
calc char peek
calc isquote eq char quote
calc isnotquote not isquote
if isquote
parseconststring
/
if isnotquote
parseexprvarref
/
emit ")\n"
skipchar eol
/
parsestat indent:
calc call lexident
trace call
calc isset eq call "set"
if isset
parsestatset indent
return
/
calc iscalc eq call "calc"
if iscalc
parsestatcalc indent
return
/
calc isif eq call "if"
if isif
parsestatif indent
return
/
calc isforever eq call "forever"
if isforever
parsestatforever indent
return
/
calc isbreak eq call "break"
if isbreak
parsestatbreak indent
return
/
calc isreturn eq call "return"
if isreturn
parsestatreturn indent
return
/
calc isemit eq call "emit"
if isemit
parsestatemit indent
return
/
calc istrace eq call "trace"
if istrace
parsestattrace indent
return
/
calc isskipchar eq call "skipchar"
if isskipchar
parsestatskipchar indent
return
/
emit indent
emit call
emit "("
set first "1"
forever
calc char peek
calc isspace eq char " "
calc isnotspace not isspace
if isnotspace
break
/
skip
calc char peek
calc isquote eq char quote
calc isnotquote not isquote
if isquote
parseconststring
/
if isnotquote
parseexprvarref
/
calc isfirst eq first "1"
calc isnotfirst not isfirst
if isnotfirst
emit ", "
/
set first "0"
/
skipchar eol
emit ")\n"
/
parseblock indent:
forever
forever
calc char peek
calc iseol eq char eol
calc isnoteol not iseol
if isnoteol
break
/
skip
/
set copy " "
forever
calc isdone eq copy indent
if isdone
break
/
skipchar "\t"
calc copy increaseindent copy
/
calc char peek
calc iseoblock eq char "/"
if iseoblock
skip
skipchar eol
break
/
skipchar "\t"
parsestat indent
/
/
parsefunc:
calc funcname lexident
trace funcname
emit "def "
emit funcname
emit "("
set first "1"
forever
calc char peek
calc isspace eq char " "
calc isnotspace not isspace
if isnotspace
break
/
skip
calc var lexident
calc isfirst eq first "1"
calc isnotfirst not isfirst
if isnotfirst
emit ", "
/
emit var
set first "0"
/
skipchar ":"
skipchar eol
emit "):\n"
parseblock " "
emit "\n"
/
emitheader:
emit "import os\n"
emit "import sys\n"
emit "\n"
emit "def eq(a, b):\n"
emit " return a == b\n"
emit "\n"
emit "def lt(a, b):\n"
emit " return a < b\n"
emit "\n"
emit "def addstringchar(a, b):\n"
emit " return a + b\n"
emit "\n"
emit "def emit(string):\n"
emit " sys.stdout.write(string)\n"
emit "\n"
emit "def trace(header, value):\n"
emit " if os.environ.get('TRACE'):\n"
emit " sys.stderr.write(f'{header}={value!r}\\n')\n"
emit "\n"
emit "eof = chr(0)\n"
emit "eol = chr(10)\n"
emit "quote = chr(34)\n"
emit "PEEK = None\n"
emit "LINE = 1\n"
emit "\n"
emit "def peek():\n"
emit " global PEEK\n"
emit " if PEEK is None:\n"
emit " char = sys.stdin.read(1)\n"
emit " trace('char', char)\n"
emit " if not char:\n"
emit " PEEK = eof\n"
emit " else:\n"
emit " PEEK = char\n"
emit " return PEEK\n"
emit "\n"
emit "def skip():\n"
emit " global LINE\n"
emit " global PEEK\n"
emit " if eol == PEEK:\n"
emit " LINE += 1\n"
emit " PEEK = None\n"
emit "\n"
emit "def skipchar(char):\n"
emit " global LINE\n"
emit " assert char == peek(), (LINE, char, peek())\n"
emit " skip()\n"
emit "\n"
/
emitfooter:
emit "if __name__ == '__main__':\n"
emit " main()\n"
/
main:
emitheader
forever
calc char peek
calc iseof eq char eof
if iseof
break
/
forever
calc char peek
calc iseol eq char eol
calc isnoteol not iseol
if isnoteol
break
/
skip
/
parsefunc
/
emitfooter
/