#! ../isforth/isforth - fload
\ ------------------------------------------------------------------------
\ Tiny Forth-based Compiler #1
\
\ Based on Jack Crenshaw's compiler tutorial, parts 1-2
\ Reads single-character tokens: 0-9 + * * / ( )
\ ------------------------------------------------------------------------

variable look	\ Lookahead char

: getchar	key look ! ;

: "  ( "text" -- a # )
	pad '"' parse tuck   pad swap cmove ; immediate

: error ( a n -- )
	cr ." Error: " type ." ." cr bye ;
: expected ( a n -- )
	cr ." Error: " type ." expected." cr bye ;

\ ------------------------------------------------------------------------

: match ( c -- )
	look @ =
		if	getchar
		else	." Expected char not found" cr bye
	then ;

: upcase ( c -- c' )
	dup 96 >  over 123 u<  and	\ Is lowercase?
		if	32 -
	then ;

: isdigit? ( c -- f )
	dup 47 >  swap 58 u<  and ;
: isalpha? ( c -- f )
	upcase dup 64 >  swap 98 u<  and ;

: getname ( -- c )
	look @ isalpha? not
		if ." Name expected" cr bye then
	look @ upcase
	getchar ;

: getnum ( -- c )
	look @ isdigit? not
		if	." Integer expected" cr bye
		else	look @ 48 -  getchar
	then ;

\ ------------------------------------------------------------------------

: isaddop? ( c -- f )	'+' over =	swap '-' =	or ;
: ismulop? ( c -- f )	'*' over =	swap '/' =	or ;

defer expression

: factor
	look @ '(' =
		if	'(' match  expression  ')' match
		else	getnum  ."  MOV EAX," . cr
		then ;

: Mul	'*' match
	factor
	."  POP EBX" cr
	."  MUL EBX" cr ;

: Div	'/' match
	factor
	."  POP EBX" cr
	."  XOR EDX,EDX" cr
	."  DIV EBX" cr ;

: term
	factor
	begin	look @ ismulop?
	while	."  PUSH EAX" cr
		look @ '*' =	if	Mul
	  else	look @ '/' =	if	Div
	  else	." expected mulop" cr bye
	  then then
	repeat ;

: Add	'+' match
	term
	."  POP EBX" cr
	."  ADD EAX,EBX" cr ;

: Sub	'-' match
	term
	."  POP EBX" cr
	."  SUB EAX,EBX" cr
	."  NEG EAX" cr ;

: (expression)
	look @ isaddop?
		if	."  XOR EAX,EAX" cr
		else	term
		then
	begin	look @ isaddop?
	while	."  PUSH EAX" cr
		look @ '+' =	if	Add
	  else	look @ '-' =	if	Sub
	  else	." expected addop" cr bye
	  then then
	repeat ;

' (expression) is expression

\ ------------------------------------------------------------------------
\ Init
\ ------------------------------------------------------------------------
 getchar
 expression
