The usual way to define the SMIE grammar of a language is by defining a new global variable that holds the precedence table by giving a set of BNF rules. For example, the grammar definition for a small Pascal-like language could look like:
(require 'smie) (defvar sample-smie-grammar (smie-prec2->grammar (smie-bnf->prec2
'((id) (inst ("begin" insts "end") ("if" exp "then" inst "else" inst) (id ":=" exp) (exp)) (insts (insts ";" insts) (inst)) (exp (exp "+" exp) (exp "*" exp) ("(" exps ")")) (exps (exps "," exps) (exp)))
'((assoc ";")) '((assoc ",")) '((assoc "+") (assoc "*")))))
A few things to note:
begin ... end
blocks
to appear anywhere anyway.
id
has no right hand side: this does not
mean that it can match only the empty string, since as mentioned any
sequence of sexps can appear anywhere anyway.
";"
as a statement separator instead,
which SMIE can handle very well.
","
and ";"
above)
are best defined with BNF rules such as (foo (foo "separator" foo) ...)
which generate precedence conflicts which are then resolved by giving
them an explicit (assoc "separator")
.
("(" exps ")")
rule was not needed to pair up parens, since
SMIE will pair up any characters that are marked as having paren syntax
in the syntax table. What this rule does instead (together with the
definition of exps
) is to make it clear that ","
should
not appear outside of parentheses.
left
or
right
, it is usually preferable to mark operators as associative,
using assoc
. For that reason "+"
and "*"
are
defined above as assoc
, although the language defines them
formally as left associative.