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
	forever
		calc char peek
		calc iseof eq char eof
		if iseof
			break
		/
		calc isquote eq char quote
		if isquote
			break
		/
		skip
	/
	skipchar quote
	emit "i8* noundef getelementptr inbounds ([14 x i8], [14 x i8]* @.str, i64 0, i64 0)"
	return
/

parseexprvarref:
	declare varname
	calc varname lexident
	emit "i8* %"
	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
	declare varidx
	skipchar " "
	calc var lexident
	skipchar " "
	emit indent
	emit "%"
	emit var
	calc varidx mapgetkey "funcvarused" var
	calc varidx intinc varidx
	mapsetkey "funcvarused" var varidx
	emit "."
	emit varidx
	emit " = call i8* @"
	parseexprcall
	emit ";"
	emit eol
	skipchar eol
	return
/

parseblock indent/

parsestatif indent:
	declare indentt
	skipchar " "
	emit indent
	emit "if ( 0 < strlen("
	parseexprvarref
	emit ") )\n"
	emit indent
	emit "{\n"
	skipchar eol
	calc indentt increaseindent indent
	parseblock indentt
	emit indent
	emit "}\n"
	return
/

parsestatforever indent:
	declare indentt
	emit indent
	emit "while (1)\n"
	emit indent
	emit "{\n"
	skipchar eol
	calc indentt increaseindent indent
	parseblock indentt
	emit indent
	emit "}\n"
	return
/

parsestatbreak indent:
	emit indent
	emit "break;\n"
	skipchar eol
	return
/

parsestatreturn indent:
	declare char
	declare isspace
	declare isnotspace
	emit indent
	emit "ret "
	calc char peek
	calc isspace eq char " "
	calc isnotspace not isspace
	if isspace
		skip
		parseexprvarref
	/
	if isnotspace
		emit "i18* 0"
	/
	emit ";"
	emit eol
	skipchar eol
	return
/

parsestattrace indent:
	declare varname
	emit indent
	emit "trace("
	emit quote
	skipchar " "
	calc varname lexident
	emit varname
	emit quote
	emit ", var_"
	emit varname
	emit ");\n"
	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 "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
	emit ");\n"
	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
	mapclear "funcvarused"
	calc funcname lexident
	trace funcname
	emit "define i8* @"
	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 "i8* %"
		emit var
		mapsetkey "funcvarused" "var" "0"
		emit "_0"
		set first "0"
	/
	calc char peek
	calc iseoblock eq char "/"
	if iseoblock
		skipchar "/"
		skipchar eol
		emit ");"
		emit "\n"
		return
	/
	skipchar ":"
	skipchar eol
	emit ")\n{\n"
	parseblock "    "
	emit "}\n\n"
	return
/

emitheader:
	emit "target datalayout = "
	emit quote
	emit "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
	emit quote
	emit eol

	emit "target triple = "
	emit quote
	emit "x86_64-pc-linux-gnu"
	emit quote
	emit eol

	emit eol

	emit "define i8* @addstringchar(i8* %0, i8* %1)"
	emit eol
	emit "{"
	emit eol
	emit "    ; todo"
	emit eol
	emit "    ret i8* %0;"
	emit eol
	emit "}"
	emit eol

	emit eol

	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
/
