Tagging

It is possible to track the identity of a particular piece. Each piece in the initial position of the game or study is assigned a unique
nonnegative integer, called its mark. Promotion does not change the mark of a piece. A tag is a named mark. We say that a tag is bound to the value of a mark. A tag represents the particular piece whose mark equals the mark of the tag.
The following keywords manipulate the mark:

:forany in the match list

A tag is defined via the :forany keyword in a match list. The :forany keyword takes two parameters: the alphanumeric name of a tag and
a piece designator.

The match filter is then conceptually run once in which each tag is bound to each possible mark, such that two conditions hold:

No two tags may be bound to the same mark.

A tag may only be bound to a mark that represents a piece that either matches, or eventually matches, the piece designator associated with that tag. Square information associated with that piece designator is ignored.

At most two tags may be contained inside a match list. Tags may not be used in a matchlist if a :relation occurs in a position list inside that match list.

:tagmatch in the position list

A :tagmatch keyword in a position list takes two parameters, the name of a tag and a piece designator. The position list match fails on the current position if the piece and square corresponding to the mark of the tag does not match the given piece designator. For example, assuming there is a tag named "foo", this position will only match if
"foo" is a white pawn:

(position :tagmatch foo P)

Piece designators and tags

A piece designator can have a piecetype designator that is the name of a tag preceded by the character '$'. Such a piecetype represents the particular piece represented by the
named tag. Because tag names are alphanumeric, square designators in such a piece designator must be enclosed in brackets.
Example:

(position $foo[a1,d4])

The piece represented by the tag named "foo" must be on a1 or d4.

Longer example

Consider the problem of recognizing all studies or games in which the same rook visits all four corners of the board. This is shown in the file rookcorners.cql, and is reproduced here:

; Find all games in which the same rook visits all four corners of the board.
(match
:pgn heijden.pgn
:output out.pgn
:forany rook [rR] ; loop over the possible rooks
(position $rook[a1])
(position $rook[h1])
(position $rook[h8])
(position $rook[a8])
)

Here, the :forany keyword in the match list introduces a tag named rook which is constrained to range over white or black rooks, or over pawns that
eventually promote to one of those.

The first position list matches games in which there is a position such that the tag rook represents a rook on a1. The next position list matches games
in which there is a postiion such that the tag represents a rook on h1. The tag represents the same mark, that is, the same piece, between the position lists.
The :forany keyword will sequentially bind the tag to each allowed mark.

Since a match list matches a game only if all its constituent position filters match it, the code does what we want here.