Overview
The overall compiler architecture is similar to the architecture described by Appel's Modern Compiler Implementation in ML, and virtually every other compiler textbook of worth. This architecture is also used by virtually every portable compiler in the world.
IR Based Compilers
Portable compilers are based around translating to and from IR, or Intermediate Representation. Compilers like GCC compile hundreds of languages to thousands of platforms. Translating from each language to each platform directly becomes requires on the order of 100 ^ 1000 separate compilers (That's 10 ^ 10000, literally, one google). Furthermore, translating directly from language to instructions is extremely difficult, and makes optimization all but impossible.
Compilation is simpler in several steps. Furthermore, if all compilers share one step that is identical, then the task is far simpler. It is no longer necessary to write 100 ^ 1000 whole compilers, but only 100 frontends and 1000 backends, only the equivalent of 550 whole compilers. Finally, it is far easier to translate, analyze, and optimize programs in multiple steps.
The common step is called intermediate representation. This step is typeless, or mostly typeless, and is broken down into pure expressions and statements. Its basic type is a "temporary", which generally maps to a register, except there are an unlimited number of temporaries allowed. Anyone interested should read Modern Compiler Implementation in ML or another book.
The Ivory Compiler
Ivory's compiler introduces two additional steps for the purposes of language semantics. Other than that, the steps are the same. Each step is described, followed by its output.
Lexer Stage: The lexer stage is standard. It produces tokens.
Tokens: Tokens are the "words" of the programming language. In the Ivory compiler, they are coupled with the position at which they occur.
Parser Stage: The parser stage is also standard. It produces the list form of an AST (abstract syntax tree). Objects are referenced by their symbols.
AST (Abstract Syntax Tree, List Form): The list-form AST is also standard. It is a tree representing the structure of the language. An analog from a spoken language is a diagrammed sentence.
Collect Stage: The collect stage is not a "standard" (meaning covered by the textbooks) stage, though many compilers have one. The collect stage's primary task is to translate the list-based AST into a table-based one. Additionally, this stage expands all templates into the definitions they give, resolves all symbol bindings, and traslates types into a slightly less abstract form. It primarily enforces semantic rules concerning declarations.
AST (Abstract Syntax Tree, Table Form): The table-form AST is non-standard. Templates may exist, but they have no meaning. Expressions are slightly different, in that type representations are slightly less abstract, object references are bound directly. Declarations are kept in a lookup table.
Semantic Stage: The semantic stage is standard, though its operation is not. It enforces all semantic rules and translates the AST into a more concrete representation. Past this stage, the compiler need not consider every possible tree when doing translations, as some could only arise from semantically incorrect input. The semantic stage does not output IR, as standard, but HLR, which resembles an object file, but still encodes all the original content of the program.
HLR (High Level Representation): HLR exists to facilitate highly-informed whole-program optimization, as well as allow the partial use of incomplete types. Its format is largely similar to an object file, and this is written out in lieu of object files in partial program compilation. An HLR has types represented, but solely for sizing and analysis purposes. All expressions contain the proper conversion statements, Modules are still represented, but only as symbol tables. Objects are organized into various scopes, the topmost of which represents global declarations. Expressions are totally pure, and only statements have side effects (this is a canonical form, which usually happens at post-IR stages).
Merging: This stage merges, analyzes and optimizes a number of HLRs that make up a whole program. The whole program can then be optimized. This stage outputs a single HLR with no unbound types or structures.
IR Generation: This is the last stage of the frontend. The compiler determines the size of all types, aligns structures, and translates to an IR representation for a particular compiler backend.
IR (Intermediate Representation): This is the IR for whatever backend is used.