concepts of category theory, logics, or type theory, in order to use it. Also, it should have good
data representation capabilities and should allow proofs of theorems about programming languages
that are easy to comprehend. Additionally, a framework providing support for parsing programs
directly in the desired language syntax may be desirable to one requiring the implementation of an
additional, external to the definitional setting, parser.
The nine requirements above are nevertheless ambitious. Some proponents of existing language
definitional frameworks may argue that their favorite framework has these properties; however,
a careful analysis of existing language definitional frameworks reveals that they actually fail to
satisfy some of these ideal features (we discussed several such frameworks and their limitations in
Chapter 3). Others may argue that their favorite framework has some of the properties above, the
“important ones”, declaring the other properties either “not interesting” or “something else”. For
example, one may say that what is important in one’s framework is to get a dynamic semantics of a
language, but its (model-theoretical) algebraic denotational semantics, proving properties about
programs, model checking, etc., are “something else” and therefore are allowed to need a different
“encoding” of the language. Our position is that an ideal language definitional framework should not
compromise any of the nine requirements above.
Whether K satisfies all the requirements above or not is, and probably will always be, open.
What we can mention with regards to this aspect, though, is that K was motivated and stimulated
by the observation that the existing language definitional frameworks fail to fully satisfy these
minimal requirements; consequently, K’s design and development were conducted aiming explicitly
to fulfill all nine requirements discussed above, promoting none of them at the expense of others.
5.2 K Overview by Example
Here we briefly describe the K framework, what it offers and how it can be used. We use as concrete
examples the IMP language (Section 3.1) and its extension IMP++ (Section 3.8), discussed in
Chapter 3 in the context of the various existing language definitional frameworks. We define both
an executable semantics and a type system for these languages. The type system is included mainly
for demonstration purposes, to show that one can use the same definitional framework, K, to define
both formal language semantics and language abstractions. The role of this section is threefold:
first, it gives the reader a better understanding of the K framework before we proceed to define it
rigorously in the remainder of this chapter; second, it shows how K avoids the limitations of the
various more conventional semantic approaches discussed in Chapter 3; and third, it shows that
K is actually easy to use, in spite of the intricate K concurrent abstract machine technicalities
discussed in Section 5.4 — indeed, users of the K framework need not be familiar with all those
intricate details, the same way users of a concurrent programming language need not be aware
of the underlying details of the concurrent computing architecture on which their programs are
executed. In fact, in this section we make no distinction between the K rewrite abstract machine
and the K technique, refering to these collectively as “the K framework”, or more simply just “K”.
Programming languages, calculi, as well as type systems or formal analyzers can be defined in K
by making use of special, potentially nested (K) cell structures, and (K) (rewrite) rules. There are
two types of K rules: computational rules, which count as computational steps, and structural rules,
which do not count as computational steps. The role of the structural rules is to rearrange the term
so that the computational rules can apply. K rules are unconditional (they can be thought of as
rule schemata and may have ordinary side conditions, though), and they are context-insensitive, so
280