  Static program analysis is a valuable tool for any programming language that
people write programs in. The prevalence of scripting languages in the world
suggests programming language interpreters are relatively easy to write. Users
of these languages lament their inability to analyze their code, therefore
programming language analyzers are not easy to write. This thesis investigates
a systematic method of creating abstract interpreters from traditional
interpreters, called Abstracting Abstract Machines.
  Abstract interpreters are difficult to develop due to technical, theoretical,
and pragmatic problems. Technical problems include engineering data structures
and algorithms. I show that modest and simple changes to the mathematical
presentation of abstract machines result in 1000 times better running time -
just seconds for moderately sized programs.
  In the theoretical realm, abstraction can make correctness difficult to
ascertain. I provide proof techniques for proving the correctness of regular,
pushdown, and stack-inspecting pushdown models of abstract computation by
leaving computational power to an external factor: allocation. Even if we don't
trust the proof, we can run models concretely against test suites to better
trust them.
  In the pragmatic realm, I show that the systematic process of abstracting
abstract machines is automatable. I develop a meta-language for expressing
abstract machines similar to other semantics engineering languages. The
language's special feature is that it provides an interface to abstract
allocation. The semantics guarantees that if allocation is finite, then the
semantics is a sound and computable approximation of the concrete semantics.
