TQL-Grammatik und EBNF-Notation

Die Tosca Query Language (TQL) ist eine formale Sprache. Such-Abfragen müssen also mithilfe einer formalen Grammatik gebildet werden, um vom System verstanden zu werden.

Der Aufbau besteht aus sogenannten Nonterminalen und Terminalen. Nonterminale sind Ausdrücke, die wiederum durch andere Ausdrücke (Nonterminale oder Terminale) ersetzt werden können.

Terminale stellen atomare Elemente dar und können nicht durch andere Ausdrücke ersetzt werden. Eine korrekte Query, die von TQL verstanden wird, muss aus einer Folge von Terminalen bestehen. Um also einen gültigen Suchausdruck erstellen zu können, werden sukzessive alle Nonterminale so ersetzt, dass am Ende der gewünschte Suchausdruck, bestehend aus Terminalen, herauskommt.

Für die Beschreibung der Grammatik der TQL wird die EBNF-Notation verwendet (siehe Kapitel "EBNF-Notation").

EBNF-Notation

EBNF-Notation

|

logisches ODER
Beispiel:

a | b = a oder b

[...]

Eckige Klammern stellen eine Option dar.

Der Ausdruck kann n-mal vorkommen: n = 0, 1

(...)

Runde Klammern dienen der Gruppierung von Ausdrücken.
Der Inhalt muss genau einmal verwendet werden.

Beispiel:

(a | b) c = a und c oder b und c

im Gegensatz zu

a | b c = a oder b und c

{...}

Geschwungene Klammern stellen eine Iteration dar.

Der Ausdruck kann n-mal vorkommen: n = 0, 1, 2, 3,...

Beispiel:

a {b} = a oder a und b oder a und b und b...

'...'

Kennzeichnet Text, der wörtlich zu nehmen ist (Terminale).

Beispiel:

'SUBPARTS'

Hilfreich ist hierbei, dass Nonterminale in TQL immer mit einem Kleinbuchstaben beginnen. Terminale sind entweder ein Sonderzeichen (z.B.: „]“ , „)“, „:“ ), oder beginnen mit einem Großbuchstaben.

TQL-Grammatik

Eine Grammatik besteht aus so genannten Produktionen. Dabei handelt es sich um Regeln, mit denen Nonterminale durch andere Nonterminale und Terminale ersetzt werden können. Eine Abfrage muss aus einer Folge von Terminalen bestehen. Um einen gültigen Suchausdruck zu bilden, müssen alle Nonterminale durch Terminale ersetzt werden:

query: = {arrowOperator [returnToken] searchExpression}

Die oben angegebene Produktion besteht aus den Nonterminalen query, arrowOperator, returnToken und searchExpression (Anmerkung: alle beginnen mit einem Kleinbuchstaben). Der returnToken ist optional und arrowOperator [returnToken] searchExpression kann, wegen der geschwungenen Klammern, beliebig oft aneinander gereiht werden.

Eine Grammatik besteht aus einer Menge von Produktionen, die von oben nach unten abgearbeitet werden. Man beginnt mit einem Startsymbol bestehend aus einem Nonterminal und ersetzt dieses solange, bis eine Such-Query bestehend aus Terminalen übrig bleibt.

Vollständige TQL-Grammatik

Startsymbol : query

query

::= { arrowOperator [ returnToken ] searchExpression }

 

searchExpression

::= ( assocName | aggregation | specialAssocName | setOperation | subsetOperation | sortOperation | objectsSelector ) [ colonToken type ] [ leftSquareBracket logicalExpression rightSpareBracket ]

 

logicalExpression

::= ( notToken logicalExpression ) | leftParenthesis logicalExpression rightParenthesis | comparisionExpression { logicalOperator logicalExpression }

 

comparisonExpression

::= expression compOperator expression

 

expression

::= term {addOperator term}

Dieser Term kann durch ein stringLiteral, intLiteral, ein Attribut oder einen Wert ersetzt werden

term

::= factor {mulOperator factor}

 

factor

::= leftParenthesis expression rightParenthesis | functionStatement | value

 

functionStatement

::= functionName leftParenthesis [ expression { comma expression } ] rightParenthesis

 

value

::= stringLiteral| intLiteral| attribute

 

attribut

::= {assocName pointToken} identifier

 

assocName

::= identifier

Der assocName wird durch einen Bezeichner (identifier) ersetzt

type

::= identifier

Durch die Angabe des Typs, wird festgelegt nach welchem Objekt in der entsprechenden Query gesucht werden soll.

stringLiteral

::= doublequote TEXT doublequote

TEXT stellt einen Platzhalter für beliebige Zeichenfolgen dar. Für Sonderzeichen muss ein umgekehrter Schrägstrich (Backslash) als Escape-Zeichen verwendet werden. Mehrere Sonderzeichen im Text können übernommen werden, indem die Zeichenkette durch Hochkomma ['] begrenzt wird.

intLiteral

::= [ "+" | "-" ] DIGITS

 

uintLiteral

::= DIGITS

 

identifier

::= (LETTER | "_") {LETTER | DIGIT | "_"} | quote TEXT quote

 

aggregation

::= "SUBPARTS" | "SUPERPART" | "SELF" | "PROJECT"

 

specialAssocName

::= "AllReferences" | "OwningObject"

 

setOperation

::= setFunction leftParenthesis search {comma search}] rightParenthesis

 

setFunction

::= "COMPLEMENT" | "UNION" | "INTERSECTION"

 

sortOperation

::= sortFunction leftParenthesis search {comma stringLiteral}] rightParenthesis

 

sortFunction

::= "SORT"

 

objectsSelector

::= "OBJECTS" leftParenthesis uniqueIdOrNodePath {comma uniqueIdOrNodePath}] rightParenthesis

 

uniqueIdOrNodePath

::= uniqueIdString | nodePathString

 

uniqueIdString

::= stringLiteral

 

nodePathString

::= stringLiteral

 

subsetOperation

::= "SUBSET" leftParenthesis intLiteral [comma uintLiteral]] rightParenthesis

 

arrowOperator

:= "=>" | "->"

 

compOperator

::= "==" | "!=" | "=i=" | "!i=" | ">" | "<" | ">=" | "<=" | "=?" | "=i?" | "!?" | "!i?" | // LIKE "=*" // LIKE (old version) "=~" | "=i~" // REGEX

compOperatoren werden verwendet, um zwei Ausdrücke miteinander zu verknüpfen und einen logischen Wert (true, false) zu ermitteln.

logicalOperator

::= "AND" | "OR"

conjunction, disjunction

addOperator

::= "+" | "-"

 

mulOperator

::= "*" | "/"

 

returnToken

::= "RETURN"

 

notToken

::= "NOT"

mit dem notToken ist es möglich, einen logischen Ausdruck zu negieren

pointToken

::= "."

 

colonToken

::= ":"

 

leftSquareBracket

::= "["

stellt eine öffnende, eckige Klammer dar

rightSquareBracket

::= "]"

stellt eine schließende, eckige Klammer dar

leftParenthesis

::= "("

stellt eine öffnende, runde Klammer dar

rightParenthesis

::= ")"

stellt eine schließende, runde Klammer dar

comma

::= ","

 

quota

::= "'"

 

doubleQuote

::= "“"

 

quantifierOperator

::= '<ANY>'

gibt alle Objekte zurück, in denen der angegebene Wert vorkommt.