Or have you ever thought about building your own programming language? The invalid operation may be detected when the program is compiled "static" type checking and will be rejected by the compiler with a compilation error message, or it may be detected while the program is running "dynamic" type checkingresulting in a run-time exception.
This can be automated but it becomes a pain when switching between build systems. This is a limitation we have chosen to accept to keep our lexer simple.
There are many ways of defining execution semantics. Andy Balaam starts his series with a lexer. Is it a method parameter? For example, a debugger could be really useful to deal with a nasty bug.
For example, the semantics may define the strategy by which expressions are evaluated to values, or the manner in which control structures conditionally execute statements.
In the second case, the compiler infers the types of expressions and declarations based on context. How do we provide these functionalities?
Different languages have different designs based on the needs of that person — for example, Python is designed among other things [ Peters04 ] to make code easy to read, and Rust is designed among other things [ Rust ] to make it easy to avoid certain kinds of mistakes.