X-Git-Url: https://git.distorted.org.uk/~mdw/sod/blobdiff_plain/ba375a80263cbbc155f66c6046e485d56935e5c6..21d6792d1c504fc73add4749a295bf2eb2cf1c3a:/doc/syntax.tex

diff --git a/doc/syntax.tex b/doc/syntax.tex
index 6dd5cf7..6c05acc 100644
--- a/doc/syntax.tex
+++ b/doc/syntax.tex
@@ -51,20 +51,20 @@ could be a token.
 
 <id-start-char> ::= <alpha-char> | "_"
 
-<id-body-char> ::= <id-start-char> @! <digit-char>
+<id-body-char> ::= <id-start-char> | <digit-char>
 
-<alpha-char> ::= "A" | "B" | \dots\ | "Z"
-\alt "a" | "b" | \dots\ | "z"
-\alt <extended-alpha-char>
+<alpha-char> ::= "A" | "B" | $\cdots$ | "Z"
+  | "a" | "b" | $\cdots$ | "z"
+  | <extended-alpha-char>
 
 <digit-char> ::= "0" | <nonzero-digit-char>
 
-<nonzero-digit-char> ::= "1" | "2" $| \ldots |$ "9"
+<nonzero-digit-char> ::= "1" | "2" | $\cdots$ | "9"
 \end{grammar}
 
 The precise definition of @<alpha-char> is left to the function
-\textsf{alpha-char-p} in the hosting Lisp system.  For portability,
-programmers are encouraged to limit themselves to the standard ASCII letters.
+@|alpha-char-p| in the hosting Lisp system.  For portability, programmers are
+encouraged to limit themselves to the standard ASCII letters.
 
 There are no reserved words at the lexical level, but the higher-level syntax
 recognizes certain identifiers as \emph{keywords} in some contexts.  There is
@@ -80,11 +80,11 @@ level.
 
 <char-literal> ::= "'" <char-literal-char> "'"
 
-<string-literal-char> ::= any character other than "\\" or "\""
-\alt "\\" <char>
+<string-literal-char> :: "\\" <char>
+  | any character other than "\\" or "\""
 
-<char-literal-char> ::= any character other than "\\" or "'"
-\alt "\\" <char>
+<char-literal-char> :: "\\" <char>
+  | any character other than "\\" or "'"
 
 <char> ::= any single character
 \end{grammar}
@@ -96,29 +96,30 @@ and the simple syntax seems adequate.  For the sake of future compatibility,
 the use of character sequences which resemble C escape sequences is
 discouraged.
 
-\subsubsection{Integer literals} \label{sec:syntax.lex.int}
+
+\subsection{Integer literals} \label{sec:syntax.lex.int}
 
 \begin{grammar}
 <integer-literal> ::= <decimal-integer>
-\alt <binary-integer>
-\alt <octal-integer>
-\alt <hex-integer>
+  | <binary-integer>
+  | <octal-integer>
+  | <hex-integer>
 
 <decimal-integer> ::= "0" | <nonzero-digit-char> @<digit-char>^*
 
-<binary-integer> ::= "0" @("b"|"B"@) @<binary-digit-char>^+
+<binary-integer> ::= "0" @("b" | "B"@) @<binary-digit-char>^+
 
 <binary-digit-char> ::= "0" | "1"
 
-<octal-integer> ::= "0" @["o"|"O"@] @<octal-digit-char>^+
+<octal-integer> ::= "0" @["o" | "O"@] @<octal-digit-char>^+
 
-<octal-digit-char> ::= "0" | "1" $| \ldots |$ "7"
+<octal-digit-char> ::= "0" | "1" | $\cdots$ | "7"
 
-<hex-integer> ::= "0" @("x"|"X"@) @<hex-digit-char>^+
+<hex-integer> ::= "0" @("x" | "X"@) @<hex-digit-char>^+
 
 <hex-digit-char> ::= <digit-char>
-\alt "A" | "B" | "C" | "D" | "E" | "F"
-\alt "a" | "b" | "c" | "d" | "e" | "f"
+  | "A" | "B" | "C" | "D" | "E" | "F"
+  | "a" | "b" | "c" | "d" | "e" | "f"
 \end{grammar}
 
 Sod understands only integers, not floating-point numbers; its integer syntax
