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 " emitln "#include " emitln "#include " emitln "#include " 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 /