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.
677 lines
10 KiB
Plaintext
677 lines
10 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 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 addstringchar 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 "0"
|
|
/
|
|
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 " 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
|
|
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 isspace
|
|
declare isnotfirst
|
|
declare isnotspace
|
|
declare var
|
|
calc funcname lexident
|
|
trace funcname
|
|
emit "char * "
|
|
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] = {-1, 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 * addstringchar(char * str, char * chr)"
|
|
emitln "{"
|
|
emitln " int str_len = strlen(str);"
|
|
emitln " assert(strlen(chr) == 1);"
|
|
emitln " char * res = malloc((str_len + 2) * sizeof(char));"
|
|
emitln " strcpy(res, str);"
|
|
emitln " res[str_len + 0] = chr[0];"
|
|
emitln " res[str_len + 1] = 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:
|
|
emit ""
|
|
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
|
|
/
|