• Keine Ergebnisse gefunden

Visibility, Names and Identifiers

Im Dokument Formal Semantics for SDL (Seite 88-92)

Part 4: RSDL Formal Definition

4.3 Static Semantics

4.3.2 Visibility, Names and Identifiers

This section introduces all formalisations for resolution of names, visibility rules and identifiers.

4.3.2.1 Name

Abstract Syntax

Name :: TOKEN

Agent-type-name = Name

Agent-name = Name

State-name = Name

Signal-name = Name

Literal-name = Name

Operation-name = Name

Timer-name = Name

Gate-name = Name

Connector-name = Name

Channel-name = Name

Variable-name = Name

Sort-name = Name

Concrete Syntax

<name> :: TOKEN

<literal> = <literal name>

<literal name> = <name>

<sort> = <basic sort>

<basic sort> = <name>

Mapping to Abstract Syntax

| <name>(x) => mk-Name(x)

Please note that TOKEN is present in both AS0 and AS1 such that it need not be mapped.

4.3.2.2 Identifier

Abstract Syntax

Identifier :: Qualifier Name

Qualifier = Path-item*

Agent-identifier = Identifier

Agent-type-identifier = Identifier

Signal-identifier = Identifier

Timer-identifier = Identifier

Gate-identifier = Identifier

Variable-identifier = Identifier

Concrete Syntax

<identifier> :: [<qualifier>] <name>

<qualifier> :: {<path item>}+

Auxiliary Functions

For identifiers a lot of auxiliary functions are defined. They all serve for formalising the resolution, visibility and the insertion of full qualifiers. Please find below the definitions for the AS0 and AS1 grammars.

ENTITYKIND =def

{ agentKind, agentTypeKind, channelKind, signalKind, variableKind, remoteVariableKind }

The following entity kinds exist: agents (blocks); agent types (block types); channels, gates; signals, timers;

variables (including formal parameters), literals, data types; remote variables;

fullIdentifier(i:<identifier>): <identifier> =def i.refersto0.myfullIdentifier The full identifier of an identifier is the full identifier of its defining entity.

fullPath(x: DefinitionAS0): <path item>* =def if x = undefined then empty

elseif x ∈ <rsdl specification> then empty elseif x ∈ <block type definition> then

fullPath(x.parentAS0) < <path item>(blocktype, x.s-<block type heading>.s-<name>) >

else fullPath(x.parentAS0) endif

The full path of a definition is constructed recursively. Please note that only types may contain definitions, as instances have been transformed before.

myfullIdentifier(x: DefinitionAS0): <identifier> =def <identifier>(x.fullPath, x.defName)

The full identifier of a definition is constructed using its full path and its name.

myFullIdentifierAS1(d: DefinitionAS1): DefinitionAS1 =def

d.inv-Mapping.myfullIdentifier.Mapping

The full identifier function for the AS1 is derived from that of the AS0.

resolutionByContainer(i:<identifier>, k:ENTITYKIND, s:DefinitionAS0):DefinitionAS0 =def

if s = undefined then undefined else let matchingDefs =

{ d ∈ DefinitionAS0: d.parentAS0.findScopeUnit = s ∧ i.s-<name> = d.defName ∧ matchingQualifier(i.s-<qualifier>, d.myfullIdentifier.s-<qualifier>)} in if | matchingDefs | = 1 then matchingDefs.take

else resolutionByContainer(i, k, s.parentAS0.findScopeUnit) endif

endif

The binding of a <name> to a definition through resolution by container proceeds in the following steps, starting in the scope unit where the <identifier> appears:

1. if a unique entity exists in the current scope unit with the same <name> and entity kind and matching

<qualifier>s, the <name> is bound to that entity; otherwise

2. resolution by container is attempted in the scope unit which defines the current scope unit.

matchingQualifier(q1: <qualifier>, q2: <qualifier>): BOOLEAN =def

if q1 = q2 then True

elseif q1 = undefined then True

elseif q1.length < q2.length then matchingQualifier(q1, q2.tail)

else matchingPathItem(q1.head, q2.head) ∧ matchingQualifier(q1.tail, q2.tail) endif

The definition above defines when two qualifiers are matching.

refersto0(i: <identifier>): DefinitionAS0 =def

if i.parentAS0 ∈ <typebased block heading> then

resolutionByContainer(i, agentTypeKind, i.parentAS0.findScopeUnit) elseif i.parentAS0 ∈ (<gate constraint> ∪ <channel path>) then