@@ -129,15 +130,16 @@ binary.  However, length and signedness indicators are not permitted.
 \subsection{Punctuation} \label{sec:syntax.lex.punct}
 
 \begin{grammar}
-<punctuation> ::= any nonalphanumeric character other than "_", "\"" or "'"
+<punctuation> ::= "<<" | ">>" | "||" | "&&"
+  | "<=" | ">=" | "==" | "!=" | "\dots"
+\alt any nonalphanumeric character other than "_", "\"", or "'"
 \end{grammar}
 
 
 \subsection{Comments} \label{sec:syntax.lex.comment}
 
 \begin{grammar}
-<comment> ::= <block-comment>
-\alt <line-comment>
+<comment> ::= <block-comment> | <line-comment>
 
 <block-comment> ::=
   "/*"
@@ -189,9 +191,356 @@ during translation.  They are read using a simple scanner which nonetheless
 understands C comments and string and character literals.
 
 A C fragment is terminated by one of a small number of delimiter characters
-determined by the immediately surrounding context -- usually a closing brace
-or bracket.  The first such delimiter character which is not enclosed in
-brackets, braces or parenthesis ends the fragment.
+determined by the immediately surrounding context -- usually some kind of
+bracket.  The first such delimiter character which is not enclosed in
+brackets, braces or parentheses ends the fragment.
+
+%%%--------------------------------------------------------------------------
+\section{C types} \label{sec:syntax.type}
+
+Sod's syntax for C types closely mirrors the standard C syntax.  A C type has
+two parts: a sequence of @<declaration-specifier>s and a @<declarator>.  In
+Sod, a type must contain at least one @<declaration-specifier> (i.e.,
+`implicit @|int|' is forbidden), and storage-class specifiers are not
+recognized.
+
+
+\subsection{Declaration specifiers} \label{sec:syntax.type.declspec}
+
+\begin{grammar}
+<declaration-specifier> ::= <type-name>
+\alt "struct" <identifier> | "union" <identifier> | "enum" <identifier>
+\alt "void" | "char" | "int" | "float" | "double"
+\alt "short" | "long"
+\alt "signed" | "unsigned"
+\alt "bool" | "_Bool"
+\alt "imaginary" | "_Imaginary" | "complex" | "_Complex"
+\alt <qualifier>
+\alt <storage-specifier>
+\alt <atomic-type>
+\alt <other-declspec>
+
+<qualifier> ::= <atomic> | "const" | "volatile" | "restrict"
+
+<plain-type> ::= @<declaration-specifier>^+ <abstract-declarator>
+
+<atomic-type> ::= <atomic> "(" <plain-type> ")"
+
+<atomic> ::= "atomic" | "_Atomic"
+
+<storage-specifier> ::= <alignas> "(" <c-fragment> ")"
+
+<alignas> ::= "alignas" "_Alignas"
+
+<type-name> ::= <identifier>
+\end{grammar}
+
+Declaration specifiers may appear in any order.  However, not all
+combinations are permitted.  A declaration specifier must consist of zero or
+more @<qualifier>s, zero or more @<storage-specifier>s, and one of the
+following, up to reordering:
+\begin{itemize}
+\item @<type-name>;
+\item @<atomic-type>;
+\item @"struct" @<identifier>; @"union" @<identifier>; @"enum" @<identifier>;
+\item @"void";
+\item @"_Bool", @"bool";
+\item @"char"; @"unsigned char"; @"signed char";
+\item @"short", @"signed short", @"short int", @"signed short int";
+  @"unsigned short", @"unsigned short int";
+\item @"int", @"signed", @"signed int"; @"unsigned", @"unsigned int";
+\item @"long", @"signed long", @"long int", @"signed long int"; @"unsigned
+  long", @"unsigned long int";
+\item @"long long", @"signed long long", @"long long int", @"signed long long
+  int"; @"unsigned long long", @"unsigned long long int";
+\item @"float"; @"double"; @"long double";
+\item @"float _Imaginary", @"float imaginary"; @"double _Imaginary", @"double
+  imaginary"; @"long double _Imaginary", @"long double imaginary";
+\item @"float _Complex", @"float complex"; @"double _Complex", @"double
+  complex"; @"long double _Complex", @"long double complex".
+\end{itemize}
+All of these have their usual C meanings.  Groups separated by commas mean
+the same thing, and Sod will not preserve the distinction.
+
+Almost all of these mean the same as they do in C.  There are some minor
+differences:
+\begin{itemize}
+\item In C, the `tag' namespace is shared between @|struct|, @|union|, and
+  @|enum|; Sod has three distinct namespaces for tags.  This may be fixed in
+  the future.
+\item The @<other-declspec> production is a syntactic extension point, where
+  extensions can introduce their own additions to the type system.
+\end{itemize}
+
+C standards from C99 onwards have tended to introduce new keywords beginning
+with an underscore followed by an uppercase letter, so as to avoid conflicts
+with existing code.  More conventional spellings are then provided by macros
+in new header files.  For example, C99 introduced @"_Bool", and a header file
+@|<stdbool.h>| which defines the macro @|bool|.  Sod recognizes both the ugly
+underscore names and the more conventional macro names on input, but always
+emits the ugly names.  This doesn't cause a compatibility problem in Sod,
+because Sod's parser recognizes keywords only in the appropriate context.
+For example, the (ill-advised) slot declaration
+\begin{prog}
+  bool bool;
+\end{prog}
+is completely acceptable, and will cause the C structure member
+\begin{prog}
+  \_Bool bool;
+\end{prog}
+to be emitted on output, which will be acceptable to C as long as
+@|<stdbool.h>| is not included.
+
+A @<type-name> is an identifier which has been declared as being a type name,
+using the @"typename" or @"class" definitions.  The following type names are
+defined in the built-in module.
+\begin{itemize}
+\item @|va_list|
+\item @|size_t|
+\item @|ptrdiff_t|
+\item @|wchar_t|
+\end{itemize}
+
+
+\subsection{Declarators} \label{sec:syntax.type.declarator}
+
+\begin{grammar}
+<declarator>$[k, a]$ ::= @<pointer>^* <primary-declarator>$[k, a]$
+
+<primary-declarator>$[k, a]$ ::= $k$
+\alt "(" <primary-declarator>$[k, a]$ ")"
+\alt <primary-declarator>$[k, a]$ @<declarator-suffix>$[a]$
+
+<pointer> ::= "*" @<qualifier>^*
+
+<declarator-suffix>$[a]$ ::= "[" <c-fragment> "]"
+\alt "(" $a$ ")"
+
+<argument-list> ::= $\epsilon$ | "\dots"
+\alt <list>$[\mbox{@<argument>}]$ @["," "\dots"@]
+
+<argument> ::= @<declaration-specifier>^+ <argument-declarator>
+
+<abstract-declarator> ::= <declarator>$[\epsilon, \mbox{@<argument-list>}]$
+
+<argument-declarator> ::=
+  <declarator>$[\mbox{@<identifier> | $\epsilon$}, \mbox{@<argument-list>}]$
+
+<simple-declarator> ::=
+  <declarator>$[\mbox{@<identifier>}, \mbox{@<argument-list>}]$
+\end{grammar}
+
+The declarator syntax is taken from C, but with some differences.
+\begin{itemize}
+\item Array dimensions are uninterpreted @<c-fragments>, terminated by a
+  closing square bracket.  This allows array dimensions to contain arbitrary
+  constant expressions.
+\item A declarator may have either a single @<identifier> at its centre or a
+  pair of @<identifier>s separated by a @`.'; this is used to refer to
+  slots or messages defined in superclasses.
+\end{itemize}
+The remaining differences are (I hope) a matter of presentation rather than
+substance.
+
+There is additional syntax to support messages and methods which accept
+keyword arguments.
+
+\begin{grammar}
+<keyword-argument> ::= <argument> @["=" <c-fragment>@]
+
+<keyword-argument-list> ::=
+  @[<list>$[\mbox{@<argument>}]$@]
+  "?" @[<list>$[\mbox{@<keyword-argument>}]$@]
+
+<method-argument-list> ::= <argument-list> | <keyword-argument-list>
+
+<dotted-name> ::= <identifier> "." <identifier>
+
+<keyword-declarator>$[k]$ ::=
+  <declarator>$[k, \mbox{@<method-argument-list>}]$
+\end{grammar}
+
+%%%--------------------------------------------------------------------------
+\section{Properties} \label{sec:syntax.prop}
+
+\begin{grammar}
+<properties> ::= "[" <list>$[\mbox{@<property>}]$ "]"
+
+<property> ::= <identifier> "=" <expression>
+
+<expression> ::= <logical-or>
+
+<logical-or> ::= <logical-and>
+  | <logical-or> "||" <logical-and>
+
+<logical-and> ::= <bitwise-or>
+  | <logical-and> "&&" <bitwise-or>
+
+<bitwise-or> ::= <bitwise-xor>
+  | <bitwise-or> "|" <bitwise-xor>
+
+<bitwise-xor> ::= <bitwise-and>
+  | <bitwise-xor> "^" <bitwise-and>
+
+<bitwise-and> ::= <equality>
+  | <bitwise-and> "&" <equality>
+
+<equality> ::= <ordering>
+  | <equality> "==" <ordering>
+  | <equality> "!=" <ordering>
+
+<ordering> ::= <shift>
+  | <ordering> "<" <shift>
+  | <ordering> "<=" <shift>
+  | <ordering> ">=" <shift>
+  | <ordering> ">" <shift>
+
+<shift> ::= <additive>
+  | <shift> "<<" <additive>
+  | <shift> ">>" <additive>
+
+<additive> ::= <term>
+  | <additive> "+" <term>
+  | <additive> "--" <term>
+
+<term> ::= <factor>
+  | <term> "*" <factor>
+  | <term> "/" <factor>
+
+<factor> ::= <primary>
+  | "!" <factor> | "~" factor
+  | "+" <factor> | "--" <factor>
+
+<primary> ::=
+     <integer-literal> | <string-literal> | <char-literal> | <identifier>
+\alt "<" <plain-type> ">" | "{" <c-fragment> "}" | "?" <s-expression>
+  | "(" <expression> ")"
+\end{grammar}
+
+\emph{Property sets} are a means for associating miscellaneous information
+with compile-time metaobjects such as modules, classes, messages, methods,
+slots, and initializers.  By using property sets, additional information can
+be passed to extensions without the need to introduce idiosyncratic syntax.
+(That said, extensions can add additional first-class syntax, if necessary.)
+
+An error is reported if an unrecognized property is associated with an
+object.
+
+
+\subsection{Property values} \label{sec:syntax.prop.value}
+
+A property has a name, given as an @<identifier>, and a value computed by
+evaluating an @<expression>.  The value can be one of a number of types.
+
+\begin{itemize}
+
+\item An @<integer-literal> denotes a value of type @|int|.
+
+\item Similarly @<string-literal> and @<char-literal> denote @|string| and
+  @|char| values respectively.  Note that, as properties, characters are
+  quite distinct from integers, whereas in C, a character literal denotes a
+  value of type @|int|.
+
+\item There are no variables in the property-value syntax.  Rather, an
+  @<identifier> denotes that identifier, as a value of type @|id|.
+
+\item A C type (a @<plain-type>, as described in \xref{sec:syntax.type})
+  between angle brackets, e.g., @|<int>|, or @|<char *>|, or @|<void (*(int,
+  void (*)(int)))(int)>|, denotes that C type, as a value of type @|type|.
+
+\item A @<c-fragment> within braces denotes the tokens between (and not
+  including) the braces, as a value of type @|c-fragment|.
+
+\end{itemize}
+
+As shown in the grammar, there are four binary operators, @"+" (addition),
+@"--" (subtraction), @"*" (multiplication), and @"/" (division);
+multiplication and division have higher precedence than addition and
+subtraction, and operators of the same precedence associate left-to-right.
+There are also unary @"+" (no effect) and @"--" (negation) operators, with
+higher precedence.  All of the above operators act only on integer operands
+and yield integer results.  (Although the unary @"+" operator yields its
+operand unchanged, an error is still reported if it is applied to a
+non-integer value.)  There are currently no bitwise, logical, or comparison
+operators.
+
+Finally, an S-expression preceded by @|?| causes the expression to be read in
+the current package (which is always @|sod-user| at the start of a module)
+and immediately evaluated (using @|eval|); the resulting value is converted
+into a property value using the \descref{gf}{decode-property}[generic
+function].
+
+
+\subsection{Property output types and coercions}
+\label{sec:syntax.prop.coerce}
+
+When a property value is inspected by the Sod translator, or an extension, it
+is \emph{coerced} so as to conform to a requested output type.  This coercion
+process is performed by the \descref{gf}{coerce-property-value}[generic
+function], and additional output types and coercions can be defined by
+extensions.  The built-in output types coercions, from the value types listed
+above, are as follows.
+
+\begin{itemize}
+
+\item The output types @|int|, @|string|, @|char|, @|id|, and @|c-fragment|
+  correspond to the like-named value types described above.  No coercions to
+  these output types are defined for the described value types.\footnote{%
+    There is a coercion to @|id| from the value type @|symbol|, but it is
+    only possible to generate a property value of type @|symbol| using Lisp.}
+
+\item The output type @|type| denotes a C type, as does the value type
+  @|type|.  In addition, a value of type @|id| can be coerced to a C type if
+  it is the name of a class, a type name explicitly declared by @|typename|,
+  or it is one of: @|bool|, @|_Bool|, @|void|, @|char|, @|short|, @|int|,
+  @|signed|, @|unsigned|, @|long|, @|size_t|, @|ptrdiff_t|, @|wchar_t|,
+  or @|va_list|.
+
+\item The @|boolean| output type denotes a boolean value, which may be either
+  true or false.  A value of type @|id| is considered true if it is @|true|,
+  @|t|, @|yes|, @|on|, @|yup|, or @|verily|; or false if it is @|false|,
+  @|nil|, @|no|, @|off|, @|nope|, or @|nowise|; it is erroneous to provide
+  any other identifier where a boolean value is wanted.  A value of type
+  @|int| is considered true if it is nonzero, or false if it is zero.
+
+\item The @|symbol| output type denotes a Lisp symbol.
+
+  A value of type @|id| is coerced to a symbol as follows.  First, the
+  identifier name is subjected to \emph{case inversion}: if all of the
+  letters in the name have the same case, either upper or lower, then they
+  are replaced with the corresponding letters in the opposite case, lower or
+  upper; if the name contains letters of both cases, then it is not changed.
+  For example, @|foo45| becomes @|FOO45|, or \emph{vice-versa}; but @|Splat|
+  remains as it is.  Second, the name is subjected to \emph{separator
+  switching}: all underscores in the name are replaced with hyphens (and
+  \emph{vice-versa}, though hyphens aren't permitted in identifiers in the
+  first place).  Finally, the resulting name is interned in the current
+  package, which will usually be @|sod-user| unless changed explicitly by the
+  module.
+
+  A value of type @|string| is coerced to a symbol as follows.  If the string
+  contains no colons, then it is case-inverted (but not separator-switched)
+  and interned in the current package.  Otherwise, the string either has the
+  form $p @|:| q$, where $q$ does not begin with a colon (the
+  \emph{single-colon} case) or $p @|::| q$ (the \emph{double-colon} case);
+  where $p$ does not contain a colon.  Both $p$ and $q$ are case-inverted
+  (but not separator-switched).  If $p$ does not name a package, then an
+  error is reported; as a special case, if $p$ is empty, then it is
+  considered to name the @|keyword| package.  Otherwise, $q$ is looked up as
+  a symbol name in package~$p$; in the single-colon case, if the symbol is
+  not an exported symbol in package~$p$, then an error is reported; in the
+  double-colon case, $q$ is interned in package~$p$ (and so there needn't be
+  an exported symbol -- or, indeed, and symbol at all -- named $q$
+  beforehand).
+
+\item The @|keyword| output type denotes symbols within the @|keyword|
+  package.  Value of type @|id| or @|string| can be coerced to a @|keyword|
+  in the same way as to a @|symbol|, as described above, only the converted
+  name is looked up in the @|keyword| package rather than the current
+  package.  (A @|string| can override this by specifying an explicit package
+  name, but this is unlikely to be very helpful.)
+
+\end{itemize}
 
 %%%--------------------------------------------------------------------------
 \section{Module syntax} \label{sec:syntax.module}
@@ -199,16 +548,20 @@ brackets, braces or parenthesis ends the fragment.
 \begin{grammar}
 <module> ::= @<definition>^*
 
-<definition> ::= <import-definition>
+<definition> ::= <property-definition> \fixme{undefined}
+\alt <import-definition>
 \alt <load-definition>
 \alt <lisp-definition>
 \alt <code-definition>
 \alt <typename-definition>
 \alt <class-definition>
+\alt <other-definition> \fixme{undefined}
 \end{grammar}
 
-A @<module> is the top-level syntactic item.  A module consists of a sequence
-of definitions.
+A @<module> is the top-level syntactic item: a source file presented to Sod
+is expected to conform with the @<module> syntax.
+
+A module consists of a sequence of definitions.
 
 \fixme{describe syntax; expand}
 Properties:
@@ -233,9 +586,9 @@ A search is made for a module source file as follows.
 \begin{itemize}
 \item The module name @<string> is converted into a filename by appending
   @`.sod', if it has no extension already.\footnote{%
-    Technically, what happens is \textsf{(merge-pathnames name (make-pathname
-    :type "SOD" :case :common))}, so exactly what this means varies
-    according to the host system.} %
+    Technically, what happens is @|(merge-pathnames name (make-pathname :type
+    "SOD" :case :common))|, so exactly what this means varies according to
+    the host system.} %
 \item The file is looked for relative to the directory containing the
   importing module.
 \item If that fails, then the file is looked for in each directory on the
