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

  • Reader stores information about functions and classes,
  • Writer holds the generated assembly instructions,
  • State stores 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.

Source code