The Semantic Analyzer is the real heart of the compiler. Its job is to validate code and figure out what the code actually means. Essentially it validates that the code is semantically correct.
This is the third post in our Compiler series. Previous posts:
Semantic Analyzer
With the output from the Parser, all the compiler has is what the user actually typed, although converted to a format that is easy for the compiler to digest.
The Semantic Analyzer knows all the rules regarding the programming language. For example, it knows that an Integer can be multiplied with a Double. It knows a String cannot be compared with a Double. It knows how to do assignments to variables. It knows that Objects can be used with the “New” command. It knows about scope information. Everything that the compiler knows to pass the initial syntax check is in the Semantic Analyzer.
If we start with the syntax tree produced by the Parser, the Semantic Analyzer will go through it and add information to the syntax tree regarding types. And not just types, but adds information about things that are implicit in the language. For example, you may not think about it but there are implicit conversions that happen should you do something like assign a Double to an Integer.
As you can see below, the Semantic Analyzer has gone through the syntax tree and updated it to include when implicit conversions (ImplicitCast) are done.

This updated tree is then handed off to the next part of the compiler, IR Generation.