if resolutionByContainer(i, signalKind, i.parentAS0.findScopeUnit) ≠ undefined then resolutionByContainer(i, signalKind, i.parentAS0.findScopeUnit)

else resolutionByContainer(i, remoteVariableKind, i.parentAS0.findScopeUnit) endif

elseif i.parentAS0 ∈ <channel endpoint> then

resolutionByContainer(i, agentKind, i.parentAS0.findScopeUnit) elseif i.parentAS0 ∈ <channel to channel connection> then

resolutionByContainer(i, channelKind, i.parentAS0.findScopeUnit)

elseif i.parentAS0 ∈ <save part> then

resolutionByContainer(i, signalKind, i.parentAS0.findScopeUnit) elseif i.parentAS0 ∈ (<stimulus> ∪ <output body gen identifier>) then

resolutionByContainer(i, signalKind, i.parentAS0.findScopeUnit) elseif i.parentAS0 ∈ <assignment> then

resolutionByContainer(i, variableKind, i.parentAS0.findScopeUnit) elseif i.parentAS0 ∈ <create request> then

resolutionByContainer(i, agentKind, i.parentAS0.findScopeUnit)

elseif i.parentAS0 ∈ <import> ∧ i.parentAS0.s-<identifier> = i then // it is the variable identifier resolutionByContainer(i, variableKind, i.parentAS0.findScopeUnit)

elseif i.parentAS0 ∈ <import> then

resolutionByContainer(i, remoteVariableKind, i.parentAS0.findScopeUnit) elseif i.parentAS0 ∈ <export> then

resolutionByContainer(i, remoteVariableKind, i.parentAS0.findScopeUnit)

elseif i.parentAS0 ∈ (<set clause> ∪ <reset clause> ∪ <timer active expression>) then resolutionByContainer(i, signalKind, i.parentAS0.findScopeUnit)

elseif i.parentAS0 ∈ <operand5> then

if resolutionByContainer(i, variableKind, i.parentAS0.findScopeUnit) ≠ undefined then resolutionByContainer(i, variableKind, i.parentAS0.findScopeUnit)

elseif i.s-<qualifier> = undefined then // it is only a <name>

predefined else undefined endif

else undefined endif

The definition above lists all places where <identifier>s appear in AS0 constructors and how to resolve them using the resolution by container. Please note the special handling for <gate constraint> and <channel path>

which refers to the following text in the language definition.

A <signal list item> which is an <identifier> denotes a <signal identifier> or <timer identifier> if this is possible according to the visibility rules or else a <remote variable identifier>.

Please note that the visibility rules are already covered by the definition of the resolution by context.

refersto1(i: Identifier): DefinitionAS1 =def

i.inv-Mapping.refersto0.Mapping

The identifier reference function for the AS1 is derived from that of the AS0.

referstoName1(n: Name): DefinitionAS1 =def

if n.parentAS1∈ Nextstate-node then let candidateStates =

{ s ∈ parentAS1ofKind(n, State-transition-graph).s-State-node-set: s.s-State-name = n } in if | candidateStates | = 1 then candidateStates.take else undefined endif

elseif n.parentAS1∈ Join-node then let candidateLabels =

{ s ∈ parentAS1ofKind(n, State-transition-graph).s-Free-action-set:

s.s-Connector-name = n } in

if | candidateLabels | = 1 then candidateLabels.take else undefined endif endlet

else undefined endif

The definition above shows how single names are resolved. Recall, that in some places no identifiers are allowed but only names, namely for states or connectors.

sortCompatible(t1: <sort>, t2: <sort>): BOOLEAN =def t1 = t2 ∧ t1 ≠ undefined

The function above defines when two sorts are compatible. Due to the limited data type part an equality is sufficient.

exprSort(e: Expression): DefinitionAS1 =def if e ∈ Literal then

mk-Name(literalSort(e.s-Name.s-TOKEN)) elseif e ∈ Operation-application then

mk-Name(operationSort(e.s-Operation-name.s-TOKEN,

< exprSort(a) | a in e.s-Expression-seq >)) elseif e ∈ Variable-access then

e.refersto1.s-Sort-name

elseif e ∈ Now-expression then mk-Name(“Time”) elseif e ∈ Pid-expression then mk-Name(“PId”)

elseif e ∈ Timer-active-expression then mk-Name(“Boolean”) else undefined

