FREE COMPUTER SCIENCE STACK LEVEL · 8 OF 14

Languages & compilers

How do syntax and semantics become machine behavior?

The question this layer answers

How do syntax and semantics become machine behavior?

Human intent becomes execution. This layer connects Parsers, Types, Compilers, VMs, Garbage collection to the rest of the computing stack.

Free Languages & compilers lessons

1. Source becomes structure

Lexing, parsing, grammars, and syntax trees

Lexing commonly groups characters into tokens; parsing checks those tokens against a grammar and constructs a syntax tree. Precedence and associativity decide whether a+b*c means a+(b*c). The tree discards punctuation that no longer matters while preserving the nesting required for later meaning.

A grammar that admits two parse trees for one token sequence leaves meaning underdetermined unless another rule resolves it. Languages define precedence, associativity, or explicit delimiters; parser generators may report conflicts. Silently accepting whichever parse happens first is not a sound semantics.

2. Types make impossible states harder to express

Static constraints and runtime meaning

Static checking rejects some programs before execution; dynamic checking attaches decisions to runtime values. Rich types can encode variants, ownership, nullability, effects, or units. No practical type system proves every desirable property, and unsafe escape hatches or external data reintroduce obligations.

Instead of a nullable result with side-channel error codes, define Success(value) or Failure(reason). Pattern matching then requires each variant to be handled, and the payload appropriate to one variant is unavailable in the other. The representation moves a runtime convention into a checkable structure.

3. Many roads to execution

Compilers, interpreters, VMs, and JITs

A native compiler can optimize ahead of time into target instructions. An interpreter can execute a syntax tree or bytecode step by step. A virtual machine defines a portable instruction set. A just-in-time compiler observes running code and compiles hot paths using runtime facts, with warm-up and deoptimization costs.

Constant folding can replace 3×7 with 21; dead-code elimination can remove work whose result is unobservable; inlining exposes cross-function opportunities. But exceptions, I/O, timing contracts, concurrency, and language rules constrain what counts as unobservable. Faster wrong code is not an optimization.

4. Language mastery: who owns memory?

Lifetime, allocation, garbage collection, and boundaries

Manual management gives explicit control but risks leaks, use-after-free, and double release. Tracing garbage collection discovers objects reachable from roots and reclaims the rest, trading control for runtime work and pauses. Ownership systems encode lifetime constraints statically. Reference counting is prompt but struggles with cycles unless supplemented.

Managed code calling native code must agree on layout, ownership, error signalling, threading, and how objects remain alive while native pointers exist. A type-safe caller can still be corrupted by a callee that writes beyond a buffer. Safe wrappers minimize and validate the unsafe surface.

Practise Languages & compilers free →