One of the major projects during my graduate studies was building a compiler for the Latte language, extended with features such as arrays, structs, and objects with single inheritance. The compiler parses Latte code using the BNFC tool and compiles it into x86 assembly.
The compiler’s core is implemented using a Reader-Writer-State monad:
data Reader = Rd
{ func :: Map.Map String TType
, clss :: Map.Map String ClassEnv
}
type Writer = [AsmInstr]
data State = St
{ nextlab :: Int
, newloc :: Int
, env :: Map.Map String (TType, String)
, rodata :: Map.Map String String
, rspOff :: Int
}
where
Readerstores information about functions and classes,Writerholds the generated assembly instructions,Statestores variables and low-level assembly information.
The compilation process includes static type checking, which is conceptually similar to the one used in the Latte Interpreter.