With the new check function, this helper method doesn't make much sense to put in the standard library. To replicate the same result, we do need to expose the current line number; adding column number is a nice bonus. Also; made it a bit clearer when a check failes in it2. Also; the builtincheckfalse was not working. Also; separated out the test input file to have more data.
507 lines
7.4 KiB
Plaintext
507 lines
7.4 KiB
Plaintext
skipchar exp:
|
|
declare act
|
|
declare lineno
|
|
declare colno
|
|
calc act peek
|
|
calc lineno stdinlineno
|
|
calc colno stdincolno
|
|
check eq exp act : "Unexpected character" act "expected" exp "at" lineno colno
|
|
skip
|
|
/
|
|
|
|
emitln data:
|
|
emit data
|
|
emit eol
|
|
/
|
|
|
|
increaseindent indent:
|
|
calc indent addstringchar indent " "
|
|
calc indent addstringchar indent " "
|
|
calc indent addstringchar indent " "
|
|
calc indent addstringchar indent " "
|
|
return indent
|
|
/
|
|
|
|
lexident:
|
|
declare word
|
|
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 ")"
|
|
/
|
|
|
|
parsestatdeclare indent:
|
|
skipchar " "
|
|
calc var lexident
|
|
skipchar eol
|
|
/
|
|
|
|
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
|
|
/
|
|
|
|
parseblock indent/
|
|
|
|
parsestatif indent:
|
|
skipchar " "
|
|
emit indent
|
|
emit "if "
|
|
parseexprvarref
|
|
emitln ":"
|
|
skipchar eol
|
|
calc indent increaseindent indent
|
|
parseblock indent
|
|
/
|
|
|
|
parsestatforever indent:
|
|
emit indent
|
|
emitln "while True:"
|
|
skipchar eol
|
|
calc indent increaseindent indent
|
|
parseblock indent
|
|
/
|
|
|
|
parsestatbreak indent:
|
|
emit indent
|
|
emitln "break"
|
|
skipchar eol
|
|
/
|
|
|
|
parsestatreturn indent:
|
|
emit indent
|
|
emit "return "
|
|
calc char peek
|
|
calc isspace eq char " "
|
|
if isspace
|
|
skip
|
|
calc char peek
|
|
calc isquote eq char quote
|
|
calc isnotquote not isquote
|
|
if isquote
|
|
parseconststring
|
|
/
|
|
if isnotquote
|
|
parseexprvarref
|
|
/
|
|
/
|
|
emit eol
|
|
skipchar eol
|
|
/
|
|
|
|
parsestatcheck indent:
|
|
declare char
|
|
declare funcname
|
|
declare iscolon
|
|
declare isnotquote
|
|
declare isquote
|
|
declare notfirst
|
|
|
|
skipchar " "
|
|
emit indent
|
|
emit "assert "
|
|
|
|
calc funcname lexident
|
|
emit funcname
|
|
emit "("
|
|
|
|
set notfirst ""
|
|
forever
|
|
skipchar " "
|
|
calc char peek
|
|
calc iscolon eq char ":"
|
|
if iscolon
|
|
break
|
|
/
|
|
|
|
if notfirst
|
|
emit ", "
|
|
/
|
|
|
|
calc char peek
|
|
calc isquote eq char quote
|
|
calc isnotquote not isquote
|
|
if isquote
|
|
parseconststring
|
|
/
|
|
if isnotquote
|
|
parseexprvarref
|
|
/
|
|
|
|
set notfirst "1"
|
|
/
|
|
|
|
skipchar ":"
|
|
|
|
emit "), ("
|
|
set notfirst ""
|
|
|
|
forever
|
|
skipchar " "
|
|
|
|
if notfirst
|
|
emit ", "
|
|
/
|
|
|
|
calc char peek
|
|
calc isquote eq char quote
|
|
calc isnotquote not isquote
|
|
if isquote
|
|
parseconststring
|
|
/
|
|
if isnotquote
|
|
parseexprvarref
|
|
/
|
|
|
|
calc char peek
|
|
calc iseol eq char eol
|
|
if iseol
|
|
break
|
|
/
|
|
|
|
set notfirst "1"
|
|
/
|
|
|
|
emitln ")"
|
|
/
|
|
|
|
parsestattrace indent:
|
|
emit indent
|
|
emit "trace("
|
|
emit quote
|
|
skipchar " "
|
|
calc varname lexident
|
|
emit varname
|
|
emit quote
|
|
emit ", "
|
|
emit varname
|
|
emitln ")"
|
|
skipchar eol
|
|
/
|
|
|
|
parsestat indent:
|
|
calc call lexident
|
|
trace call
|
|
calc isset eq call "declare"
|
|
if isset
|
|
parsestatdeclare indent
|
|
return
|
|
/
|
|
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 istrace eq call "trace"
|
|
if istrace
|
|
parsestattrace indent
|
|
return
|
|
/
|
|
calc ischeck eq call "check"
|
|
if ischeck
|
|
parsestatcheck 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 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"
|
|
/
|
|
skipchar eol
|
|
emitln ")"
|
|
/
|
|
|
|
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 isnotfirst ""
|
|
forever
|
|
calc char peek
|
|
calc isspace eq char " "
|
|
calc isnotspace not isspace
|
|
if isnotspace
|
|
break
|
|
/
|
|
skip
|
|
calc var lexident
|
|
if isnotfirst
|
|
emit ", "
|
|
/
|
|
emit var
|
|
set isnotfirst "1"
|
|
/
|
|
calc char peek
|
|
calc iseoblock eq char "/"
|
|
if iseoblock
|
|
skipchar "/"
|
|
skipchar eol
|
|
emitln "):"
|
|
emitln " pass # ahead declaration"
|
|
emit eol
|
|
return
|
|
/
|
|
skipchar ":"
|
|
skipchar eol
|
|
emitln "):"
|
|
parseblock " "
|
|
emit eol
|
|
/
|
|
|
|
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 ""
|
|
/
|
|
|
|
emitfooter:
|
|
emitln "if __name__ == '__main__':"
|
|
emitln " main()"
|
|
/
|
|
|
|
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
|
|
/
|