Introduction
Operational semantics defines the meaning of a program by specifying how it executes. Rather than assigning abstract mathematical meanings (denotational) or stating properties (axiomatic), operational semantics describes the concrete steps a program takes during execution. This approach is intuitive, directly implementable, and particularly useful for understanding program behavior and proving properties about execution.
This article explores the foundations of operational semantics, including transition systems, evaluation rules, and practical applications.
Historical Context
Operational semantics emerged from work in the 1970s and 1980s, particularly through the contributions of Gordon Plotkin and others. Plotkin’s structural operational semantics (SOS) provided a systematic framework for defining execution rules. This approach has become the standard method for specifying programming language semantics in practice.
Core Concepts
Transition Systems
A transition system models computation as a sequence of state transitions:
Definition: A transition system is a tuple (S, โ) where:
- S: A set of states (configurations)
- โ โ S ร S: A transition relation (s โ s’ means we can move from s to s')
Execution: An execution is a sequence of states sโ โ sโ โ sโ โ … where sโ is an initial state.
Termination: A state s is terminal if there is no s’ such that s โ s'.
Configurations
A configuration represents the current state of computation:
Components:
- Current expression/statement being evaluated
- Current environment (variable bindings)
- Current store (memory state)
- Call stack (for function calls)
Example: For evaluating 2 + 3:
Configuration: โจ2 + 3, ฯโฉ
where ฯ is the current state
Evaluation Relations
An evaluation relation specifies how expressions and statements are evaluated:
Notation:
- โจe, ฯโฉ โ v means “expression e in state ฯ evaluates to value v”
- โจs, ฯโฉ โ โจs’, ฯ’โฉ means “statement s in state ฯ transitions to s’ in state ฯ'”
Structural Operational Semantics (SOS)
Structural Operational Semantics provides a systematic way to define evaluation rules using inference rules.
Inference Rules
Format:
Premiseโ Premiseโ ... Premiseโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Conclusion
Interpretation: If all premises are true, then the conclusion is true.
Evaluation Rules for Expressions
Atomic Values:
โโโโโโโโโโโโโโโโโ
โจn, ฯโฉ โ n
(A number evaluates to itself)
Variables:
โโโโโโโโโโโโโโโโโ
โจx, ฯโฉ โ ฯ(x)
(A variable evaluates to its value in the state)
Binary Operations:
โจeโ, ฯโฉ โ vโ โจeโ, ฯโฉ โ vโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โจeโ + eโ, ฯโฉ โ vโ + vโ
(Evaluate both operands, then apply the operation)
Conditional:
โจb, ฯโฉ โ true โจeโ, ฯโฉ โ v
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โจif b then eโ else eโ, ฯโฉ โ v
โจb, ฯโฉ โ false โจeโ, ฯโฉ โ v
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โจif b then eโ else eโ, ฯโฉ โ v
Evaluation Rules for Statements
Skip:
โโโโโโโโโโโโโโโโโ
โจskip, ฯโฉ โ โจฯโฉ
(Skip does nothing, returns the state unchanged)
Assignment:
โจe, ฯโฉ โ v
โโโโโโโโโโโโโโโโโโโโโโโโโโ
โจx := e, ฯโฉ โ โจฯ[x โฆ v]โฉ
(Evaluate the expression, update the state)
Sequence:
โจsโ, ฯโฉ โ โจฯ'โฉ โจsโ, ฯ'โฉ โ โจฯ''โฉ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โจsโ; sโ, ฯโฉ โ โจฯ''โฉ
(Execute first statement, then second)
If Statement:
โจb, ฯโฉ โ true โจsโ, ฯโฉ โ โจฯ'โฉ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โจif b then sโ else sโ, ฯโฉ โ โจฯ'โฉ
While Loop:
โจb, ฯโฉ โ false
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โจwhile b do s, ฯโฉ โ โจฯโฉ
โจb, ฯโฉ โ true โจs, ฯโฉ โ โจฯ'โฉ โจwhile b do s, ฯ'โฉ โ โจฯ''โฉ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โจwhile b do s, ฯโฉ โ โจฯ''โฉ
Evaluation Strategies
Different evaluation strategies lead to different operational semantics:
Eager Evaluation (Strict)
Evaluate arguments before applying functions:
โจeโ, ฯโฉ โ vโ โจeโ, ฯโฉ โ vโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โจf(eโ, eโ), ฯโฉ โ โฆfโง(vโ, vโ)
Characteristics:
- All arguments evaluated
- Predictable performance
- May evaluate unnecessary expressions
Lazy Evaluation
Delay evaluation until needed:
โจeโ, ฯโฉ โ ฮปx. e โจeโ, ฯโฉ โ vโ โจe[x โฆ vโ], ฯโฉ โ v
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โจeโ(eโ), ฯโฉ โ v
Characteristics:
- Arguments passed unevaluated
- Avoids unnecessary computation
- More complex to reason about
Call-by-Value vs Call-by-Name
Call-by-Value: Evaluate arguments, pass values
โจeโ, ฯโฉ โ ฮปx. e โจeโ, ฯโฉ โ v
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โจeโ(eโ), ฯโฉ โ โจe[x โฆ v], ฯโฉ
Call-by-Name: Pass unevaluated expressions
โจeโ, ฯโฉ โ ฮปx. e
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โจeโ(eโ), ฯโฉ โ โจe[x โฆ eโ], ฯโฉ
Big-Step vs Small-Step Semantics
Big-Step Semantics (Natural Semantics)
Describes complete evaluation from start to finish:
Notation: โจe, ฯโฉ โ v (e evaluates to v in one big step)
Advantages:
- Concise and intuitive
- Directly implementable as interpreter
- Easier to reason about termination
Disadvantage:
- Difficult to express non-terminating computations
- Hard to reason about intermediate states
Small-Step Semantics (Structural Operational Semantics)
Describes individual computation steps:
Notation: โจe, ฯโฉ โ โจe’, ฯ’โฉ (one step of computation)
Advantages:
- Handles non-termination naturally
- Captures intermediate states
- Useful for debugging and analysis
Disadvantage:
- More verbose
- Requires multiple steps for complete evaluation
Relationship: Big-step evaluation is the transitive closure of small-step:
โจe, ฯโฉ โ v iff โจe, ฯโฉ โ* โจv, ฯ'โฉ
Practical Example: Simple Imperative Language
Language:
e ::= n | x | eโ + eโ | eโ * eโ
b ::= true | false | eโ = eโ | eโ < eโ | ยฌb | bโ โง bโ
s ::= skip | x := e | sโ; sโ | if b then sโ else sโ | while b do s
Small-Step Semantics:
Arithmetic:
โจn, ฯโฉ โ n
โจx, ฯโฉ โ ฯ(x)
โจeโ + eโ, ฯโฉ โ โจeโ', ฯโฉ + eโ if โจeโ, ฯโฉ โ โจeโ', ฯโฉ
โจvโ + eโ, ฯโฉ โ โจvโ + eโ', ฯโฉ if โจeโ, ฯโฉ โ โจeโ', ฯโฉ
โจvโ + vโ, ฯโฉ โ vโ + vโ
Statements:
โจskip, ฯโฉ โ ฯ
โจx := e, ฯโฉ โ ฯ[x โฆ v] if โจe, ฯโฉ โ* v
โจsโ; sโ, ฯโฉ โ โจsโ', ฯ'โฉ; sโ if โจsโ, ฯโฉ โ โจsโ', ฯ'โฉ
โจskip; sโ, ฯโฉ โ โจsโ, ฯโฉ
Applications
Language Implementation
Operational semantics directly guides interpreter implementation:
def eval_expr(e, state):
if isinstance(e, int):
return e
elif isinstance(e, str): # variable
return state[e]
elif e[0] == '+':
return eval_expr(e[1], state) + eval_expr(e[2], state)
# ... more cases
Program Verification
Prove properties about program execution:
Example: Prove that x := 5; y := x + 1 results in y = 6
โจx := 5; y := x + 1, ฯโฉ
โ โจy := x + 1, ฯ[x โฆ 5]โฉ
โ ฯ[x โฆ 5, y โฆ 6]
Equivalence Checking
Prove two programs are equivalent:
Example: x := 5; y := x โก x := 5; y := 5
Both evaluate to the same final state.
Debugging and Tracing
Small-step semantics enables step-by-step execution:
- Debuggers use small-step semantics
- Trace execution for analysis
- Identify where errors occur
Advanced Topics
Concurrency
For concurrent programs, extend transition systems:
โจsโ, ฯโฉ โ โจsโ', ฯ'โฉ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โจsโ โฅ sโ, ฯโฉ โ โจsโ' โฅ sโ, ฯ'โฉ
(Either process can take a step)
Exception Handling
Add exception states:
โจe, ฯโฉ โ exception
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โจtry e catch h, ฯโฉ โ โจh, ฯโฉ
Non-Determinism
Allow multiple possible transitions:
โจe, ฯโฉ โ โจeโ', ฯ'โฉ or โจe, ฯโฉ โ โจeโ', ฯ'โฉ
Glossary
Big-Step Semantics: Evaluation relation describing complete computation from start to finish
Configuration: The current state of computation (expression, environment, store)
Evaluation Relation: A relation specifying how expressions and statements are evaluated
Inference Rule: A rule with premises and conclusion used to define evaluation
Operational Semantics: Defining meaning through execution steps
Small-Step Semantics: Transition relation describing individual computation steps
State: An assignment of values to variables
Structural Operational Semantics (SOS): Systematic framework for defining evaluation rules
Terminal State: A state with no outgoing transitions
Transition System: A set of states with a transition relation
Practice Problems
Problem 1: Define small-step semantics for 2 + 3 * 4 and show the evaluation steps.
Solution:
โจ2 + 3 * 4, ฯโฉ
โ โจ2 + 12, ฯโฉ (evaluate 3 * 4)
โ โจ14, ฯโฉ (evaluate 2 + 12)
Problem 2: Write operational semantics rules for a repeat-until loop: repeat s until b.
Solution:
โจs, ฯโฉ โ โจฯ'โฉ โจb, ฯ'โฉ โ false โจrepeat s until b, ฯ'โฉ โ โจฯ''โฉ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โจrepeat s until b, ฯโฉ โ โจฯ''โฉ
โจs, ฯโฉ โ โจฯ'โฉ โจb, ฯ'โฉ โ true
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โจrepeat s until b, ฯโฉ โ โจฯ'โฉ
Problem 3: Prove that while false do s is equivalent to skip.
Solution:
โจwhile false do s, ฯโฉ โ โจฯโฉ (by while rule with false condition)
โจskip, ฯโฉ โ โจฯโฉ
Both evaluate to the same state, so they're equivalent.
Related Resources
- Operational Semantics: https://en.wikipedia.org/wiki/Operational_semantics
- Structural Operational Semantics: https://en.wikipedia.org/wiki/Structural_operational_semantics
- Semantics of Programming Languages: “Semantics of Programming Languages” by Carl Gunter
- Formal Semantics: https://plato.stanford.edu/entries/formal-semantics/
- Programming Language Semantics: https://en.wikipedia.org/wiki/Semantics_(computer_science)
- Transition Systems: https://en.wikipedia.org/wiki/Transition_system
- Evaluation Strategy: https://en.wikipedia.org/wiki/Evaluation_strategy
- Call-by-Value vs Call-by-Name: https://en.wikipedia.org/wiki/Evaluation_strategy
- Formal Methods: https://plato.stanford.edu/entries/formal-methods/
- Program Verification: https://en.wikipedia.org/wiki/Program_verification
- Compiler Design: https://en.wikipedia.org/wiki/Compiler
- Interpreter Pattern: https://en.wikipedia.org/wiki/Interpreter_pattern
- Abstract Syntax Tree: https://en.wikipedia.org/wiki/Abstract_syntax_tree
- Type Systems: https://plato.stanford.edu/entries/type-theory/
- Lambda Calculus: https://plato.stanford.edu/entries/lambda-calculus/
Conclusion
Operational semantics provides a concrete, intuitive way to specify and reason about program execution. By defining evaluation rules that describe how programs compute step-by-step, operational semantics bridges the gap between informal program understanding and formal mathematical reasoning.
The flexibility of operational semanticsโsupporting both big-step and small-step approaches, handling various evaluation strategies, and extending to concurrent and exceptional programsโmakes it the most widely used approach for specifying programming language semantics in practice.
Understanding operational semantics is essential for language designers, compiler developers, and anyone involved in formal verification. It provides the foundation for implementing interpreters, proving program properties, and understanding the precise behavior of programming languages.
Comments