@@ -245,7 +598,7 @@ A search is made for a module source file as follows.
 \end{itemize}
 At this point, if the file has previously been imported, nothing further
 happens.\footnote{%
-  This check is done using \textsf{truename}, so it should see through simple
+  This check is done using @|truename|, so it should see through simple
   tricks like symbolic links.  However, it may be confused by fancy things
   like bind mounts and so on.} %
 
@@ -262,23 +615,22 @@ A search is made for a Lisp source file as follows.
 \begin{itemize}
 \item The name @<string> is converted into a filename by appending @`.lisp',
   if it has no extension already.\footnote{%
-    Technically, what happens is \textsf{(merge-pathnames name (make-pathname
-    :type "LISP" :case :common))}, so exactly what this means varies
-    according to the host system.} %
+    Technically, what happens is @|(merge-pathnames name (make-pathname :type
+    "LISP" :case :common))|, so exactly what this means varies according to
+    the host system.} %
 \item A search is then made in the same manner as for module imports
   (\xref{sec:syntax-module}).
 \end{itemize}
-If the file is found, it is loaded using the host Lisp's \textsf{load}
-function.
+If the file is found, it is loaded using the host Lisp's @|load| function.
 
 Note that Sod doesn't attempt to compile Lisp files, or even to look for
 existing compiled files.  The right way to package a substantial extension to
 the Sod translator is to provide the extension as a standard ASDF system (or
 similar) and leave a dropping @|foo-extension.lisp| in the module path saying
 something like
-\begin{quote}
-  \textsf{(asdf:load-system :foo-extension)}
-\end{quote}
+\begin{prog}
+  (asdf:load-system :foo-extension)
+\end{prog}
 which will arrange for the extension to be compiled if necessary.
 
 (This approach means that the language doesn't need to depend on any
@@ -318,14 +670,18 @@ declarations instead.
 
 \begin{grammar}
 <code-definition> ::=
-  "code" <identifier> ":" <item-name> @[<constraints>@]
+  "code" <reason> ":" <item-name> @[<constraints>@]
   "{" <c-fragment> "}"
+\alt
+  "code" <reason> ":" <constraints> ";"
+
+<reason> ::= <identifier>
 
 <constraints> ::= "[" <list>$[\mbox{@<constraint>}]$ "]"
 
 <constraint> ::= @<item-name>^+
 
-<item-name> ::= <identifier> @! "(" @<identifier>^+ ")"
+<item-name> ::= <identifier> | "(" @<identifier>^+ ")"
 \end{grammar}
 
 The @<c-fragment> will be output unchanged to one of the output files.
@@ -354,180 +710,25 @@ preprocessor directives in order to declare types and functions for use
 elsewhere in the generated output files.
 
 
-\subsection{Property sets} \label{sec:syntax.module.properties}
-\begin{grammar}
-<properties> ::= "[" <list>$[\mbox{@<property>}]$ "]"
-
-<property> ::= <identifier> "=" <expression>
-\end{grammar}
+\subsection{Static instance definitions} \label{sec:syntax.module.instance}
 
-Property sets are a means for associating miscellaneous information with
-classes and related items.  By using property sets, additional information
-can be passed to extensions without the need to introduce idiosyncratic
-syntax.
-
-A property has a name, given as an @<identifier>, and a value computed by
-evaluating an @<expression>.  The value can be one of a number of types,
-though the only operators currently defined act on integer values only.
-
-\subsubsection{The expression evaluator}
 \begin{grammar}
-<expression> ::= <term> | <expression> "+" <term> | <expression> "--" <term>
-
-<term> ::= <factor> | <term> "*" <factor> | <term> "/" <factor>
+<static-instance-definition> ::=
+  "instance" <identifier> <identifier>
+  @[":" <list>$[\mbox{@<instance-initializer>}]$@] ";"
 
-<factor> ::= <primary> | "+" <factor> | "--" <factor>
-
-<primary> ::=
-     <integer-literal> | <string-literal> | <char-literal> | <identifier>
-\alt "<" <plain-type> ">"
-\alt "?" <s-expression>
-\alt "(" <expression> ")"
-\end{grammar}
-
-The arithmetic expression syntax is simple and standard; there are currently
-no bitwise, logical, or comparison operators.
-
-A @<primary> expression may be a literal or an identifier.  Note that
-identifiers stand for themselves: they \emph{do not} denote values.  For more
-fancy expressions, the syntax
-\begin{quote}
-  @"?" @<s-expression>
-\end{quote}
-causes the @<s-expression> to be evaluated using the Lisp \textsf{eval}
-function.
-%%% FIXME crossref to extension docs
-
-
-\subsection{C types} \label{sec:syntax.module.types}
-
-Sod's syntax for C types closely mirrors the standard C syntax.  A C type has
-two parts: a sequence of @<declaration-specifier>s and a @<declarator>.  In
-Sod, a type must contain at least one @<declaration-specifier> (i.e.,
-`implicit @"int"' is forbidden), and storage-class specifiers are not
-recognized.
-
-\subsubsection{Declaration specifiers}
-\begin{grammar}
-<declaration-specifier> ::= <type-name>
-\alt "struct" <identifier> | "union" <identifier> | "enum" <identifier>
-\alt "void" | "char" | "int" | "float" | "double"
-\alt "short" | "long"
-\alt "signed" | "unsigned"
-\alt "bool" | "_Bool"
-\alt "imaginary" | "_Imaginary" | "complex" | "_Complex"
-\alt <qualifier>
-\alt <storage-specifier>
-\alt <atomic-type>
-
-<qualifier> ::= <atomic> | "const" | "volatile" | "restrict"
-
-<plain-type> ::= @<declaration-specifier>^+ <abstract-declarator>
-
-<atomic-type> ::=
-  <atomic> "(" <plain-type> ")"
-
-<atomic> ::= "atomic" | "_Atomic"
-
-<storage-specifier> ::= <alignas> "(" <c-fragment> ")"
-
-<alignas> ::= "alignas" "_Alignas"
-
-<type-name> ::= <identifier>
+<instance-initializer> ::= <identifier> "." <identifier> "=" <c-fragment>
 \end{grammar}
 
