Feat: add now can add two full strings Fix: it2 would have different working for emit eof Fix: eq and lt would return bools on it0 and it1 Fix: Functions always return something (there is no such thing as an empty type). Fix: Return value from main is now always ignored. Fix: Output from check is same on all iterations
696 lines
11 KiB
Plaintext
696 lines
11 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 add indent " "
|
|
return indent
|
|
/
|
|
|
|
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
|
|
/
|
|
|
|
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 varname
|
|
calc varname lexident
|
|
emit "var_"
|
|
emit varname
|
|
return
|
|
/
|
|
|
|
parseexprcall:
|
|
declare char
|
|
declare first
|
|
declare funcname
|
|
declare isspace
|
|
declare isnotspace
|
|
declare isfirst
|
|
declare isnotfirst
|
|
declare isquote
|
|
declare isnotquote
|
|
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 ")"
|
|
return
|
|
/
|
|
|
|
parsestatdeclare indent:
|
|
declare var
|
|
skipchar " "
|
|
calc var lexident
|
|
emit indent
|
|
emit "char * var_"
|
|
emit var
|
|
emit ";"
|
|
emit eol
|
|
skipchar eol
|
|
return
|
|
/
|
|
|
|
parsestatset indent:
|
|
declare var
|
|
skipchar " "
|
|
calc var lexident
|
|
skipchar " "
|
|
emit indent
|
|
emit "var_"
|
|
emit var
|
|
emit " = "
|
|
parseconststring
|
|
emit ";"
|
|
emit eol
|
|
skipchar eol
|
|
return
|
|
/
|
|
|
|
parsestatcalc indent:
|
|
declare var
|
|
skipchar " "
|
|
calc var lexident
|
|
skipchar " "
|
|
emit indent
|
|
emit "var_"
|
|
emit var
|
|
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 funcname
|
|
declare iscolon
|
|
declare iseol
|
|
declare isnotquote
|
|
declare isquote
|
|
declare notfirst
|
|
|
|
skipchar " "
|
|
emit indent
|
|
emit "if( 0 == strlen("
|
|
|
|
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 ":"
|
|
|
|
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 ", var_eol"
|
|
emitln ");"
|
|
|
|
emit indent
|
|
emitln " exit(1);"
|
|
emit indent
|
|
emitln "}"
|
|
/
|
|
|
|
parsestattrace indent:
|
|
declare varname
|
|
emit indent
|
|
emit "trace("
|
|
emit quote
|
|
skipchar " "
|
|
calc varname lexident
|
|
emit varname
|
|
emit quote
|
|
emit ", var_"
|
|
emit varname
|
|
emitln ");"
|
|
skipchar eol
|
|
return
|
|
/
|
|
|
|
parsestat indent:
|
|
declare call
|
|
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
|
|
/
|
|
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
|
|
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 funcname
|
|
declare iseoblock
|
|
declare isfirst
|
|
declare ismain
|
|
declare isnotmain
|
|
declare isspace
|
|
declare isnotfirst
|
|
declare isnotspace
|
|
declare var
|
|
calc funcname lexident
|
|
calc ismain eq funcname "main"
|
|
calc isnotmain not ismain
|
|
trace funcname
|
|
emit "char * "
|
|
if ismain
|
|
emit "__main"
|
|
/
|
|
if isnotmain
|
|
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 "char * var_"
|
|
emit var
|
|
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 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 ""
|
|
emitln ""
|
|
emitln "char * eq(char * a, char * b)"
|
|
emitln "{"
|
|
emitln " return (strcmp(a, b) == 0) ? var_true : var_false;"
|
|
emitln "}"
|
|
emitln ""
|
|
emitln "char * lt(char * a, char * b)"
|
|
emitln "{"
|
|
emitln " return (strcmp(a, b) < 0) ? var_true : var_false;"
|
|
emitln "}"
|
|
emitln "char * not(char * a)"
|
|
emitln "{"
|
|
emitln " return (strcmp(a, var_true) != 0) ? var_true : var_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(var_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 ""
|
|
return
|
|
/
|
|
|
|
emitfooter:
|
|
emitln "int main() {"
|
|
emitln " __main();"
|
|
emitln " return 0;"
|
|
emitln "}"
|
|
return
|
|
/
|
|
|
|
main:
|
|
declare char
|
|
declare iseof
|
|
declare iseol
|
|
declare isnoteol
|
|
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
|
|
return
|
|
/
|