# Expression Template Language

The formal syntax for SNOMED CT expression templates (v1.1.1) is shown below. This syntax is derived by combining:

* Compositional Grammar v2.4,
* Template Syntax v1.1.1, and
* Expression Constraint Language v1.4.

As explained in [SNOMED CT Language Templates](https://docs.snomed.org/snomed-ct-specifications/snomed-ct-template-syntax-specification/6-snomed-ct-language-templates), references to the Template Syntax are also added into the Compositional Grammar rules to enable slots to be included within an expression template. Please note that rules that appear in both Compositional Grammar and the Expression Constraint Language (e.g. conceptId and term) are removed from the Expression Constraint Language (by commenting out) to avoid duplication.

```abnf
; Compositional Grammar v2.4 with slot references (in blue)
expressionTemplate = ws [ ( definitionStatus / tokenReplacementSlot) ws] subExpression ws
subExpression = focusConcept [ws ":" ws refinement]
definitionStatus = equivalentTo / subtypeOf
equivalentTo = "==="
subtypeOf = "<<<"
focusConcept = [templateInformationSlot ws] conceptReference *(ws "+" ws [templateInformationSlot ws] conceptReference)
conceptReference = conceptReplacementSlot / expressionReplacementSlot / ( conceptId [ws "|" ws term ws "|"] )
conceptId = sctId
term = nonwsNonPipe *( *SP nonwsNonPipe )
refinement = (attributeSet / attributeGroup) *( ws ["," ws] attributeGroup )
attributeGroup = [ templateInformationSlot ws ] "{" ws attributeSet ws "}"
attributeSet = attribute *(ws "," ws attribute)
attribute = [ templateInformationSlot ws ] attributeName ws "=" ws attributeValue
attributeName = conceptReference
attributeValue = expressionValue / QM stringValue QM / "#" numericValue / booleanValue / concreteValueReplacementSlot
expressionValue = conceptReference / "(" ws subExpression ws ")"
stringValue = 1*(anyNonEscapedChar / escapedChar)
numericValue = ["-"/"+"] (decimalValue / integerValue)
integerValue = digitNonZero *digit / zero
decimalValue = integerValue "." 1*digit
booleanValue = true / false
true = ("t"/"T") ("r"/"R") ("u"/"U") ("e"/"E")
false = ("f"/"F") ("a"/"A") ("l"/"L") ("s"/"S") ("e"/"E")
sctId = digitNonZero 5*17( digit )
ws = *( SP / HTAB / CR / LF ) ; optional white space
SP = %x20 ; space
HTAB = %x09 ; tab
CR = %x0D ; carriage return
LF = %x0A ; line feed
QM = %x22 ; quotation mark
BS = %x5C ; back slash
digit = %x30-39
zero = %x30
digitNonZero = %x31-39
nonwsNonPipe = %x21-7B / %x7D-7E / UTF8-2 / UTF8-3 / UTF8-4
anyNonEscapedChar = HTAB / CR / LF / %x20-21 / %x23-5B / %x5D-7E / UTF8-2 / UTF8-3 / UTF8-4
escapedChar = BS QM / BS BS
UTF8-2 = %xC2-DF UTF8-tail
UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) / %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) / %xF4 %x80-8F 2( UTF8-tail )
UTF8-tail = %x80-BF
; Template Syntax v1.1
templateSlot = templateReplacementSlot / templateInformationSlot
templateReplacementSlot = conceptReplacementSlot / expressionReplacementSlot / tokenReplacementSlot / concreteValueReplacementSlot
conceptReplacementSlot = "[[" ws "+" ws conceptReplacement [slotName ws] "]]"
expressionReplacementSlot = "[[" ws "+" ws expressionReplacement [slotName ws] "]]"
tokenReplacementSlot = "[[" ws "+" ws tokenReplacement [slotName ws] "]]"
concreteValueReplacementSlot = "[[" ws "+" ws concreteValueReplacement [slotName ws] "]]"
conceptReplacement = "id" ws [ "(" ws slotExpressionConstraint ws ")" ws]
expressionReplacement = ["scg" ws] ["(" ws slotExpressionConstraint ws ")" ws]
tokenReplacement = "tok" ws [ "(" ws slotTokenSet ws ")" ws]
concreteValueReplacement = stringReplacement / integerReplacement / decimalReplacement / booleanReplacement
stringReplacement = "str" ws [ "(" ws slotStringSet ws ")" ws]
integerReplacement = "int" ws [ "(" ws slotIntegerSet ws ")" ws]
decimalReplacement = "dec" ws [ "(" ws slotDecimalSet ws ")" ws]
booleanReplacement = "bool" ws [ "(" ws slotBooleanSet ws ")" ws]
slotTokenSet = slotToken *(mws slotToken)
slotStringSet = slotStringValue *(mws slotStringValue)
slotStringValue = QM stringValue QM
slotIntegerSet = ( slotIntegerValue / slotIntegerRange) *(mws (slotIntegerValue / slotIntegerRange))
slotDecimalSet = ( slotDecimalValue / slotDecimalRange) *(mws (slotDecimalValue / slotDecimalRange))
slotBooleanSet = slotBooleanValue *(mws slotBooleanValue)
slotBooleanValue = booleanValue
slotIntegerRange = ( slotIntegerMinimum to [ slotIntegerMaximum ] ) / ( to slotIntegerMaximum )
slotIntegerMinimum = [ exclusiveMinimum ] slotIntegerValue
slotIntegerMaximum = [ exclusiveMaximum ] slotIntegerValue
slotIntegerValue = "#" ["-"/"+"] integerValue
slotDecimalRange = ( slotDecimalMinimum to [ slotDecimalMaximum ] ) / ( to slotDecimalMaximum )
slotDecimalMinimum = [ exclusiveMinimum ] slotDecimalValue
slotDecimalMaximum = [ exclusiveMaximum ] slotDecimalValue
slotDecimalValue = "#" ["-"/"+"] decimalValue
exclusiveMinimum = ">"
exclusiveMaximum = "<"
slotName = "@" (slotStringValue / nonQuoteStringValue)
slotToken = definitionStatus / memberOf / constraintOperator / conjunction / disjunction / exclusion / reverseFlag / expressionComparisonOperator / numericComparisonOperator / stringComparisonOperator /booleanComparisonOperator
nonQuoteStringValue = *(%x21 / %x23-26 / %x2A-3F / %x41-5A / %x5C / %x5E-7E) ; string with no ws, quotes, at, square brackets or round brackets
templateInformationSlot = "[[" ws slotInformation ws "]]"
slotInformation = [cardinality ws] [slotName ws]
; Expression Constraint Language v1.4
slotExpressionConstraint = ws ( slotRefinedExpressionConstraint / slotCompoundExpressionConstraint / slotDottedExpressionConstraint / slotSubExpressionConstraint ) ws
slotRefinedExpressionConstraint = slotSubExpressionConstraint ws ":" ws slotEclRefinement
slotCompoundExpressionConstraint = slotConjunctionExpressionConstraint / slotDisjunctionExpressionConstraint / slotExclusionExpressionConstraint
slotConjunctionExpressionConstraint = slotSubExpressionConstraint 1*(ws conjunction ws slotSubExpressionConstraint)
slotDisjunctionExpressionConstraint = slotSubExpressionConstraint 1*(ws disjunction ws slotSubExpressionConstraint)
slotExclusionExpressionConstraint = slotSubExpressionConstraint ws exclusion ws slotSubExpressionConstraint
slotDottedExpressionConstraint = slotSubExpressionConstraint 1*(ws slotDottedExpressionAttribute)
slotDottedExpressionAttribute = dot ws slotEclAttributeName
slotSubExpressionConstraint = [constraintOperator ws] [memberOf ws] (slotEclFocusConcept / "(" ws slotExpressionConstraint ws ")")
slotEclFocusConcept = slotEclConceptReference / wildCard
dot = "."
memberOf = "^"
slotEclConceptReference = conceptId [ws "|" ws term ws "|"]
; conceptId = sctId
; term = 1nonwsNonPipe ( 1SP 1nonwsNonPipe )
wildcard = "*"
constraintOperator = childOf / descendantOrSelfOf / descendantOf / parentOf / ancestorOrSelfOf / ancestorOf
descendantOf = "<"
descendantOrSelfOf = "<<"
childOf = "<!"
ancestorOf = ">"
ancestorOrSelfOf = ">>"
parentOf = ">!"
conjunction = (("a"/"A") ("n"/"N") ("d"/"D") mws) / ","
disjunction = ("o"/"O") ("r"/"R") mws
exclusion = ("m"/"M") ("i"/"I") ("n"/"N") ("u"/"U") ("s"/"S") mws
slotEclRefinement = slotSubRefinement ws [slotConjunctionRefinementSet / slotDisjunctionRefinementSet]
slotConjunctionRefinementSet = 1*(ws conjunction ws slotSubRefinement)
slotDisjunctionRefinementSet = 1*(ws disjunction ws slotSubRefinement)
slotSubRefinement = slotEclAttributeSet / slotEclAttributeGroup / "(" ws slotEclRefinement ws ")"
slotEclAttributeSet = slotSubAttributeSet ws [slotConjunctionAttributeSet / slotDisjunctionAttributeSet]
slotConjunctionAttributeSet = 1*(ws conjunction ws slotSubAttributeSet)
slotDisjunctionAttributeSet = 1*(ws disjunction ws slotSubAttributeSet)
slotSubAttributeSet = slotEclAttribute / "(" ws slotEclAttributeSet ws ")"
slotEclAttributeGroup = ["[" cardinality "]" ws] "{" ws slotEclAttributeSet ws "}"
slotEclAttribute = ["[" cardinality "]" ws] [reverseFlag ws] slotEclAttributeName ws (expressionComparisonOperator ws slotSubExpressionConstraint / numericComparisonOperator ws (slotIntegerValue /slotDecimalValue) / stringComparisonOperator ws slotStringValue / booleanComparisonOperator ws slotBooleanValue)
cardinality = minValue to maxValue
minValue = nonNegativeIntegerValue
to = ".."
maxValue = nonNegativeIntegerValue / many
many = "*"
reverseFlag = "R"
slotEclAttributeName = slotSubExpressionConstraint
expressionComparisonOperator = "=" / "!="
numericComparisonOperator = "=" / "!=" / "<=" / "<" / ">=" / ">"
stringComparisonOperator = "=" / "!="
booleanComparisonOperator = "=" / "!="
; stringValue = 1*(anyNonEscapedChar / escapedChar)
; integerValue = digitNonZero *digit / zero
; decimalValue = integerValue "." 1*digit
; booleanValue = true / false
; true = ("t"/"T") ("r"/"R") ("u"/"U") ("e"/"E")
; false = ("f"/"F") ("a"/"A") ("l"/"L") ("s"/"S") ("e"/"E")
nonNegativeIntegerValue = (digitNonZero *digit ) / zero
; sctId = digitNonZero 5*17( digit )
; ws = *( SP / HTAB / CR / LF / comment ) ; optional white space
mws = 1*( SP / HTAB / CR / LF / comment ) ; mandatory white space
comment = "/*" (nonStarChar / starWithNonFSlash) "/"
nonStarChar = SP / HTAB / CR / LF / %x21-29 / %x2B-7E /UTF8-2 / UTF8-3 / UTF8-4
starWithNonFSlash = %x2A nonFSlash
nonFSlash = SP / HTAB / CR / LF / %x21-2E / %x30-7E /UTF8-2 / UTF8-3 / UTF8-4
; SP = %x20 ; space
; HTAB = %x09 ; tab
; CR = %x0D ; carriage return
; LF = %x0A ; line feed
; QM = %x22 ; quotation mark
; BS = %x5C ; back slash
; digit = %x30-39
; zero = %x30
; digitNonZero = %x31-39
; nonwsNonPipe = %x21-7B / %x7D-7E / UTF8-2 / UTF8-3 / UTF8-4
; anyNonEscapedChar = SP / HTAB / CR / LF / %x20-21 / %x23-5B / %x5D-7E / UTF8-2 / UTF8-3 / UTF8-4
; escapedChar = BS QM / BS BS
; UTF8-2 = %xC2-DF UTF8-tail
; UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) / %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
; UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) / %xF4 %x80-8F 2( UTF8-tail )
; UTF8-tail = %x80-BF
```

<a href="https://docs.google.com/forms/d/e/1FAIpQLScTmbZIf0UEQwYDkY27EEWBkaiYkHSbR0_9DmFrMLXoQLyL7Q/viewform?usp=pp_url&#x26;entry.1767247133=SNOMED+Template+Syntax+Specification&#x26;entry.670899847=Expression%20Template%20Language" class="button primary">Provide Feedback</a>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.snomed.org/snomed-ct-specifications/snomed-ct-template-syntax-specification/6-snomed-ct-language-templates/6.1-expression-template-language.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
