Feat: Adds mapclear, mapgetkey, mapsetkey
Feat: Error on undefined function Fix: All ids are now prefix to prevent native var clashes. This was already done on it2, but now also in it0 and it1. Redid it2 to match. Fix: generate-recipes would not complain on missing exp. Fix: Adds documentation and test for not Chore: __check helper function for ease of use in it0, it1. Chore: some reordering to match more between iterations.
This commit is contained in:
parent
6055cddab2
commit
670532059a
@ -39,6 +39,36 @@ def skip():
|
||||
|
||||
PEEK = None
|
||||
|
||||
def __check(func, args: list[str], msg: list[str]) -> None:
|
||||
result = func(*args)
|
||||
if result:
|
||||
return
|
||||
|
||||
sys.stderr.write('ERROR: ' + ' '.join(msg) + '\n')
|
||||
sys.stderr.flush()
|
||||
exit(1)
|
||||
|
||||
MAPSTORE = {}
|
||||
|
||||
def mapclear(mapname: str) -> str:
|
||||
MAPSTORE.pop(mapname)
|
||||
return ""
|
||||
|
||||
def mapgetkey(mapname: str, key: str, default: str) -> str:
|
||||
return MAPSTORE.get(mapname, {}).get(key, default)
|
||||
|
||||
def mapsetkey(mapname: str, key: str, value: str) -> str:
|
||||
MAPSTORE.setdefault(mapname, {})
|
||||
MAPSTORE[mapname][key] = value
|
||||
return ""
|
||||
|
||||
def registerid(id: str) -> str:
|
||||
idname = mapgetkey("REGISTERID", id, "")
|
||||
if idname:
|
||||
return idname
|
||||
idname = "id_" + id
|
||||
return idname
|
||||
|
||||
def emitln(data):
|
||||
emit(data)
|
||||
emit(eol)
|
||||
@ -81,12 +111,15 @@ def parseconststring():
|
||||
emit(quote)
|
||||
|
||||
def parseexprvarref():
|
||||
var = lexident()
|
||||
emit(var)
|
||||
varname = lexident()
|
||||
varid = registerid(varname)
|
||||
emit(varid)
|
||||
|
||||
def parseexprcall():
|
||||
funcname = lexident()
|
||||
emit(funcname)
|
||||
__check(mapgetkey, ["FUNCREG", funcname, ""], ["Function", funcname, "does not exist"])
|
||||
funcid = registerid(funcname)
|
||||
emit(funcid)
|
||||
emit('(')
|
||||
|
||||
first = True
|
||||
@ -109,11 +142,12 @@ def parsestatdeclare(indent):
|
||||
|
||||
def parsestatset(indent):
|
||||
skipchar(' ')
|
||||
var = lexident()
|
||||
varname = lexident()
|
||||
varid = registerid(varname)
|
||||
skipchar(' ')
|
||||
|
||||
emit(' ' * indent)
|
||||
emit(var)
|
||||
emit(varid)
|
||||
emit(' = ')
|
||||
|
||||
parseconststring()
|
||||
@ -123,11 +157,12 @@ def parsestatset(indent):
|
||||
|
||||
def parsestatcalc(indent):
|
||||
skipchar(' ')
|
||||
var = lexident()
|
||||
varname = lexident()
|
||||
varid = registerid(varname)
|
||||
skipchar(' ')
|
||||
|
||||
emit(' ' * indent)
|
||||
emit(var)
|
||||
emit(varid)
|
||||
emit(' = ')
|
||||
|
||||
parseexprcall()
|
||||
@ -174,11 +209,13 @@ def parsestatreturn(indent):
|
||||
def parsestatcheck(indent):
|
||||
skipchar(' ')
|
||||
emit(' ' * indent)
|
||||
emit('if not ')
|
||||
emit('__check(')
|
||||
|
||||
func_name = lexident()
|
||||
emit(func_name)
|
||||
emit('(')
|
||||
funcname = lexident()
|
||||
funcid = registerid(funcname)
|
||||
trace("funcid", funcid)
|
||||
emit(funcid)
|
||||
emit(', [')
|
||||
notfirst = False
|
||||
|
||||
while True:
|
||||
@ -199,9 +236,7 @@ def parsestatcheck(indent):
|
||||
|
||||
skipchar(':')
|
||||
|
||||
emitln('):')
|
||||
emit(' ' * (indent + 1))
|
||||
emit('sys.stderr.write(\' \'.join(["ERROR:", ')
|
||||
emit('], [')
|
||||
notfirst = False
|
||||
|
||||
while True:
|
||||
@ -218,23 +253,21 @@ def parsestatcheck(indent):
|
||||
if eol == peek():
|
||||
break
|
||||
notfirst = True
|
||||
emitln(']))')
|
||||
emit(' ' * (indent + 1))
|
||||
emitln('sys.stderr.write(eol)')
|
||||
emit(' ' * (indent + 1))
|
||||
emitln('sys.exit(1)')
|
||||
|
||||
emitln('])')
|
||||
|
||||
def parsestattrace(indent):
|
||||
skipchar(' ')
|
||||
emit(' ' * indent)
|
||||
emit('trace("')
|
||||
emit('__trace("')
|
||||
|
||||
var_name = lexident()
|
||||
varname = lexident()
|
||||
varid = registerid(varname)
|
||||
skipchar(eol)
|
||||
|
||||
emit(var_name)
|
||||
emit(varname)
|
||||
emit('", ')
|
||||
emit(var_name)
|
||||
emit(varid)
|
||||
emitln(')')
|
||||
|
||||
def parsestat(indent):
|
||||
@ -277,8 +310,12 @@ def parsestat(indent):
|
||||
parsestattrace(indent)
|
||||
return
|
||||
|
||||
__check(mapgetkey, ["FUNCREG", call, ""], ["Function", call, "does not exist"])
|
||||
|
||||
callid = registerid(call)
|
||||
|
||||
emit(' ' * indent)
|
||||
emit(call)
|
||||
emit(callid)
|
||||
emit('(')
|
||||
|
||||
first = True
|
||||
@ -315,19 +352,22 @@ def parseblock(indent):
|
||||
|
||||
def parsefunc():
|
||||
funcname = lexident()
|
||||
funcid = registerid(funcname)
|
||||
mapsetkey("FUNCREG", funcname, "1")
|
||||
|
||||
trace('funcname', funcname)
|
||||
emit('def ')
|
||||
emit(funcname)
|
||||
emit(funcid)
|
||||
emit('(')
|
||||
|
||||
first = True
|
||||
while ' ' == peek():
|
||||
skip()
|
||||
var = lexident()
|
||||
varname = lexident()
|
||||
varid = registerid(varname)
|
||||
if not first:
|
||||
emit(", ")
|
||||
emit(var)
|
||||
emit(varid)
|
||||
first = False
|
||||
|
||||
if '/' == peek():
|
||||
@ -352,26 +392,26 @@ def emitheader():
|
||||
emitln("import os")
|
||||
emitln("import sys")
|
||||
emitln("")
|
||||
emitln("def eq(a: str, b: str) -> str:")
|
||||
emitln("def __eq(a: str, b: str) -> str:")
|
||||
emitln(" return '1' if a == b else ''")
|
||||
emitln("")
|
||||
emitln("def lt(a: str, b: str) -> str:")
|
||||
emitln("def __lt(a: str, b: str) -> str:")
|
||||
emitln(" return '1' if a < b else ''")
|
||||
emitln("")
|
||||
emitln("def add(a: str, b: str) -> str:")
|
||||
emitln("def __add(a: str, b: str) -> str:")
|
||||
emitln(" return a + b")
|
||||
emitln("")
|
||||
emitln("def emit(string):")
|
||||
emitln("def __emit(string):")
|
||||
emitln(" sys.stdout.buffer.write(string.encode('latin_1'))")
|
||||
emitln(" sys.stdout.flush()")
|
||||
emitln("")
|
||||
emitln("def trace(header, value):")
|
||||
emitln("def __trace(header, value):")
|
||||
emitln(" if os.environ.get('TRACE'):")
|
||||
emitln(" sys.stderr.write(f'{header}={value!r}\\n')")
|
||||
emitln("")
|
||||
emitln("eof = chr(0xFF)")
|
||||
emitln("eol = chr(10)")
|
||||
emitln("quote = chr(34)")
|
||||
emitln("__EOF = chr(0xFF)")
|
||||
emitln("__EOL = chr(10)")
|
||||
emitln("__QUOTE = chr(34)")
|
||||
emitln("")
|
||||
emitln("STDINCOLNO = 0")
|
||||
emitln("STDINLINENO = 1")
|
||||
@ -379,41 +419,106 @@ def emitheader():
|
||||
emitln("")
|
||||
emitln("def _readchar():")
|
||||
emitln(" char = sys.stdin.read(1)")
|
||||
emitln(" trace('char', char)")
|
||||
emitln(" __trace('char', char)")
|
||||
emitln(" if not char:")
|
||||
emitln(" return eof")
|
||||
emitln(" return __EOF")
|
||||
emitln(" return char")
|
||||
emitln("")
|
||||
emitln("def peek():")
|
||||
emitln("def __peek():")
|
||||
emitln(" return STDINPEEK")
|
||||
emitln("")
|
||||
emitln("def skip():")
|
||||
emitln("def __skip():")
|
||||
emitln(" global STDINCOLNO")
|
||||
emitln(" global STDINLINENO")
|
||||
emitln(" global STDINPEEK")
|
||||
emitln(" if eol == STDINPEEK:")
|
||||
emitln(" if __EOL == STDINPEEK:")
|
||||
emitln(" STDINLINENO += 1")
|
||||
emitln(" STDINCOLNO = 0")
|
||||
emitln(" STDINCOLNO += 1")
|
||||
emitln(" STDINPEEK = _readchar()")
|
||||
emitln("")
|
||||
emitln("def stdinlineno():")
|
||||
emitln("def __stdinlineno():")
|
||||
emitln(" global STDINLINENO")
|
||||
emitln(" return str(STDINLINENO)")
|
||||
emitln("")
|
||||
emitln("def stdincolno():")
|
||||
emitln("def __stdincolno():")
|
||||
emitln(" global STDINCOLNO")
|
||||
emitln(" return str(STDINCOLNO)")
|
||||
emitln("")
|
||||
emitln("skip()")
|
||||
emitln("__skip()")
|
||||
emitln("")
|
||||
emitln("MAPSTORE = {}")
|
||||
emitln("")
|
||||
emitln("def __mapclear(mapname: str) -> str:")
|
||||
emitln(" MAPSTORE.pop(mapname)")
|
||||
emitln(" return ''")
|
||||
emitln("")
|
||||
emitln("def __mapgetkey(mapname: str, key: str, default: str) -> str:")
|
||||
emitln(" return MAPSTORE.get(mapname, {}).get(key, default)")
|
||||
emitln("")
|
||||
emitln("def __mapsetkey(mapname: str, key: str, value: str) -> str:")
|
||||
emitln(" MAPSTORE.setdefault(mapname, {})")
|
||||
emitln(" MAPSTORE[mapname][key] = value")
|
||||
emitln(" return ''")
|
||||
emitln("")
|
||||
emitln("def __not(a: str) -> str:")
|
||||
emitln(" if a:")
|
||||
emitln(" return ''")
|
||||
emitln(" return '1'")
|
||||
emitln("")
|
||||
emitln("def __check(func, args: list[str], msg: list[str]) -> None:")
|
||||
emitln(" result = func(*args)")
|
||||
emitln(" if result:")
|
||||
emitln(" return")
|
||||
emitln("")
|
||||
emitln(" sys.stderr.write('ERROR: ' + ' '.join(msg) + '\\n')")
|
||||
emitln(" sys.stderr.flush()")
|
||||
emitln(" exit(1)")
|
||||
emitln("")
|
||||
emitln("# ### END OF RUNTIME ### #")
|
||||
emitln("")
|
||||
|
||||
def emitfooter():
|
||||
emit("if __name__ == '__main__':\n")
|
||||
emit(" main()\n")
|
||||
mainid = registerid("main")
|
||||
emitln("if __name__ == '__main__':")
|
||||
emit(" ")
|
||||
emit(mainid)
|
||||
emitln("()")
|
||||
|
||||
def main():
|
||||
emitheader()
|
||||
|
||||
# Standard library constants
|
||||
mapsetkey("REGISTERID", "eof", "__EOF")
|
||||
mapsetkey("REGISTERID", "eol", "__EOL")
|
||||
mapsetkey("REGISTERID", "quote", "__QUOTE")
|
||||
|
||||
# Standard library functions
|
||||
mapsetkey("FUNCREG", "add", "1")
|
||||
mapsetkey("REGISTERID", "add", "__add")
|
||||
mapsetkey("FUNCREG", "emit", "1")
|
||||
mapsetkey("REGISTERID", "emit", "__emit")
|
||||
mapsetkey("FUNCREG", "eq", "1")
|
||||
mapsetkey("REGISTERID", "eq", "__eq")
|
||||
mapsetkey("FUNCREG", "lt", "1")
|
||||
mapsetkey("REGISTERID", "lt", "__lt")
|
||||
mapsetkey("FUNCREG", "not", "1")
|
||||
mapsetkey("REGISTERID", "not", "__not")
|
||||
mapsetkey("FUNCREG", "mapclear", "1")
|
||||
mapsetkey("REGISTERID", "mapclear", "__mapclear")
|
||||
mapsetkey("FUNCREG", "mapgetkey", "1")
|
||||
mapsetkey("REGISTERID", "mapgetkey", "__mapgetkey")
|
||||
mapsetkey("FUNCREG", "mapsetkey", "1")
|
||||
mapsetkey("REGISTERID", "mapsetkey", "__mapsetkey")
|
||||
mapsetkey("FUNCREG", "peek", "1")
|
||||
mapsetkey("REGISTERID", "peek", "__peek")
|
||||
mapsetkey("FUNCREG", "skip", "1")
|
||||
mapsetkey("REGISTERID", "skip", "__skip")
|
||||
mapsetkey("FUNCREG", "stdincolno", "1")
|
||||
mapsetkey("REGISTERID", "stdincolno", "__stdincolno")
|
||||
mapsetkey("FUNCREG", "stdinlineno", "1")
|
||||
mapsetkey("REGISTERID", "stdinlineno", "__stdinlineno")
|
||||
|
||||
while True:
|
||||
if eof == peek():
|
||||
break
|
||||
|
||||
@ -36,5 +36,8 @@ lang0py.py: lang0py.lang0 lang0py2.exe
|
||||
mv $@.tmp $@
|
||||
-diff lang0py2.py lang0py.py
|
||||
|
||||
$(LANG0PY): $(CURDIR)/../0-lang0py/lang0py.py $(CURDIR)/../0-lang0py/lang0py.lang0
|
||||
cd ../0-lang0py && make lang0py.exe
|
||||
|
||||
clean:
|
||||
rm -f lang0py*.py lang0py*.c lang0py*.o lang0py*.exe
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
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
|
||||
registerid id:
|
||||
declare idname
|
||||
declare newidx
|
||||
|
||||
calc idname mapgetkey "REGISTERID" id ""
|
||||
if idname
|
||||
return idname
|
||||
/
|
||||
|
||||
calc idname add "id_" id
|
||||
return idname
|
||||
/
|
||||
|
||||
emitln data:
|
||||
@ -14,11 +16,6 @@ emitln data:
|
||||
emit eol
|
||||
/
|
||||
|
||||
increaseindent indent:
|
||||
calc indent add indent " "
|
||||
return indent
|
||||
/
|
||||
|
||||
lexident:
|
||||
declare word
|
||||
set word ""
|
||||
@ -38,6 +35,22 @@ lexident:
|
||||
return word
|
||||
/
|
||||
|
||||
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
|
||||
/
|
||||
|
||||
increaseindent indent:
|
||||
calc indent add indent " "
|
||||
return indent
|
||||
/
|
||||
|
||||
parseconststring:
|
||||
skipchar quote
|
||||
emit quote
|
||||
@ -60,12 +73,15 @@ parseconststring:
|
||||
|
||||
parseexprvarref:
|
||||
calc varname lexident
|
||||
emit varname
|
||||
calc varid registerid varname
|
||||
emit varid
|
||||
/
|
||||
|
||||
parseexprcall:
|
||||
calc funcname lexident
|
||||
emit funcname
|
||||
calc funcid registerid funcname
|
||||
check mapgetkey "FUNCREG" funcname "" : "Function" funcname "does not exist"
|
||||
emit funcid
|
||||
emit "("
|
||||
set first "1"
|
||||
forever
|
||||
@ -97,16 +113,18 @@ parseexprcall:
|
||||
|
||||
parsestatdeclare indent:
|
||||
skipchar " "
|
||||
calc var lexident
|
||||
calc varname lexident
|
||||
calc varid registerid varname
|
||||
skipchar eol
|
||||
/
|
||||
|
||||
parsestatset indent:
|
||||
skipchar " "
|
||||
calc var lexident
|
||||
calc varname lexident
|
||||
calc varid registerid varname
|
||||
skipchar " "
|
||||
emit indent
|
||||
emit var
|
||||
emit varid
|
||||
emit " = "
|
||||
parseconststring
|
||||
emit eol
|
||||
@ -115,10 +133,11 @@ parsestatset indent:
|
||||
|
||||
parsestatcalc indent:
|
||||
skipchar " "
|
||||
calc var lexident
|
||||
calc varname lexident
|
||||
calc varid registerid varname
|
||||
skipchar " "
|
||||
emit indent
|
||||
emit var
|
||||
emit varid
|
||||
emit " = "
|
||||
parseexprcall
|
||||
emit eol
|
||||
@ -188,11 +207,12 @@ parsestatcheck indent:
|
||||
|
||||
skipchar " "
|
||||
emit indent
|
||||
emit "if not "
|
||||
emit "__check("
|
||||
|
||||
calc funcname lexident
|
||||
emit funcname
|
||||
emit "("
|
||||
calc funcid registerid funcname
|
||||
emit funcid
|
||||
emit ", ["
|
||||
|
||||
set notfirst ""
|
||||
forever
|
||||
@ -222,10 +242,7 @@ parsestatcheck indent:
|
||||
|
||||
skipchar ":"
|
||||
|
||||
emitln "):"
|
||||
calc indent increaseindent indent
|
||||
emit indent
|
||||
emit "sys.stderr.write(' '.join(['ERROR:', "
|
||||
emit "], ["
|
||||
|
||||
set notfirst ""
|
||||
|
||||
@ -255,23 +272,20 @@ parsestatcheck indent:
|
||||
set notfirst "1"
|
||||
/
|
||||
|
||||
emitln "]))"
|
||||
emit indent
|
||||
emitln "sys.stderr.write(eol)"
|
||||
emit indent
|
||||
emitln "sys.exit(1)"
|
||||
emitln "])"
|
||||
/
|
||||
|
||||
parsestattrace indent:
|
||||
emit indent
|
||||
emit "trace("
|
||||
emit "__trace("
|
||||
emit quote
|
||||
skipchar " "
|
||||
calc varname lexident
|
||||
calc varid registerid varname
|
||||
emit varname
|
||||
emit quote
|
||||
emit ", "
|
||||
emit varname
|
||||
emit varid
|
||||
emitln ")"
|
||||
skipchar eol
|
||||
/
|
||||
@ -324,8 +338,10 @@ parsestat indent:
|
||||
parsestatcheck indent
|
||||
return
|
||||
/
|
||||
check mapgetkey "FUNCREG" call "" : "Function" call "does not exist"
|
||||
calc callid registerid call
|
||||
emit indent
|
||||
emit call
|
||||
emit callid
|
||||
emit "("
|
||||
set first "1"
|
||||
forever
|
||||
@ -390,9 +406,11 @@ parseblock indent:
|
||||
|
||||
parsefunc:
|
||||
calc funcname lexident
|
||||
calc funcid registerid funcname
|
||||
trace funcname
|
||||
mapsetkey "FUNCREG" funcname "1"
|
||||
emit "def "
|
||||
emit funcname
|
||||
emit funcid
|
||||
emit "("
|
||||
set isnotfirst ""
|
||||
forever
|
||||
@ -403,11 +421,12 @@ parsefunc:
|
||||
break
|
||||
/
|
||||
skip
|
||||
calc var lexident
|
||||
calc varname lexident
|
||||
calc varid registerid varname
|
||||
if isnotfirst
|
||||
emit ", "
|
||||
/
|
||||
emit var
|
||||
emit varid
|
||||
set isnotfirst "1"
|
||||
/
|
||||
calc char peek
|
||||
@ -431,26 +450,31 @@ emitheader:
|
||||
emitln "import os"
|
||||
emitln "import sys"
|
||||
emitln ""
|
||||
emitln "def eq(a: str, b: str) -> str:"
|
||||
emitln "def __eq(a: str, b: str) -> str:"
|
||||
emitln " return '1' if a == b else ''"
|
||||
emitln ""
|
||||
emitln "def lt(a: str, b: str) -> str:"
|
||||
emitln "def __lt(a: str, b: str) -> str:"
|
||||
emitln " return '1' if a < b else ''"
|
||||
emitln ""
|
||||
emitln "def add(a: str, b :str) -> str:"
|
||||
emitln "def __not(a: str) -> str:"
|
||||
emitln " if a:"
|
||||
emitln " return ''"
|
||||
emitln " return '1'"
|
||||
emitln ""
|
||||
emitln "def __add(a: str, b :str) -> str:"
|
||||
emitln " return a + b"
|
||||
emitln ""
|
||||
emitln "def emit(string):"
|
||||
emitln "def __emit(string):"
|
||||
emitln " sys.stdout.buffer.write(string.encode('latin_1'))"
|
||||
emitln " sys.stdout.flush()"
|
||||
emitln ""
|
||||
emitln "def trace(header, value):"
|
||||
emitln "def __trace(header, value):"
|
||||
emitln " if os.environ.get('TRACE'):"
|
||||
emitln " sys.stderr.write(f'{header}={value!r}\\n')"
|
||||
emitln ""
|
||||
emitln "eof = chr(0xFF)"
|
||||
emitln "eol = chr(10)"
|
||||
emitln "quote = chr(34)"
|
||||
emitln "__EOF = chr(0xFF)"
|
||||
emitln "__EOL = chr(10)"
|
||||
emitln "__QUOTE = chr(34)"
|
||||
emitln ""
|
||||
emitln "STDINCOLNO = 0"
|
||||
emitln "STDINLINENO = 1"
|
||||
@ -458,43 +482,105 @@ emitheader:
|
||||
emitln ""
|
||||
emitln "def _readchar():"
|
||||
emitln " char = sys.stdin.read(1)"
|
||||
emitln " trace('char', char)"
|
||||
emitln " __trace('char', char)"
|
||||
emitln " if not char:"
|
||||
emitln " return eof"
|
||||
emitln " return __EOF"
|
||||
emitln " return char"
|
||||
emitln ""
|
||||
emitln "def peek():"
|
||||
emitln "def __peek():"
|
||||
emitln " return STDINPEEK"
|
||||
emitln ""
|
||||
emitln "def skip():"
|
||||
emitln "def __skip():"
|
||||
emitln " global STDINCOLNO"
|
||||
emitln " global STDINLINENO"
|
||||
emitln " global STDINPEEK"
|
||||
emitln " if eol == STDINPEEK:"
|
||||
emitln " if __EOL == STDINPEEK:"
|
||||
emitln " STDINLINENO += 1"
|
||||
emitln " STDINCOLNO = 0"
|
||||
emitln " STDINCOLNO += 1"
|
||||
emitln " STDINPEEK = _readchar()"
|
||||
emitln ""
|
||||
emitln "def stdinlineno():"
|
||||
emitln "def __stdinlineno():"
|
||||
emitln " global STDINLINENO"
|
||||
emitln " return str(STDINLINENO)"
|
||||
emitln ""
|
||||
emitln "def stdincolno():"
|
||||
emitln "def __stdincolno():"
|
||||
emitln " global STDINCOLNO"
|
||||
emitln " return str(STDINCOLNO)"
|
||||
emitln ""
|
||||
emitln "skip()"
|
||||
emitln "__skip()"
|
||||
emitln ""
|
||||
emitln ""
|
||||
emitln "MAPSTORE = {}"
|
||||
emitln ""
|
||||
emitln "def __mapclear(mapname: str) -> str:"
|
||||
emitln " MAPSTORE.pop(mapname)"
|
||||
emitln " return ''"
|
||||
emitln ""
|
||||
emitln "def __mapgetkey(mapname: str, key: str, default: str) -> str:"
|
||||
emitln " return MAPSTORE.get(mapname, {}).get(key, default)"
|
||||
emitln ""
|
||||
emitln "def __mapsetkey(mapname: str, key: str, value: str) -> str:"
|
||||
emitln " MAPSTORE.setdefault(mapname, {})"
|
||||
emitln " MAPSTORE[mapname][key] = value"
|
||||
emitln " return ''"
|
||||
emitln ""
|
||||
emitln "def __check(func, args: list[str], msg: list[str]) -> None:"
|
||||
emitln " result = func(*args)"
|
||||
emitln " if result:"
|
||||
emitln " return"
|
||||
emitln ""
|
||||
emitln " sys.stderr.write('ERROR: ' + ' '.join(msg) + '\\n')"
|
||||
emitln " sys.stderr.flush()"
|
||||
emitln " exit(1)"
|
||||
emitln ""
|
||||
emitln "# ### END OF RUNTIME ### #"
|
||||
emitln ""
|
||||
/
|
||||
|
||||
emitfooter:
|
||||
declare mainid
|
||||
calc mainid registerid "main"
|
||||
|
||||
emitln "if __name__ == '__main__':"
|
||||
emitln " main()"
|
||||
emit " "
|
||||
emit mainid
|
||||
emitln "()"
|
||||
/
|
||||
|
||||
main:
|
||||
emitheader
|
||||
|
||||
mapsetkey "REGISTERID" "eof" "__EOF"
|
||||
mapsetkey "REGISTERID" "eol" "__EOL"
|
||||
mapsetkey "REGISTERID" "quote" "__QUOTE"
|
||||
|
||||
mapsetkey "FUNCREG" "add" "1"
|
||||
mapsetkey "REGISTERID" "add" "__add"
|
||||
mapsetkey "FUNCREG" "emit" "1"
|
||||
mapsetkey "REGISTERID" "emit" "__emit"
|
||||
mapsetkey "FUNCREG" "eq" "1"
|
||||
mapsetkey "REGISTERID" "eq" "__eq"
|
||||
mapsetkey "FUNCREG" "lt" "1"
|
||||
mapsetkey "REGISTERID" "lt" "__lt"
|
||||
mapsetkey "FUNCREG" "not" "1"
|
||||
mapsetkey "REGISTERID" "not" "__not"
|
||||
mapsetkey "FUNCREG" "mapclear" "1"
|
||||
mapsetkey "REGISTERID" "mapclear" "__mapclear"
|
||||
mapsetkey "FUNCREG" "mapgetkey" "1"
|
||||
mapsetkey "REGISTERID" "mapgetkey" "__mapgetkey"
|
||||
mapsetkey "FUNCREG" "mapsetkey" "1"
|
||||
mapsetkey "REGISTERID" "mapsetkey" "__mapsetkey"
|
||||
mapsetkey "FUNCREG" "peek" "1"
|
||||
mapsetkey "REGISTERID" "peek" "__peek"
|
||||
mapsetkey "FUNCREG" "skip" "1"
|
||||
mapsetkey "REGISTERID" "skip" "__skip"
|
||||
mapsetkey "FUNCREG" "stdincolno" "1"
|
||||
mapsetkey "REGISTERID" "stdincolno" "__stdincolno"
|
||||
mapsetkey "FUNCREG" "stdinlineno" "1"
|
||||
mapsetkey "REGISTERID" "stdinlineno" "__stdinlineno"
|
||||
|
||||
|
||||
forever
|
||||
calc char peek
|
||||
calc iseof eq char eof
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
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
|
||||
registerid id:
|
||||
declare idname
|
||||
declare newidx
|
||||
|
||||
calc idname mapgetkey "REGISTERID" id ""
|
||||
if idname
|
||||
return idname
|
||||
/
|
||||
|
||||
calc idname add "id_" id
|
||||
return idname
|
||||
/
|
||||
|
||||
emitln data:
|
||||
@ -14,11 +16,6 @@ emitln data:
|
||||
emit eol
|
||||
/
|
||||
|
||||
increaseindent indent:
|
||||
calc indent add indent " "
|
||||
return indent
|
||||
/
|
||||
|
||||
lexident:
|
||||
declare char
|
||||
declare isbeforea
|
||||
@ -41,6 +38,22 @@ lexident:
|
||||
return word
|
||||
/
|
||||
|
||||
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
|
||||
/
|
||||
|
||||
increaseindent indent:
|
||||
calc indent add indent " "
|
||||
return indent
|
||||
/
|
||||
|
||||
parseconststring:
|
||||
declare char
|
||||
declare iseof
|
||||
@ -66,16 +79,18 @@ parseconststring:
|
||||
/
|
||||
|
||||
parseexprvarref:
|
||||
declare varid
|
||||
declare varname
|
||||
calc varname lexident
|
||||
emit "var_"
|
||||
emit varname
|
||||
calc varid registerid varname
|
||||
emit varid
|
||||
return
|
||||
/
|
||||
|
||||
parseexprcall:
|
||||
declare char
|
||||
declare first
|
||||
declare funcid
|
||||
declare funcname
|
||||
declare isspace
|
||||
declare isnotspace
|
||||
@ -84,7 +99,9 @@ parseexprcall:
|
||||
declare isquote
|
||||
declare isnotquote
|
||||
calc funcname lexident
|
||||
emit funcname
|
||||
check mapgetkey "FUNCREG" funcname "" : "Function" funcname "does not exist"
|
||||
calc funcid registerid funcname
|
||||
emit funcid
|
||||
emit "("
|
||||
set first "1"
|
||||
forever
|
||||
@ -116,12 +133,14 @@ parseexprcall:
|
||||
/
|
||||
|
||||
parsestatdeclare indent:
|
||||
declare var
|
||||
declare varid
|
||||
declare varname
|
||||
skipchar " "
|
||||
calc var lexident
|
||||
calc varname lexident
|
||||
calc varid registerid varname
|
||||
emit indent
|
||||
emit "char * var_"
|
||||
emit var
|
||||
emit "char * "
|
||||
emit varid
|
||||
emit ";"
|
||||
emit eol
|
||||
skipchar eol
|
||||
@ -129,13 +148,14 @@ parsestatdeclare indent:
|
||||
/
|
||||
|
||||
parsestatset indent:
|
||||
declare var
|
||||
declare varid
|
||||
declare varname
|
||||
skipchar " "
|
||||
calc var lexident
|
||||
calc varname lexident
|
||||
calc varid registerid varname
|
||||
skipchar " "
|
||||
emit indent
|
||||
emit "var_"
|
||||
emit var
|
||||
emit varid
|
||||
emit " = "
|
||||
parseconststring
|
||||
emit ";"
|
||||
@ -145,13 +165,14 @@ parsestatset indent:
|
||||
/
|
||||
|
||||
parsestatcalc indent:
|
||||
declare var
|
||||
declare varid
|
||||
declare varname
|
||||
skipchar " "
|
||||
calc var lexident
|
||||
calc varname lexident
|
||||
calc varid registerid varname
|
||||
skipchar " "
|
||||
emit indent
|
||||
emit "var_"
|
||||
emit var
|
||||
emit varid
|
||||
emit " = "
|
||||
parseexprcall
|
||||
emit ";"
|
||||
@ -235,6 +256,7 @@ parsestatreturn indent:
|
||||
|
||||
parsestatcheck indent:
|
||||
declare char
|
||||
declare funcid
|
||||
declare funcname
|
||||
declare iscolon
|
||||
declare iseol
|
||||
@ -247,7 +269,8 @@ parsestatcheck indent:
|
||||
emit "if( 0 == strlen("
|
||||
|
||||
calc funcname lexident
|
||||
emit funcname
|
||||
calc funcid registerid funcname
|
||||
emit funcid
|
||||
emit "("
|
||||
|
||||
set notfirst ""
|
||||
@ -325,7 +348,7 @@ parsestatcheck indent:
|
||||
emit quote
|
||||
emit "%s"
|
||||
emit quote
|
||||
emit ", var_eol"
|
||||
emit ", __EOL"
|
||||
emitln ");"
|
||||
|
||||
emit indent
|
||||
@ -335,16 +358,18 @@ parsestatcheck indent:
|
||||
/
|
||||
|
||||
parsestattrace indent:
|
||||
declare varid
|
||||
declare varname
|
||||
emit indent
|
||||
emit "trace("
|
||||
emit "__trace("
|
||||
emit quote
|
||||
skipchar " "
|
||||
calc varname lexident
|
||||
calc varid registerid varname
|
||||
emit varname
|
||||
emit quote
|
||||
emit ", var_"
|
||||
emit varname
|
||||
emit ", "
|
||||
emit varid
|
||||
emitln ");"
|
||||
skipchar eol
|
||||
return
|
||||
@ -352,6 +377,7 @@ parsestattrace indent:
|
||||
|
||||
parsestat indent:
|
||||
declare call
|
||||
declare callid
|
||||
declare char
|
||||
declare first
|
||||
declare iscall
|
||||
@ -408,8 +434,10 @@ parsestat indent:
|
||||
parsestattrace indent
|
||||
return
|
||||
/
|
||||
check mapgetkey "FUNCREG" call "" : "Function" call "does not exist"
|
||||
calc callid registerid call
|
||||
emit indent
|
||||
emit call
|
||||
emit callid
|
||||
emit "("
|
||||
set first "1"
|
||||
forever
|
||||
@ -423,17 +451,17 @@ parsestat indent:
|
||||
calc char peek
|
||||
calc isquote eq char quote
|
||||
calc isnotquote not isquote
|
||||
calc isfirst eq first "1"
|
||||
calc isnotfirst not isfirst
|
||||
if isnotfirst
|
||||
emit ", "
|
||||
/
|
||||
if isquote
|
||||
parseconststring
|
||||
/
|
||||
if isnotquote
|
||||
parseexprvarref
|
||||
/
|
||||
calc isfirst eq first "1"
|
||||
calc isnotfirst not isfirst
|
||||
if isnotfirst
|
||||
emit ", "
|
||||
/
|
||||
set first "0"
|
||||
/
|
||||
skipchar eol
|
||||
@ -483,6 +511,7 @@ parseblock indent:
|
||||
parsefunc:
|
||||
declare char
|
||||
declare first
|
||||
declare funcid
|
||||
declare funcname
|
||||
declare iseoblock
|
||||
declare isfirst
|
||||
@ -491,18 +520,14 @@ parsefunc:
|
||||
declare isspace
|
||||
declare isnotfirst
|
||||
declare isnotspace
|
||||
declare var
|
||||
declare varid
|
||||
declare varname
|
||||
calc funcname lexident
|
||||
calc ismain eq funcname "main"
|
||||
calc isnotmain not ismain
|
||||
mapsetkey "FUNCREG" funcname "1"
|
||||
calc funcid registerid funcname
|
||||
trace funcname
|
||||
emit "char * "
|
||||
if ismain
|
||||
emit "__main"
|
||||
/
|
||||
if isnotmain
|
||||
emit funcname
|
||||
/
|
||||
emit funcid
|
||||
emit "("
|
||||
set first "1"
|
||||
forever
|
||||
@ -513,14 +538,15 @@ parsefunc:
|
||||
break
|
||||
/
|
||||
skip
|
||||
calc var lexident
|
||||
calc varname lexident
|
||||
calc varid registerid varname
|
||||
calc isfirst eq first "1"
|
||||
calc isnotfirst not isfirst
|
||||
if isnotfirst
|
||||
emit ", "
|
||||
/
|
||||
emit "char * var_"
|
||||
emit var
|
||||
emit "char * "
|
||||
emit varid
|
||||
set first "0"
|
||||
/
|
||||
calc char peek
|
||||
@ -548,28 +574,28 @@ emitheader:
|
||||
emitln "#include <string.h>"
|
||||
emitln ""
|
||||
emitln ""
|
||||
emitln "char var_eof[2] = {0xFF, 0};"
|
||||
emitln "char var_eol[2] = {10, 0};"
|
||||
emitln "char var_quote[2] = {34, 0};"
|
||||
emitln "char var_false[1] = {0};"
|
||||
emitln "char var_true[2] = {'1', 0};"
|
||||
emitln "char __EOF[2] = {0xFF, 0};"
|
||||
emitln "char __EOL[2] = {10, 0};"
|
||||
emitln "char __QUOTE[2] = {34, 0};"
|
||||
emitln "char __FALSE[1] = {0};"
|
||||
emitln "char __TRUE[2] = {'1', 0};"
|
||||
emitln ""
|
||||
emitln ""
|
||||
emitln "char * eq(char * a, char * b)"
|
||||
emitln "char * __eq(char * a, char * b)"
|
||||
emitln "{"
|
||||
emitln " return (strcmp(a, b) == 0) ? var_true : var_false;"
|
||||
emitln " return (strcmp(a, b) == 0) ? __TRUE : __FALSE;"
|
||||
emitln "}"
|
||||
emitln ""
|
||||
emitln "char * lt(char * a, char * b)"
|
||||
emitln "char * __lt(char * a, char * b)"
|
||||
emitln "{"
|
||||
emitln " return (strcmp(a, b) < 0) ? var_true : var_false;"
|
||||
emitln " return (strcmp(a, b) < 0) ? __TRUE : __FALSE;"
|
||||
emitln "}"
|
||||
emitln "char * not(char * a)"
|
||||
emitln "char * __not(char * a)"
|
||||
emitln "{"
|
||||
emitln " return (strcmp(a, var_true) != 0) ? var_true : var_false;"
|
||||
emitln " return (0 == strlen(a)) ? __TRUE : __FALSE;"
|
||||
emitln "}"
|
||||
emitln ""
|
||||
emitln "char * add(char * lft, char * rgt)"
|
||||
emitln "char * __add(char * lft, char * rgt)"
|
||||
emitln "{"
|
||||
emitln " int lft_len = strlen(lft);"
|
||||
emitln " int rgt_len = strlen(rgt);"
|
||||
@ -580,13 +606,13 @@ emitheader:
|
||||
emitln " return res;"
|
||||
emitln "}"
|
||||
emitln ""
|
||||
emitln "char * emit(char * str)"
|
||||
emitln "char * __emit(char * str)"
|
||||
emitln "{"
|
||||
emitln " fputs(str, stdout);"
|
||||
emitln " return 0;"
|
||||
emitln "}"
|
||||
emitln ""
|
||||
emitln "char * trace(char * var_name, char * var_value)"
|
||||
emitln "char * __trace(char * var_name, char * var_value)"
|
||||
emitln "{"
|
||||
emit " const char * env_trace = getenv("
|
||||
emit quote
|
||||
@ -601,7 +627,7 @@ emitheader:
|
||||
emit quote
|
||||
emitln ", stderr);"
|
||||
emitln " fputs(var_value, stderr);"
|
||||
emitln " fputs(var_eol, stderr);"
|
||||
emitln " fputs(__EOL, stderr);"
|
||||
emitln " return 0;"
|
||||
emitln "}"
|
||||
emitln ""
|
||||
@ -617,13 +643,13 @@ emitheader:
|
||||
emitln " return res;"
|
||||
emitln "}"
|
||||
emitln ""
|
||||
emitln "char * peek()"
|
||||
emitln "char * __peek()"
|
||||
emitln "{"
|
||||
emitln " if( !STDINPEEK ) STDINPEEK = _readchar(); // First byte read"
|
||||
emitln " return STDINPEEK;"
|
||||
emitln "}"
|
||||
emitln ""
|
||||
emitln "void skip()"
|
||||
emitln "void __skip()"
|
||||
emitln "{"
|
||||
emitln " if( !STDINPEEK ) STDINPEEK = _readchar(); // First byte read, not even peek()'d"
|
||||
emitln " if( STDINPEEK[0] == 10 ) {"
|
||||
@ -634,7 +660,7 @@ emitheader:
|
||||
emitln " STDINPEEK = _readchar();"
|
||||
emitln "}"
|
||||
emitln ""
|
||||
emitln "char * stdinlineno()"
|
||||
emitln "char * __stdinlineno()"
|
||||
emitln "{"
|
||||
emitln " char * res = malloc(8*sizeof(char));"
|
||||
emit " sprintf(res, "
|
||||
@ -645,7 +671,7 @@ emitheader:
|
||||
emitln " return res;"
|
||||
emitln "}"
|
||||
emitln ""
|
||||
emitln "char * stdincolno()"
|
||||
emitln "char * __stdincolno()"
|
||||
emitln "{"
|
||||
emitln " char * res = malloc(8*sizeof(char));"
|
||||
emit " sprintf(res, "
|
||||
@ -656,12 +682,135 @@ emitheader:
|
||||
emitln " return res;"
|
||||
emitln "}"
|
||||
emitln ""
|
||||
emitln "struct KEYVALUE"
|
||||
emitln "{"
|
||||
emitln " char * key;"
|
||||
emitln " char * value;"
|
||||
emitln " struct KEYVALUE * nextkeyvalue;"
|
||||
emitln "};"
|
||||
emitln ""
|
||||
emitln "struct MAP"
|
||||
emitln "{"
|
||||
emitln " char * mapname;"
|
||||
emitln " struct KEYVALUE * firstkeyvalue;"
|
||||
emitln " struct MAP * nextmap;"
|
||||
emitln "};"
|
||||
emitln ""
|
||||
emitln "struct MAP * MAPSTORE = 0;"
|
||||
emitln ""
|
||||
emitln "struct MAP * __map_get(char * mapname, int create)"
|
||||
emitln "{"
|
||||
emitln " struct MAP *prevmap, *map;"
|
||||
emitln ""
|
||||
emitln " prevmap = 0;"
|
||||
emitln " map = MAPSTORE;"
|
||||
emitln " while( map ) {"
|
||||
emitln " if( strcmp(mapname, map->mapname) == 0) break;"
|
||||
emitln " prevmap = map;"
|
||||
emitln " map = map->nextmap;"
|
||||
emitln " }"
|
||||
emitln ""
|
||||
emitln " if( map ) {"
|
||||
emitln " return map;"
|
||||
emitln " }"
|
||||
emitln ""
|
||||
emitln " if( !create ) {"
|
||||
emitln " return 0;"
|
||||
emitln " }"
|
||||
emitln ""
|
||||
emitln " map = malloc(sizeof(struct MAP));"
|
||||
emitln " map->mapname = mapname;"
|
||||
emitln " map->firstkeyvalue = 0;"
|
||||
emitln " map->nextmap = 0;"
|
||||
emitln " if( prevmap == 0) {"
|
||||
emitln " MAPSTORE = map;"
|
||||
emitln " } else {"
|
||||
emitln " prevmap->nextmap = map;"
|
||||
emitln " }"
|
||||
emitln ""
|
||||
emitln " return map;"
|
||||
emitln "}"
|
||||
emitln ""
|
||||
emitln "struct KEYVALUE * __map_keyvalue_get(struct MAP * map, char * key, int create)"
|
||||
emitln "{"
|
||||
emitln " struct KEYVALUE *prevkeyvalue, *keyvalue;"
|
||||
emitln ""
|
||||
emitln " prevkeyvalue = 0;"
|
||||
emitln " keyvalue = map->firstkeyvalue;"
|
||||
emitln " while( keyvalue ) {"
|
||||
emitln " if( strcmp(key, keyvalue->key) == 0) break;"
|
||||
emitln " prevkeyvalue = keyvalue;"
|
||||
emitln " keyvalue = keyvalue->nextkeyvalue;"
|
||||
emitln " }"
|
||||
emitln ""
|
||||
emitln " if( keyvalue ) {"
|
||||
emitln " return keyvalue;"
|
||||
emitln " }"
|
||||
emitln ""
|
||||
emitln " if( !create ) {"
|
||||
emitln " return 0;"
|
||||
emitln " }"
|
||||
emitln ""
|
||||
emitln " keyvalue = malloc(sizeof(struct KEYVALUE));"
|
||||
emitln " keyvalue->key = key;"
|
||||
emitln " keyvalue->nextkeyvalue = 0;"
|
||||
emitln " if( prevkeyvalue == 0) {"
|
||||
emitln " map->firstkeyvalue = keyvalue;"
|
||||
emitln " } else {"
|
||||
emitln " prevkeyvalue->nextkeyvalue = keyvalue;"
|
||||
emitln " }"
|
||||
emitln ""
|
||||
emitln " return keyvalue;"
|
||||
emitln "}"
|
||||
emitln ""
|
||||
emitln "char * __mapclear(char * mapname)"
|
||||
emitln "{"
|
||||
emitln " struct MAP * map = __map_get(mapname, 0);"
|
||||
emitln " if( map ) {"
|
||||
emitln " map->firstkeyvalue = 0;"
|
||||
emitln " }"
|
||||
emitln ""
|
||||
emit " return "
|
||||
emit quote
|
||||
emit quote
|
||||
emitln ";"
|
||||
emitln "}"
|
||||
emitln ""
|
||||
emitln "char * __mapgetkey(char * mapname, char * key, char * def)"
|
||||
emitln "{"
|
||||
emitln " struct MAP * map = __map_get(mapname, 0);"
|
||||
emitln " if( !map ) return def;"
|
||||
emitln ""
|
||||
emitln " struct KEYVALUE *keyvalue = __map_keyvalue_get(map, key, 0);"
|
||||
emitln " if( !keyvalue ) return def;"
|
||||
emitln ""
|
||||
emitln " return keyvalue->value;"
|
||||
emitln "}"
|
||||
emitln ""
|
||||
emitln "char * __mapsetkey(char * mapname, char * key, char * value)"
|
||||
emitln "{"
|
||||
emitln " struct MAP *map = __map_get(mapname, 1);"
|
||||
emitln " struct KEYVALUE *keyvalue = __map_keyvalue_get(map, key, 1);"
|
||||
emitln " keyvalue->value = value;"
|
||||
emit " return "
|
||||
emit quote
|
||||
emit quote
|
||||
emitln ";"
|
||||
emitln "}"
|
||||
emitln ""
|
||||
emitln "// ### END OF RUNTIME ### //"
|
||||
emitln ""
|
||||
return
|
||||
/
|
||||
|
||||
emitfooter:
|
||||
declare mainid
|
||||
calc mainid registerid "main"
|
||||
|
||||
emitln "int main() {"
|
||||
emitln " __main();"
|
||||
emit " "
|
||||
emit mainid
|
||||
emitln "();"
|
||||
emitln " return 0;"
|
||||
emitln "}"
|
||||
return
|
||||
@ -672,7 +821,38 @@ main:
|
||||
declare iseof
|
||||
declare iseol
|
||||
declare isnoteol
|
||||
|
||||
emitheader
|
||||
|
||||
mapsetkey "REGISTERID" "eof" "__EOF"
|
||||
mapsetkey "REGISTERID" "eol" "__EOL"
|
||||
mapsetkey "REGISTERID" "quote" "__QUOTE"
|
||||
|
||||
mapsetkey "FUNCREG" "add" "1"
|
||||
mapsetkey "REGISTERID" "add" "__add"
|
||||
mapsetkey "FUNCREG" "emit" "1"
|
||||
mapsetkey "REGISTERID" "emit" "__emit"
|
||||
mapsetkey "FUNCREG" "eq" "1"
|
||||
mapsetkey "REGISTERID" "eq" "__eq"
|
||||
mapsetkey "FUNCREG" "lt" "1"
|
||||
mapsetkey "REGISTERID" "lt" "__lt"
|
||||
mapsetkey "FUNCREG" "not" "1"
|
||||
mapsetkey "REGISTERID" "not" "__not"
|
||||
mapsetkey "FUNCREG" "mapclear" "1"
|
||||
mapsetkey "REGISTERID" "mapclear" "__mapclear"
|
||||
mapsetkey "FUNCREG" "mapgetkey" "1"
|
||||
mapsetkey "REGISTERID" "mapgetkey" "__mapgetkey"
|
||||
mapsetkey "FUNCREG" "mapsetkey" "1"
|
||||
mapsetkey "REGISTERID" "mapsetkey" "__mapsetkey"
|
||||
mapsetkey "FUNCREG" "peek" "1"
|
||||
mapsetkey "REGISTERID" "peek" "__peek"
|
||||
mapsetkey "FUNCREG" "skip" "1"
|
||||
mapsetkey "REGISTERID" "skip" "__skip"
|
||||
mapsetkey "FUNCREG" "stdincolno" "1"
|
||||
mapsetkey "REGISTERID" "stdincolno" "__stdincolno"
|
||||
mapsetkey "FUNCREG" "stdinlineno" "1"
|
||||
mapsetkey "REGISTERID" "stdinlineno" "__stdinlineno"
|
||||
|
||||
forever
|
||||
calc char peek
|
||||
calc iseof eq char eof
|
||||
|
||||
23
README.md
23
README.md
@ -155,6 +155,29 @@ Return true if the given strings are the same.
|
||||
|
||||
Return true if a would sort before b.
|
||||
|
||||
#### mapclear mapname
|
||||
|
||||
Maps are global and can be used from any function.
|
||||
|
||||
Clears all values set in the map named `mapname`.
|
||||
|
||||
#### mapgetkey mapname key
|
||||
|
||||
Maps are global and can be used from any function.
|
||||
|
||||
Looks up `key` in the map named `mapname` and returns it.
|
||||
If not found, returns an empty string.
|
||||
|
||||
#### mapsetkey mapname key value
|
||||
|
||||
Maps are global and can be used from any function.
|
||||
|
||||
Adds a mapping from `key` to `value` to the map named `mapname`.
|
||||
|
||||
#### not a
|
||||
|
||||
Returns "1" if a is empty; otherwise, returns "".
|
||||
|
||||
#### peek
|
||||
|
||||
Checks stdin for the next character and returns it.
|
||||
|
||||
@ -6,6 +6,7 @@ PYVERSION=3.12
|
||||
PYPREFIX=/usr
|
||||
CYTHON=cython3
|
||||
CC=gcc
|
||||
CFLAGS=-ggdb
|
||||
|
||||
all: verify-results
|
||||
|
||||
@ -38,17 +39,17 @@ clean:
|
||||
$(MAKE) -C ../0-lang0py
|
||||
|
||||
build/%.it0.py: %.lang0 ../0-lang0py/lang0py.exe
|
||||
cat $< | ../0-lang0py/lang0py.exe > $@.tmp
|
||||
-cat $< | ../0-lang0py/lang0py.exe > $@.tmp 2> build/$*.it0.cmperr
|
||||
mv $@.tmp $@
|
||||
|
||||
build/%.it0.c: build/%.it0.py
|
||||
$(CYTHON) -3 --embed -o $@ $^
|
||||
|
||||
build/%.it0.o: build/%.it0.c
|
||||
$(CC) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION)
|
||||
$(CC) $(CFLAGS) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION)
|
||||
|
||||
build/%.it0: build/%.it0.o
|
||||
$(CC) -o $@ $^ -lpython$(PYVERSION)
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lpython$(PYVERSION)
|
||||
|
||||
###
|
||||
# it1
|
||||
@ -57,17 +58,17 @@ build/%.it0: build/%.it0.o
|
||||
$(MAKE) -C ../1-lang0py
|
||||
|
||||
build/%.it1.py: %.lang0 ../1-lang0py/lang0py.exe
|
||||
cat $< | ../1-lang0py/lang0py.exe > $@.tmp
|
||||
-cat $< | ../1-lang0py/lang0py.exe > $@.tmp 2> build/$*.it1.cmperr
|
||||
mv $@.tmp $@
|
||||
|
||||
build/%.it1.c: build/%.it1.py
|
||||
$(CYTHON) -3 --embed -o $@ $^
|
||||
|
||||
build/%.it1.o: build/%.it1.c
|
||||
$(CC) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION)
|
||||
$(CC) $(CFLAGS) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION)
|
||||
|
||||
build/%.it1: build/%.it1.o
|
||||
$(CC) -o $@ $^ -lpython$(PYVERSION)
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lpython$(PYVERSION)
|
||||
|
||||
###
|
||||
# it2
|
||||
@ -76,11 +77,11 @@ build/%.it1: build/%.it1.o
|
||||
$(MAKE) -C ../2-lang0c
|
||||
|
||||
build/%.it2.c: %.lang0 ../2-lang0c/lang0c.exe
|
||||
cat $< | ../2-lang0c/lang0c.exe > $@.tmp
|
||||
-cat $< | ../2-lang0c/lang0c.exe > $@.tmp 2> build/$*.it2.cmperr
|
||||
mv $@.tmp $@
|
||||
|
||||
build/%.it2.o: build/%.it2.c
|
||||
$(CC) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION)
|
||||
$(CC) $(CFLAGS) -o $@ -c $^ -I$(PYPREFIX)/include/python$(PYVERSION)
|
||||
|
||||
build/%.it2: build/%.it2.o
|
||||
$(CC) -o $@ $^ -lpython$(PYVERSION)
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lpython$(PYVERSION)
|
||||
|
||||
3
tests/build/test_builtins/.gitignore
vendored
3
tests/build/test_builtins/.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
/*.it0
|
||||
/*.it0.c
|
||||
/*.it0.cmperr
|
||||
/*.it0.o
|
||||
/*.it0.py
|
||||
/*.it0.py.tmp
|
||||
@ -8,6 +9,7 @@
|
||||
/*.it0.stdout
|
||||
/*.it1
|
||||
/*.it1.c
|
||||
/*.it1.cmperr
|
||||
/*.it1.o
|
||||
/*.it1.py
|
||||
/*.it1.py.tmp
|
||||
@ -16,6 +18,7 @@
|
||||
/*.it1.stdout
|
||||
/*.it2
|
||||
/*.it2.c
|
||||
/*.it2.cmperr
|
||||
/*.it2.c.tmp
|
||||
/*.it2.o
|
||||
/*.it2.result
|
||||
|
||||
3
tests/build/test_flow_control/.gitignore
vendored
3
tests/build/test_flow_control/.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
/*.it0
|
||||
/*.it0.c
|
||||
/*.it0.cmperr
|
||||
/*.it0.o
|
||||
/*.it0.py
|
||||
/*.it0.py.tmp
|
||||
@ -8,6 +9,7 @@
|
||||
/*.it0.stdout
|
||||
/*.it1
|
||||
/*.it1.c
|
||||
/*.it1.cmperr
|
||||
/*.it1.o
|
||||
/*.it1.py
|
||||
/*.it1.py.tmp
|
||||
@ -16,6 +18,7 @@
|
||||
/*.it1.stdout
|
||||
/*.it2
|
||||
/*.it2.c
|
||||
/*.it2.cmperr
|
||||
/*.it2.c.tmp
|
||||
/*.it2.o
|
||||
/*.it2.result
|
||||
|
||||
3
tests/build/test_parsing/.gitignore
vendored
3
tests/build/test_parsing/.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
/*.it0
|
||||
/*.it0.c
|
||||
/*.it0.cmperr
|
||||
/*.it0.o
|
||||
/*.it0.py
|
||||
/*.it0.py.tmp
|
||||
@ -8,6 +9,7 @@
|
||||
/*.it0.stdout
|
||||
/*.it1
|
||||
/*.it1.c
|
||||
/*.it1.cmperr
|
||||
/*.it1.o
|
||||
/*.it1.py
|
||||
/*.it1.py.tmp
|
||||
@ -16,6 +18,7 @@
|
||||
/*.it1.stdout
|
||||
/*.it2
|
||||
/*.it2.c
|
||||
/*.it2.cmperr
|
||||
/*.it2.c.tmp
|
||||
/*.it2.o
|
||||
/*.it2.result
|
||||
|
||||
3
tests/build/test_stdlib_constants/.gitignore
vendored
3
tests/build/test_stdlib_constants/.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
/*.it0
|
||||
/*.it0.c
|
||||
/*.it0.cmperr
|
||||
/*.it0.o
|
||||
/*.it0.py
|
||||
/*.it0.py.tmp
|
||||
@ -8,6 +9,7 @@
|
||||
/*.it0.stdout
|
||||
/*.it1
|
||||
/*.it1.c
|
||||
/*.it1.cmperr
|
||||
/*.it1.o
|
||||
/*.it1.py
|
||||
/*.it1.py.tmp
|
||||
@ -16,6 +18,7 @@
|
||||
/*.it1.stdout
|
||||
/*.it2
|
||||
/*.it2.c
|
||||
/*.it2.cmperr
|
||||
/*.it2.c.tmp
|
||||
/*.it2.o
|
||||
/*.it2.result
|
||||
|
||||
3
tests/build/test_stdlib_functions/.gitignore
vendored
3
tests/build/test_stdlib_functions/.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
/*.it0
|
||||
/*.it0.c
|
||||
/*.it0.cmperr
|
||||
/*.it0.o
|
||||
/*.it0.py
|
||||
/*.it0.py.tmp
|
||||
@ -8,6 +9,7 @@
|
||||
/*.it0.stdout
|
||||
/*.it1
|
||||
/*.it1.c
|
||||
/*.it1.cmperr
|
||||
/*.it1.o
|
||||
/*.it1.py
|
||||
/*.it1.py.tmp
|
||||
@ -16,6 +18,7 @@
|
||||
/*.it1.stdout
|
||||
/*.it2
|
||||
/*.it2.c
|
||||
/*.it2.cmperr
|
||||
/*.it2.c.tmp
|
||||
/*.it2.o
|
||||
/*.it2.result
|
||||
|
||||
26
tests/build/test_validation/.gitignore
vendored
Normal file
26
tests/build/test_validation/.gitignore
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
/*.it0
|
||||
/*.it0.c
|
||||
/*.it0.cmperr
|
||||
/*.it0.o
|
||||
/*.it0.py
|
||||
/*.it0.py.tmp
|
||||
/*.it0.result
|
||||
/*.it0.stderr
|
||||
/*.it0.stdout
|
||||
/*.it1
|
||||
/*.it1.c
|
||||
/*.it1.cmperr
|
||||
/*.it1.o
|
||||
/*.it1.py
|
||||
/*.it1.py.tmp
|
||||
/*.it1.result
|
||||
/*.it1.stderr
|
||||
/*.it1.stdout
|
||||
/*.it2
|
||||
/*.it2.c
|
||||
/*.it2.cmperr
|
||||
/*.it2.c.tmp
|
||||
/*.it2.o
|
||||
/*.it2.result
|
||||
/*.it2.stderr
|
||||
/*.it2.stdout
|
||||
3
tests/build/test_variables/.gitignore
vendored
3
tests/build/test_variables/.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
/*.it0
|
||||
/*.it0.c
|
||||
/*.it0.cmperr
|
||||
/*.it0.o
|
||||
/*.it0.py
|
||||
/*.it0.py.tmp
|
||||
@ -8,6 +9,7 @@
|
||||
/*.it0.stdout
|
||||
/*.it1
|
||||
/*.it1.c
|
||||
/*.it1.cmperr
|
||||
/*.it1.o
|
||||
/*.it1.py
|
||||
/*.it1.py.tmp
|
||||
@ -16,6 +18,7 @@
|
||||
/*.it1.stdout
|
||||
/*.it2
|
||||
/*.it2.c
|
||||
/*.it2.cmperr
|
||||
/*.it2.c.tmp
|
||||
/*.it2.o
|
||||
/*.it2.result
|
||||
|
||||
@ -2,6 +2,12 @@ import glob
|
||||
import os
|
||||
import sys
|
||||
|
||||
STAGE0_MAP = {
|
||||
'it0': '.py',
|
||||
'it1': '.py',
|
||||
'it2': '.c',
|
||||
}
|
||||
|
||||
class Rule:
|
||||
def __init__(self, target: str, prerequisites: list[str], recipe: list[str]) -> None:
|
||||
self.target = target
|
||||
@ -23,15 +29,25 @@ def make_rules(file_path, lang0it):
|
||||
result: list[Rule] = []
|
||||
|
||||
stdin = file_path.replace('.lang0', '.stdin')
|
||||
exp_stdout = file_path.replace('.lang0', '.exp.stdout')
|
||||
exp_cmperr = file_path.replace('.lang0', '.exp.cmperr')
|
||||
exp_stderr = file_path.replace('.lang0', '.exp.stderr')
|
||||
exp_stdout = file_path.replace('.lang0', '.exp.stdout')
|
||||
|
||||
act_cmperr = 'build/' + file_path.replace('.lang0', f'.{lang0it}.cmperr')
|
||||
|
||||
act_result = 'build/' + file_path.replace('.lang0', f'.{lang0it}.result')
|
||||
act_stderr = 'build/' + file_path.replace('.lang0', f'.{lang0it}.stderr')
|
||||
act_stdout = 'build/' + file_path.replace('.lang0', f'.{lang0it}.stdout')
|
||||
|
||||
act_result = 'build/' + file_path.replace('.lang0', f'.{lang0it}.result')
|
||||
program = 'build/' + file_path.replace('.lang0', f'.{lang0it}')
|
||||
|
||||
if os.path.isfile(exp_stdout) or os.path.isfile(exp_stderr):
|
||||
program_stage0 = program + STAGE0_MAP[lang0it]
|
||||
|
||||
if os.path.isfile(exp_cmperr):
|
||||
# No need to try to run the program
|
||||
exp_list = [exp_cmperr]
|
||||
act_list = [act_cmperr]
|
||||
elif os.path.isfile(exp_stdout) or os.path.isfile(exp_stderr):
|
||||
result.append(Rule(
|
||||
act_stdout,
|
||||
[program] + ([stdin] if os.path.isfile(stdin) else []),
|
||||
@ -41,12 +57,14 @@ def make_rules(file_path, lang0it):
|
||||
]
|
||||
))
|
||||
|
||||
exp_list = [exp_stdout, exp_stderr]
|
||||
act_list = [act_stdout, act_stderr]
|
||||
exp_list = [exp_stdout, exp_stderr]
|
||||
act_list = [act_stdout, act_stderr]
|
||||
else:
|
||||
assert False, f'Missing expectations for {file_path}'
|
||||
|
||||
result.append(Rule(
|
||||
act_result,
|
||||
[act_stdout] + [
|
||||
([program_stage0] if os.path.isfile(exp_cmperr) else [act_stdout]) + [
|
||||
x
|
||||
for x in exp_list
|
||||
if os.path.isfile(x)
|
||||
@ -64,8 +82,6 @@ def make_rules(file_path, lang0it):
|
||||
]
|
||||
))
|
||||
|
||||
assert result[-1].prerequisites, f'Missing expectations for {file_path}'
|
||||
|
||||
return result
|
||||
|
||||
def main(program, write_to, *lang0it):
|
||||
|
||||
1
tests/test_parsing/test_target_reserved_names.exp.stdout
Normal file
1
tests/test_parsing/test_target_reserved_names.exp.stdout
Normal file
@ -0,0 +1 @@
|
||||
11
|
||||
8
tests/test_parsing/test_target_reserved_names.lang0
Normal file
8
tests/test_parsing/test_target_reserved_names.lang0
Normal file
@ -0,0 +1,8 @@
|
||||
main:
|
||||
declare assert
|
||||
declare class
|
||||
set assert "1"
|
||||
set class "1"
|
||||
emit assert
|
||||
emit class
|
||||
/
|
||||
14
tests/test_stdlib_functions/test_map.exp.stdout
Normal file
14
tests/test_stdlib_functions/test_map.exp.stdout
Normal file
@ -0,0 +1,14 @@
|
||||
TESTMAP.abc0: def
|
||||
OTHERMAP.abc0: def
|
||||
TESTMAP.abc0: blue
|
||||
TESTMAP.abc1: green
|
||||
TESTMAP.abc2: def
|
||||
OTHERMAP.abc0: blue
|
||||
OTHERMAP.abc1: green
|
||||
OTHERMAP.abc2: def
|
||||
TESTMAP.abc0: def
|
||||
TESTMAP.abc1: def
|
||||
TESTMAP.abc2: def
|
||||
OTHERMAP.abc0: blue
|
||||
OTHERMAP.abc1: green
|
||||
OTHERMAP.abc2: def
|
||||
36
tests/test_stdlib_functions/test_map.lang0
Normal file
36
tests/test_stdlib_functions/test_map.lang0
Normal file
@ -0,0 +1,36 @@
|
||||
print mapname key:
|
||||
declare value
|
||||
calc value mapgetkey mapname key "def"
|
||||
emit mapname
|
||||
emit "."
|
||||
emit key
|
||||
emit ": "
|
||||
emit value
|
||||
emit eol
|
||||
/
|
||||
|
||||
main:
|
||||
print "TESTMAP" "abc0"
|
||||
print "OTHERMAP" "abc0"
|
||||
|
||||
mapsetkey "TESTMAP" "abc0" "blue"
|
||||
mapsetkey "TESTMAP" "abc1" "green"
|
||||
mapsetkey "OTHERMAP" "abc0" "blue"
|
||||
mapsetkey "OTHERMAP" "abc1" "green"
|
||||
|
||||
print "TESTMAP" "abc0"
|
||||
print "TESTMAP" "abc1"
|
||||
print "TESTMAP" "abc2"
|
||||
print "OTHERMAP" "abc0"
|
||||
print "OTHERMAP" "abc1"
|
||||
print "OTHERMAP" "abc2"
|
||||
|
||||
mapclear "TESTMAP"
|
||||
|
||||
print "TESTMAP" "abc0"
|
||||
print "TESTMAP" "abc1"
|
||||
print "TESTMAP" "abc2"
|
||||
print "OTHERMAP" "abc0"
|
||||
print "OTHERMAP" "abc1"
|
||||
print "OTHERMAP" "abc2"
|
||||
/
|
||||
4
tests/test_stdlib_functions/test_not.exp.stdout
Normal file
4
tests/test_stdlib_functions/test_not.exp.stdout
Normal file
@ -0,0 +1,4 @@
|
||||
not == 1
|
||||
not a ==
|
||||
not 1 ==
|
||||
not -1 ==
|
||||
16
tests/test_stdlib_functions/test_not.lang0
Normal file
16
tests/test_stdlib_functions/test_not.lang0
Normal file
@ -0,0 +1,16 @@
|
||||
test a:
|
||||
declare var
|
||||
calc var not a
|
||||
emit "not "
|
||||
emit a
|
||||
emit " == "
|
||||
emit var
|
||||
emit eol
|
||||
/
|
||||
|
||||
main:
|
||||
test ""
|
||||
test "a"
|
||||
test "1"
|
||||
test "-1"
|
||||
/
|
||||
1
tests/test_validation/test_undefined_call.exp.cmperr
Normal file
1
tests/test_validation/test_undefined_call.exp.cmperr
Normal file
@ -0,0 +1 @@
|
||||
ERROR: Function funca does not exist
|
||||
4
tests/test_validation/test_undefined_call.lang0
Normal file
4
tests/test_validation/test_undefined_call.lang0
Normal file
@ -0,0 +1,4 @@
|
||||
main:
|
||||
declare var
|
||||
calc var funca "1"
|
||||
/
|
||||
1
tests/test_validation/test_undefined_function.exp.cmperr
Normal file
1
tests/test_validation/test_undefined_function.exp.cmperr
Normal file
@ -0,0 +1 @@
|
||||
ERROR: Function routine does not exist
|
||||
3
tests/test_validation/test_undefined_function.lang0
Normal file
3
tests/test_validation/test_undefined_function.lang0
Normal file
@ -0,0 +1,3 @@
|
||||
main:
|
||||
routine "1"
|
||||
/
|
||||
Loading…
x
Reference in New Issue
Block a user