lang0/2-lang0c/lang0c.lang0
Johan B.W. de Vries 670532059a 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.
2025-05-04 18:06:04 +02:00

876 lines
16 KiB
Plaintext

registerid id:
declare idname
declare newidx
calc idname mapgetkey "REGISTERID" id ""
if idname
return idname
/
calc idname add "id_" id
return idname
/
emitln data:
emit data
emit eol
/
lexident:
declare char
declare isbeforea
declare isafterz
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 add word char
skip
/
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
declare isquote
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
return
/
parseexprvarref:
declare varid
declare varname
calc varname lexident
calc varid registerid varname
emit varid
return
/
parseexprcall:
declare char
declare first
declare funcid
declare funcname
declare isspace
declare isnotspace
declare isfirst
declare isnotfirst
declare isquote
declare isnotquote
calc funcname lexident
check mapgetkey "FUNCREG" funcname "" : "Function" funcname "does not exist"
calc funcid registerid funcname
emit funcid
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 ")"
return
/
parsestatdeclare indent:
declare varid
declare varname
skipchar " "
calc varname lexident
calc varid registerid varname
emit indent
emit "char * "
emit varid
emit ";"
emit eol
skipchar eol
return
/
parsestatset indent:
declare varid
declare varname
skipchar " "
calc varname lexident
calc varid registerid varname
skipchar " "
emit indent
emit varid
emit " = "
parseconststring
emit ";"
emit eol
skipchar eol
return
/
parsestatcalc indent:
declare varid
declare varname
skipchar " "
calc varname lexident
calc varid registerid varname
skipchar " "
emit indent
emit varid
emit " = "
parseexprcall
emit ";"
emit eol
skipchar eol
return
/
parseblock indent/
parsestatif indent:
declare indentt
skipchar " "
emit indent
emit "if ( 0 < strlen("
parseexprvarref
emitln ") )"
emit indent
emitln "{"
skipchar eol
calc indentt increaseindent indent
parseblock indentt
emit indent
emitln "}"
return
/
parsestatforever indent:
declare indentt
emit indent
emitln "while (1)"
emit indent
emitln "{"
skipchar eol
calc indentt increaseindent indent
parseblock indentt
emit indent
emitln "}"
return
/
parsestatbreak indent:
emit indent
emitln "break;"
skipchar eol
return
/
parsestatreturn indent:
declare char
declare isspace
declare isnotquote
declare isquote
declare isnotspace
emit indent
emit "return "
calc char peek
calc isspace eq char " "
calc isnotspace not isspace
if isspace
skip
calc char peek
calc isquote eq char quote
calc isnotquote not isquote
if isquote
parseconststring
/
if isnotquote
parseexprvarref
/
/
if isnotspace
emit quote
emit quote
/
emit ";"
emit eol
skipchar eol
return
/
parsestatcheck indent:
declare char
declare funcid
declare funcname
declare iscolon
declare iseol
declare isnotquote
declare isquote
declare notfirst
skipchar " "
emit indent
emit "if( 0 == strlen("
calc funcname lexident
calc funcid registerid funcname
emit funcid
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 ":"
emitln ")) )"
emit indent
emitln "{"
emit indent
emit " fprintf(stderr, "
emit quote
emit "%s"
emit quote
emit ", "
emit quote
emit "ERROR:"
emit quote
emitln ");"
forever
skipchar " "
emit indent
emit " fprintf(stderr, "
emit quote
emit " %s"
emit quote
emit ", "
calc char peek
calc isquote eq char quote
calc isnotquote not isquote
if isquote
parseconststring
/
if isnotquote
parseexprvarref
/
emitln ");"
calc char peek
calc iseol eq char eol
if iseol
break
/
/
emit indent
emit " fprintf(stderr, "
emit quote
emit "%s"
emit quote
emit ", __EOL"
emitln ");"
emit indent
emitln " exit(1);"
emit indent
emitln "}"
/
parsestattrace indent:
declare varid
declare varname
emit indent
emit "__trace("
emit quote
skipchar " "
calc varname lexident
calc varid registerid varname
emit varname
emit quote
emit ", "
emit varid
emitln ");"
skipchar eol
return
/
parsestat indent:
declare call
declare callid
declare char
declare first
declare iscall
declare isfirst
declare isspace
declare isquote
declare isnotfirst
declare isnotspace
declare isnotquote
calc call lexident
trace call
calc iscall eq call "declare"
if iscall
parsestatdeclare indent
return
/
calc iscall eq call "set"
if iscall
parsestatset indent
return
/
calc iscall eq call "calc"
if iscall
parsestatcalc indent
return
/
calc iscall eq call "if"
if iscall
parsestatif indent
return
/
calc iscall eq call "forever"
if iscall
parsestatforever indent
return
/
calc iscall eq call "break"
if iscall
parsestatbreak indent
return
/
calc iscall eq call "return"
if iscall
parsestatreturn indent
return
/
calc iscall eq call "check"
if iscall
parsestatcheck indent
return
/
calc iscall eq call "trace"
if iscall
parsestattrace indent
return
/
check mapgetkey "FUNCREG" call "" : "Function" call "does not exist"
calc callid registerid call
emit indent
emit callid
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
calc isfirst eq first "1"
calc isnotfirst not isfirst
if isnotfirst
emit ", "
/
if isquote
parseconststring
/
if isnotquote
parseexprvarref
/
set first "0"
/
skipchar eol
emitln ");"
return
/
parseblock indent:
declare char
declare copy
declare iseol
declare isnoteol
declare isdone
declare iseoblock
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
/
return
/
parsefunc:
declare char
declare first
declare funcid
declare funcname
declare iseoblock
declare isfirst
declare ismain
declare isnotmain
declare isspace
declare isnotfirst
declare isnotspace
declare varid
declare varname
calc funcname lexident
mapsetkey "FUNCREG" funcname "1"
calc funcid registerid funcname
trace funcname
emit "char * "
emit funcid
emit "("
set first "1"
forever
calc char peek
calc isspace eq char " "
calc isnotspace not isspace
if isnotspace
break
/
skip
calc varname lexident
calc varid registerid varname
calc isfirst eq first "1"
calc isnotfirst not isfirst
if isnotfirst
emit ", "
/
emit "char * "
emit varid
set first "0"
/
calc char peek
calc iseoblock eq char "/"
if iseoblock
skipchar "/"
skipchar eol
emitln ");"
return
/
skipchar ":"
skipchar eol
emitln ")"
emitln "{"
parseblock " "
emitln "}"
emit eol
return
/
emitheader:
emitln "#include <assert.h>"
emitln "#include <stdio.h>"
emitln "#include <stdlib.h>"
emitln "#include <string.h>"
emitln ""
emitln ""
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 "{"
emitln " return (strcmp(a, b) == 0) ? __TRUE : __FALSE;"
emitln "}"
emitln ""
emitln "char * __lt(char * a, char * b)"
emitln "{"
emitln " return (strcmp(a, b) < 0) ? __TRUE : __FALSE;"
emitln "}"
emitln "char * __not(char * a)"
emitln "{"
emitln " return (0 == strlen(a)) ? __TRUE : __FALSE;"
emitln "}"
emitln ""
emitln "char * __add(char * lft, char * rgt)"
emitln "{"
emitln " int lft_len = strlen(lft);"
emitln " int rgt_len = strlen(rgt);"
emitln " char * res = malloc((lft_len + rgt_len + 1) * sizeof(char));"
emitln " strcpy(res, lft);"
emitln " strcpy(res + lft_len, rgt);"
emitln " res[lft_len + rgt_len] = 0;"
emitln " return res;"
emitln "}"
emitln ""
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 "{"
emit " const char * env_trace = getenv("
emit quote
emit "TRACE"
emit quote
emitln ");"
emitln " if( !env_trace ) return 0;"
emitln " fputs(var_name, stderr);"
emit " fputs("
emit quote
emit "="
emit quote
emitln ", stderr);"
emitln " fputs(var_value, stderr);"
emitln " fputs(__EOL, stderr);"
emitln " return 0;"
emitln "}"
emitln ""
emitln "int STDINCOLNO = 1;"
emitln "int STDINLINENO = 1;"
emitln "char * STDINPEEK = 0;"
emitln ""
emitln "char * _readchar()"
emitln "{"
emitln " char * res = malloc(2*sizeof(char));"
emitln " res[0] = getc(stdin);"
emitln " res[1] = 0;"
emitln " return res;"
emitln "}"
emitln ""
emitln "char * __peek()"
emitln "{"
emitln " if( !STDINPEEK ) STDINPEEK = _readchar(); // First byte read"
emitln " return STDINPEEK;"
emitln "}"
emitln ""
emitln "void __skip()"
emitln "{"
emitln " if( !STDINPEEK ) STDINPEEK = _readchar(); // First byte read, not even peek()'d"
emitln " if( STDINPEEK[0] == 10 ) {"
emitln " STDINLINENO += 1;"
emitln " STDINCOLNO = 0;"
emitln " }"
emitln " STDINCOLNO += 1;"
emitln " STDINPEEK = _readchar();"
emitln "}"
emitln ""
emitln "char * __stdinlineno()"
emitln "{"
emitln " char * res = malloc(8*sizeof(char));"
emit " sprintf(res, "
emit quote
emit "%d"
emit quote
emitln ", STDINLINENO);"
emitln " return res;"
emitln "}"
emitln ""
emitln "char * __stdincolno()"
emitln "{"
emitln " char * res = malloc(8*sizeof(char));"
emit " sprintf(res, "
emit quote
emit "%d"
emit quote
emitln ", STDINCOLNO);"
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() {"
emit " "
emit mainid
emitln "();"
emitln " return 0;"
emitln "}"
return
/
main:
declare char
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
if iseof
break
/
forever
calc char peek
calc iseol eq char eol
calc isnoteol not iseol
if isnoteol
break
/
skip
/
parsefunc
/
emitfooter
return
/