-A @<type-name> is an identifier which has been declared as being a type name,
-using the @"typename" or @"class" definitions.  The following type names are
-defined in the built-in module.
-\begin{itemize}
-\item @"va_list"
-\item @"size_t"
-\item @"ptrdiff_t"
-\item @"wchar_t"
-\end{itemize}
-
-Declaration specifiers may appear in any order.  However, not all
-combinations are permitted.  A declaration specifier must consist of zero or
-more @<qualifier>s, zero or more @<storage-specifier>s, and one of the
-following, up to reordering.
-\begin{itemize}
-\item @<type-name>
-\item @<atomic-type>
-\item @"struct" @<identifier>, @"union" @<identifier>, @"enum" @<identifier>
-\item @"void"
-\item @"_Bool", @"bool"
-\item @"char", @"unsigned char", @"signed char"
-\item @"short", @"unsigned short", @"signed short"
-\item @"short int", @"unsigned short int", @"signed short int"
-\item @"int", @"unsigned int", @"signed int", @"unsigned", @"signed"
-\item @"long", @"unsigned long", @"signed long"
-\item @"long int", @"unsigned long int", @"signed long int"
-\item @"long long", @"unsigned long long", @"signed long long"
-\item @"long long int", @"unsigned long long int", @"signed long long int"
-\item @"float", @"double", @"long double"
-\item @"float _Imaginary", @"double _Imaginary", @"long double _Imaginary"
-\item @"float imaginary", @"double imaginary", @"long double imaginary"
-\item @"float _Complex", @"double _Complex", @"long double _Complex"
-\item @"float complex", @"double complex", @"long double complex"
-\end{itemize}
-All of these have their usual C meanings.
-
-\subsubsection{Declarators}
-\begin{grammar}
-<declarator>$[k, a]$ ::= @<pointer>^* <primary-declarator>$[k, a]$
-
-<primary-declarator>$[k, a]$ ::= $k$
-\alt "(" <primary-declarator>$[k, a]$ ")"
-\alt <primary-declarator>$[k, a]$ @<declarator-suffix>$[a]$
-
-<pointer> ::= "*" @<qualifier>^*
-
-<declarator-suffix>$[a]$ ::= "[" <c-fragment> "]"
-\alt "(" $a$ ")"
-
-<argument-list> ::= $\epsilon$ | "\dots"
-\alt <list>$[\mbox{@<argument>}]$ @["," "\dots"@]
-
-<argument> ::= @<declaration-specifier>^+ <argument-declarator>
-
-<abstract-declarator> ::= <declarator>$[\epsilon, \mbox{@<argument-list>}]$
-
-<argument-declarator> ::=
-  <declarator>$[\mbox{@<identifier> @! $\epsilon$}, \mbox{@<argument-list>}]$
-
-<simple-declarator> ::=
-  <declarator>$[\mbox{@<identifier>}, \mbox{@<argument-list>}]$
-\end{grammar}
-
-The declarator syntax is taken from C, but with some differences.
-\begin{itemize}
-\item Array dimensions are uninterpreted @<c-fragments>, terminated by a
-  closing square bracket.  This allows array dimensions to contain arbitrary
-  constant expressions.
-\item A declarator may have either a single @<identifier> at its centre or a
-  pair of @<identifier>s separated by a @`.'; this is used to refer to
-  slots or messages defined in superclasses.
-\end{itemize}
-The remaining differences are (I hope) a matter of presentation rather than
-substance.
-
-There is additional syntax to support messages and methods which accept
-keyword arguments.
-
-\begin{grammar}
-<keyword-argument> ::= <argument> @["=" <c-fragment>@]
-
-<keyword-argument-list> ::=
-  @[<list>$[\mbox{@<argument>}]$@]
-  "?" @[<list>$[\mbox{@<keyword-argument>}]$@]
-
-<method-argument-list> ::= <argument-list> @! <keyword-argument-list>
-
-<dotted-name> ::= <identifier> "." <identifier>
-
-<keyword-declarator>$[k]$ ::=
-  <declarator>$[k, \mbox{@<method-argument-list>}]$
-\end{grammar}
+Properties:
+\begin{description}
+\item[@"extern"] A boolean flag: if true, then the instance is public, and
+  will be declared in the output header file; if false (the default), then
+  the instance is only available to code defined within the module.
+\item[@"const"] A boolean flag: if true (the default), then the instance is
+  read-only, and may end up in write-protected storage at run-time; if false,
+  then the instance will be writable.
+\end{description}
 
 
 \subsection{Class definitions} \label{sec:syntax.module.class}
@@ -572,6 +773,7 @@ class Sub: Super \{                                             \\ \ind
 \alt <fragment-item>
 \alt <message-item>
 \alt <method-item>
+\alt <other-item> \fixme{undefined}
 \end{grammar}
 
 A full class definition provides a complete description of a class.
@@ -585,8 +787,9 @@ The @<list>$[\mbox{@<identifier>}]$ names the direct superclasses for the new
 class.  It is an error if any of these @<identifier>s does not name a defined
 class.  The superclass list is required, and must not be empty; listing
 @|SodObject| as your class's superclass is a good choice if nothing else
-seems suitable.  It's not possible to define a \emph{root class} in the Sod
-language: you must use Lisp to do this, and it's quite involved.
+seems suitable.  A class with no direct superclasses is called a \emph{root
+class}.  It is not possible to define a root class in the Sod language: you
+must use Lisp to do this, and it's quite involved.
 
 The @<properties> provide additional information.  The standard class
 properties are as follows.
@@ -721,6 +924,9 @@ Properties:
 \begin{description}
 \item[@|message_class|] A symbol naming the Lisp class to use to represent
   the message.
+\item[@|readonly|] A boolean indicating whether the message guarantees not to
+  modify its receiver.  If this is true, the receiver will be declared
+  @"const".
 \item[@|combination|] A keyword naming the aggregating method combination to
   use.
 \item[@|most_specific|] A keyword, either @`first' or @`last', according to
