first draft of Springer volume
authorlcp
Wed, 23 Mar 1994 11:10:16 +0100
changeset 291 a615050a7494
parent 290 37d580c16af5
child 292 cc69ef31cfc3
first draft of Springer volume
doc-src/Logics/LK.tex
doc-src/Logics/defining.tex
--- a/doc-src/Logics/LK.tex	Tue Mar 22 12:43:51 1994 +0100
+++ b/doc-src/Logics/LK.tex	Wed Mar 23 11:10:16 1994 +0100
@@ -1,5 +1,5 @@
 %% $Id$
-\chapter{First-order sequent calculus}
+\chapter{First-Order Sequent Calculus}
 The directory~\ttindexbold{LK} implements classical first-order logic through
 Gentzen's sequent calculus (see Gallier~\cite{gallier86} or
 Takeuti~\cite{takeuti87}).  Resembling the method of semantic tableaux, the
@@ -244,7 +244,7 @@
 \ttindex{res_inst_tac} can instantiate the variable~{\tt?P} in these rules,
 specifying the formula to duplicate.
 
-See the files \ttindexbold{LK/lk.thy} and \ttindexbold{LK/lk.ML}
+See the files {\tt LK/lk.thy} and {\tt LK/lk.ML}
 for complete listings of the rules and derived rules.
 
 
@@ -279,7 +279,7 @@
 
 \item[\ttindexbold{cutL_tac} {\it P\/} {\it i}] 
 reads an \LK{} formula~$P$, and applies the cut rule to subgoal~$i$.  It
-then deletes some formula from the let side of the new subgoal $i+1$,
+then deletes some formula from the left side of the new subgoal $i+1$,
 replacing that formula by~$P$.
 \end{description}
 All the structural rules --- cut, contraction, and thinning --- can be
@@ -309,10 +309,11 @@
 checks that each conclusion formula is unifiable (using {\tt could_unify})
 with some subgoal formula.
 
-\item[\ttindexbold{could_resolve} $(t,u)$] 
-tests whether two sequents could be resolved.  Sequent $t$ is a premise
-(subgoal), while $u$ is the conclusion of an object-rule.  It uses {\tt
-could_res} to check the left and right sides of the two sequents.
+\item[\ttindexbold{could_resolve_seq} $(t,u)$] 
+  tests whether two sequents could be resolved.  Sequent $t$ is a premise
+  (subgoal), while $u$ is the conclusion of an object-rule.  It simply
+  calls {\tt could_res} twice to check that both the left and the right
+  sides of the sequents are compatible.
 
 \item[\ttindexbold{filseq_resolve_tac} {\it thms} {\it maxr} {\it i}] 
 uses {\tt filter_thms could_resolve} to extract the {\it thms} that are
@@ -324,10 +325,10 @@
 
 
 \section{Packaging sequent rules}
-For theorem proving, rules can be classified as {\bf safe} or {\bf
-unsafe}.  An unsafe rule (typically a weakened quantifier rule) may reduce
-a provable goal to an unprovable set of subgoals, and should only be used
-as a last resort.  
+For theorem proving, rules can be classified as {\bf safe} or {\bf unsafe}.
+An unsafe rule may reduce a provable goal to an unprovable set of subgoals,
+and should only be used as a last resort.  Typical examples are the
+weakened quantifier rules {\tt allL_thin} and {\tt exR_thin}.
 
 A {\bf pack} is a pair whose first component is a list of safe
 rules, and whose second is a list of unsafe rules.  Packs can be extended
@@ -541,7 +542,7 @@
 \[  \turn \neg (\exists x. \forall y. y\in x \bimp y\not\in y) \]
 This does not require special properties of membership; we may
 generalize $x\in y$ to an arbitrary predicate~$F(x,y)$.  The theorem has a
-short manual proof.  See the directory \ttindexbold{LK/ex} for many more
+short manual proof.  See the directory {\tt LK/ex} for many more
 examples.
 
 We set the main goal and move the negated formula to the left.
--- a/doc-src/Logics/defining.tex	Tue Mar 22 12:43:51 1994 +0100
+++ b/doc-src/Logics/defining.tex	Wed Mar 23 11:10:16 1994 +0100
@@ -1,128 +1,123 @@
 %% $Id$
+%%  \([a-zA-Z][a-zA-Z]}\.\) \([^ ]\)             \1  \2
+%%  @\([a-z0-9]\)       ^{(\1)}
 