endif

The function above calculates the sort of an expression.

findScopeUnit(entity: DefinitionAS0): DefinitionAS0 =def

if entity = undefined then undefined

elseif entity ∈ (<agent type definition> ∪ <agent definition>) then entity else findScopeUnit(entity.parentAS0)

endif

The function findScopeUnit searches for the next enclosing scope unit starting from the current place.

visible(entity: DefinitionAS0, scope: DefinitionAS0): BOOLEAN =def

if scope = undefined then False

else entity.parentAS0.findScopeUnit = scope ∨ visible(entity, scope.parentAS0.findScopeUnit) endif

An entity is visible in a scope unit if: it has its defining context in that scope unit; or the entity is visible in the scope unit which defines that scope unit.

defName(d: DefinitionAS0): <name> =def

if d ∈ <block type definition> then d.s-<block type heading>.s-<name>

elseif d ∈ <block definition> then d.s-<block heading>.s-<name>

elseif d ∈ <textual typebased block definition> then d.s-<typebased block heading>.s-<name>

elseif d ∈ <channel definition> then d.s-<name>

elseif d ∈ <textual gate definition> then d.s-<gate>

elseif d ∈ <signal definition> then d.s-<signal definition item>-seq.head.s-<name>

elseif d ∈ <timer definition> then d.s-<timer definition item>-seq.head

elseif d ∈ <variable definition> then d.s-<variables of sort>-seq.head.s-<name>-seq.head elseif d ∈ <remote variable definition> then

d.s-<remote variable definition gen name>-seq.head.s-<name>-seq.head else undefined

endif

The function defName extracts the name of a definition.

getEntityKind(d: DefinitionAS0): ENTITYKIND =def

if d ∈ <agent type definition> then agentTypeKind elseif d ∈ <agent type reference> then agentTypeKind elseif d ∈ <agent definition> then agentKind

elseif d ∈ <textual typebased agent definition> then agentKind elseif d ∈ <agent reference> then agentKind

elseif d ∈ <signal definition> then signalKind elseif d ∈ <timer definition> then signalKind elseif d ∈ <variable definition> then variableKind

elseif d ∈ <remote variable definition> then remoteVariableKind elseif d ∈ <channel definition> then channelKind

elseif d ∈ <gate in definition> then channelKind else undefined

endif

Conditions on Concrete Syntax

=5=> ∀ i ∈ <identifier>: i.refersto0 ≠ undefined ∧ visible(i.refersto0, i.findScopeUnit) An entity can be referenced by using an <identifier>, if the entity is visible.

=5=>∀d, d' ∈ DefinitionAS0: getEntityKind(d) ≠ undefined ∧ getEntityKind(d) = getEntityKind(d') ⇒ myfullIdentifier(d) ≠ myfullIdentifier(d')

All entities with the same entity kind must have different Identifiers.

Transformations

i=<identifier>(q, n) provided fullIdentifier(i).s-<qualifier> ≠ q =4=> <identifier>(fullIdentifier(i).s-<qualifier>, n)

For all identifiers, the corresponding full qualifiers have to be inserted.

Mapping to Abstract Syntax

| i=<identifier>(q, name) =>

if i.refersto0 = predefined then mk-Literal(Mapping(name)) else mk-Identifier(Mapping(q), Mapping(name))

endif

| <qualifier>(q) => Mapping(q)

4.3.2.3 Path Item

Path items are mapped straightforwardly to the AS1.

Abstract Syntax

Path-item = Agent-type-qualifier | Agent-qualifier Agent-type-qualifier :: Agent-type-name

Agent-qualifier :: Agent-name

Concrete Syntax

<path item> :: <scope unit kind> <name>

<scope unit kind> = block | block type Auxiliary Functions

matchingPathItem(p1: <path item>, p2: <path item>): BOOLEAN =def

if p1.s-<scope unit kind> = block then

p1.s-<name>.newName = p2.s-<name> ∧ p2.s-<scope unit kind> = blocktype else p1 = p2

endif

The function matchingPathItem provides the comparison between path items. Please note that for path items containing agent names the implicitly introduced agent type names have to be considered.

Mapping to Abstract Syntax

| <path item>(block, n) => mk-Agent-qualifier(Mapping(n))

| <path item>(blocktype, n) => mk-Agent-type-qualifier(Mapping(n))

Im Dokument Formal Semantics for SDL (Seite 88-92)