Mul(Int 2, Add(Var "foo", Int 1))
We could express the same structure in a language like Java using a class hierarchy, although it
would be a little more complicated:
abstract class Expr { }
class Var extends Expr { String name; .. }
class Int extends Expr { int val; ... }
class Add extends Expr { Expr exp1, exp2; ... }
class Mul extends Expr { Expr exp1, exp2; ... }
class Assgn extends Expr { String var, Expr exp1, exp2; .. }
2 Operational semantics
We have an intuitive notion of what expressions mean. For example, the 7 + (4 * 2) evaluates to 15,
and i := 6 + 1 ; 2 * 3 * i evaluates to 42. In this section, we will formalize this intuition precisely.
An operational semantics describes how a program executes on an abstract machine. A small-step
operational semantics describes how such an execution proceeds in terms of successive reductions—
here, of an expression—until we reach a value that represents the result of the computation. The
state of the abstract machine is often referred to as a configuration. For our language a configuration
must include two pieces of information:
• a store (also known as environment or state), which maps integer values to variables. Dur-
ing program execution, we will refer to the store to determine the values associated with
variables, and also update the store to reect assignment of new values to variables,
• the expression to evaluate.
We will represent stores as partial functions from Var to Int and configurations as pairs of expres-
sions and stores:
Store ≜ Var ⇀ Int
Config ≜ Store × Exp
We will denote configurations using angle brackets. For instance, ⟨σ, (foo + 2) * (bar + 2)⟩ is a con-
figuration where σ is a store and (foo + 2) * (bar + 2) is an expression that uses two variables, foo
and bar . The small-step operational semantics for our language is a relation →⊆ Config ×Config
that describes how one configuration transitions to a new configuration. That is, the relation →
shows us how to evaluate programs one step at a time. We use infix notation for the relation →.
That is, given any two configurations ⟨σ
1
, e
1
⟩ and ⟨σ
2
, e
2
⟩, if (⟨e
1
, σ
1
⟩, ⟨e
2
, σ
2
⟩) is in the relation →,
then we write ⟨σ
1
, e
1
⟩ → ⟨σ
2
, e
2
⟩. For example, we have ⟨σ, (4 + 2) * y⟩ → ⟨σ, 6 * y⟩. That is, we can
evaluate the configuration ⟨σ, (4 + 2) * y⟩ one step to get the configuration ⟨σ, 6 * y⟩.
Using this approach, defining the semantics of the language boils down to to defining the
relation → that describes the transitions between configurations.
One issue here is that the domain of integers is infinite, as is the domain of expressions. There-
fore, there is an infinite number of possible machine configurations, and an infinite number of
possible single-step transitions. We need a finite way of describing an infinite set of possible tran-
sitions. We can compactly describe → using inference rules:
3
评论0
最新资源