-\newcommand{\rmindex}[1]{{#1}\index{#1}\@}
-\newcommand{\mtt}[1]{\mbox{\tt #1}}
-\newcommand{\ttfct}[1]{\mathop{\mtt{#1}}\nolimits}
-\newcommand{\ttrel}[1]{\mathrel{\mtt{#1}}}
-\newcommand{\Constant}{\ttfct{Constant}}
-\newcommand{\Variable}{\ttfct{Variable}}
-\newcommand{\Appl}[1]{\ttfct{Appl}\mathopen{\mtt[}#1\mathclose{\mtt]}}
-
+\newcommand\rmindex[1]{{#1}\index{#1}\@}
+\newcommand\mtt[1]{\mbox{\tt #1}}
+\newcommand\ttfct[1]{\mathop{\mtt{#1}}\nolimits}
+\newcommand\ttapp{\mathrel{\hbox{\tt\$}}}
+\newcommand\Constant{\ttfct{Constant}}
+\newcommand\Variable{\ttfct{Variable}}
+\newcommand\Appl[1]{\ttfct{Appl}\mathopen{\mtt[}#1\mathclose{\mtt]}}
+\newcommand\AST{{\sc ast}}
+\let\rew=\longrightarrow
 
 
 \chapter{Defining Logics} \label{Defining-Logics}
 
-This chapter is intended for Isabelle experts. It explains how to define new
-logical systems, Isabelle's {\em raison d'\^etre}. Isabelle logics are
-hierarchies of theories. A number of simple examples are contained in {\em
-Introduction to Isabelle}; the full syntax of theory definition files ({\tt
-.thy} files) is shown in {\em The Isabelle Reference Manual}. This chapter's
-chief purpose is a thorough description of all syntax related matters
-concerning theories. The most important sections are \S\ref{sec:mixfix} about
-mixfix declarations and \S\ref{sec:macros} describing the macro system. The
-concluding examples of \S\ref{sec:min_logics} are more concerned with the
-logical aspects of the definition of theories. Sections marked with * can be
-skipped on first reading.
+This chapter explains how to define new formal systems --- in particular,
+their concrete syntax.  While Isabelle can be regarded as a theorem prover
+for set theory, higher-order logic or the sequent calculus, its
+distinguishing feature is support for the definition of new logics.
 
+Isabelle logics are hierarchies of theories, which are described and
+illustrated in {\em Introduction to Isabelle}.  That material, together
+with the theory files provided in the examples directories, should suffice
+for all simple applications.  The easiest way to define a new theory is by
+modifying a copy of an existing theory.
+
+This chapter is intended for experienced Isabelle users.  It documents all
+aspects of theories concerned with syntax: mixfix declarations, pretty
+printing, macros and translation functions.  The extended examples of
+\S\ref{sec:min_logics} demonstrate the logical aspects of the definition of
+theories.  Sections marked with * are highly technical and might be skipped
+on the first reading.
 
 
-\section{Precedence grammars} \label{sec:precedence_grammars}
+\section{Priority grammars} \label{sec:priority_grammars}
+\index{grammars!priority|(} 
 
-The precise syntax of a logic is best defined by a \rmindex{context-free
-grammar}. In order to simplify the description of mathematical languages, we
-introduce an extended format which permits {\bf
-precedences}\indexbold{precedence}. This scheme generalizes precedence
-declarations in \ML\ and {\sc prolog}. In this extended grammar format,
-nonterminals are decorated by integers, their precedence. In the sequel,
-precedences are shown as subscripts. A nonterminal $A@p$ on the right-hand
-side of a production may only be replaced using a production $A@q = \gamma$
-where $p \le q$.
+The syntax of an Isabelle logic is specified by a {\bf priority grammar}.
+A context-free grammar\index{grammars!context-free} contains a set of
+productions of the form $A=\gamma$, where $A$ is a nonterminal and
+$\gamma$, the right-hand side, is a string of terminals and nonterminals.
+Isabelle uses an extended format permitting {\bf priorities}, or
+precedences.  Each nonterminal is decorated by an integer priority, as
+in~$A^{(p)}$.  A nonterminal $A^{(p)}$ in a derivation may be replaced
+using a production $A^{(q)} = \gamma$ only if $p \le q$.  Any priority
+grammar can be translated into a normal context free grammar by introducing
+new nonterminals and productions.
 
 Formally, a set of context free productions $G$ induces a derivation
-relation $\rew@G$ on strings as follows:
-\[ \alpha A@p \beta ~\rew@G~ \alpha\gamma\beta ~~~iff~~~
-   \exists (A@q=\gamma) \in G.~q \ge p
-\]
-Any extended grammar of this kind can be translated into a normal context
-free grammar. However, this translation may require the introduction of a
-large number of new nonterminals and productions.
+relation $\rew@G$.  Let $\alpha$ and $\beta$ denote strings of terminal or
+nonterminal symbols.  Then
+\[ \alpha\, A^{(p)}\, \beta ~\rew@G~ \alpha\,\gamma\,\beta \] 
+if and only if $G$ contains some production $A^{(q)}=\gamma$ for~$q\ge p$.
 
-\begin{example} \label{ex:precedence}
 The following simple grammar for arithmetic expressions demonstrates how
-binding power and associativity of operators can be enforced by precedences.
+binding power and associativity of operators can be enforced by priorities.
 \begin{center}
 \begin{tabular}{rclr}
-  $A@9$ & = & {\tt0} \\
-  $A@9$ & = & {\tt(} $A@0$ {\tt)} \\
-  $A@0$ & = & $A@0$ {\tt+} $A@1$ \\
-  $A@2$ & = & $A@3$ {\tt*} $A@2$ \\
-  $A@3$ & = & {\tt-} $A@3$
+  $A^{(9)}$ & = & {\tt0} \\
+  $A^{(9)}$ & = & {\tt(} $A^{(0)}$ {\tt)} \\
+  $A^{(0)}$ & = & $A^{(0)}$ {\tt+} $A^{(1)}$ \\
+  $A^{(2)}$ & = & $A^{(3)}$ {\tt*} $A^{(2)}$ \\
+  $A^{(3)}$ & = & {\tt-} $A^{(3)}$
 \end{tabular}
 \end{center}
-The choice of precedences determines that {\tt -} binds tighter than {\tt *}
-which binds tighter than {\tt +}, and that {\tt +} associates to the left and
-{\tt *} to the right.
-\end{example}
+The choice of priorities determines that {\tt -} binds tighter than {\tt *},
+which binds tighter than {\tt +}.  Furthermore {\tt +} associates to the
+left and {\tt *} to the right.
 
 To minimize the number of subscripts, we adopt the following conventions:
 \begin{itemize}
-\item All precedences $p$ must be in the range $0 \leq p \leq max_pri$ for
-  some fixed $max_pri$.
-\item Precedence $0$ on the right-hand side and precedence $max_pri$ on the
+\item All priorities $p$ must be in the range $0 \leq p \leq max_pri$ for
+  some fixed integer $max_pri$.
+\item Priority $0$ on the right-hand side and priority $max_pri$ on the
   left-hand side may be omitted.
 \end{itemize}
-In addition, we write the production $A@p = \alpha$ as $A = \alpha~(p)$,
-i.e.\ the precedence of the left-hand side actually appears in the uttermost
-right. Finally, alternatives may be separated by $|$, and repetition
+The production $A^{(p)} = \alpha$ is written as $A = \alpha~(p)$;
+the priority of the left-hand side actually appears in a column on the far
+right.  Finally, alternatives may be separated by $|$, and repetition
 indicated by \dots.
 
-Using these conventions and assuming $max_pri=9$, the grammar in
-Example~\ref{ex:precedence} becomes
+Using these conventions and assuming $max_pri=9$, the grammar takes the form
 \begin{center}
 \begin{tabular}{rclc}
 $A$ & = & {\tt0} & \hspace*{4em} \\
  & $|$ & {\tt(} $A$ {\tt)} \\
- & $|$ & $A$ {\tt+} $A@1$ & (0) \\
- & $|$ & $A@3$ {\tt*} $A@2$ & (2) \\
- & $|$ & {\tt-} $A@3$ & (3)
+ & $|$ & $A$ {\tt+} $A^{(1)}$ & (0) \\
+ & $|$ & $A^{(3)}$ {\tt*} $A^{(2)}$ & (2) \\
+ & $|$ & {\tt-} $A^{(3)}$ & (3)
 \end{tabular}
 \end{center}
-
+\index{grammars!priority|)}
 
 
-\section{Basic syntax} \label{sec:basic_syntax}
-
-The basis of all extensions by object-logics is the \rmindex{Pure theory},
-bound to the \ML-identifier \ttindex{Pure.thy}. It contains, among many other
-things, the \rmindex{Pure syntax}. An informal account of this basic syntax
-(meta-logic, types etc.) may be found in {\em Introduction to Isabelle}. A
-more precise description using a precedence grammar is shown in
-Figure~\ref{fig:pure_gram}.
-
-\begin{figure}[htb]
+\begin{figure}
 \begin{center}
 \begin{tabular}{rclc}
 $prop$ &=& \ttindex{PROP} $aprop$ ~~$|$~~ {\tt(} $prop$ {\tt)} \\
-     &$|$& $logic@3$ \ttindex{==} $logic@2$ & (2) \\
-     &$|$& $logic@3$ \ttindex{=?=} $logic@2$ & (2) \\
-     &$|$& $prop@2$ \ttindex{==>} $prop@1$ & (1) \\
-     &$|$& {\tt[|} $prop$ {\tt;} \dots {\tt;} $prop$ {\tt|]} {\tt==>} $prop@1$ & (1) \\
+     &$|$& $logic^{(3)}$ \ttindex{==} $logic^{(2)}$ & (2) \\
+     &$|$& $logic^{(3)}$ \ttindex{=?=} $logic^{(2)}$ & (2) \\
+     &$|$& $prop^{(2)}$ \ttindex{==>} $prop^{(1)}$ & (1) \\
+     &$|$& {\tt[|} $prop$ {\tt;} \dots {\tt;} $prop$ {\tt|]} {\tt==>} $prop^{(1)}$ & (1) \\
      &$|$& {\tt!!} $idts$ {\tt.} $prop$ & (0) \\\\
 $logic$ &=& $prop$ ~~$|$~~ $fun$ \\\\
 $aprop$ &=& $id$ ~~$|$~~ $var$
-    ~~$|$~~ $fun@{max_pri}$ {\tt(} $logic$ {\tt,} \dots {\tt,} $logic$ {\tt)} \\\\
+    ~~$|$~~ $fun^{(max_pri)}$ {\tt(} $logic$ {\tt,} \dots {\tt,} $logic$ {\tt)} \\\\
 $fun$ &=& $id$ ~~$|$~~ $var$ ~~$|$~~ {\tt(} $fun$ {\tt)} \\
-    &$|$& $fun@{max_pri}$ {\tt(} $logic$ {\tt,} \dots {\tt,} $logic$ {\tt)} \\
-    &$|$& $fun@{max_pri}$ {\tt::} $type$ \\
+    &$|$& $fun^{(max_pri)}$ {\tt(} $logic$ {\tt,} \dots {\tt,} $logic$ {\tt)} \\
+    &$|$& $fun^{(max_pri)}$ {\tt::} $type$ \\
     &$|$& \ttindex{\%} $idts$ {\tt.} $logic$ & (0) \\\\
-$idts$ &=& $idt$ ~~$|$~~ $idt@1$ $idts$ \\\\
+$idts$ &=& $idt$ ~~$|$~~ $idt^{(1)}$ $idts$ \\\\
 $idt$ &=& $id$ ~~$|$~~ {\tt(} $idt$ {\tt)} \\
     &$|$& $id$ \ttindex{::} $type$ & (0) \\\\
-$type$ &=& $tfree$ ~~$|$~~ $tvar$ ~~$|$~~ $tfree$ {\tt::} $sort$
+$type$ &=& $tid$ ~~$|$~~ $tvar$ ~~$|$~~ $tid$ {\tt::} $sort$
   ~~$|$~~ $tvar$ {\tt::} $sort$ \\
-     &$|$& $id$ ~~$|$~~ $type@{max_pri}$ $id$
+     &$|$& $id$ ~~$|$~~ $type^{(max_pri)}$ $id$
                 ~~$|$~~ {\tt(} $type$ {\tt,} \dots {\tt,} $type$ {\tt)} $id$ \\
-     &$|$& $type@1$ \ttindex{=>} $type$ & (0) \\
+     &$|$& $type^{(1)}$ \ttindex{=>} $type$ & (0) \\
      &$|$& {\tt[}  $type$ {\tt,} \dots {\tt,} $type$ {\tt]} {\tt=>} $type$&(0)\\
      &$|$& {\tt(} $type$ {\tt)} \\\\
 $sort$ &=& $id$ ~~$|$~~ {\tt\ttlbrace\ttrbrace}
@@ -132,142 +127,160 @@
 \indexbold{idts@$idts$} \indexbold{logic@$logic$} \indexbold{prop@$prop$}
 \indexbold{fun@$fun$}
 \end{center}
-\caption{Meta-Logic Syntax}
-\label{fig:pure_gram}
+\caption{Meta-logic syntax}\label{fig:pure_gram}
 \end{figure}
 
-The following main categories are defined:
-\begin{description}
-  \item[$prop$] Terms of type $prop$, i.e.\ formulae of the meta-logic.
+
+\section{The Pure syntax} \label{sec:basic_syntax}
+\index{syntax!Pure|(}
 
-  \item[$aprop$] Atomic propositions.
+At the root of all object-logics lies the Pure theory,\index{theory!Pure}
+bound to the \ML{} identifier \ttindex{Pure.thy}.  It contains, among many
+other things, the Pure syntax. An informal account of this basic syntax
+(meta-logic, types, \ldots) may be found in {\em Introduction to Isabelle}.
+A more precise description using a priority grammar is shown in
+Fig.\ts\ref{fig:pure_gram}.  The following nonterminals are defined:
+\begin{description}
+  \item[$prop$] Terms of type $prop$.  These are formulae of the meta-logic.
 
-  \item[$logic$] Terms of types in class $logic$. Initially, $logic$ contains
-    merely $prop$. As the syntax is extended by new object-logics, more
-    productions for $logic$ are added automatically (see below).
+  \item[$aprop$] Atomic propositions.  These typically include the
+    judgement forms of the object-logic; its definition introduces a
+    meta-level predicate for each judgement form.
+
+  \item[$logic$] Terms whose type belongs to class $logic$.  Initially,
+    this category contains just $prop$.  As the syntax is extended by new
+    object-logics, more productions for $logic$ are added automatically
+    (see below).
 
   \item[$fun$] Terms potentially of function type.
 
-  \item[$type$] Meta-types.
+  \item[$type$] Types of the meta-logic.
 
-  \item[$idts$] A list of identifiers, possibly constrained by types. Note
-    that \verb|x :: nat y| is parsed as \verb|x :: (nat y)|, i.e.\ {\tt y}
-    would be treated like a type constructor applied to {\tt nat}.
+  \item[$idts$] A list of identifiers, possibly constrained by types.  
 \end{description}
 
-
-\subsection{Logical types and default syntax}
+\begin{warn}
+  Note that \verb|x::nat y| is parsed as \verb|x::(nat y)|, treating {\tt
+    y} like a type constructor applied to {\tt nat}.  The likely result is
+  an error message.  To avoid this interpretation, use parentheses and
+  write \verb|(x::nat) y|.
 
-Isabelle is concerned with mathematical languages which have a certain
-minimal vocabulary: identifiers, variables, parentheses, and the lambda
-calculus. Logical types, i.e.\ those of class $logic$, are automatically
-equipped with this basic syntax. More precisely, for any type constructor
-$ty$ with arity $(\vec{s})c$, where $c$ is a subclass of $logic$, the
-following productions are added:
+  Similarly, \verb|x::nat y::nat| is parsed as \verb|x::(nat y::nat)| and
+  yields a syntax error.  The correct form is \verb|(x::nat) (y::nat)|.
+\end{warn}
+
+\subsection{Logical types and default syntax}\label{logical-types}
+Isabelle's representation of mathematical languages is based on the typed
+$\lambda$-calculus.  All logical types, namely those of class $logic$, are
+automatically equipped with a basic syntax of types, identifiers,
+variables, parentheses, $\lambda$-abstractions and applications.  
+
+More precisely, for each type constructor $ty$ with arity $(\vec{s})c$,
+where $c$ is a subclass of $logic$, several productions are added:
 \begin{center}
 \begin{tabular}{rclc}
 $ty$ &=& $id$ ~~$|$~~ $var$ ~~$|$~~ {\tt(} $ty$ {\tt)} \\
-  &$|$& $fun@{max_pri}$ {\tt(} $logic$ {\tt,} \dots {\tt,} $logic$ {\tt)}\\
-  &$|$& $ty@{max_pri}$ {\tt::} $type$\\\\
+  &$|$& $fun^{(max_pri)}$ {\tt(} $logic$ {\tt,} \dots {\tt,} $logic$ {\tt)}\\
+  &$|$& $ty^{(max_pri)}$ {\tt::} $type$\\\\
 $logic$ &=& $ty$
 \end{tabular}
 \end{center}
 
 
-\subsection{Lexical matters *}
-
-The parser does not process input strings directly, it rather operates on
-token lists provided by Isabelle's \rmindex{lexical analyzer} (the
-\bfindex{lexer}). There are two different kinds of tokens: {\bf
-  delimiters}\indexbold{delimiter} and {\bf names}\indexbold{name}.
+\subsection{Lexical matters}
+The parser does not process input strings directly.  It operates on token
+lists provided by Isabelle's \bfindex{lexer}.  There are two kinds of
+tokens: \bfindex{delimiters} and \bfindex{name tokens}.
 
-Delimiters can be regarded as reserved words\index{reserved word} of the
-syntax and the user can add new ones, when extending theories. In
-Figure~\ref{fig:pure_gram} they appear in typewriter font, e.g.\ {\tt PROP},
-{\tt ==}, {\tt =?=}, {\tt ;}.
+Delimiters can be regarded as reserved words of the syntax.  You can
+add new ones when extending theories.  In Fig.\ts\ref{fig:pure_gram} they
+appear in typewriter font, for example {\tt ==}, {\tt =?=} and
+{\tt PROP}\@.
 
-Names on the other hand have a fixed predefined syntax. The lexer
-distinguishes four kinds of them: identifiers\index{identifier},
-unknowns\index{unknown}\index{scheme variable|see{unknown}}, type
-variables\index{type variable}, type unknowns\index{type unknown}\index{type
-scheme variable|see{type unknown}}; they are denoted by $id$\index{id@$id$},
-$var$\index{var@$var$}, $tfree$\index{tfree@$tfree$},
-$tvar$\index{tvar@$tvar$}, respectively. Typical examples are {\tt x}, {\tt
-?x7}, {\tt 'a}, {\tt ?'a3}, the exact syntax is:
+Name tokens have a predefined syntax.  The lexer distinguishes four
+disjoint classes of names: \rmindex{identifiers}, \rmindex{unknowns}, type
+identifiers\index{identifiers!type}, type unknowns\index{unknowns!type}.
+They are denoted by $id$\index{id@$id$}, $var$\index{var@$var$},
+$tid$\index{tid@$tid$}, $tvar$\index{tvar@$tvar$}, respectively.  Typical
+examples are {\tt x}, {\tt ?x7}, {\tt 'a}, {\tt ?'a3}.  Here is the precise
+syntax:
 \begin{eqnarray*}
 id        & =   & letter~quasiletter^* \\
 var       & =   & \mbox{\tt ?}id ~~|~~ \mbox{\tt ?}id\mbox{\tt .}nat \\
-tfree     & =   & \mbox{\tt '}id \\
-tvar      & =   & \mbox{\tt ?}tfree ~~|~~
-                  \mbox{\tt ?}tfree\mbox{\tt .}nat \\[1ex]
+tid     & =   & \mbox{\tt '}id \\
+tvar      & =   & \mbox{\tt ?}tid ~~|~~
+                  \mbox{\tt ?}tid\mbox{\tt .}nat \\[1ex]
 letter    & =   & \mbox{one of {\tt a}\dots {\tt z} {\tt A}\dots {\tt Z}} \\
 digit     & =   & \mbox{one of {\tt 0}\dots {\tt 9}} \\
 quasiletter & =  & letter ~~|~~ digit ~~|~~ \mbox{\tt _} ~~|~~ \mbox{\tt '} \\
 nat       & =   & digit^+
 \end{eqnarray*}
-A $var$ or $tvar$ describes an \rmindex{unknown} which is internally a pair
+A $var$ or $tvar$ describes an unknown, which is internally a pair
 of base name and index (\ML\ type \ttindex{indexname}).  These components are
-either explicitly separated by a dot as in {\tt ?x.1} or {\tt ?x7.3} or
-directly run together as in {\tt ?x1}. The latter form is possible, if the
-base name does not end with digits; if the index is 0, it may be dropped
-altogether: {\tt ?x} abbreviates {\tt ?x0} or {\tt ?x.0}.
+either separated by a dot as in {\tt ?x.1} or {\tt ?x7.3} or
+run together as in {\tt ?x1}.  The latter form is possible if the
+base name does not end with digits.  If the index is 0, it may be dropped
+altogether: {\tt ?x} abbreviates both {\tt ?x0} and {\tt ?x.0}.
 
-Note that $id$, $var$, $tfree$, $tvar$ are mutually disjoint, but it is
-perfectly legal that they overlap with the set of delimiters (e.g.\ {\tt
-  PROP}, {\tt ALL}, {\tt EX}).
+The lexer repeatedly takes the maximal prefix of the input string that
+forms a valid token.  A maximal prefix that is both a delimiter and a name
+is treated as a delimiter.  Spaces, tabs and newlines are separators; they
+never occur within tokens.
 
-The lexical analyzer translates input strings to token lists by repeatedly
-taking the maximal prefix of the input string that forms a valid token. A
-maximal prefix that is both a delimiter and a name is treated as a delimiter.
-Spaces, tabs and newlines are separators; they never occur within tokens.
+Delimiters need not be separated by white space.  For example, if {\tt -}
+is a delimiter but {\tt --} is not, then the string {\tt --} is treated as
+two consecutive occurrences of the token~{\tt -}.  In contrast, \ML\ 
+treats {\tt --} as a single symbolic name.  The consequence of Isabelle's
+more liberal scheme is that the same string may be parsed in different ways
+after extending the syntax: after adding {\tt --} as a delimiter, the input
+{\tt --} is treated as a single token.
 
-Note that delimiters need not necessarily be surrounded by white space to be
-recognized as separate. For example, if {\tt -} is a delimiter but {\tt --}
-is not, then the string {\tt --} is treated as two consecutive occurrences of
-{\tt -}. This is in contrast to \ML\ which always treats {\tt --} as a single
-symbolic name. The consequence of Isabelle's more liberal scheme is that the
-same string may be parsed in different ways after extending the syntax: after
-adding {\tt --} as a delimiter, the input {\tt --} is treated as a single
-token.
+Name tokens are terminal symbols, strictly speaking, but we can generally
+regard them as nonterminals.  This is because a name token carries with it
+useful information, the name.  Delimiters, on the other hand, are nothing
+but than syntactic sugar.
 
 
-\subsection{Inspecting syntax *}
-
-You may get the \ML\ representation of the syntax of any Isabelle theory by
-applying \index{*syn_of}
-\begin{ttbox}
-  syn_of: theory -> Syntax.syntax
-\end{ttbox}
-\ttindex{Syntax.syntax} is an abstract type. Values of this type can be
-displayed by the following functions: \index{*Syntax.print_syntax}
-\index{*Syntax.print_gram} \index{*Syntax.print_trans}
+\subsection{*Inspecting the syntax}
 \begin{ttbox}
-  Syntax.print_syntax: Syntax.syntax -> unit
-  Syntax.print_gram: Syntax.syntax -> unit
-  Syntax.print_trans: Syntax.syntax -> unit
+syn_of              : theory -> Syntax.syntax
+Syntax.print_syntax : Syntax.syntax -> unit
+Syntax.print_gram   : Syntax.syntax -> unit
+Syntax.print_trans  : Syntax.syntax -> unit
 \end{ttbox}
-{\tt Syntax.print_syntax} shows virtually all information contained in a
-syntax. Its output is divided into labeled sections. The syntax proper is
-represented by {\tt lexicon}, {\tt roots} and {\tt prods}. The rest refers to
-the manifold facilities to apply syntactic translations (macro expansion
-etc.).
+The abstract type \ttindex{Syntax.syntax} allows manipulation of syntaxes
+in \ML.  You can display values of this type by calling the following
+functions:
+\begin{description}
+\item[\ttindexbold{syn_of} {\it thy}] returns the syntax of the Isabelle
+  theory~{\it thy} as an \ML\ value.
+
+\item[\ttindexbold{Syntax.print_syntax} {\it syn}] shows virtually all
+  information contained in the syntax {\it syn}.  The displayed output can
+  be large.  The following two functions are more selective.
 
-To cope with the verbosity of {\tt Syntax.print_syntax}, there are
-\ttindex{Syntax.print_gram} and \ttindex{Syntax.print_trans} to print the
-syntax proper and the translation related information only.
+\item[\ttindexbold{Syntax.print_gram} {\it syn}] shows the grammar part
+  of~{\it syn}, namely the lexicon, roots and productions.
 
-Let's have a closer look at part of Pure's syntax:
+\item[\ttindexbold{Syntax.print_trans} {\it syn}] shows the translation
+  part of~{\it syn}, namely the constants, parse/print macros and
+  parse/print translations.
+\end{description}
+
+Let us demonstrate these functions by inspecting Pure's syntax.  Even that
+is too verbose to display in full.
 \begin{ttbox}
 Syntax.print_syntax (syn_of Pure.thy);
-{\out lexicon: "!!" "%" "(" ")" "," "." "::" ";" "==" "==>" \dots}
+{\out lexicon: "!!" "\%" "(" ")" "," "." "::" ";" "==" "==>" \dots}
 {\out roots: logic type fun prop}
 {\out prods:}
-{\out   type = tfree  (1000)}
+{\out   type = tid  (1000)}
 {\out   type = tvar  (1000)}
 {\out   type = id  (1000)}
-{\out   type = tfree "::" sort[0]  => "_ofsort" (1000)}
+{\out   type = tid "::" sort[0]  => "_ofsort" (1000)}
 {\out   type = tvar "::" sort[0]  => "_ofsort" (1000)}
 {\out   \vdots}
+\ttbreak
 {\out consts: "_K" "_appl" "_aprop" "_args" "_asms" "_bigimpl" \dots}
 {\out parse_ast_translation: "_appl" "_bigimpl" "_bracket"}
 {\out   "_idtyp" "_lambda" "_tapp" "_tappl"}
@@ -278,416 +291,200 @@
 {\out print_ast_translation: "==>" "_abs" "_idts" "fun"}
 \end{ttbox}
 
+As you can see, the output is divided into labeled sections.  The grammar
+is represented by {\tt lexicon}, {\tt roots} and {\tt prods}.  The rest
+refers to syntactic translations and macro expansion.  Here is an
+explanation of the various sections.
 \begin{description}
-  \item[\ttindex{lexicon}] The set of delimiters used for lexical analysis.
+  \item[\ttindex{lexicon}] lists the delimiters used for lexical
+    analysis.\index{delimiters} 
 
-  \item[\ttindex{roots}]
-    The legal syntactic categories to start parsing with. You name the
-    desired root directly as a string when calling lower level functions or
-    specifying macros. Higher level functions usually expect a type and
-    derive the actual root as follows:\index{root_of_type@$root_of_type$}
-    \begin{itemize}
-      \item $root_of_type(\tau@1 \To \tau@2) = \mtt{fun}$.
-
-      \item $root_of_type(\tau@1 \mathrel{ty} \tau@2) = ty$.
-
-      \item $root_of_type((\tau@1, \dots, \tau@n)ty) = ty$.
-
-      \item $root_of_type(\alpha) = \mtt{logic}$.
-    \end{itemize}
-    Thereby $\tau@1, \dots, \tau@n$ are types, $ty$ an infix or ordinary type
-    constructor and $\alpha$ a type variable or unknown. Note that only the
-    outermost type constructor is taken into account.
+  \item[\ttindex{roots}] lists the grammar's nonterminal symbols.  You must
+    name the desired root when calling lower level functions or specifying
+    macros.  Higher level functions usually expect a type and derive the
+    actual root as described in~\S\ref{sec:grammar}.
 
-  \item[\ttindex{prods}]
-    The list of productions describing the precedence grammar. Nonterminals
-    $A@n$ are rendered in {\sc ascii} as {\tt $A$[$n$]}, delimiters are
-    quoted. Some productions have strings attached after an {\tt =>}. These
-    strings later become the heads of parse trees, but they also play a vital
-    role when terms are printed (see \S\ref{sec:asts}).
+  \item[\ttindex{prods}] lists the productions of the priority grammar.
+    The nonterminal $A^{(n)}$ is rendered in {\sc ascii} as {\tt $A$[$n$]}.
+    Each delimiter is quoted.  Some productions are shown with {\tt =>} and
+    an attached string.  These strings later become the heads of parse
+    trees; they also play a vital role when terms are printed (see
+    \S\ref{sec:asts}).
 
-    Productions which do not have string attached and thus do not create a
-    new parse tree node are called {\bf copy productions}\indexbold{copy
-    production}. They must have exactly one
-    argument\index{argument!production} (i.e.\ nonterminal or name token)
-    on the right-hand side. The parse tree generated when parsing that
-    argument is simply passed up as the result of parsing the whole copy
-    production.
+    Productions with no strings attached are called {\bf copy
+      productions}\indexbold{productions!copy}.  Their right-hand side must
+    have exactly one nonterminal symbol (or name token).  The parser does
+    not create a new parse tree node for copy productions, but simply
+    returns the parse tree of the right-hand symbol.
 
-    A special kind of copy production is one where the argument is a
-    nonterminal and no additional syntactic sugar (delimiters) exists. It is
-    called a \bfindex{chain production}. Chain productions should be seen as
-    an abbreviation mechanism: conceptually, they are removed from the
-    grammar by adding appropriate new rules. Precedence information attached
-    to chain productions is ignored, only the dummy value $-1$ is displayed.
+    If the right-hand side consists of a single nonterminal with no
+    delimiters, then the copy production is called a {\bf chain
+      production}\indexbold{productions!chain}.  Chain productions should
+    be seen as abbreviations: conceptually, they are removed from the
+    grammar by adding new productions.  Priority information
+    attached to chain productions is ignored, only the dummy value $-1$ is
+    displayed.
 
   \item[\ttindex{consts}, \ttindex{parse_rules}, \ttindex{print_rules}]
-    This is macro related information (see \S\ref{sec:macros}).
-
-  \item[\tt *_translation]
-    \index{*parse_ast_translation} \index{*parse_translation}
-    \index{*print_translation} \index{*print_ast_translation}
-    The sets of constants that invoke translation functions. These are more
-    arcane matters (see \S\ref{sec:asts} and \S\ref{sec:tr_funs}).
-\end{description}
-
-You may inspect the syntax of any theory using the above calling
-sequence. Beware that, as more and more material accumulates, the output
-becomes longer and longer.
-% When extending syntaxes, new {\tt roots}, {\tt prods}, {\tt parse_rules}
-% and {\tt print_rules} are appended to the end. The other lists are
-% displayed sorted.
-
-
-\section{Abstract syntax trees} \label{sec:asts}
-
-Figure~\ref{fig:parse_print} shows a simplified model of the parsing and
-printing process.
-
-\begin{figure}[htb]
-\begin{center}
-\begin{tabular}{cl}
-string          & \\
-$\downarrow$    & parser \\
-parse tree      & \\
-$\downarrow$    & \rmindex{parse ast translation} \\
-ast             & \\
-$\downarrow$    & ast rewriting (macros) \\
-ast             & \\
-$\downarrow$    & \rmindex{parse translation}, type-inference \\
---- well-typed term --- & \\
-$\downarrow$    & \rmindex{print translation} \\
-ast             & \\
-$\downarrow$    & ast rewriting (macros) \\
-ast             & \\
-$\downarrow$    & \rmindex{print ast translation}, printer \\
-string          &
-\end{tabular}
-\end{center}
-\caption{Parsing and Printing}
-\label{fig:parse_print}
-\end{figure}
-
-The parser takes an input string (more precisely the token list produced by
-the lexer) and produces a \rmin«ôx{parse tree}, which is directly derived
-from the productions involved. By applying some internal transformations the
-parse tree becomes an \bfindex{abstract syntax tree} (\bfindex{ast}). Macro
-expansion, further translations and finally type inference yields a
-well-typed term\index{term!well-typed}.
-
-The printing process is the reverse, except for some subtleties to be
-discussed later.
-
-Asts are an intermediate form between the very raw parse trees and the typed
-$\lambda$-terms. An ast is either an atom (constant or variable) or a list of
-{\em at least two\/} subasts. Internally, they have type
-\ttindex{Syntax.ast}: \index{*Constant} \index{*Variable} \index{*Appl}
-\begin{ttbox}
-datatype ast = Constant of string
-             | Variable of string
-             | Appl of ast list
-\end{ttbox}
-
-We write constant atoms as quoted strings, variable atoms as non-quoted
-strings and applications as list of subasts separated by space and enclosed
-in parentheses. For example:
-\begin{ttbox}
-  Appl [Constant "_constrain",
-    Appl [Constant "_abs", Variable "x", Variable "t"],
-    Appl [Constant "fun", Variable "'a", Variable "'b"]]
-\end{ttbox}
-is written as {\tt ("_constrain" ("_abs" x t) ("fun" 'a 'b))}.
-Note that {\tt ()} and {\tt (f)} are both illegal.
-
-The resemblance of Lisp's S-expressions is intentional, but notice the two
-kinds of atomic symbols: $\Constant x$ and $\Variable x$. This distinction
-has some more obscure reasons and you can ignore it about half of the time.
-You should not take the names ``{\tt Constant}'' and ``{\tt Variable}'' too
-literally. In the later translation to terms, $\Variable x$ may become a
-constant, free or bound variable, even a type constructor or class name; the
-actual outcome depends on the context.
-
-Similarly, you can think of ${\tt (} f~x@1~\ldots~x@n{\tt )}$ as some sort of
-application of $f$ to the arguments $x@1, \ldots, x@n$. But the actual kind
-of application (say a type constructor $f$ applied to types $x@1, \ldots,
-x@n$) is determined later by context, too.
-
-Forms like {\tt (("_abs" x $t$) $u$)} are perfectly legal, but asts are not
-higher-order: the {\tt "_abs"} does not yet bind the {\tt x} in any way,
-though later at the term level, {\tt ("_abs" x $t$)} will become an {\tt Abs}
-node and occurrences of {\tt x} in $t$ will be replaced by {\tt Bound}s. Even
-if non-constant heads of applications may seem unusual, asts should be
-regarded as first-order. Purists may think of ${\tt (} f~x@1~\ldots~x@n{\tt
-)}$ as a first-order application of some invisible $(n+1)$-ary constant.
-
-
-\subsection{Parse trees to asts}
-
-Asts are generated from parse trees by applying some translation functions,
-which are internally called {\bf parse ast translations}\indexbold{parse ast
-translation}.
-
-We can think of the raw output of the parser as trees built up by nesting the
-right-hand sides of those productions that were used to derive a word that
-matches the input token list. Then parse trees are simply lists of tokens and
-sub parse trees, the latter replacing the nonterminals of the productions.
-Note that we refer here to the actual productions in their internal form as
-displayed by {\tt Syntax.print_syntax}.
-
-Ignoring parse ast translations, the mapping
-$ast_of_pt$\index{ast_of_pt@$ast_of_pt$} from parse trees to asts is derived
-from the productions involved as follows:
-\begin{itemize}
-  \item Name tokens: $ast_of_pt(t) = \Variable s$, where $t$ is an $id$,
-    $var$, $tfree$ or $tvar$ token, and $s$ its associated string.
-
-  \item Copy productions: $ast_of_pt(\ldots P \ldots) = ast_of_pt(P)$.
-
-  \item $0$-ary productions: $ast_of_pt(\ldots \mtt{=>} c) = \Constant c$.
+    relate to macros (see \S\ref{sec:macros}).
 
-  \item $n$-ary productions: $ast_of_pt(\ldots P@1 \ldots P@n \ldots \mtt{=>}
-    c) = \Appl{\Constant c,$ $ast_of_pt(P@1),$ $\ldots,$ $ast_of_pt(P@n)}$,
-    where $n \ge 1$.
-\end{itemize}
-where $P, P@1, \ldots, P@n$ denote parse trees or name tokens and ``\dots''
-zero or more delimiters. Delimiters are stripped and do not appear in asts.
-The following table presents some simple examples:
-\begin{center}
-{\tt\begin{tabular}{ll}
-\rm input string    & \rm ast \\\hline
-"f"                 & f \\
-"'a"                & 'a \\
-"t == u"            & ("==" t u) \\
-"f(x)"              & ("_appl" f x) \\
-"f(x, y)"           & ("_appl" f ("_args" x y)) \\
-"f(x, y, z)"        & ("_appl" f ("_args" x ("_args" y z))) \\
-"\%x y.\ t"         & ("_lambda" ("_idts" x y) t) \\
-\end{tabular}}  
-\end{center}
-Some of these examples illustrate why further translations are desirable in
-order to provide some nice standard form of asts before macro expansion takes
-place. Hence the Pure syntax provides predefined parse ast
-translations\index{parse ast translation!of Pure} for ordinary applications,
-type applications, nested abstractions, meta implications and function types.
-Their net effect on some representative input strings is shown in
-Figure~\ref{fig:parse_ast_tr}.
-
-\begin{figure}[htb]
-\begin{center}
-{\tt\begin{tabular}{ll}
-\rm string                  & \rm ast \\\hline
-"f(x, y, z)"                & (f x y z) \\
-"'a ty"                     & (ty 'a) \\
-"('a, 'b) ty"               & (ty 'a 'b) \\
-"\%x y z.\ t"               & ("_abs" x ("_abs" y ("_abs" z t))) \\
-"\%x ::\ 'a.\ t"            & ("_abs" ("_constrain" x 'a) t) \\
-"[| P; Q; R |] => S"        & ("==>" P ("==>" Q ("==>" R S))) \\
-"['a, 'b, 'c] => 'd"        & ("fun" 'a ("fun" 'b ("fun" 'c 'd)))
-\end{tabular}}
-\end{center}
-\caption{Built-in Parse Ast Translations}
-\label{fig:parse_ast_tr}
-\end{figure}
-
-This translation process is guided by names of constant heads of asts. The
-list of constants invoking parse ast translations is shown in the output of
-{\tt Syntax.print_syntax} under {\tt parse_ast_translation}.
-
-
-\subsection{Asts to terms *}
-
-After the ast has been normalized by the macro expander (see
-\S\ref{sec:macros}), it is transformed into a term with yet another set of
-translation functions interspersed: {\bf parse translations}\indexbold{parse
-translation}. The result is a non-typed term\index{term!non-typed} which may
-contain type constraints, that is 2-place applications with head {\tt
-"_constrain"}. The second argument of a constraint is a type encoded as term.
-Real types will be introduced later during type inference, which is not
-discussed here.
-
-If we ignore the built-in parse translations of Pure first, then the mapping
-$term_of_ast$\index{term_of_ast@$term_of_ast$} from asts to (non-typed) terms
-is defined by:
-\begin{itemize}
-  \item $term_of_ast(\Constant x) = \ttfct{Const} (x, \mtt{dummyT})$.
-
-  \item $term_of_ast(\Variable \mtt{"?}xi\mtt") = \ttfct{Var} ((x, i),
-    \mtt{dummyT})$, where $x$ is the base name and $i$ the index extracted
-    from $xi$.
-
-  \item $term_of_ast(\Variable x) = \ttfct{Free} (x, \mtt{dummyT})$.
+  \item[\ttindex{parse_ast_translation}, \ttindex{print_ast_translation}]
+    list sets of constants that invoke translation functions for abstract
+    syntax trees.  Section \S\ref{sec:asts} below discusses this obscure
+    matter. 
 
-  \item $term_of_ast(\Appl{f, x@1, \ldots, x@n}) = term_of_ast(f) ~{\tt\$}~
-    term_of_ast(x@1)$ {\tt\$} \dots\ {\tt\$} $term_of_ast(x@n)$.
-\end{itemize}
-Note that {\tt Const}, {\tt Var}, {\tt Free} belong to the datatype {\tt
-term} and \ttindex{dummyT} is bound to some dummy {\tt typ}, which is ignored
-during type-inference.
-
-So far the outcome is still a first-order term. {\tt Abs}s and {\tt Bound}s
-are introduced by parse translations associated with {\tt "_abs"} and {\tt
-"!!"} (and any other user defined binder).
-
-
-\subsection{Printing of terms *}
-
-When terms are prepared for printing, they are first transformed into asts
-via $ast_of_term$\index{ast_of_term@$ast_of_term$} (ignoring {\bf print
-translations}\indexbold{print translation}):
-\begin{itemize}
-  \item $ast_of_term(\ttfct{Const} (x, \tau)) = \Constant x$.
-
-  \item $ast_of_term(\ttfct{Free} (x, \tau)) = constrain (\Variable x,
-    \tau)$.
-
-  \item $ast_of_term(\ttfct{Var} ((x, i), \tau)) = constrain (\Variable
-    \mtt{"?}xi\mtt", \tau)$, where $\mtt?xi$ is the string representation of
-    the {\tt indexname} $(x, i)$.
-
-  \item $ast_of_term(\ttfct{Abs} (x, \tau, t)) = \ttfct{Appl}
-    \mathopen{\mtt[} \Constant \mtt{"_abs"}, constrain(\Variable x', \tau),$
-    $ast_of_term(t') \mathclose{\mtt]}$, where $x'$ is a version of $x$
-    renamed away from all names occurring in $t$, and $t'$ the body $t$ with
-    all {\tt Bound}s referring to this {\tt Abs} replaced by $\ttfct{Free}
-    (x', \mtt{dummyT})$.
-
-  \item $ast_of_term(\ttfct{Bound} i) = \Variable \mtt{"B.}i\mtt"$. Note that
-    the occurrence of loose bound variables is abnormal and should never
-    happen when printing well-typed terms.
-
-  \item $ast_of_term(f \ttrel{\$} x@1 \ttrel{\$} \ldots \ttrel{\$} x@n) =
-    \ttfct{Appl} \mathopen{\mtt[} ast_of_term(f), ast_of_term(x@1), \ldots,$
-    $ast_of_term(x@n) \mathclose{\mtt]}$, where $f$ is not an application.
-
-  \item $constrain(x, \tau) = x$, if $\tau = \mtt{dummyT}$ \index{*dummyT} or
-    \ttindex{show_types} not set to {\tt true}.
-
-  \item $constrain(x, \tau) = \Appl{\Constant \mtt{"_constrain"}, x, ty}$,
-    where $ty$ is the ast encoding of $\tau$. That is: type constructors as
-    {\tt Constant}s, type variables as {\tt Variable}s and type applications
-    as {\tt Appl}s with the head type constructor as first element.
-    Additionally, if \ttindex{show_sorts} is set to {\tt true}, some type
-    variables are decorated with an ast encoding of their sort.
-\end{itemize}
-
-\medskip
-After an ast has been normalized wrt.\ the print macros, it is transformed
-into the final output string. The built-in {\bf print ast
-translations}\indexbold{print ast translation} are essentially the reverse
-ones of the parse ast translations of Figure~\ref{fig:parse_ast_tr}.
-
-For the actual printing process, the names attached to grammar productions of
-the form $\ldots A@{p@1}^1 \ldots A@{p@n}^n \ldots \mtt{=>} c$ play a vital
-role. Whenever an ast with constant head $c$, i.e.\ $\mtt"c\mtt"$ or
-$(\mtt"c\mtt"~ x@1 \ldots x@n)$, is encountered it is printed according to
-the production for $c$. This means that first the arguments $x@1$ \dots $x@n$
-are printed, then put in parentheses if necessary for reasons of precedence,
-and finally joined to a single string, separated by the syntactic sugar of
-the production (denoted by ``\dots'' above).
-
-If an application $(\mtt"c\mtt"~ x@1 \ldots x@m)$ has more arguments than the
-corresponding production, it is first split into $((\mtt"c\mtt"~ x@1 \ldots
-x@n) ~ x@{n+1} \ldots x@m)$. Applications with too few arguments or with
-non-constant head or without a corresponding production are printed as
-$f(x@1, \ldots, x@l)$ or $(\alpha@1, \ldots, \alpha@l) ty$. A single
-$\Variable x$ is simply printed as $x$.
-
-Note that the system does {\em not\/} insert blanks automatically. They
-should be part of the mixfix declaration the production has been derived
-from, if they are required to separate tokens. Mixfix declarations may also
-contain pretty printing annotations.
-
+  \item[\ttindex{parse_translation}, \ttindex{print_translation}] list sets
+    of constants that invoke translation functions for terms (see
+    \S\ref{sec:tr_funs}).
+\end{description}
+\index{syntax!Pure|)}
 
 
 \section{Mixfix declarations} \label{sec:mixfix}
+\index{mixfix declaration|(} 
 
-When defining theories, the user usually declares new constants as names
-associated with a type followed by an optional \bfindex{mixfix annotation}.
-If none of the constants are introduced with mixfix annotations, there is no
-concrete syntax to speak of: terms can only be abstractions or applications
-of the form $f(t@1, \dots, t@n)$. Since this notation quickly becomes
-unreadable, Isabelle supports syntax definitions in the form of unrestricted
-context-free \index{context-free grammar} \index{precedence grammar}
-precedence grammars using mixfix annotations.
+When defining a theory, you declare new constants by giving their names,
+their type, and an optional {\bf mixfix annotation}.  Mixfix annotations
+allow you to extend Isabelle's basic $\lambda$-calculus syntax with
+readable notation.  They can express any context-free priority grammar.
+Isabelle syntax definitions are inspired by \OBJ~\cite{OBJ}; they are more
+general than the priority declarations of \ML\ and Prolog.  
+
+A mixfix annotation defines a production of the priority grammar.  It
+describes the concrete syntax, the translation to abstract syntax, and the
+pretty printing.  Special case annotations provide a simple means of
+specifying infix operators, binders and so forth.
 
-Mixfix annotations describe the {\em concrete\/} syntax, a standard
-translation into the abstract syntax and a pretty printing scheme, all in
-one. Isabelle syntax definitions are inspired by \OBJ's~\cite{OBJ} {\em
-mixfix\/} syntax. Each mixfix annotation defines a precedence grammar
-production and optionally associates a constant with it.
-
-There is a general form of mixfix annotation and some shortcuts for common
-cases like infix operators.
+\subsection{Grammar productions}\label{sec:grammar}
+Let us examine the treatment of the production
+\[ A^{(p)}= w@0\, A@1^{(p@1)}\, w@1\, A@2^{(p@2)}\, \ldots\,  
+                  A@n^{(p@n)}\, w@n. \]
+Here $A@i^{(p@i)}$ is a nonterminal with priority~$p@i$ for $i=1$,
+\ldots,~$n$, while $w@0$, \ldots,~$w@n$ are strings of terminals.
+In the corresponding mixfix annotation, the priorities are given separately
+as $[p@1,\ldots,p@n]$ and~$p$.  The nonterminal symbols are identified with
+types~$\tau$, $\tau@1$, \ldots,~$\tau@n$ respectively, and the production's
+effect on nonterminals is expressed as the function type
+\[ [\tau@1, \ldots, \tau@n]\To \tau. \]
+Finally, the template
+\[ w@0  \;_\; w@1 \;_\; \ldots \;_\; w@n \]
+describes the strings of terminals.
 
-The general \bfindex{mixfix declaration} as it may occur within the {\tt
-consts} section\index{consts section@{\tt consts} section} of a {\tt .thy}
-file, specifies a constant declaration and a grammar production at the same
-time. It has the form {\tt $c$ ::\ "$\tau$" ("$sy$" $ps$ $p$)} and is
-interpreted as follows:
-\begin{itemize}
-  \item {\tt $c$ ::\ "$\tau$"} is the actual constant declaration without any
-    syntactic significance.
+A simple type is typically declared for each nonterminal symbol.  In
+first-order logic, type~$i$ stands for terms and~$o$ for formulae.  Only
+the outermost type constructor is taken into account.  For example, any
+type of the form $\sigma list$ stands for a list;  productions may refer
+to the symbol {\tt list} and will apply lists of any type.
+
+The symbol associated with a type is called its {\bf root} since it may
+serve as the root of a parse tree.  Precisely, the root of $(\tau@1, \dots,
+\tau@n)ty$ is $ty$, where $\tau@1$, \ldots, $\tau@n$ are types and $ty$ is
+a type constructor.  Type infixes are a special case of this; in
+particular, the root of $\tau@1 \To \tau@2$ is {\tt fun}.  Finally, the
+root of a type variable is {\tt logic}; general productions might
+refer to this nonterminal.
 
-  \item $sy$ is the right-hand side of the production, specified as a
-    symbolic string. In general, $sy$ is of the form $\alpha@0 \_ \alpha@1
-    \dots \alpha@{n-1} \_ \alpha@n$, where each occurrence of \ttindex{_}
-    denotes an argument\index{argument!mixfix} position and the strings
-    $\alpha@i$ do not contain (non-escaped) {\tt _}. The $\alpha@i$ may
-    consist of delimiters\index{delimiter}, spaces\index{space (pretty
-      printing)} or \rmindex{pretty printing} annotations (see below).
+Identifying nonterminals with types allows a constant's type to specify
+syntax as well.  We can declare the function~$f$ to have type $[\tau@1,
+\ldots, \tau@n]\To \tau$ and, through a mixfix annotation, specify the
+layout of the function's $n$ arguments.  The constant's name, in this
+case~$f$, will also serve as the label in the abstract syntax tree.  There
+are two exceptions to this treatment of constants:
+\begin{enumerate}
+  \item A production need not map directly to a logical function.  In this
+    case, you must declare a constant whose purpose is purely syntactic.
+    By convention such constants begin with the symbol~{\tt\at}, 
+    ensuring that they can never be written in formulae.
+
+  \item A copy production has no associated constant.
+\end{enumerate}
+There is something artificial about this representation of productions,
+but it is convenient, particularly for simple theory extensions.
 
-  \item $\tau$ specifies the syntactic categories of the arguments on the
-    left-hand and of the right-hand side. Arguments may be nonterminals or
-    name tokens. If $sy$ is of the form above, $\tau$ must be a nested
-    function type with at least $n$ argument positions, say $\tau = [\tau@1,
-    \dots, \tau@n] \To \tau'$. The syntactic category of argument $i$ is
-    derived from type $\tau@i$ (see $root_of_type$ in
-    \S\ref{sec:basic_syntax}). The result, i.e.\ the left-hand side of the
-    production, is derived from type $\tau'$. Note that the $\tau@i$ and
-    $\tau'$ may be function types.
+\subsection{The general mixfix form}
+Here is a detailed account of the general \bfindex{mixfix declaration} as
+it may occur within the {\tt consts} section of a {\tt .thy} file.
+\begin{center}
+  {\tt "$c$" ::\ "$\sigma$" ("$template$" $ps$ $p$)}
+\end{center}
+This constant declaration and mixfix annotation is interpreted as follows:
+\begin{itemize}
+\item The string {\tt "$c$"} is the name of the constant associated with
+  the production.  If $c$ is empty (given as~{\tt ""}) then this is a copy
+  production.\index{productions!copy} Otherwise, parsing an instance of the
+  phrase $template$ generates the \AST{} {\tt ("$c$" $a@1$ $\ldots$
+    $a@n$)}, where $a@i$ is the \AST{} generated by parsing the $i$-th
+  argument.
+
+  \item The constant $c$, if non-empty, is declared to have type $\sigma$.
 
-  \item $c$ is the name of the constant associated with the production. If
-    $c$ is the empty string {\tt ""} then this is a \rmindex{copy
-    production}. Otherwise, parsing an instance of the phrase $sy$ generates
-    the ast {\tt ("$c$" $a@1$ $\ldots$ $a@n$)}, where $a@i$ is the ast
-    generated by parsing the $i$-th argument.
+  \item The string $template$ specifies the right-hand side of
+    the production.  It has the form
+    \[ w@0 \;_\; w@1 \;_\; \ldots \;_\; w@n, \] 
+    where each occurrence of \ttindex{_} denotes an
+    argument\index{argument!mixfix} position and the~$w@i$ do not
+    contain~{\tt _}.  (If you want a literal~{\tt _} in the concrete
+    syntax, you must escape it as described below.)  The $w@i$ may
+    consist of \rmindex{delimiters}, spaces or \rmindex{pretty
+      printing} annotations (see below).
 
-  \item $ps$ is an optional list of at most $n$ integers, say {\tt [$p@1$,
-    $\ldots$, $p@m$]}, where $p@i$ is the minimal \rmindex{precedence}
-    required of any phrase that may appear as the $i$-th argument. Missing
-    precedences default to $0$.
+  \item The type $\sigma$ specifies the production's nonterminal symbols (or name
+    tokens).  If $template$ is of the form above then $\sigma$ must be a
+    function type with at least~$n$ argument positions, say $\sigma =
+    [\tau@1, \dots, \tau@n] \To \tau$.  Nonterminal symbols are derived
+    from the type $\tau@1$, \ldots,~$\tau@n$, $\tau$ as described above.
+    Any of these may be function types; the corresponding root is then {\tt
+      fun}. 
 
-  \item $p$ is the \rmindex{precedence} the of this production.
+  \item The optional list~$ps$ may contain at most $n$ integers, say {\tt
+      [$p@1$, $\ldots$, $p@m$]}, where $p@i$ is the minimal
+    priority\indexbold{priorities} required of any phrase that may appear
+    as the $i$-th argument.  Missing priorities default to~$0$.
+
+  \item The integer $p$ is the priority of this production.  If omitted, it
+    defaults to the maximal priority.
+
+    Priorities, or precedences, range between $0$ and
+    $max_pri$\indexbold{max_pri@$max_pri$} (= 1000).
 \end{itemize}
 
-Precedences\index{precedence!range of} may range between $0$ and
-$max_pri$\indexbold{max_pri@$max_pri$} (= 1000). If you want to ignore them,
-the safest way to do so is to use the declaration {\tt $c$ ::\ "$\tau$"
-("$sy$")}. The resulting production puts no precedence constraints on any of
-its arguments and has maximal precedence itself.
+The declaration {\tt $c$ ::\ "$\sigma$" ("$template$")} specifies no
+priorities.  The resulting production puts no priority constraints on any
+of its arguments and has maximal priority itself.  Omitting priorities in
+this manner will introduce syntactic ambiguities unless the production's
+right-hand side is fully bracketed, as in \verb|"if _ then _ else _ fi"|.
 
-\begin{example}
-The following theory specification contains a {\tt consts} section that
-encodes the precedence grammar of Example~\ref{ex:precedence} as mixfix
-declarations:
+\begin{warn}
+  Theories must sometimes declare types for purely syntactic purposes.  One
+  example is {\tt type}, the built-in type of types.  This is a `type of
+  all types' in the syntactic sense only.  Do not declare such types under
+  {\tt arities} as belonging to class $logic$, for that would allow their
+  use in arbitrary Isabelle expressions~(\S\ref{logical-types}).
+\end{warn}
+
+\subsection{Example: arithmetic expressions}
+This theory specification contains a {\tt consts} section with mixfix
+declarations encoding the priority grammar from
+\S\ref{sec:priority_grammars}:
 \begin{ttbox}
 EXP = Pure +
 types
-  exp 0
+  exp
 arities
   exp :: logic
 consts
-  "0" :: "exp"                ("0" 9)
-  "+" :: "[exp, exp] => exp"  ("_ + _" [0, 1] 0)
-  "*" :: "[exp, exp] => exp"  ("_ * _" [3, 2] 2)
-  "-" :: "exp => exp"         ("- _" [3] 3)
+  "0" :: "exp"                ("0"      9)
+  "+" :: "[exp, exp] => exp"  ("_ + _"  [0, 1] 0)
+  "*" :: "[exp, exp] => exp"  ("_ * _"  [3, 2] 2)
+  "-" :: "exp => exp"         ("- _"    [3] 3)
 end
 \end{ttbox}
 Note that the {\tt arities} declaration causes {\tt exp} to be added to the
-syntax' roots. If you put the above text into a file {\tt exp.thy} and load
+syntax' roots.  If you put the text above into a file {\tt exp.thy} and load
 it via {\tt use_thy "EXP"}, you can run some tests:
 \begin{ttbox}
 val read_exp = Syntax.test_read (syn_of EXP.thy) "exp";
+{\out val it = fn : string -> unit}
 read_exp "0 * 0 * 0 * 0 + 0 + 0 + 0";
 {\out tokens: "0" "*" "0" "*" "0" "*" "0" "+" "0" "+" "0" "+" "0"}
 {\out raw: ("+" ("+" ("+" ("*" "0" ("*" "0" ("*" "0" "0"))) "0") "0") "0")}
@@ -698,711 +495,149 @@
 {\out \vdots}
 \end{ttbox}
 The output of \ttindex{Syntax.test_read} includes the token list ({\tt
-tokens}) and the raw ast directly derived from the parse tree, ignoring parse
-ast translations. The rest is tracing information provided by the macro
-expander (see \S\ref{sec:macros}).
+  tokens}) and the raw \AST{} directly derived from the parse tree,
+ignoring parse \AST{} translations.  The rest is tracing information
+provided by the macro expander (see \S\ref{sec:macros}).
 
-Executing {\tt Syntax.print_gram (syn_of EXP.thy)} reveals the actual grammar
-productions derived from the above mixfix declarations (lots of additional
-information deleted):
+Executing {\tt Syntax.print_gram} reveals the productions derived
+from our mixfix declarations (lots of additional information deleted):
 \begin{ttbox}
-exp = "0"  => "0" (9)
-exp = exp[0] "+" exp[1]  => "+" (0)
-exp = exp[3] "*" exp[2]  => "*" (2)
-exp = "-" exp[3]  => "-" (3)
+Syntax.print_gram (syn_of EXP.thy);
+{\out exp = "0"  => "0" (9)}
+{\out exp = exp[0] "+" exp[1]  => "+" (0)}
+{\out exp = exp[3] "*" exp[2]  => "*" (2)}
+{\out exp = "-" exp[3]  => "-" (3)}
 \end{ttbox}
-\end{example}
 
-Let us now have a closer look at the structure of the string $sy$ appearing
-in mixfix annotations. This string specifies a list of parsing and printing
-directives, namely delimiters\index{delimiter},
-arguments\index{argument!mixfix}, spaces\index{space (pretty printing)},
-blocks of indentation\index{block (pretty printing)} and optional or forced
-line breaks\index{break (pretty printing)}. These are encoded via the
+
+\subsection{The mixfix template}
+Let us take a closer look at the string $template$ appearing in mixfix
+annotations.  This string specifies a list of parsing and printing
+directives: delimiters\index{delimiter}, arguments\index{argument!mixfix},
+spaces, blocks of indentation and line breaks.  These are encoded via the
 following character sequences:
 
+\index{pretty printing|(}
 \begin{description}
-  \item[~\ttindex_~] An argument\index{argument!mixfix} position.
+  \item[~\ttindex_~] An argument\index{argument!mixfix} position, which
+    stands for a nonterminal symbol or name token.
 
-  \item[~$d$~] A \rmindex{delimiter}, i.e.\ a non-empty sequence of
-    non-special or escaped characters. Escaping a character\index{escape
-      character} means preceding it with a {\tt '} (quote). Thus you have to
-    write {\tt ''} if you really want a single quote. Delimiters may never
-    contain white space, though.
+  \item[~$d$~] A \rmindex{delimiter}, namely a non-empty sequence of
+    non-special or escaped characters.  Escaping a character\index{escape
+      character} means preceding it with a {\tt '} (single quote).  Thus
+    you have to write {\tt ''} if you really want a single quote.  You must
+    also escape {\tt _}, {\tt (}, {\tt )} and {\tt /}.  Delimiters may
+    never contain white space, though.
 
-  \item[~$s$~] A non-empty sequence of spaces\index{space (pretty printing)}
-    for printing.
+  \item[~$s$~] A non-empty sequence of spaces for printing.  This
+    and the following specifications do not affect parsing at all.
 
-  \item[~{\ttindex($n$}~] Open a block\index{block (pretty printing)}. $n$ is
-    an optional sequence of digits that specifies the amount of indentation
-    to be added when a line break occurs within the block. If {\tt(} is not
-    followed by a digit, the indentation defaults to $0$.
+  \item[~{\ttindex($n$}~] Open a pretty printing block.  The optional
+    number $n$ specifies how much indentation to add when a line break
+    occurs within the block.  If {\tt(} is not followed by digits, the
+    indentation defaults to~$0$.
 
-  \item[~\ttindex)~] Close a block.
-
-  \item[~\ttindex{//}~] Force a line break\index{break (pretty printing)}.
+  \item[~\ttindex)~] Close a pretty printing block.
 
-  \item[~\ttindex/$s$~] Allow a line break\index{break (pretty printing)}.
-    Spaces $s$ right after {\tt /} are only printed if the break is not
-    taken.
-\end{description}
+  \item[~\ttindex{//}~] Force a line break.
 
-In terms of parsing, arguments are nonterminals or name tokens and
-delimiters are delimiters. The other directives have only significance for
-printing. The \rmindex{pretty printing} mechanisms of Isabelle is essentially
-the one described in \cite{paulson91}.
+  \item[~\ttindex/$s$~] Allow a line break.  Here $s$ stands for the string
+    of spaces (zero or more) right after the {\tt /} character.  These
+    spaces are printed if the break is not taken.
+\end{description}
+Isabelle's pretty printer resembles the one described in
+Paulson~\cite{paulson91}.  \index{pretty printing|)}
 
 
 \subsection{Infixes}
-
-Infix\index{infix} operators associating to the left or right can be declared
-conveniently using \ttindex{infixl} or \ttindex{infixr}.
-
-Roughly speaking, the form {\tt $c$ ::\ "$\tau$" (infixl $p$)} abbreviates:
+\indexbold{infix operators}
+Infix operators associating to the left or right can be declared
+using {\tt infixl} or {\tt infixr}.
+Roughly speaking, the form {\tt $c$ ::\ "$\sigma$" (infixl $p$)}
+abbreviates the declarations
 \begin{ttbox}
-"op \(c\)" ::\ "\(\tau\)"   ("op \(c\)")
-"op \(c\)" ::\ "\(\tau\)"   ("(_ \(c\)/ _)" [\(p\), \(p + 1\)] \(p\))
+"op \(c\)" :: "\(\sigma\)"   ("op \(c\)")
+"op \(c\)" :: "\(\sigma\)"   ("(_ \(c\)/ _)" [\(p\), \(p+1\)] \(p\))
 \end{ttbox}
-and {\tt $c$ ::\ "$\tau$" (infixr $p$)} abbreviates:
+and {\tt $c$ ::\ "$\sigma$" (infixr $p$)} abbreviates the declarations
 \begin{ttbox}
-"op \(c\)" ::\ "\(\tau\)"   ("op \(c\)")
-"op \(c\)" ::\ "\(\tau\)"   ("(_ \(c\)/ _)" [\(p + 1\), \(p\)] \(p\))
+"op \(c\)" :: "\(\sigma\)"   ("op \(c\)")
+"op \(c\)" :: "\(\sigma\)"   ("(_ \(c\)/ _)" [\(p+1\), \(p\)] \(p\))
 \end{ttbox}
-
+The infix operator is declared as a constant with the prefix {\tt op}.
 Thus, prefixing infixes with \ttindex{op} makes them behave like ordinary
-function symbols. Special characters occurring in $c$ have to be escaped as
-in delimiters. Also note that the expanded forms above would be actually
-illegal at the user level because of duplicate declarations of constants.
+function symbols, as in \ML.  Special characters occurring in~$c$ must be
+escaped, as in delimiters, using a single quote.
+
+The expanded forms above would be actually illegal in a {\tt .thy} file
+because they declare the constant \hbox{\tt"op \(c\)"} twice.
 
 
 \subsection{Binders}
-
-A \bfindex{binder} is a variable-binding construct, such as a
-\rmindex{quantifier}. The constant declaration \indexbold{*binder}
+\indexbold{binders}
+\begingroup
+\def\Q{{\cal Q}}
+A {\bf binder} is a variable-binding construct such as a quantifier.  The
+binder declaration \indexbold{*binder}
 \begin{ttbox}
-\(c\) ::\ "\(\tau\)"   (binder "\(Q\)" \(p\))
+\(c\) :: "\(\sigma\)"   (binder "\(\Q\)" \(p\))
 \end{ttbox}
-introduces a binder $c$ of type $\tau$, which must have the form $(\tau@1 \To
-\tau@2) \To \tau@3$. Its concrete syntax is $Q~x.P$. A binder is like a
-generalized quantifier where $\tau@1$ is the type of the bound variable $x$,
-$\tau@2$ the type of the body $P$, and $\tau@3$ the type of the whole term.
-For example $\forall$ can be declared like this:
+introduces a constant~$c$ of type~$\sigma$, which must have the form
+$(\tau@1 \To \tau@2) \To \tau@3$.  Its concrete syntax is $\Q~x.P$, where
+$x$ is a bound variable of type~$\tau@1$, the body~$P$ has type $\tau@2$
+and the whole term has type~$\tau@3$.  Special characters in $\Q$ must be
+escaped using a single quote.
+
+Let us declare the quantifier~$\forall$:
 \begin{ttbox}
 All :: "('a => o) => o"   (binder "ALL " 10)
 \end{ttbox}
-This allows us to write $\forall x.P$ either as {\tt All(\%$x$.$P$)} or {\tt
-ALL $x$.$P$}. When printing terms, Isabelle usually uses the latter form, but
-has to fall back on $\mtt{All}(P)$, if $P$ is not an abstraction.
+This let us write $\forall x.P$ as either {\tt All(\%$x$.$P$)} or {\tt ALL
+  $x$.$P$}.  When printing, Isabelle prefers the latter form, but must fall
+back on $\mtt{All}(P)$ if $P$ is not an abstraction.  Both $P$ and {\tt ALL
+  $x$.$P$} have type~$o$, the type of formulae, while the bound variable
+can be polymorphic.
 
-Binders $c$ of type $(\sigma \To \tau) \To \tau$ can be nested; then the
-internal form $c(\lambda x@1. c(\lambda x@2. \ldots c(\lambda x@n. P)
-\ldots))$ corresponds to external $Q~x@1~x@2 \ldots x@n. P$.
+The binder~$c$ of type $(\sigma \To \tau) \To \tau$ can be nested.  The
+external form $\Q~x@1~x@2 \ldots x@n. P$ corresponds to the internal form
+\[ c(\lambda x@1. c(\lambda x@2. \ldots c(\lambda x@n. P) \ldots)) \]
 
 \medskip
 The general binder declaration
 \begin{ttbox}
-\(c\) ::\ "(\(\tau@1\) => \(\tau@2\)) => \(\tau@3\)"   (binder "\(Q\)" \(p\))
+\(c\)    :: "(\(\tau@1\) => \(\tau@2\)) => \(\tau@3\)"   (binder "\(\Q\)" \(p\))
 \end{ttbox}
 is internally expanded to
 \begin{ttbox}
-\(c\)   ::\ "(\(\tau@1\) => \(\tau@2\)) => \(\tau@3\)"
-"\(Q\)" ::\ "[idts, \(\tau@2\)] => \(\tau@3\)"   ("(3\(Q\)_./ _)" \(p\))
-\end{ttbox}
-with $idts$ being the syntactic category for a list of $id$s optionally
-constrained (see Figure~\ref{fig:pure_gram}). Note that special characters in
-$Q$ have to be escaped as in delimiters.
-
-Additionally, a parse translation\index{parse translation!for binder} for $Q$
-and a print translation\index{print translation!for binder} for $c$ is
-installed. These perform behind the scenes the translation between the
-internal and external forms.
-
-
-
-\section{Syntactic translations (macros)} \label{sec:macros}
-
-So far we have pretended that there is a close enough relationship between
-concrete and abstract syntax to allow an automatic translation from one to
-the other using the constant name supplied with each non-copy production. In
-many cases this scheme is not powerful enough. Some typical examples involve
-variable binding constructs (e.g.\ {\tt ALL x:A.P} vs.\ {\tt Ball(A, \%x.P)}
-or convenient notations for enumerations like finite sets, lists etc.\ (e.g.\
-{\tt [x, y, z]} vs.\ {\tt Cons(x, Cons(y, Cons(z, Nil)))}).
-
-Isabelle offers such translation facilities at two different levels, namely
-{\bf macros}\indexbold{macro} and {\bf translation functions}.
-
-Macros are specified by first-order rewriting systems that operate on asts.
-They are usually easy to read and in most cases not very difficult to write.
-Unfortunately, some more obscure translations cannot be expressed as macros
-and you have to fall back on the more powerful mechanism of translation
-functions written in \ML. These are quite unreadable and hard to write (see
-\S\ref{sec:tr_funs}).
-
-\medskip
-Let us now get started with the macro system by a simple example:
-
-\begin{example}~ \label{ex:set_trans}
-
-\begin{ttbox}
-SET = Pure +
-types
-  i, o 0
-arities
-  i, o :: logic
-consts
-  Trueprop      :: "o => prop"              ("_" 5)
-  Collect       :: "[i, i => o] => i"
-  "{\at}Collect"    :: "[idt, i, o] => i"       ("(1{\ttlbrace}_:_./ _{\ttrbrace})")
-  Replace       :: "[i, [i, i] => o] => i"
-  "{\at}Replace"    :: "[idt, idt, i, o] => i"  ("(1{\ttlbrace}_./ _:_, _{\ttrbrace})")
-  Ball          :: "[i, i => o] => o"
-  "{\at}Ball"       :: "[idt, i, o] => o"       ("(3ALL _:_./ _)" 10)
-translations
-  "{\ttlbrace}x:A. P{\ttrbrace}"    == "Collect(A, %x. P)"
-  "{\ttlbrace}y. x:A, Q{\ttrbrace}" == "Replace(A, %x y. Q)"
-  "ALL x:A. P"  == "Ball(A, %x. P)"
-end
-\end{ttbox}
-
-This and the following theories are complete working examples, though they
-are fragmentary as they contain merely syntax. The full theory definition can
-be found in {\tt ZF/zf.thy}.
-
-{\tt SET} defines constants for set comprehension ({\tt Collect}),
-replacement ({\tt Replace}) and bounded universal quantification ({\tt
-Ball}). Without additional syntax you would have to express $\forall x \in A.
-P(x)$ as {\tt Ball(A, P)}. Since this is quite awkward, we define additional
-constants with appropriate concrete syntax. These constants are decorated
-with {\tt\at} to stress their pure syntactic purpose; they should never occur
-within the final well-typed terms. Another consequence is that the user
-cannot refer to such names directly, since they are not legal identifiers.
-
-The translations cause the replacement of external forms by internal forms
-after parsing, and vice versa before printing of terms.
-\end{example}
-
-This is only a very simple but common instance of a more powerful mechanism.
-As a specification of what is to be translated, it should be comprehensible
-without further explanations. But there are also some snags and other
-peculiarities that are typical for macro systems in general. The purpose of
-this section is to explain how Isabelle's macro system really works.
-
-
-\subsection{Specifying macros}
-
-Basically macros are rewrite rules on asts. But unlike other macro systems of
-various programming languages, Isabelle's macros work in both directions.
-Therefore a syntax contains two lists of rules: one for parsing and one for
-printing.
-
-The {\tt translations} section\index{translations section@{\tt translations}
-section} consists of a list of rule specifications of the form:
-
-\begin{center}
-{\tt $[$ ($root$) $]$ $string$ $[$ => $|$ <= $|$ == $]$ $[$ ($root$) $]$
-$string$}.
-\end{center}
-
-This specifies a \rmindex{parse rule} ({\tt =>}) a \rmindex{print rule} ({\tt
-  <=}) or both ({\tt ==}). The two $string$s preceded by optional
-parenthesized $root$s are the left-hand and right-hand side of the rule in
-user-defined syntax.
-
-Rules are internalized wrt.\ an intermediate signature that is obtained from
-the parent theories' ones by adding all material of all sections preceding
-{\tt translations} in the {\tt .thy} file. Especially, new syntax defined in
-{\tt consts} is already effective.
-
-Then part of the process that transforms input strings into terms is applied:
-lexing, parsing and parse ast translations (see \S\ref{sec:asts}). Macros
-specified in the parents are {\em not\/} expanded. Also note that the lexer
-runs in a different mode that additionally accepts identifiers of the form
-$\_~letter~quasiletter^*$ (like {\tt _idt}, {\tt _K}). The syntactic category
-to parse is specified by $root$, which defaults to {\tt logic}.
-
-Finally, Isabelle tries to guess which atoms of the resulting ast of the rule
-should be treated as constants during matching (see below). These names are
-extracted from all class, type and constant declarations made so far.
-
-\medskip
-The result are two lists of translation rules in internal form, that is pairs
-of asts. They can be viewed using {\tt Syntax.print_syntax} (sections
-\ttindex{parse_rules} and \ttindex{print_rules}). For {\tt SET} of
-Example~\ref{ex:set_trans} these are:
-\begin{ttbox}
-parse_rules:
-  ("{\at}Collect" x A P)  ->  ("Collect" A ("_abs" x P))
-  ("{\at}Replace" y x A Q)  ->  ("Replace" A ("_abs" x ("_abs" y Q)))
-  ("{\at}Ball" x A P)  ->  ("Ball" A ("_abs" x P))
-print_rules:
-  ("Collect" A ("_abs" x P))  ->  ("{\at}Collect" x A P)
-  ("Replace" A ("_abs" x ("_abs" y Q)))  ->  ("{\at}Replace" y x A Q)
-  ("Ball" A ("_abs" x P))  ->  ("{\at}Ball" x A P)
+\(c\)    :: "(\(\tau@1\) => \(\tau@2\)) => \(\tau@3\)"
+"\(\Q\)"\hskip-3pt  :: "[idts, \(\tau@2\)] => \(\tau@3\)"   ("(3\(\Q\)_./ _)" \(p\))
 \end{ttbox}
-
-Note that in this notation all rules are oriented left to right. In the {\tt
-translations} section, which has been split into two parts, print rules
-appeared right to left.
-
-\begin{warn}
-Be careful not to choose names for variables in rules that are actually
-treated as constant. If in doubt, check the rules in their internal form or
-the section labeled {\tt consts} in the output of {\tt Syntax.print_syntax}.
-\end{warn}
-
-
-\subsection{Applying rules}
-
-In the course of parsing and printing terms, asts are generated as an
-intermediate form as pictured in Figure~\ref{fig:parse_print}. These asts are
-normalized wrt.\ the given lists of translation rules in a uniform manner. As
-stated earlier, asts are supposed to be first-order `terms'. The rewriting
-systems derived from {\tt translations} sections essentially resemble
-traditional first-order term rewriting systems. We first examine how a single
-rule is applied.
-
-Let $t$ be the ast to be normalized and $(l, r)$ some translation rule. A
-subast $u$ of $t$ is called {\bf redex}\indexbold{redex (ast)} (reducible
-expression), if it is an instance of $l$. In this case $l$ is said to {\bf
-match}\indexbold{match (ast)} $u$. A redex matched by $l$ may be replaced by
-the corresponding instance of $r$, thus {\bf rewriting}\index{rewrite (ast)}
-the ast $t$.
-
-Matching requires some notion of {\bf place-holders}\indexbold{place-holder
-(ast)} that may occur in rule patterns but not in ordinary asts, which are
-considered ground. Here we simply use {\tt Variable}s for this purpose.
-
-More formally, the matching of $u$ by $l$ is performed as follows (the rule
-pattern is the second argument): \index{match (ast)@$match$ (ast)}
-\begin{itemize}
-  \item $match(\Constant x, \Constant x) = \mbox{OK}$.
-
-  \item $match(\Variable x, \Constant x) = \mbox{OK}$.
-
-  \item $match(u, \Variable x) = \mbox{OK, bind}~x~\mbox{to}~u$.
-
-  \item $match(\Appl{u@1, \ldots, u@n}, \Appl{l@1, \ldots, l@n}) = match(u@1,
-    l@1), \ldots, match(u@n, l@n)$.
-
-  \item $match(u, l) = \mbox{FAIL}$ in any other case.
-\end{itemize}
-
-This means that a {\tt Constant} pattern matches any atomic asts of the same
-name, while a {\tt Variable} matches any ast. If successful, $match$ yields a
-substitution $\sigma$ that is applied to $r$, generating the appropriate
-instance that replaces $u$.
-
-\medskip
-In order to make things simple and fast, ast rewrite rules $(l, r)$ are
-restricted by the following conditions:
-\begin{itemize}
-  \item Rules have to be left linear, i.e.\ $l$ must not contain any {\tt
-    Variable} more than once.
-
-  \item Rules must have constant heads, i.e.\ $l = \mtt"c\mtt"$ or $l =
-    (\mtt"c\mtt" ~ x@1 \ldots x@n)$.
-
-  \item The set of variables contained in $r$ has to be a subset of those of
-    $l$.
-\end{itemize}
-
-\medskip
-Having first-order matching in mind, the second case of $match$ may look a
-bit odd. But this is exactly the place, where {\tt Variable}s of non-rule
-asts behave like {\tt Constant}s. The deeper meaning of this is related with
-asts being very `primitive' in some sense, ignorant of the underlying
-`semantics', not far removed from parse trees. At this level it is not yet
-known, which $id$s will become constants, bounds, frees, types or classes. As
-$ast_of_pt$ (see \S\ref{sec:asts}) shows, former parse tree heads appear in
-asts as {\tt Constant}s, while $id$s, $var$s, $tfree$s and $tvar$s become
-{\tt Variable}s.
-
-This is at variance with asts generated from terms before printing (see
-$ast_of_term$ in \S\ref{sec:asts}), where all constants and type constructors
-become {\tt Constant}s.
-
-\begin{warn}
-This means asts may contain quite a messy mixture of {\tt Variable}s and {\tt
-Constant}s, which is insignificant at macro level because $match$ treats them
-alike.
-\end{warn}
-
-Because of this behaviour, different kinds of atoms with the same name are
-indistinguishable, which may make some rules prone to misbehaviour. Regard
-the following fragmentary example:
-\begin{ttbox}
-types
-  Nil 0
-consts
-  Nil     :: "'a list"
-  "[]"    :: "'a list"    ("[]")
-translations
-  "[]"    == "Nil"
-\end{ttbox}
-Then the term {\tt Nil} will be printed as {\tt []}, just as expected. What
-happens with \verb|%Nil.t| or {\tt x::Nil} is left as an exercise.
-
-
-\subsection{Rewriting strategy}
-
-When normalizing an ast by repeatedly applying translation rules until no
-more rule is applicable, there are in each step two choices: which rule to
-apply next, and which redex to reduce.
-
-We could assume that the user always supplies terminating and confluent
-rewriting systems, but this would often complicate things unnecessarily.
-Therefore, we reveal part of the actual rewriting strategy: The normalizer
-always applies the first matching rule reducing an unspecified redex chosen
-first.
-
-Thereby, `first rule' is roughly speaking meant wrt.\ the appearance of the
-rules in the {\tt translations} sections. But this is more tricky than it
-seems: If a given theory is {\em extended}, new rules are simply appended to
-the end. But if theories are {\em merged}, it is not clear which list of
-rules has priority over the other. In fact the merge order is left
-unspecified. This shouldn't cause any problems in practice, since
-translations of different theories usually do not overlap. {\tt
-Syntax.print_syntax} shows the rules in their internal order.
-
-\medskip
-You can watch the normalization of asts during parsing and printing by
-setting \ttindex{Syntax.trace_norm_ast} to {\tt true}. An alternative is the
-use of \ttindex{Syntax.test_read}, which is always in trace mode. The
-information displayed when tracing\index{tracing (ast)} includes: the ast
-before normalization ({\tt pre}), redexes with results ({\tt rewrote}), the
-normal form finally reached ({\tt post}) and some statistics ({\tt
-normalize}). If tracing is off, \ttindex{Syntax.stat_norm_ast} can be set to
-{\tt true} in order to enable printing of the normal form and statistics
-only.
-
-
-\subsection{More examples}
-
-Let us first reconsider Example~\ref{ex:set_trans}, which is concerned with
-variable binding constructs.
-
-There is a minor disadvantage over an implementation via translation
-functions (as done for binders):
-
-\begin{warn}
-If \ttindex{eta_contract} is set to {\tt true}, terms will be
-$\eta$-contracted {\em before\/} the ast rewriter sees them. Thus some
-abstraction nodes needed for print rules to match may get lost. E.g.\
-\verb|Ball(A, %x. P(x))| is contracted to {\tt Ball(A, P)}, the print rule is
-no longer applicable and the output will be {\tt Ball(A, P)}. Note that
-$\eta$-expansion via macros is {\em not\/} possible.
-\end{warn}
+with $idts$ being the nonterminal symbol for a list of $id$s optionally
+constrained (see Fig.\ts\ref{fig:pure_gram}).  The declaration also
+installs a parse translation\index{translations!parse} for~$\Q$ and a print
+translation\index{translations!print} for~$c$ to translate between the
+internal and external forms.
+\endgroup
 
-\medskip
-Another common trap are meta constraints. If \ttindex{show_types} is set to
-{\tt true}, bound variables will be decorated by their meta types at the
-binding place (but not at occurrences in the body). E.g.\ matching with
-\verb|Collect(A, %x. P)| binds {\tt x} to something like {\tt ("_constrain" y
-"i")} rather than only {\tt y}. Ast rewriting will cause the constraint to
-appear in the external form, say \verb|{y::i:A::i. P::o}|. Therefore your
-syntax should be ready for such constraints to be re-read. This is the case
-in our example, because of the category {\tt idt} of the first argument.
-
-\begin{warn}
-Choosing {\tt id} instead of {\tt idt} is a very common error, especially
-since it appears in former versions of most of Isabelle's object-logics.
-\end{warn}
-
-\begin{example} \label{ex:finset_trans}
-This example demonstrates the use of recursive macros to implement a
-convenient notation for finite sets.
-\begin{ttbox}
-FINSET = SET +
-types
-  is 0
-consts
-  ""            :: "i => is"                ("_")
-  "{\at}Enum"       :: "[i, is] => is"          ("_,/ _")
-  empty         :: "i"                      ("{\ttlbrace}{\ttrbrace}")
-  insert        :: "[i, i] => i"
-  "{\at}Finset"     :: "is => i"                ("{\ttlbrace}(_){\ttrbrace}")
-translations
-  "{\ttlbrace}x, xs{\ttrbrace}"     == "insert(x, {\ttlbrace}xs{\ttrbrace})"
-  "{\ttlbrace}x{\ttrbrace}"         == "insert(x, {\ttlbrace}{\ttrbrace})"
-end
-\end{ttbox}
-
-Finite sets are internally built up by {\tt empty} and {\tt insert}.
-Externally we would like to see \verb|{x, y, z}| rather than {\tt insert(x,
-insert(y, insert(z, empty)))}.
-
-First we define the generic syntactic category {\tt is} for one or more
-objects of type {\tt i} separated by commas (including breaks for pretty
-printing). The category has to be declared as a 0-place type constructor, but
-without {\tt arities} declaration. Hence {\tt is} is not a logical type, no
-default productions will be added, and we can cook our own syntax for {\tt
-is} (first two lines of {\tt consts} section). If we had needed generic
-enumerations of type $\alpha$ (i.e.\ {\tt logic}), we could have used the
-predefined category \ttindex{args} and skipped this part altogether.
-
-Next follows {\tt empty}, which is already equipped with its syntax
-\verb|{}|, and {\tt insert} without concrete syntax. The syntactic constant
-{\tt\at Finset} provides concrete syntax for enumerations of {\tt i} enclosed
-in curly braces. Remember that a pair of parentheses specifies a block of
-indentation for pretty printing. The category {\tt is} can later be reused
-for other enumerations like lists or tuples.
-
-The translations may look a bit odd at first sight, but rules can only be
-fully understood in their internal forms, which are:
-\begin{ttbox}
-parse_rules:
-  ("{\at}Finset" ("{\at}Enum" x xs))  ->  ("insert" x ("{\at}Finset" xs))
-  ("{\at}Finset" x)  ->  ("insert" x "empty")
-print_rules:
-  ("insert" x ("{\at}Finset" xs))  ->  ("{\at}Finset" ("{\at}Enum" x xs))
-  ("insert" x "empty")  ->  ("{\at}Finset" x)
-\end{ttbox}
-This shows that \verb|{x, xs}| indeed matches any set enumeration of at least
-two elements, binding the first to {\tt x} and the rest to {\tt xs}.
-Likewise, \verb|{xs}| and \verb|{x}| represent any set enumeration. Note that
-the parse rules only work in this order.
-
-\medskip
-Some rules are prone to misbehaviour, as
-\verb|%empty insert. insert(x, empty)| shows, which is printed as
-\verb|%empty insert. {x}|. This problem arises, because the ast rewriter
-cannot discern constants, frees, bounds etc.\ and looks only for names of
-atoms.
-
-Thus the names of {\tt Constant}s occurring in the (internal) left-hand side
-of translation rules should be regarded as `reserved keywords'. It is good
-practice to choose non-identifiers here like {\tt\at Finset} or sufficiently
-long and strange names.
-\end{example}
-
-\begin{example} \label{ex:prod_trans}
-One of the well-formedness conditions for ast rewrite rules stated earlier
-implies that you can never introduce new {\tt Variable}s on the right-hand
-side. Something like \verb|"K(B)" => "%x. B"| is illegal and could cause
-variable capturing, if it were allowed. In such cases you usually have to
-fall back on translation functions. But there is a trick that makes things
-quite readable in some cases: {\em calling parse translations by parse
-rules}. This is demonstrated here.
-\begin{ttbox}
-PROD = FINSET +
-consts
-  Pi            :: "[i, i => i] => i"
-  "{\at}PROD"       :: "[idt, i, i] => i"     ("(3PROD _:_./ _)" 10)
-  "{\at}->"         :: "[i, i] => i"          ("(_ ->/ _)" [51, 50] 50)
-translations
-  "PROD x:A. B" => "Pi(A, %x. B)"
-  "A -> B"      => "Pi(A, _K(B))"
-end
-ML
-  val print_translation = [("Pi", dependent_tr' ("{\at}PROD", "{\at}->"))];
-\end{ttbox}
-
-{\tt Pi} is an internal constant for constructing dependent products. Two
-external forms exist: {\tt PROD x:A.B}, the general case, and {\tt A -> B},
-an abbreviation for \verb|Pi(A, %x.B)| with {\tt B} not actually depending on
-{\tt x}.
-
-Now the second parse rule is where the trick comes in: {\tt _K(B)} is
-introduced during ast rewriting, which later becomes \verb|%x.B| due to a
-parse translation associated with \ttindex{_K}. Note that a leading {\tt _}
-in $id$s is allowed in translation rules, but not in ordinary terms. This
-special behaviour of the lexer is very useful for `forging' asts containing
-names that are not directly accessible normally.
-
-Unfortunately, there is no such trick for printing, so we have to add a {\tt
-ML} section for the print translation \ttindex{dependent_tr'}.
-
-The parse translation for {\tt _K} is already installed in Pure, and {\tt
-dependent_tr'} is exported by the syntax module for public use. See
-\S\ref{sec:tr_funs} for more of the arcane lore of translation functions.
-\end{example}
-
-
-
-\section{Translation functions *} \label{sec:tr_funs}
-
-This section is about the remaining translation mechanism which enables the
-designer of theories to do almost everything with terms or asts during the
-parsing or printing process, by writing \ML-functions. The logic \LK\ is a
-good example of a quite sophisticated use of this to transform between
-internal and external representations of associative sequences. The high
-level macro system described in \S\ref{sec:macros} fails here completely.
-
-\begin{warn}
-A full understanding of the matters presented here requires some familiarity
-with Isabelle's internals, especially the datatypes {\tt term}, {\tt typ},
-{\tt Syntax.ast} and the encodings of types and terms as such at the various
-stages of the parsing or printing process. You probably do not really want to
-use translation functions at all!
-\end{warn}
-
-As already mentioned in \S\ref{sec:asts}, there are four kinds of translation
-functions. All such functions are associated with a name which specifies an
-ast's or term's head invoking that function. Such names can be (logical or
-syntactic) constants or type constructors.
-
-{\tt Syntax.print_syntax} displays the sets of names associated with the
-translation functions of a {\tt Syntax.syntax} under
-\ttindex{parse_ast_translation}, \ttindex{parse_translation},
-\ttindex{print_translation} and \ttindex{print_ast_translation}. The user can
-add new ones via the {\tt ML} section\index{ML section@{\tt ML} section} of a
-{\tt .thy} file. But there may never be more than one function of the same
-kind per name.
-
-\begin{warn}
-Conceptually, the {\tt ML} section should appear between {\tt consts} and
-{\tt translations}, i.e.\ newly installed translation functions are already
-effective when macros and logical rules are parsed. {\tt ML} has to be the
-last section because the {\tt .thy} file parser is unable to detect the end
-of \ML\ code in another way than by end-of-file.
-\end{warn}
-
-All text of the {\tt ML} section is simply copied verbatim into the \ML\ file
-generated from a {\tt .thy} file. Definitions made here by the user become
-components of a \ML\ structure of the same name as the theory to be created.
-Therefore local things should be declared within {\tt local}. The following
-special \ML\ values, which are all optional, serve as the interface for the
-installation of user defined translation functions.
-
-\begin{ttbox}
-val parse_ast_translation: (string * (ast list -> ast)) list
-val parse_translation: (string * (term list -> term)) list
-val print_translation: (string * (term list -> term)) list
-val print_ast_translation: (string * (ast list -> ast)) list
-\end{ttbox}
-
-The basic idea behind all four kinds of functions is relatively simple (see
-also Figure~\ref{fig:parse_print}): Whenever --- during the transformations
-between parse trees, asts and terms --- a combination of the form
-$(\mtt"c\mtt"~x@1 \ldots x@n)$ is encountered, and a translation function $f$
-of appropriate kind exists for $c$, the result will be $f \mtt[ x@1, \ldots,
-x@n \mtt]$. Thereby, $x@1, \ldots, x@n$ (with $n \ge 0$) are asts for ast
-translations and terms for term translations. A `combination' at ast level is
-of the form $\Constant c$ or $\Appl{\Constant c, x@1, \ldots, x@n}$, and at
-term level $\ttfct{Const} (c, \tau)$ or $\ttfct{Const} (c, \tau) \ttrel{\$}
-x@1 \ttrel{\$} \dots \ttrel{\$} x@n$.
-
-\medskip
-Translation functions at ast level differ from those at term level only in
-the same way, as asts and terms differ. Terms, being more complex and more
-specific, allow more sophisticated transformations (typically involving
-abstractions and bound variables).
-
-On the other hand, {\em parse\/} (ast) translations differ from {\em print\/}
-(ast) translations more fundamentally:
-\begin{description}
-  \item[Parse (ast) translations] are applied bottom-up, i.e.\ the arguments
-    supplied ($x@1, \ldots, x@n$ above) are already in translated form.
-    Additionally, they may not fail, exceptions are re-raised after printing
-    an error message.
-
-  \item[Print (ast) translations] are applied top-down, i.e.\ supplied with
-    arguments that are partly still in internal form. The result is again fed
-    into the translation machinery as a whole. Therefore a print (ast)
-    translation should not introduce as head a constant of the same name that
-    invoked it in the first place. Alternatively, exception \ttindex{Match}
-    may be raised, indicating failure of translation.
-\end{description}
-
-Another difference between the parsing and the printing process is, which
-atoms are {\tt Constant}s or {\tt Const}s, i.e.\ able to invoke translation
-functions.
-
-For parse ast translations only former parse tree heads are {\tt Constant}s
-(see also $ast_of_pt$ in \S\ref{sec:asts}). These and additionally introduced
-{\tt Constant}s (e.g.\ by macros), become {\tt Const}s for parse translations
-(see also $term_of_ast$ in \S\ref{sec:asts}).
-
-The situation is slightly different, when terms are prepared for printing,
-since the role of atoms is known. Initially, all logical constants and type
-constructors may invoke print translations. New constants may be introduced
-by these or by macros, able to invoke parse ast translations.
-
-
-\subsection{A simple example *}
-
-Presenting a simple and useful example of translation functions is not that
-easy, since the macro system is sufficient for most simple applications. By
-convention, translation functions always have names ending with {\tt
-_ast_tr}, {\tt _tr}, {\tt _tr'} or {\tt _ast_tr'}. You may look for such
-names in the sources of Pure Isabelle for more examples.
-
-\begin{example} \label{ex:tr_funs}
-
-We continue Example~\ref{ex:prod_trans} by presenting the \ML\ sources of the
-parse translation for \ttindex{_K} and the print translation
-\ttindex{dependent_tr'}:
-\begin{ttbox}
-(* nondependent abstraction *)
-fun k_tr (*"_K"*) [t] = Abs ("x", dummyT, incr_boundvars 1 t)
-  | k_tr (*"_K"*) ts = raise TERM("k_tr",ts);
-
-(* dependent / nondependent quantifiers *)
-fun dependent_tr' (q, r) (A :: Abs (x, T, B) :: ts) =
-      if 0 mem (loose_bnos B) then
-        let val (x', B') = variant_abs (x, dummyT, B);
-        in list_comb (Const (q, dummyT) $ Free (x', T) $ A $ B', ts)
-        end
-      else list_comb (Const (r, dummyT) $ A $ B, ts)
-  | dependent_tr' _ _ = raise Match;
-\end{ttbox}
-This text is taken from the Pure sources. Ordinary user translations
-would typically appear within the {\tt ML} section of the {\tt .thy} file. To
-link {\tt k_tr} into the parser requires the definition
-\begin{ttbox}
-val parse_translation = [("_K",k_tr)];
-\end{ttbox}
-For {\tt k_tr} this is not necessary, as it is built-in, but user-defined
-translation functions are added in exactly the same way.  \medskip
-
-If {\tt k_tr} is called with exactly one argument $t$, it creates a new {\tt
-Abs} node with a body derived from $t$: loose {\tt Bound}s, i.e.\ those
-referring to outer {\tt Abs}s, are incremented using
-\ttindex{incr_boundvars}. This and many other basic term manipulation
-functions are defined in {\tt Pure/term.ML}, the comments there being in most
-cases the only documentation.
-
-Since terms fed into parse translations are not yet typed, the type of the
-bound variable in the new {\tt Abs} is simply {\tt dummyT}.
-
-\medskip
-The argument $(q, r)$ for {\tt dependent_tr'} is supplied already during the
-installation within an {\tt ML} section. This yields a parse translation that
-transforms something like $c(A, \mtt{Abs}(x, T, B), t@1, \ldots, t@n)$ into
-$q(x', A, B', t@1, \ldots, t@n)$ or $r(A, B, t@1, \ldots, t@n)$. The latter
-form, if $B$ does not actually depend on $x$. This is checked using
-\ttindex{loose_bnos}, yet another function of {\tt Pure/term.ML}. Note that
-$x'$ is a version of $x$ renamed away from all names in $B$, and $B'$ the
-body $B$ with {\tt Bound}s referring to our {\tt Abs} node replaced by
-$\ttfct{Free} (x', \mtt{dummyT})$.
-
-We have to be more careful with types here. While types of {\tt Const}s are
-completely ignored, type constraints may be printed for some {\tt Free}s and
-{\tt Var}s (if \ttindex{show_types} is set to {\tt true}). Variables of type
-\ttindex{dummyT} are never printed with constraint, though. Thus, a
-constraint of $x'$ may only appear at its binding place, since {\tt Free}s of
-$B'$ replacing the appropriate {\tt Bound}s of $B$ via \ttindex{variant_abs}
-have all type {\tt dummyT}. \end{example}
-
+\index{mixfix declaration|)}
 
 
 \section{Example: some minimal logics} \label{sec:min_logics}
+This section presents some examples that have a simple syntax.  They
+demonstrate how to define new object-logics from scratch.
 
-This concluding section presents some examples that are very simple from a
-syntactic point of view. They should rather demonstrate how to define new
-object-logics from scratch. In particular we need to say how an object-logic
-syntax is hooked up to the meta-logic. Since all theorems must conform to the
-syntax for $prop$ (see Figure~\ref{fig:pure_gram}), that syntax has to be
-extended with the object-level syntax. Assume that the syntax of your
-object-logic defines a category $o$ of formulae. These formulae can now
-appear in axioms and theorems wherever $prop$ does if you add the production
+First we must define how an object-logic syntax embedded into the
+meta-logic.  Since all theorems must conform to the syntax for~$prop$ (see
+Fig.\ts\ref{fig:pure_gram}), that syntax has to be extended with the
+object-level syntax.  Assume that the syntax of your object-logic defines a
+nonterminal symbol~$o$ of formulae.  These formulae can now appear in
+axioms and theorems wherever $prop$ does if you add the production
 \[ prop ~=~ o. \]
-More precisely, you need a coercion from formulae to propositions:
+This is not a copy production but a coercion from formulae to propositions:
 \begin{ttbox}
 Base = Pure +
 types
-  o 0
+  o
 arities
   o :: logic
 consts
@@ -1410,12 +645,12 @@
 end
 \end{ttbox}
 The constant {\tt Trueprop} (the name is arbitrary) acts as an invisible
-coercion function. Assuming this definition resides in a file {\tt base.thy},
+coercion function.  Assuming this definition resides in a file {\tt base.thy},
 you have to load it with the command {\tt use_thy "Base"}.
 
-One of the simplest nontrivial logics is {\em minimal logic\/} of
-implication. Its definition in Isabelle needs no advanced features but
-illustrates the overall mechanism quite nicely:
+One of the simplest nontrivial logics is {\bf minimal logic} of
+implication.  Its definition in Isabelle needs no advanced features but
+illustrates the overall mechanism nicely:
 \begin{ttbox}
 Hilbert = Base +
 consts
@@ -1426,40 +661,46 @@
   MP    "[| P --> Q; P |] ==> Q"
 end
 \end{ttbox}
-After loading this definition you can start to prove theorems in this logic:
+After loading this definition from the file {\tt hilbert.thy}, you can
+start to prove theorems in the logic:
 \begin{ttbox}
 goal Hilbert.thy "P --> P";
 {\out Level 0}
 {\out P --> P}
 {\out  1.  P --> P}
+\ttbreak
 by (resolve_tac [Hilbert.MP] 1);
 {\out Level 1}
 {\out P --> P}
 {\out  1.  ?P --> P --> P}
 {\out  2.  ?P}
+\ttbreak
 by (resolve_tac [Hilbert.MP] 1);
 {\out Level 2}
 {\out P --> P}
 {\out  1.  ?P1 --> ?P --> P --> P}
 {\out  2.  ?P1}
 {\out  3.  ?P}
+\ttbreak
 by (resolve_tac [Hilbert.S] 1);
 {\out Level 3}
 {\out P --> P}
 {\out  1.  P --> ?Q2 --> P}
 {\out  2.  P --> ?Q2}
+\ttbreak
 by (resolve_tac [Hilbert.K] 1);
 {\out Level 4}
 {\out P --> P}
 {\out  1.  P --> ?Q2}
+\ttbreak
 by (resolve_tac [Hilbert.K] 1);
 {\out Level 5}
 {\out P --> P}
 {\out No subgoals!}
 \end{ttbox}
-As you can see, this Hilbert-style formulation of minimal logic is easy to
-define but difficult to use. The following natural deduction formulation is
-far preferable:
+As we can see, this Hilbert-style formulation of minimal logic is easy to
+define but difficult to use.  The following natural deduction formulation is
+better:
 \begin{ttbox}
 MinI = Base +
 consts
@@ -1469,14 +710,14 @@
   impE  "[| P --> Q; P |] ==> Q"
 end
 \end{ttbox}
-Note, however, that although the two systems are equivalent, this fact cannot
-be proved within Isabelle: {\tt S} and {\tt K} can be derived in {\tt MinI}
-(exercise!), but {\tt impI} cannot be derived in {\tt Hilbert}. The reason is
-that {\tt impI} is only an {\em admissible\/} rule in {\tt Hilbert},
-something that can only be shown by induction over all possible proofs in
-{\tt Hilbert}.
+Note, however, that although the two systems are equivalent, this fact
+cannot be proved within Isabelle.  Axioms {\tt S} and {\tt K} can be
+derived in {\tt MinI} (exercise!), but {\tt impI} cannot be derived in {\tt
+  Hilbert}.  The reason is that {\tt impI} is only an {\bf admissible} rule
+in {\tt Hilbert}, something that can only be shown by induction over all
+possible proofs in {\tt Hilbert}.
 
-It is a very simple matter to extend minimal logic with falsity:
+We may easily extend minimal logic with falsity:
 \begin{ttbox}
 MinIF = MinI +
 consts
@@ -1490,13 +731,20 @@
 MinC = Base +
 consts
   "&" :: "[o, o] => o"   (infixr 30)
+\ttbreak
 rules
   conjI  "[| P; Q |] ==> P & Q"
   conjE1 "P & Q ==> P"
   conjE2 "P & Q ==> Q"
 end
 \end{ttbox}
-And if we want to have all three connectives together, we define:
+And if we want to have all three connectives together, we create and load a
+theory file consisting of a single line:\footnote{We can combine the
+  theories without creating a theory file using the ML declaration
+\begin{ttbox}
+val MinIFC_thy = merge_theories(MinIF,MinC)
+\end{ttbox}
+\index{*merge_theories|fnote}}
 \begin{ttbox}
 MinIFC = MinIF + MinC
 \end{ttbox}
@@ -1509,3 +757,826 @@
 \end{ttbox}
 Try this as an exercise!
 
+\medskip
+Unless you need to define macros or syntax translation functions, you may
+skip the rest of this chapter.
+
+
+\section{*Abstract syntax trees} \label{sec:asts}
+\index{trees!abstract syntax|(} The parser, given a token list from the
+lexer, applies productions to yield a parse tree\index{trees!parse}.  By
+applying some internal transformations the parse tree becomes an abstract
+syntax tree, or \AST{}.  Macro expansion, further translations and finally
+type inference yields a well-typed term\index{terms!obtained from ASTs}.
+The printing process is the reverse, except for some subtleties to be
+discussed later.
+
+Figure~\ref{fig:parse_print} outlines the parsing and printing process.
+Much of the complexity is due to the macro mechanism.  Using macros, you
+can specify most forms of concrete syntax without writing any \ML{} code.
+
+\begin{figure}
+\begin{center}
+\begin{tabular}{cl}
+string          & \\
+$\downarrow$    & parser \\
+parse tree      & \\
+$\downarrow$    & parse \AST{} translation \\
+\AST{}             & \\
+$\downarrow$    & \AST{} rewriting (macros) \\
+\AST{}             & \\
+$\downarrow$    & parse translation, type inference \\
+--- well-typed term --- & \\
+$\downarrow$    & print translation \\
+\AST{}             & \\
+$\downarrow$    & \AST{} rewriting (macros) \\
+\AST{}             & \\
+$\downarrow$    & print \AST{} translation, printer \\
+string          &
+\end{tabular}
+\index{translations!parse}\index{translations!parse AST}
+\index{translations!print}\index{translations!print AST}
+
+\end{center}
+\caption{Parsing and printing}\label{fig:parse_print}
+\end{figure}
+
+Abstract syntax trees are an intermediate form between the raw parse trees
+and the typed $\lambda$-terms.  An \AST{} is either an atom (constant or
+variable) or a list of {\em at least two\/} subtrees.  Internally, they
+have type \ttindex{Syntax.ast}: \index{*Constant} \index{*Variable}
+\index{*Appl}
+\begin{ttbox}
+datatype ast = Constant of string
+             | Variable of string
+             | Appl of ast list
+\end{ttbox}
+
+Isabelle uses an S-expression syntax for abstract syntax trees.  Constant
+atoms are shown as quoted strings, variable atoms as non-quoted strings and
+applications as a parenthesized list of subtrees.  For example, the \AST
+\begin{ttbox}
+Appl [Constant "_constrain",
+  Appl [Constant "_abs", Variable "x", Variable "t"],
+  Appl [Constant "fun", Variable "'a", Variable "'b"]]
+\end{ttbox}
+is shown as {\tt ("_constrain" ("_abs" x t) ("fun" 'a 'b))}.
+Both {\tt ()} and {\tt (f)} are illegal because they have too few
+subtrees. 
+
+The resemblance of Lisp's S-expressions is intentional, but there are two
+kinds of atomic symbols: $\Constant x$ and $\Variable x$.  Do not take the
+names ``{\tt Constant}'' and ``{\tt Variable}'' too literally; in the later
+translation to terms, $\Variable x$ may become a constant, free or bound
+variable, even a type constructor or class name; the actual outcome depends
+on the context.
+
+Similarly, you can think of ${\tt (} f~x@1~\ldots~x@n{\tt )}$ as the
+application of~$f$ to the arguments $x@1, \ldots, x@n$.  But the kind of
+application is determined later by context; it could be a type constructor
+applied to types.
+
+Forms like {\tt (("_abs" x $t$) $u$)} are legal, but \AST{}s are
+first-order: the {\tt "_abs"} does not bind the {\tt x} in any way.  Later
+at the term level, {\tt ("_abs" x $t$)} will become an {\tt Abs} node and
+occurrences of {\tt x} in $t$ will be replaced by bound variables (the term
+constructor \ttindex{Bound}).
+
+
+\subsection{Transforming parse trees to \AST{}s}
+The parse tree is the raw output of the parser.  Translation functions,
+called {\bf parse AST translations}\indexbold{translations!parse AST},
+transform the parse tree into an abstract syntax tree.
+
+The parse tree is constructed by nesting the right-hand sides of the
+productions used to recognize the input.  Such parse trees are simply lists
+of tokens and constituent parse trees, the latter representing the
+nonterminals of the productions.  Let us refer to the actual productions in
+the form displayed by {\tt Syntax.print_syntax}.
+
+Ignoring parse \AST{} translations, parse trees are transformed to \AST{}s
+by stripping out delimiters and copy productions.  More precisely, the
+mapping $ast_of_pt$\index{ast_of_pt@$ast_of_pt$} is derived from the
+productions as follows:
+\begin{itemize}
+  \item Name tokens: $ast_of_pt(t) = \Variable s$, where $t$ is an $id$,
+    $var$, $tid$ or $tvar$ token, and $s$ its associated string.
+
+  \item Copy productions: $ast_of_pt(\ldots P \ldots) = ast_of_pt(P)$.
+    Here $\ldots$ stands for strings of delimiters, which are
+    discarded.  $P$ stands for the single constituent that is not a
+    delimiter; it is either a nonterminal symbol or a name token.
+
+  \item $0$-ary productions: $ast_of_pt(\ldots \mtt{=>} c) = \Constant c$.
+    Here there are no constituents other than delimiters, which are
+    discarded. 
+
+  \item $n$-ary productions, where $n \ge 1$: delimiters are discarded and
+    the remaining constituents $P@1$, \ldots, $P@n$ are built into an
+    application whose head constant is~$c$:
+    \begin{eqnarray*}
+      \lefteqn{ast_of_pt(\ldots P@1 \ldots P@n \ldots \mtt{=>} c)} \\
+      &&\qquad{}= \Appl{\Constant c, ast_of_pt(P@1), \ldots, ast_of_pt(P@n)}
+    \end{eqnarray*}
+\end{itemize}
+Figure~\ref{fig:parse_ast} presents some simple examples, where {\tt ==},
+{\tt _appl}, {\tt _args}, and so forth name productions of the Pure syntax.
+These examples illustrate the need for further translations to make \AST{}s
+closer to the typed $\lambda$-calculus.  The Pure syntax provides
+predefined parse \AST{} translations\index{translations!parse AST} for
+ordinary applications, type applications, nested abstractions, meta
+implications and function types.  Figure~\ref{fig:parse_ast_tr} shows their
+effect on some representative input strings.
+
+
+\begin{figure}
+\begin{center}
+\tt\begin{tabular}{ll}
+\rm input string    & \rm \AST \\\hline
+"f"                 & f \\
+"'a"                & 'a \\
+"t == u"            & ("==" t u) \\
+"f(x)"              & ("_appl" f x) \\
+"f(x, y)"           & ("_appl" f ("_args" x y)) \\
+"f(x, y, z)"        & ("_appl" f ("_args" x ("_args" y z))) \\
+"\%x y.\ t"         & ("_lambda" ("_idts" x y) t) \\
+\end{tabular}
+\end{center}
+\caption{Parsing examples using the Pure syntax}\label{fig:parse_ast} 
+\end{figure}
+
+\begin{figure}
+\begin{center}
+\tt\begin{tabular}{ll}
+\rm input string            & \rm \AST{} \\\hline
+"f(x, y, z)"                & (f x y z) \\
+"'a ty"                     & (ty 'a) \\
+"('a, 'b) ty"               & (ty 'a 'b) \\
+"\%x y z.\ t"               & ("_abs" x ("_abs" y ("_abs" z t))) \\
+"\%x ::\ 'a.\ t"            & ("_abs" ("_constrain" x 'a) t) \\
+"[| P; Q; R |] => S"        & ("==>" P ("==>" Q ("==>" R S))) \\
+"['a, 'b, 'c] => 'd"        & ("fun" 'a ("fun" 'b ("fun" 'c 'd)))
+\end{tabular}
+\end{center}
+\caption{Built-in parse \AST{} translations}\label{fig:parse_ast_tr}
+\end{figure}
+
+The names of constant heads in the \AST{} control the translation process.
+The list of constants invoking parse \AST{} translations appears in the
+output of {\tt Syntax.print_syntax} under {\tt parse_ast_translation}.
+
+
+\subsection{Transforming \AST{}s to terms}
+The \AST{}, after application of macros (see \S\ref{sec:macros}), is
+transformed into a term.  This term is probably ill-typed since type
+inference has not occurred yet.  The term may contain type constraints
+consisting of applications with head {\tt "_constrain"}; the second
+argument is a type encoded as a term.  Type inference later introduces
+correct types or rejects the input.
+
+Another set of translation functions, namely parse
+translations,\index{translations!parse}, may affect this process.  If we
+ignore parse translations for the time being, then \AST{}s are transformed
+to terms by mapping \AST{} constants to constants, \AST{} variables to
+schematic or free variables and \AST{} applications to applications.
+
+More precisely, the mapping $term_of_ast$\index{term_of_ast@$term_of_ast$}
+is defined by
+\begin{itemize}
+\item Constants: $term_of_ast(\Constant x) = \ttfct{Const} (x,
+  \mtt{dummyT})$.
+
+\item Schematic variables: $term_of_ast(\Variable \mtt{"?}xi\mtt") =
+  \ttfct{Var} ((x, i), \mtt{dummyT})$, where $x$ is the base name and $i$
+  the index extracted from $xi$.
+
+\item Free variables: $term_of_ast(\Variable x) = \ttfct{Free} (x,
+  \mtt{dummyT})$.
+
+\item Function applications with $n$ arguments:
+    \begin{eqnarray*}
+      \lefteqn{term_of_ast(\Appl{f, x@1, \ldots, x@n})} \\
+      &&\qquad{}= term_of_ast(f) \ttapp
+         term_of_ast(x@1) \ttapp \ldots \ttapp term_of_ast(x@n)
+    \end{eqnarray*}
+\end{itemize}
+Here \ttindex{Const}, \ttindex{Var}, \ttindex{Free} and
+\verb|$|\index{$@{\tt\$}} are constructors of the datatype {\tt term},
+while \ttindex{dummyT} stands for some dummy type that is ignored during
+type inference.
+
+So far the outcome is still a first-order term.  Abstractions and bound
+variables (constructors \ttindex{Abs} and \ttindex{Bound}) are introduced
+by parse translations.  Such translations are attached to {\tt "_abs"},
+{\tt "!!"} and user-defined binders.
+
+
+\subsection{Printing of terms}
+The output phase is essentially the inverse of the input phase.  Terms are
+translated via abstract syntax trees into strings.  Finally the strings are
+pretty printed.
+
+Print translations (\S\ref{sec:tr_funs}) may affect the transformation of
+terms into \AST{}s.  Ignoring those, the transformation maps
+term constants, variables and applications to the corresponding constructs
+on \AST{}s.  Abstractions are mapped to applications of the special
+constant {\tt _abs}.
+
+More precisely, the mapping $ast_of_term$\index{ast_of_term@$ast_of_term$}
+is defined as follows:
+\begin{itemize}
+  \item $ast_of_term(\ttfct{Const} (x, \tau)) = \Constant x$.
+
+  \item $ast_of_term(\ttfct{Free} (x, \tau)) = constrain (\Variable x,
+    \tau)$.
+
+  \item $ast_of_term(\ttfct{Var} ((x, i), \tau)) = constrain (\Variable
+    \mtt{"?}xi\mtt", \tau)$, where $\mtt?xi$ is the string representation of
+    the {\tt indexname} $(x, i)$.
+
+  \item For the abstraction $\lambda x::\tau.t$, let $x'$ be a variant
+    of~$x$ renamed to differ from all names occurring in~$t$, and let $t'$
+    be obtained from~$t$ by replacing all bound occurrences of~$x$ by
+    the free variable $x'$.  This replaces corresponding occurrences of the
+    constructor \ttindex{Bound} by the term $\ttfct{Free} (x',
+    \mtt{dummyT})$:
+   \begin{eqnarray*}
+      \lefteqn{ast_of_term(\ttfct{Abs} (x, \tau, t))} \\
+      &&\qquad{}=   \ttfct{Appl}
+                  \mathopen{\mtt[} 
+                  \Constant \mtt{"_abs"}, constrain(\Variable x', \tau), \\
+      &&\qquad\qquad\qquad ast_of_term(t') \mathclose{\mtt]}.
+    \end{eqnarray*}
+
+  \item $ast_of_term(\ttfct{Bound} i) = \Variable \mtt{"B.}i\mtt"$.  
+    The occurrence of constructor \ttindex{Bound} should never happen
+    when printing well-typed terms; it indicates a de Bruijn index with no
+    matching abstraction.
+
+  \item Where $f$ is not an application,
+    \begin{eqnarray*}
+      \lefteqn{ast_of_term(f \ttapp x@1 \ttapp \ldots \ttapp x@n)} \\
+      &&\qquad{}= \ttfct{Appl} 
+                  \mathopen{\mtt[} ast_of_term(f), 
+                  ast_of_term(x@1), \ldots,ast_of_term(x@n) 
+                  \mathclose{\mtt]}
+    \end{eqnarray*}
+\end{itemize}
+
+Type constraints are inserted to allow the printing of types, which is
+governed by the boolean variable \ttindex{show_types}.  Constraints are
+treated as follows:
+\begin{itemize}
+  \item $constrain(x, \tau) = x$, if $\tau = \mtt{dummyT}$ \index{*dummyT} or
+    \ttindex{show_types} not set to {\tt true}.
+
+  \item $constrain(x, \tau) = \Appl{\Constant \mtt{"_constrain"}, x, ty}$,
+    where $ty$ is the \AST{} encoding of $\tau$.  That is, type constructors as
+    {\tt Constant}s, type identifiers as {\tt Variable}s and type applications
+    as {\tt Appl}s with the head type constructor as first element.
+    Additionally, if \ttindex{show_sorts} is set to {\tt true}, some type
+    variables are decorated with an \AST{} encoding of their sort.
+\end{itemize}
+
+The \AST{}, after application of macros (see \S\ref{sec:macros}), is
+transformed into the final output string.  The built-in {\bf print AST
+  translations}\indexbold{translations!print AST} effectively reverse the
+parse \AST{} translations of Fig.\ts\ref{fig:parse_ast_tr}.
+
+For the actual printing process, the names attached to productions
+of the form $\ldots A^{(p@1)}@1 \ldots A^{(p@n)}@n \ldots \mtt{=>} c$ play
+a vital role.  Each \AST{} with constant head $c$, namely $\mtt"c\mtt"$ or
+$(\mtt"c\mtt"~ x@1 \ldots x@n)$, is printed according to the production
+for~$c$.  Each argument~$x@i$ is converted to a string, and put in
+parentheses if its priority~$(p@i)$ requires this.  The resulting strings
+and their syntactic sugar (denoted by ``\dots'' above) are joined to make a
+single string.
+
+If an application $(\mtt"c\mtt"~ x@1 \ldots x@m)$ has more arguments than the
+corresponding production, it is first split into $((\mtt"c\mtt"~ x@1 \ldots
+x@n) ~ x@{n+1} \ldots x@m)$. Applications with too few arguments or with
+non-constant head or without a corresponding production are printed as
+$f(x@1, \ldots, x@l)$ or $(\alpha@1, \ldots, \alpha@l) ty$.  An occurrence of
+$\Variable x$ is simply printed as~$x$.
+
+Blanks are {\em not\/} inserted automatically.  If blanks are required to
+separate tokens, specify them in the mixfix declaration, possibly preceeded
+by a slash~({\tt/}) to allow a line break.
+\index{trees!abstract syntax|)}
+
+
+
+\section{*Macros: Syntactic rewriting} \label{sec:macros}
+\index{macros|(}\index{rewriting!syntactic|(} 
+
+Mixfix declarations alone can handle situations where there is a direct
+connection between the concrete syntax and the underlying term.  Sometimes
+we require a more elaborate concrete syntax, such as quantifiers and list
+notation.  Isabelle's {\bf macros} and {\bf translation functions} can
+perform translations such as
+\begin{center}\tt
+  \begin{tabular}{r@{$\quad\protect\rightleftharpoons\quad$}l}
+    ALL x:A.P   & Ball(A, \%x.P)        \\ \relax
+    [x, y, z]   & Cons(x, Cons(y, Cons(z, Nil)))
+  \end{tabular}
+\end{center}
+Translation functions (see \S\ref{sec:tr_funs}) must be coded in ML; they
+are the most powerful translation mechanism but are difficult to read or
+write.  Macros are specified by first-order rewriting systems that operate
+on abstract syntax trees.  They are usually easy to read and write, and can
+express all but the most obscure translations.
+
+Figure~\ref{fig:set_trans} defines a fragment of first-order logic and set
+theory.\footnote{This and the following theories are complete working
+  examples, though they specify only syntax, no axioms.  The file {\tt
+    ZF/zf.thy} presents the full set theory definition, including many
+  macro rules.}  Theory {\tt SET} defines constants for set comprehension
+({\tt Collect}), replacement ({\tt Replace}) and bounded universal
+quantification ({\tt Ball}).  Each of these binds some variables.  Without
+additional syntax we should have to express $\forall x \in A.  P$ as {\tt
+  Ball(A,\%x.P)}, and similarly for the others.
+
+\begin{figure}
+\begin{ttbox}
+SET = Pure +
+types
+  i, o
+arities
+  i, o :: logic
+consts
+  Trueprop      :: "o => prop"              ("_" 5)
+  Collect       :: "[i, i => o] => i"
+  "{\at}Collect"    :: "[idt, i, o] => i"       ("(1{\ttlbrace}_:_./ _{\ttrbrace})")
+  Replace       :: "[i, [i, i] => o] => i"
+  "{\at}Replace"    :: "[idt, idt, i, o] => i"  ("(1{\ttlbrace}_./ _:_, _{\ttrbrace})")
+  Ball          :: "[i, i => o] => o"
+  "{\at}Ball"       :: "[idt, i, o] => o"       ("(3ALL _:_./ _)" 10)
+translations
+  "{\ttlbrace}x:A. P{\ttrbrace}"    == "Collect(A, \%x. P)"
+  "{\ttlbrace}y. x:A, Q{\ttrbrace}" == "Replace(A, \%x y. Q)"
+  "ALL x:A. P"  == "Ball(A, \%x. P)"
+end
+\end{ttbox}
+\caption{Macro example: set theory}\label{fig:set_trans}
+\end{figure}
+
+The theory specifies a variable-binding syntax through additional
+productions that have mixfix declarations.  Each non-copy production must
+specify some constant, which is used for building \AST{}s.  The additional
+constants are decorated with {\tt\at} to stress their purely syntactic
+purpose; they should never occur within the final well-typed terms.
+Furthermore, they cannot be written in formulae because they are not legal
+identifiers.
+
+The translations cause the replacement of external forms by internal forms
+after parsing, and vice versa before printing of terms.  As a specification
+of the set theory notation, they should be largely self-explanatory.  The
+syntactic constants, {\tt\at Collect}, {\tt\at Replace} and {\tt\at Ball},
+appear implicitly in the macro rules via their mixfix forms.
+
+Macros can define variable-binding syntax because they operate on \AST{}s,
+which have no inbuilt notion of bound variable.  The macro variables {\tt
+  x} and~{\tt y} have type~{\tt idt} and therefore range over identifiers,
+in this case bound variables.  The macro variables {\tt P} and~{\tt Q}
+range over formulae containing bound variable occurrences.
+
+Other applications of the macro system can be less straightforward, and
+there are peculiarities.  The rest of this section will describe in detail
+how Isabelle macros are preprocessed and applied.
+
+
+\subsection{Specifying macros}
+Macros are basically rewrite rules on \AST{}s.  But unlike other macro
+systems found in programming languages, Isabelle's macros work in both
+directions.  Therefore a syntax contains two lists of rewrites: one for
+parsing and one for printing.
+
+The {\tt translations} section\index{translations section@{\tt translations}
+section} specifies macros.  The syntax for a macro is
+\[ (root)\; string \quad
+   \left\{\begin{array}[c]{c} \mtt{=>} \\ \mtt{<=} \\ \mtt{==} \end{array}
+   \right\} \quad
+   (root)\; string 
+\]
+%
+This specifies a parse rule ({\tt =>}), a print rule ({\tt <=}), or both
+({\tt ==}).  The two strings specify the left and right-hand sides of the
+macro rule.  The $(root)$ specification is optional; it specifies the
+nonterminal for parsing the $string$ and if omitted defaults to {\tt
+  logic}.  \AST{} rewrite rules $(l, r)$ must obey certain conditions:
+\begin{itemize}
+\item Rules must be left linear: $l$ must not contain repeated variables.
+
+\item Rules must have constant heads, namely $l = \mtt"c\mtt"$ or $l =
+  (\mtt"c\mtt" ~ x@1 \ldots x@n)$.
+
+\item Every variable in~$r$ must also occur in~$l$.
+\end{itemize}
+
+Macro rules may refer to any syntax from the parent theories.  They may
+also refer to anything defined before the the {\tt .thy} file's {\tt
+  translations} section --- including any mixfix declarations.
+
+Upon declaration, both sides of the macro rule undergo parsing and parse
+\AST{} translations (see \S\ref{sec:asts}), but do not themselves undergo
+macro expansion.  The lexer runs in a different mode that additionally
+accepts identifiers of the form $\_~letter~quasiletter^*$ (like {\tt _idt},
+{\tt _K}).  Thus, a constant whose name starts with an underscore can
+appear in macro rules but not in ordinary terms.
+
+Some atoms of the macro rule's \AST{} are designated as constants for
+matching.  These are all names that have been declared as classes, types or
+constants.
+
+The result of this preprocessing is two lists of macro rules, each stored
+as a pair of \AST{}s.  They can be viewed using {\tt Syntax.print_syntax}
+(sections \ttindex{parse_rules} and \ttindex{print_rules}).  For
+theory~{\tt SET} of Fig.~\ref{fig:set_trans} these are
+\begin{ttbox}
+parse_rules:
+  ("{\at}Collect" x A P)  ->  ("Collect" A ("_abs" x P))
+  ("{\at}Replace" y x A Q)  ->  ("Replace" A ("_abs" x ("_abs" y Q)))
+  ("{\at}Ball" x A P)  ->  ("Ball" A ("_abs" x P))
+print_rules:
+  ("Collect" A ("_abs" x P))  ->  ("{\at}Collect" x A P)
+  ("Replace" A ("_abs" x ("_abs" y Q)))  ->  ("{\at}Replace" y x A Q)
+  ("Ball" A ("_abs" x P))  ->  ("{\at}Ball" x A P)
+\end{ttbox}
+
+\begin{warn}
+  Avoid choosing variable names that have previously been used as
+  constants, types or type classes; the {\tt consts} section in the output
+  of {\tt Syntax.print_syntax} lists all such names.  If a macro rule works
+  incorrectly, inspect its internal form as shown above, recalling that
+  constants appear as quoted strings and variables without quotes.
+\end{warn}
+
+\begin{warn}
+If \ttindex{eta_contract} is set to {\tt true}, terms will be
+$\eta$-contracted {\em before\/} the \AST{} rewriter sees them.  Thus some
+abstraction nodes needed for print rules to match may vanish.  For example,
+\verb|Ball(A, %x. P(x))| contracts {\tt Ball(A, P)}; the print rule does
+not apply and the output will be {\tt Ball(A, P)}.  This problem would not
+occur if \ML{} translation functions were used instead of macros (as is
+done for binder declarations).
+\end{warn}
+
+
+\begin{warn}
+Another trap concerns type constraints.  If \ttindex{show_types} is set to
+{\tt true}, bound variables will be decorated by their meta types at the
+binding place (but not at occurrences in the body).  Matching with
+\verb|Collect(A, %x. P)| binds {\tt x} to something like {\tt ("_constrain" y
+"i")} rather than only {\tt y}.  \AST{} rewriting will cause the constraint to
+appear in the external form, say \verb|{y::i:A::i. P::o}|.  
+
+To allow such constraints to be re-read, your syntax should specify bound
+variables using the nonterminal~\ttindex{idt}.  This is the case in our
+example.  Choosing {\tt id} instead of {\tt idt} is a common error,
+especially since it appears in former versions of most of Isabelle's
+object-logics.
+\end{warn}
+
+
+
+\subsection{Applying rules}
+As a term is being parsed or printed, an \AST{} is generated as an
+intermediate form (recall Fig.\ts\ref{fig:parse_print}).  The \AST{} is
+normalized by applying macro rules in the manner of a traditional term
+rewriting system.  We first examine how a single rule is applied.
+
+Let $t$ be the abstract syntax tree to be normalized and $(l, r)$ some
+translation rule.  A subtree~$u$ of $t$ is a {\bf redex} if it is an
+instance of~$l$; in this case $l$ is said to {\bf match}~$u$.  A redex
+matched by $l$ may be replaced by the corresponding instance of~$r$, thus
+{\bf rewriting} the \AST~$t$.  Matching requires some notion of {\bf
+  place-holders} that may occur in rule patterns but not in ordinary
+\AST{}s; {\tt Variable} atoms serve this purpose.
+
+The matching of the object~$u$ by the pattern~$l$ is performed as follows:
+\begin{itemize}
+  \item Every constant matches itself.
+
+  \item $\Variable x$ in the object matches $\Constant x$ in the pattern.
+    This point is discussed further below.
+
+  \item Every \AST{} in the object matches $\Variable x$ in the pattern,
+    binding~$x$ to~$u$.
+
+  \item One application matches another if they have the same number of
+    subtrees and corresponding subtrees match.
+
+  \item In every other case, matching fails.  In particular, {\tt
+      Constant}~$x$ can only match itself.
+\end{itemize}
+A successful match yields a substitution that is applied to~$r$, generating
+the instance that replaces~$u$.
+
+The second case above may look odd.  This is where {\tt Variable}s of
+non-rule \AST{}s behave like {\tt Constant}s.  Recall that \AST{}s are not
+far removed from parse trees; at this level it is not yet known which
+identifiers will become constants, bounds, frees, types or classes.  As
+\S\ref{sec:asts} describes, former parse tree heads appear in \AST{}s as
+{\tt Constant}s, while $id$s, $var$s, $tid$s and $tvar$s become {\tt
+  Variable}s.  On the other hand, when \AST{}s generated from terms for
+printing, all constants and type constructors become {\tt Constant}s; see
+\S\ref{sec:asts}.  Thus \AST{}s may contain a messy mixture of {\tt
+  Variable}s and {\tt Constant}s.  This is insignificant at macro level
+because matching treats them alike.
+
+Because of this behaviour, different kinds of atoms with the same name are
+indistinguishable, which may make some rules prone to misbehaviour.  Example:
+\begin{ttbox}
+types
+  Nil
+consts
+  Nil     :: "'a list"
+  "[]"    :: "'a list"    ("[]")
+translations
+  "[]"    == "Nil"
+\end{ttbox}
+The term {\tt Nil} will be printed as {\tt []}, just as expected.  What
+happens with \verb|%Nil.t| or {\tt x::Nil} is left as an exercise.
+
+Normalizing an \AST{} involves repeatedly applying macro rules until none
+is applicable.  Macro rules are chosen in the order that they appear in the
+{\tt translations} section.  You can watch the normalization of \AST{}s
+during parsing and printing by setting \ttindex{Syntax.trace_norm_ast} to
+{\tt true}.\index{tracing!of macros} Alternatively, use
+\ttindex{Syntax.test_read}.  The information displayed when tracing
+includes the \AST{} before normalization ({\tt pre}), redexes with results
+({\tt rewrote}), the normal form finally reached ({\tt post}) and some
+statistics ({\tt normalize}).  If tracing is off,
+\ttindex{Syntax.stat_norm_ast} can be set to {\tt true} in order to enable
+printing of the normal form and statistics only.
+
+
+\subsection{Example: the syntax of finite sets}
+This example demonstrates the use of recursive macros to implement a
+convenient notation for finite sets.
+\begin{ttbox}
+FINSET = SET +
+types
+  is
+consts
+  ""            :: "i => is"                ("_")
+  "{\at}Enum"       :: "[i, is] => is"          ("_,/ _")
+  empty         :: "i"                      ("{\ttlbrace}{\ttrbrace}")
+  insert        :: "[i, i] => i"
+  "{\at}Finset"     :: "is => i"                ("{\ttlbrace}(_){\ttrbrace}")
+translations
+  "{\ttlbrace}x, xs{\ttrbrace}"     == "insert(x, {\ttlbrace}xs{\ttrbrace})"
+  "{\ttlbrace}x{\ttrbrace}"         == "insert(x, {\ttlbrace}{\ttrbrace})"
+end
+\end{ttbox}
+Finite sets are internally built up by {\tt empty} and {\tt insert}.  The
+declarations above specify \verb|{x, y, z}| as the external representation
+of
+\begin{ttbox}
+insert(x, insert(y, insert(z, empty)))
+\end{ttbox}
+
+The nonterminal symbol~{\tt is} stands for one or more objects of type~{\tt
+  i} separated by commas.  The mixfix declaration \hbox{\verb|"_,/ _"|}
+allows a line break after the comma for pretty printing; if no line break
+is required then a space is printed instead.
+
+The nonterminal is declared as the type~{\tt is}, but with no {\tt arities}
+declaration.  Hence {\tt is} is not a logical type and no default
+productions are added.  If we had needed enumerations of the nonterminal
+{\tt logic}, which would include all the logical types, we could have used
+the predefined nonterminal symbol \ttindex{args} and skipped this part
+altogether.  The nonterminal~{\tt is} can later be reused for other
+enumerations of type~{\tt i} like lists or tuples.
+
+Next follows {\tt empty}, which is already equipped with its syntax
+\verb|{}|, and {\tt insert} without concrete syntax.  The syntactic
+constant {\tt\at Finset} provides concrete syntax for enumerations of~{\tt
+  i} enclosed in curly braces.  Remember that a pair of parentheses, as in
+\verb|"{(_)}"|, specifies a block of indentation for pretty printing.
+
+The translations may look strange at first.  Macro rules are best
+understood in their internal forms:
+\begin{ttbox}
+parse_rules:
+  ("{\at}Finset" ("{\at}Enum" x xs))  ->  ("insert" x ("{\at}Finset" xs))
+  ("{\at}Finset" x)  ->  ("insert" x "empty")
+print_rules:
+  ("insert" x ("{\at}Finset" xs))  ->  ("{\at}Finset" ("{\at}Enum" x xs))
+  ("insert" x "empty")  ->  ("{\at}Finset" x)
+\end{ttbox}
+This shows that \verb|{x, xs}| indeed matches any set enumeration of at least
+two elements, binding the first to {\tt x} and the rest to {\tt xs}.
+Likewise, \verb|{xs}| and \verb|{x}| represent any set enumeration.  
+The parse rules only work in the order given.
+
+\begin{warn}
+  The \AST{} rewriter cannot discern constants from variables and looks
+  only for names of atoms.  Thus the names of {\tt Constant}s occurring in
+  the (internal) left-hand side of translation rules should be regarded as
+  reserved keywords.  Choose non-identifiers like {\tt\at Finset} or
+  sufficiently long and strange names.  If a bound variable's name gets
+  rewritten, the result will be incorrect; for example, the term
+\begin{ttbox}
+\%empty insert. insert(x, empty)
+\end{ttbox}
+  gets printed as \verb|%empty insert. {x}|.
+\end{warn}
+
+
+\subsection{Example: a parse macro for dependent types}\label{prod_trans}
+As stated earlier, a macro rule may not introduce new {\tt Variable}s on
+the right-hand side.  Something like \verb|"K(B)" => "%x. B"| is illegal;
+it allowed, it could cause variable capture.  In such cases you usually
+must fall back on translation functions.  But a trick can make things
+readable in some cases: {\em calling translation functions by parse
+  macros}:
+\begin{ttbox}
+PROD = FINSET +
+consts
+  Pi            :: "[i, i => i] => i"
+  "{\at}PROD"       :: "[idt, i, i] => i"     ("(3PROD _:_./ _)" 10)
+  "{\at}->"         :: "[i, i] => i"          ("(_ ->/ _)" [51, 50] 50)
+\ttbreak
+translations
+  "PROD x:A. B" => "Pi(A, \%x. B)"
+  "A -> B"      => "Pi(A, _K(B))"
+end
+ML
+  val print_translation = [("Pi", dependent_tr' ("{\at}PROD", "{\at}->"))];
+\end{ttbox}
+
+Here {\tt Pi} is an internal constant for constructing general products.
+Two external forms exist: the general case {\tt PROD x:A.B} and the
+function space {\tt A -> B}, which abbreviates \verb|Pi(A, %x.B)| when {\tt B}
+does not depend on~{\tt x}.
+
+The second parse macro introduces {\tt _K(B)}, which later becomes \verb|%x.B|
+due to a parse translation associated with \ttindex{_K}.  The order of the
+parse rules is critical.  Unfortunately there is no such trick for
+printing, so we have to add a {\tt ML} section for the print translation
+\ttindex{dependent_tr'}.
+
+Recall that identifiers with a leading {\tt _} are allowed in translation
+rules, but not in ordinary terms.  Thus we can create \AST{}s containing
+names that are not directly expressible.
+
+The parse translation for {\tt _K} is already installed in Pure, and {\tt
+dependent_tr'} is exported by the syntax module for public use.  See
+\S\ref{sec:tr_funs} below for more of the arcane lore of translation functions.
+\index{macros|)}\index{rewriting!syntactic|)}
+
+
+
+\section{*Translation functions} \label{sec:tr_funs}
+\index{translations|(} 
+%
+This section describes the translation function mechanism.  By writing
+\ML{} functions, you can do almost everything with terms or \AST{}s during
+parsing and printing.  The logic \LK\ is a good example of sophisticated
+transformations between internal and external representations of
+associative sequences; here, macros would be useless.
+
+A full understanding of translations requires some familiarity
+with Isabelle's internals, especially the datatypes {\tt term}, {\tt typ},
+{\tt Syntax.ast} and the encodings of types and terms as such at the various
+stages of the parsing or printing process.  Most users should never need to
+use translation functions.
+
+\subsection{Declaring translation functions}
+There are four kinds of translation functions.  Each such function is
+associated with a name, which triggers calls to it.  Such names can be
+constants (logical or syntactic) or type constructors.
+
+{\tt Syntax.print_syntax} displays the sets of names associated with the
+translation functions of a {\tt Syntax.syntax} under
+\ttindex{parse_ast_translation}, \ttindex{parse_translation},
+\ttindex{print_translation} and \ttindex{print_ast_translation}.  You can
+add new ones via the {\tt ML} section\index{ML section@{\tt ML} section} of
+a {\tt .thy} file.  There may never be more than one function of the same
+kind per name.  Conceptually, the {\tt ML} section should appear between
+{\tt consts} and {\tt translations}; newly installed translation functions
+are already effective when macros and logical rules are parsed.
+
+The {\tt ML} section is copied verbatim into the \ML\ file generated from a
+{\tt .thy} file.  Definitions made here are accessible as components of an
+\ML\ structure; to make some definitions private, use an \ML{} {\tt local}
+declaration.  The {\tt ML} section may install translation functions by
+declaring any of the following identifiers:
+\begin{ttbox}
+val parse_ast_translation : (string * (ast list -> ast)) list
+val print_ast_translation : (string * (ast list -> ast)) list
+val parse_translation     : (string * (term list -> term)) list
+val print_translation     : (string * (term list -> term)) list
+\end{ttbox}
+
+\subsection{The translation strategy}
+All four kinds of translation functions are treated similarly.  They are
+called during the transformations between parse trees, \AST{}s and terms
+(recall Fig.\ts\ref{fig:parse_print}).  Whenever a combination of the form
+$(\mtt"c\mtt"~x@1 \ldots x@n)$ is encountered, and a translation function
+$f$ of appropriate kind exists for $c$, the result is computed by the \ML{}
+function call $f \mtt[ x@1, \ldots, x@n \mtt]$.
+
+For \AST{} translations, the arguments $x@1, \ldots, x@n$ are \AST{}s.  A
+combination has the form $\Constant c$ or $\Appl{\Constant c, x@1, \ldots,
+  x@n}$.  For term translations, the arguments are terms and a combination
+has the form $\ttfct{Const} (c, \tau)$ or $\ttfct{Const} (c, \tau) \ttapp
+x@1 \ttapp \ldots \ttapp x@n$.  Terms allow more sophisticated
+transformations than \AST{}s do, typically involving abstractions and bound
+variables.
+
+Regardless of whether they act on terms or \AST{}s,
+parse translations differ from print translations fundamentally:
+\begin{description}
+\item[Parse translations] are applied bottom-up.  The arguments are already
+  in translated form.  The translations must not fail; exceptions trigger
+  an error message.
+
+\item[Print translations] are applied top-down.  They are supplied with
+  arguments that are partly still in internal form.  The result again
+  undergoes translation; therefore a print translation should not introduce
+  as head the very constant that invoked it.  The function may raise
+  exception \ttindex{Match} to indicate failure; in this event it has no
+  effect.
+\end{description}
+
+Only constant atoms --- constructor \ttindex{Constant} for \AST{}s and
+\ttindex{Const} for terms --- can invoke translation functions.  This
+causes another difference between parsing and printing.
+
+Parsing starts with a string and the constants are not yet identified.
+Only parse tree heads create {\tt Constant}s in the resulting \AST; recall
+$ast_of_pt$ in \S\ref{sec:asts}.  Macros and parse \AST{} translations may
+introduce further {\tt Constant}s.  When the final \AST{} is converted to a
+term, all {\tt Constant}s become {\tt Const}s; recall $term_of_ast$ in
+\S\ref{sec:asts}.
+
+Printing starts with a well-typed term and all the constants are known.  So
+all logical constants and type constructors may invoke print translations.
+These, and macros, may introduce further constants.
+
+
+\subsection{Example: a print translation for dependent types}
+\indexbold{*_K}\indexbold{*dependent_tr'}
+Let us continue the dependent type example (page~\pageref{prod_trans}) by
+examining the parse translation for {\tt _K} and the print translation
+{\tt dependent_tr'}, which are both built-in.  By convention, parse
+translations have names ending with {\tt _tr} and print translations have
+names ending with {\tt _tr'}.  Search for such names in the Isabelle
+sources to locate more examples.
+
+Here is the parse translation for {\tt _K}:
+\begin{ttbox}
+fun k_tr [t] = Abs ("x", dummyT, incr_boundvars 1 t)
+  | k_tr ts = raise TERM("k_tr",ts);
+\end{ttbox}
+If {\tt k_tr} is called with exactly one argument~$t$, it creates a new
+{\tt Abs} node with a body derived from $t$.  Since terms given to parse
+translations are not yet typed, the type of the bound variable in the new
+{\tt Abs} is simply {\tt dummyT}.  The function increments all {\tt Bound}
+nodes referring to outer abstractions by calling \ttindex{incr_boundvars},
+a basic term manipulation function defined in {\tt Pure/term.ML}.
+
+Here is the print translation for dependent types:
+\begin{ttbox}
+fun dependent_tr' (q,r) (A :: Abs (x, T, B) :: ts) =
+      if 0 mem (loose_bnos B) then
+        let val (x', B') = variant_abs (x, dummyT, B);
+        in list_comb (Const (q, dummyT) $ Free (x', T) $ A $ B', ts)
+        end
+      else list_comb (Const (r, dummyT) $ A $ B, ts)
+  | dependent_tr' _ _ = raise Match;
+\end{ttbox}
+The argument {\tt (q,r)} is supplied to {\tt dependent_tr'} by a curried
+function application during its installation.  We could set up print
+translations for both {\tt Pi} and {\tt Sigma} by including
+\begin{ttbox}
+val print_translation =
+  [("Pi",    dependent_tr' ("{\at}PROD", "{\at}->")),
+   ("Sigma", dependent_tr' ("{\at}SUM", "{\at}*"))];
+\end{ttbox}
+within the {\tt ML} section.  The first of these transforms ${\tt Pi}(A,
+\mtt{Abs}(x, T, B))$ into $\hbox{\tt{\at}PROD}(x', A, B')$ or
+$\hbox{\tt{\at}->}r(A, B)$, choosing the latter form if $B$ does not depend
+on~$x$.  It checks this using \ttindex{loose_bnos}, yet another function
+from {\tt Pure/term.ML}.  Note that $x'$ is a version of $x$ renamed away
+from all names in $B$, and $B'$ the body $B$ with {\tt Bound} nodes
+referring to our {\tt Abs} node replaced by $\ttfct{Free} (x',
+\mtt{dummyT})$.
+
+We must be careful with types here.  While types of {\tt Const}s are
+ignored, type constraints may be printed for some {\tt Free}s and
+{\tt Var}s if \ttindex{show_types} is set to {\tt true}.  Variables of type
+\ttindex{dummyT} are never printed with constraint, though.  The line
+\begin{ttbox}
+        let val (x', B') = variant_abs (x, dummyT, B);
+\end{ttbox}\index{*variant_abs}
+replaces bound variable occurrences in~$B$ by the free variable $x'$ with
+type {\tt dummyT}.  Only the binding occurrence of~$x'$ is given the
+correct type~{\tt T}, so this is the only place where a type
+constraint might appear. 
+\index{translations|)}
+
+
+