This is term_lint.pl
, a small tool for checking terms
against a tree grammar (abstract syntax).
The grammar is a sequence of grammar rules. Each rule is of the form
Nonterminal ::= Body. There should be no two rules for the same
nonterminal (use |
instead), but this is not checked.
Body has the following meaning:
|
B{}
(A)FswithA1,...()
,An
match term F(A1,...,An) where F is a functor in Fs
Argument expressions (in argument tuples) can be:
?
A term is "missing" (see below) or matches
argument expression A
{}
(A).
(A,)As a special case, [_]
means "list of any type".
Options (A?) are resolved as follows: If the term under consideration is a solution of predicate missing/1 (to be defined along with the grammar rules), there is a match; otherwise a term of type A must be matched.
Predicates to be defined along with the grammar rules are:
missing()
/
1start_symbol()
/
1Here are a few example grammars to illustrate the explanations above.
Arithmetic expressions, simple verbose version:
var ::= {VarName} where atom(VarName). num ::= {Number} where number(Number). expr ::= var | num | expr + expr | expr - expr | expr * expr | expr / expr.
Arithmetic expressions, more condensed version:
expr ::= {Leaf} where (atom(Leaf) ; number(Leaf)) | functors [+, -, *, /] with (expr, expr).
*Simple type system*:
type ::= atoms [number, character, string] | function_type([type] /* argument types */, type? /* return type if any */). missing(none). /* what to match if no return type is given */
Partial specification (some parts are not constrained):
allowed ::= lst([_]) /* argument is list of some unknown things */ | opt(allowed?) /* argument is missing, or of type allowed */ | any({_}). /* argument is any term (anything unifies with _) */ missing(nothing).
In this last example, some allowed terms are:
lst([]), lst([f(f)]), lst([x,y]), ... opt(nothing), opt(lst([])), opt(opt(nothing)), ... any(foo), any(g(f(x))), ...
One more thing, which might not be explicit from the stuff above: The anonymous variable _ (free variables in general) may appear in the grammar, but only inside[]or {}:
.
(Arg1,){}
(Arg1){}
(foo(_G1453))but:
foo()
::= foo(Arg1)
foo ::= foo({_})
foo()
::= Xwherecond(X)
foo ::= {X} where cond(X)
The interpreter does not check these things at the moment. Which means that grammars containing variables in weird places will misbehave in weird ways.