Concrete Syntax

ExpressionInOclCS

The ExpressionInOcl symbol has been added to setup the initial environment of an expression.

ExpressionInOclCS ::= OclExpressionCS

Abstract syntax mapping

ExpressionInOclCS.ast : OclExpression

Synthesized attributes

ExpressionInOclCS.ast = OclExpressionCS.ast

Inherited attributes

The environment of the OCL expression must be defined, but what exactly needs to be in the environment depends on the  context of the OCL expression. The following rule is therefore not complete. It defines the env attribute by adding the self  variable to an empty environment, as well as a Namespace containing all elements visible from self. (In Section 12.2, "The ExpressionInOcl Type,"  the contextualClassifier will be defined for the various places where an ocl expression may occur.) In the context of a pre- or postcondition, the result variable as well as variable definitions for any named operation parameters can be added in a similar way.

OclExpressionCS.env =
    ExpressionInOclCS.contextualClassifier.namespace.getEnvironmentWithParents()
        .addElement ('self', ExpressionInOclCS.contextualClassifier, true)

OclExpressionCS

An OclExpression has several production rules, one for each subclass of OclExpression. Note that UnspecifiedValueExp is handled explicitly in OclMessageArgCS, because that is the only place where it is allowed.

  1. OclExpressionCS ::= PropertyCallExpCS
  2. OclExpressionCS ::= VariableExpCS
  3. OclExpressionCS ::= LiteralExpCS
  4. OclExpressionCS ::= LetExpCS
  5. OclExpressionCS ::= OclMessageExpCS
  6. OclExpressionCS ::= IfExpCS
Abstract syntax mapping

OclExpressionCS.ast : OclExpression

Synthesized attributes

  1. OclExpressionCS.ast = PropertyCallExpCS.ast
  2. OclExpressionCS.ast = VariableExpCS.ast
  3. OclExpressionCS.ast = LiteralExpCS.ast
  4. OclExpressionCS.ast = LetExpCS.ast
  5. OclExpressionCS.ast = OclMessageExpCS.ast
  6. OclExpressionCS.ast = IfExpCS.ast
Inherited attributes

  1.  PropertyCallExpCS.env = OclExpressionCS.env
  2.  VariableExpCS.env = OclExpressionCS.env
  3.  LiteralExpCS.env = OclExpressionCS.env
  4.  LetExpCS.env = OclExpressionCS.env
  5.  OclMessageExpCS.env = OclExpressionCS.env
  6.  IfExpCS.env = OclExpressionCS.env
Disambiguating rules

The disambiguating rules are defined in the children.

VariableExpCS

A variable expression is just a name that refers to a variable.

VariableExpCS ::= simpleNameCS

Abstract syntax mapping

VariableExpCS.ast : VariableExpression

Synthesized attributes

VariableExpCS.ast.referredVariable =
    env.lookup(simpleNameCS.ast).referredElement.oclAsType(VariableDeclaration)


Inherited attributes

-- none

Disambiguating rules

  1. simpleName must be a name of a visible VariableDeclaration in the current environment.

  2. env.lookup (simpleNameCS.ast).referredElement.oclIsKindOf (VariableDeclaration)

simpleNameCS

This production rule represents a single name. No special rules are applicable. The exact syntax of a String is undefined  in UML 1.4, and remains undefined in OCL 2.0. The reason for this is internationalization.

simpleNameCS ::= <String>

Abstract syntax mapping

simpleNameGr.ast : String

Synthesized attributes

simpleNameGr.ast = <String>

Inherited attributes

-- none

Disambiguating rules

-- none

pathNameCS

This rule represents a path name, which is held in its ast as a sequence of Strings.

pathNameCS ::= simpleNameCS ('::' pathNameCS )?

Abstract syntax mapping

pathNameCS.ast : Sequence(String)

Synthesized attributes

pathNameCS.ast = Sequence{simpleNameCS.ast}->union(pathNameCS.ast)

Inherited attributes

-- none

Disambiguating rules


-- none

LiteralExpCS

This rule represents literal expressions.

  1.   LiteralExpCS ::= EnumLiteralExpCS
  2.  LiteralExpCS ::= CollectionLiteralExpCS
  3.  LiteralExpCS ::= TupleLiteralExpCS
  4.  LiteralExpCS ::= PrimitiveLiteralExpCS
Abstract syntax mapping

LiteralExpCS.ast : LiteralExp

Synthesized attributes

  1.   LiteralExpCS.ast = EnumLiteralExpCS.ast
  2.  LiteralExpCS.ast = CollectionLiteralExpCS.ast
  3.  LiteralExpCS.ast = TupleLiteralExpCS.ast
  4.  LiteralExpCS.ast = PrimitiveLiteralExpCS.ast
Inherited attributes

  1.   EnumLiteralExpCS.env = LiteralExpCS.env
  2.   CollectionLiteralExpCS.env = LiteralExpCS.env
  3.   TupleLiteralExpCS.env = LiteralExpCS.env
  4.   PrimitiveLiteralExpCS.env = LiteralExpCS.env

Disambiguating rules

-- none

EnumLiteralExpCS

The rule represents Enumeration Literal expressions.

EnumLiteralExpCS ::= pathNameCS '::' simpleNameCS

Abstract syntax mapping

EnumLiteralExpCS.ast : EnumLiteralExp

Synthesized attributes

EnumLiteralExpCS.ast.type =
    env.lookupPathName (pathNameCS.ast).referredElement.oclAsType (Classifier)
EnumLiteralExpCS.ast.referredEnumLiteral =
    EnumLiteralExpCS.ast.type.oclAsType (Enumeration).literal->
        select (l | l.name = simpleNameCS.ast )->any(true)

Inherited attributes

-- none

Disambiguating rules

  1.  The specified name must indeed reference an enumeration:

  2. not EnumLiteralExpCS.ast.type.oclIsUndefined() and
    EnumLiteralExpCS.ast.type.oclIsKindOf (Enumeration)

CollectionLiteralExpCS

This rule represents a collection literal expression.

CollectionLiteralExpCS ::= CollectionTypeIdentifierCS
`{` CollectionLiteralPartsCS? `}'

Abstract syntax mapping

CollectionLiteralExpCS.ast : CollectionLiteralExp

Synthesized attributes

CollectionLiteralExpCS.ast.parts = CollectionLiteralPartsCS.ast
CollectionLiteralExpCS.ast.kind = CollectionTypeIdentifierCS.ast

Inherited attributes

CollectionTypeIdentifierCS.env = CollectionLiteralExpCS.env
CollectionLiteralPartsCS.env = CollectionLiteralExpCS.env

Disambiguating rules

  1.  In a literal the collectiuon type may not be Collection

  2. CollectionTypeIdentifierCS.ast <> 'Collection'

CollectionTypeIdentifierCS

This rule represent the type indentifier in a collection literal expression. The Collection type is an abstract type on M1 level, so it has no corresponding literals.

  1.   CollectionTypeIdentifierCS ::= 'Set'
  2.  CollectionTypeIdentifierCS ::= 'Bag'
  3.  CollectionTypeIdentifierCS ::= 'Sequence'
  4.  CollectionTypeIdentifierCS ::= 'Collection'
  5.  CollectionTypeIdentifierCS ::= 'OrderedSet'
Abstract syntax mapping

CollectionTypeIdentifierCS.ast : CollectionKind

Synthesized attributes

  1. CollectionTypeIdentifierCS.ast = CollectionKind::Set
  2. CollectionTypeIdentifierCS.ast = CollectionKind::Bag
  3. CollectionTypeIdentifierCS.ast = CollectionKind::Sequence
  4. CollectionTypeIdentifierCS.ast = CollectionKind::Collection
  5. CollectionTypeIdentifierCS.ast = CollectionKind::OrderedSet
Inherited attributes

-- none

Disambiguating rules

-- none

CollectionLiteralPartsCS

This production rule describes a sequence of items that are the contents of a collection literal.

CollectionLiteralPartsCS[1] = CollectionLiteralPartCS
    ( ',' CollectionLiteralPartsCS[2] )?

Abstract syntax mapping

CollectionLiteralPartsCS[1].ast : Sequence(CollectionLiteralPart)

Synthesized attributes

CollectionLiteralPartsCS[1].ast =
    Sequence{CollectionLiteralPartCS.ast}->union(CollectionLiteralPartsCS[2].ast)

Inherited attributes

CollectionLiteralPartCS.env = CollectionLiteralPartsCS[1].env
CollectionLiteralPartSCS[2].env = CollectionLiteralPartsCS[1].env

Disambiguating rules

-- none

CollectionLiteralPartCS

  1.   CollectionLiteralPartCS ::= CollectionRangeCS
  2.  CollectionLiteralPartCS ::= OclExpressionCS
Abstract syntax mapping

CollectionLiteralPartCS.ast : CollectionLiteralPart

Synthesized attributes

  1.   CollectionLiteralPartCS.ast = CollectionRange.ast
  2.  CollectionLiteralPartCS.ast.oclIsKindOf(CollectionItem) and        CollectionLiteralPartCS.ast.oclAsType(CollectionItem).OclExpression =
            OclExpressionCS.ast

Inherited attributes

 CollectionRangeCS.env = CollectionLiteralPartCS.env
 OclExpressionCS.env = CollectionLiteralPartCS.env

Disambiguating rules

-- none

CollectionRangeCS

CollectionRangeCS ::= OclExpressionCS[1] '..' OclExpressionCS[2]

Abstract syntax mapping

CollectionRangeCS.ast : CollectionRange

Synthesized attributes

CollectionRangeCS.ast.first = OclExpressionCS[1].ast
CollectionRangeCS.ast.last = OclExpressionCS[2].ast


Inherited attributes

OclExpressionCS[1].env = CollectionRangeCS.env
OclExpressionCS[2].env = CollectionRangeCS.env


Disambiguating rules

-- none

PrimitiveLiteralExpCS

This includes Real, Boolean, Integer and String literals. Exprecially String literals must take internationalisation into account and might need to remain undefined in this specification.

  1.   PrimitiveLiteralExpCS ::= IntegerLiteralExpCS
  2.   PrimitiveLiteralExpCS ::= RealLiteralExpCS
  3.   PrimitiveLiteralExpCS ::= StringLiteralExpCS
  4.   PrimitiveLiteralExpCS ::= BooleanLiteralExpCS

Abstract syntax mapping

PrimitiveLiteralExpCS.ast : PrimitiveLiteralExp

Synthesized attributes

  1.   PrimitiveLiteralExpCS.ast = IntegerLiteralExpCS.ast
  2.  PrimitiveLiteralExpCS.ast = RealLiteralExpCS.ast
  3.  PrimitiveLiteralExpCS.ast = StringLiteralExpCS.ast
  4.  PrimitiveLiteralExpCS.ast = BooleanLiteralExpCS.ast
Inherited attributes

-- none

Disambiguating rules

-- none

TupleLiteralExpCS

This rule represents tuple literal expressions.

TupleLiteralExpCS ::= `Tuple' `{` variableDeclarationListCS `}'

Abstract syntax mapping

TupleLiteralExpCS.ast : TupleLiteralExp

Synthesized attributes

TupleLiteralExpCS.tuplePart = variableDeclarationListCS.ast

Inherited attributes

variableDeclarationListCS[1].env = TupleLiteralExpCS.env

Disambiguating rules

The initExpression and type of all VariableDeclarations must exist.

TupleLiteralExpCS.tuplePart->forAll( varDecl |
    varDecl.initExpression->notEmpty() and not varDecl.type.oclIsUndefined() )

IntegerLiteralExpCS

This rule represents integer literal expressions.

IntegerLiteralExpCS ::= <String>

Abstract syntax mapping

IntegerLiteralExpCS.ast : IntegerLiteralExp

Synthesized attributes

IntegerLiteralExpCS.ast.integerSymbol = <String>.toInteger()

Inherited attributes

-- none

Disambiguating rules

-- none

RealLiteralExpCS

This rule represents real literal expressions.

RealLiteralExpCS ::= <String>

Abstract syntax mapping

RealLiteralExpCS.ast : RealLiteralExp

Synthesized attributes

RealLiteralExpCS.ast.realSymbol = <String>.toReal()

Inherited attributes

-- none

Disambiguating rules

-- none

StringLiteralExpCS

This rule represents string literal expressions.

StringLiteralExpCS ::= ''' <String> '''

Abstract syntax mapping

StringLiteralExpCS.ast : StringLiteralExp

Synthesized attributes

StringLiteralExpCS.ast.symbol = <String>

Inherited attributes

-- none

Disambiguating rules

-- none

BooleanLiteralExpCS

This rule represents boolean literal expressions.

  1.   BooleanLiteralExpCS ::= 'true'
  2.   BooleanLiteralExpCS ::= 'false'

Abstract syntax mapping

BooleanLiteralExpCS.ast : BooleanLiteralExp

Synthesized attributes
  1.   BooleanLiteralExpCS.ast.booleanSymbol = true
  2.  BooleanLiteralExpCS.ast.booleanSymbol = false

Inherited attributes

-- none

Disambiguating rules

-- none

PropertyCallExpCS

This rule represents property call expressions.
  1.   PropertyCallExpCS ::= ModelPropertyCallExpCS
  2.  PropertyCallExpCS ::= LoopExpCS

Abstract syntax mapping

PropertyCallExpCS.ast : PropertyCallExp

Synthesized attributes
  1.   PropertyCallExpCS.ast = ModelPropertyCallCS.ast
  2.  PropertyCallExpCS.ast = LoopExpCS.ast

Inherited attributes
  1.   ModelPropertyCallCS.env = PropertyCallExpCS.env
  2.   LoopExpCS.env = PropertyCallExpCS.env
Disambiguating rules

The disambiguating rules are defined in the children.

LoopExpCS

This rule represents loop expressions.
  1.   LoopExpCS ::= IteratorExpCS
  2.   LoopExpCS ::= IterateExpCS
Abstract syntax mapping

LoopExpCS.ast : LoopExp

Synthesized attributes
  1.   LoopExpCS.ast = IteratorExpCS.ast
  2.  LoopExpCS.ast = IterateExpCS.ast
Inherited attributes
  1.   IteratorExpCS.env = LoopExpCS.env
  2.   IterateExpCS.env = LoopExpCS.env
Disambiguating rules

-- none

IteratorExpCS

The first alternative is a straightforward Iterator expression, with optional iterator variable. The second and third alternatives are so-called implicit collect iterators. B is for operations and C for attributes, D for navigations and E for associationclasses.

  1.   IteratorExpCS ::= OclExpressionCS[1] '->' simpleNameCS
  2.         '(' (VariableDeclarationCS[1],
                (',' VariableDeclarationCS[2])? '|' )?
                    OclExpressionCS[2]
            ')'
  3.   IteratorExpCS ::= OclExpressionCS '.' simpleNameCS '('argumentsCS?')'
  4.   IteratorExpCS ::= OclExpressionCS '.' simpleNameCS
  5.   IteratorExpCS ::= OclExpressionCS '.' simpleNameCS ('[' argumentsCS ']')?
  6.   IteratorExpCS ::= OclExpressionCS '.' simpleNameCS ('[' argumentsCS ']')?
Abstract syntax mapping

IteratorExpCS.ast : IteratorExp

Synthesized attributes

    -- the ast needs to be determined bit by bit, first the source association of IteratorExp
[A] IteratorExpCS.ast.source = OclExpressionCS[1].ast
    - next the iterator association of IteratorExp
    -- when the variable declaration is present, its ast is the iterator of this iteratorExp
    -- when the variable declaration is not present, the iterator has a default name and
    -- type
    -- In any case, the iterator does not have an init expression
[A] IteratorExpCS.ast.iterators->at(1).name = if VariableDeclarationCS[1]->isEmpty()
        then ''
        else VariableDeclarationCS[1].ast.name
        endif
[A] IteratorExpCS.ast.iterator->at(1).type =
        if VariableDeclarationCS[1]->isEmpty() or
            (VariableDeclarationCS[1]->notEmpty() and
                VariableDeclarationCS[1].ast.type.oclIsUndefined() )
        then
             OclExpressionCS[1].type.oclAsType (CollectionType).elementType
        else
             VariableDeclarationCS[1].ast.type
        endif
    -- The optional second iterator
[A] if VariableDeclarationCS[2]->isEmpty() then
        IteratorExpCS.ast.iterators->size() = 1
    else
        IteratorExpCS.ast.iterators->at(2).name = VariableDeclarationCS[2].ast.name
    and
        IteratorExpCS.ast.iterators->at(2).type =
            if VariableDeclarationCS[2]->isEmpty() or
                (VariableDeclarationCS[2]->notEmpty() and
                    VariableDeclarationCS[2].ast.type.oclIsUndefined() )
            then
                OclExpressionCS[1].type.oclAsType (CollectionType).elementType
            else
                VariableDeclarationCS[2].ast.type
            endif
    endif
[A] IteratorExpCS.ast.iterators->forAll(initExpression->isEmpty())
    -- next the name attribute and body association of the IteratorExp
[A] IteratorExpCS.ast.name = simpleNameCS.ast and
[A] IteratorExpCS.ast.body = OclExpressionCS[2].ast

    -- Alternative B is an implicit collect of an operation over a collection
[B] IteratorExpCS.ast.iterator.type =
        OclExpressionCS.ast.type.oclAsType (CollectionType).elementType
[B] IteratorExpCS.ast.source = OclExpressionCS.ast
[B] IteratorExpCS.ast.name = 'collect'
[B] -- the body of the implicit collect is the operation call referred to by 'name'
    IteratorExpCS.ast.body.oclIsKindOf (OperationCallExp) and
    let body : OperationCallExp = IteratorExpCS.ast.body.oclAsType(OperationCallExp)
    in
    body.arguments = argumentsCS.ast
    and
    body.source.oclIsKindOf(VariableExp)
    and
    body.source.oclAsType (VariableExp).referredVariable = IteratorExpCS.ast.iterator
    and
    body.referredOperation =
        OclExpressionCS.ast.type.oclAsType (CollectionType ).elementType
            .lookupOperation( simpleNameCS.ast,
                if (argumentsCS->notEmpty())
                then arguments.ast->collect(type)
                else Sequence{} endif)

    -- Alternative C/D is an implicit collect of an association or attribute over a collection
[C, D] IteratorExpCS.ast.iterator.type =
    OclExpressionCS.ast.type.oclAsType (CollectionType).elementType
[C, D] IteratorExpCS.ast.source = OclExpressionCS.ast
[C, D] IteratorExpCS.ast.name = 'collect'
[C]     -- the body of the implicit collect is the attribute referred to by 'name'
       let refAtt : Attribute = OclExpressionCS.ast.type.oclAsType (CollectionType).
                elementType.lookupAttribute( simpleNameCS.ast),
       in
            IteratorExpCS.ast.body.oclIsKindOf (AttributeCallExp) and
       let body : AttributeCallExp = IteratorExpCS.ast.body.oclAsType(AttributeCallExp)
       in
            body.source.oclIsKindOf(VariableExp)
            and
            body.source.oclAsType (VariableExp).referredVariable = IteratorExpCS.ast.iterator
            and
            body.referredAttribute = refAtt
[D] -- the body of the implicit collect is the navigation call referred to by 'name'
    let refNav : AssociationEnd = OclExpressionCS.ast.type.oclAsType (CollectionType).
        elementType.lookupAssociationEnd(simpleNameCS.ast)
    in
    IteratorExpCS.ast.body.oclIsKindOf (AssociationEndCallExp) and
    let body : AssociationEndCallExp =
                IteratorExpCS.ast.body.oclAsType(AssociationEndCallExp)
        in
        body.source.oclIsKindOf(VariableExp)
        and
        body.source.oclAsType (VariableExp).referredVariable = IteratorExpCS.ast.iterator
        and
        body.referredAssociationEnd = refNav
        and
        body.ast.qualifiers = argumentsCS.ast

[E] -- the body of the implicit collect is the navigation to the association class
    -- referred to by 'name'
    let refClass : AssociationClass =
                                            OclExpressionCS.ast.type.oclAsType (CollectionType).
    elementType.lookupAssociationClass(simpleNameCS.ast)
    in
        IteratorExpCS.ast.body.oclIsKindOf (AssociationClassCallExp) and
    let body : AssociationClassCallExp =
                IteratorExpCS.ast.body.oclAsType(AssociationClassCallExp)
    in
        body.source.oclIsKindOf(VariableExp)
        and
        body.source.oclAsType (VariableExp).referredVariable = IteratorExpCS.ast.iterator
        and
        body.referredAssociationClass = refNav
        and
        body.ast.qualifiers = argumentsCS.ast
   

Inherited attributes

[A] OclExpressionCS[1].env = IteratorExpCS.env
[A] VariableDeclarationCS.env = IteratorExpCS.env
    -- inside an iterator expression the body is evaluated with a new environment that
    -- includes the iterator variable.
[A] OclExpressionCS[2].env =
    IteratorExpCS.env.nestedEnvironment().addElement(VariableDeclarationCS.ast.varName,
            VariableDeclarationCS.ast,
                true)
[B] OclExpressionCS.env = IteratorExpCS.env
[B] argumentsCS.env = IteratorExpCS.env
[C] OclExpressionCS.env = IteratorExpCS.env
[D] OclExpressionCS.env = IteratorExpCS.env

Disambiguating rules

[1] [A] When the variable declaration is present, it may not have an init expression.
VariableDeclarationCS->notEmpty() implies
VariableDeclarationCS.ast.initExpression->isEmpty()

[2] [B] The source must be of a collection type.
OclExpressionCS.ast.type.oclIsKindOf(CollectionType)

[3] [C] The source must be of a collection type.
OclExpressionCS.ast.type.oclIsKindOf(CollectionType)

[4] [C] The referred attribute must be present.
refAtt->notEmpty()

[5] [D] The referred navifation must be present.
refNav->notEmpty()

IterateExpCS

IterateExpCS ::= OclExpressionCS[1] '->' 'iterate'
    '(' (VariableDeclarationCS[1] ';')?
        VariableDeclarationCS[2] '|'
        OclExpressionCS[2]
     ')'

Abstract syntax mapping

IterateExpCS.ast : IterateExp

Synthesized attributes

-- the ast needs to be determined bit by bit, first the source association of IterateExp
IterateExpCS.ast.source = OclExpressionCS[1].ast
-- next the iterator association of IterateExp
-- when the first variable declaration is present, its ast is the iterator of this
-- iterateExp, when the variable declaration is not present, the iterator has a default
-- name and type,
-- in any case, the iterator has an empty init expression.
IterateExpCS.ast.iterator.name = if VariableDeclarationCS[1]->isEmpty() then ''
    else VariableDeclarationCS[1].ast.name
    endif
IterateExpCS.ast.iterator.type =
    if VariableDeclarationCS[1]->isEmpty() or
        (VariableDeclarationCS[1]->notEmpty() and
            VariableDeclarationCS[1].ast.type.oclIsUndefined() )
    then
        OclExpressionCS[1].type.oclAsType (CollectionType).elementType
    else
        VariableDeclarationCS[1].ast.type
    endif
IterateExpCS.ast.iterator.initExpression->isEmpty()
-- next the name attribute and body and result association of the IterateExp
IterateExpCS.ast.result = VariableDeclarationCS[2].ast
IterateExpCS.ast.name = 'iterate'
IterateExpCS.ast.body = OclExpressionCS[2].ast

Inherited attributes

OclExpressionCS[1].env = IteratorExpCS.env
VariableDeclarationCS[1].env = IteratorExpCS.env
VariableDeclarationCS[2].env = IteratorExpCS.env
-- Inside an iterate expression the body is evaluated with a new environment that includes
-- the iterator variable and the result variable.
OclExpressionCS[2].env =
    IteratorExpCS.env.nestedEnvironment().addElement
        (VariableDeclarationCS[1].ast.varName,
            VariableDeclarationCS[1].ast,
        true).addElement
        (VariableDeclarationCS[2].ast.varName,
            VariableDeclarationCS[2].ast,
        true)

Disambiguating rules

  1.   A result variable declaration must have a type and an initial value

  2. not VariableDeclarationCS[2].ast.type.oclIsUndefined() VariableDeclarationCS[2].ast.initExpression->notEmpty()

  3. When the first variable declaration is present, it may not have an init expression.

    VariableDeclarationCS[1]->notEmpty() implies
    VariableDeclarationCS[1].ast.initExpression->isEmpty()

VariableDeclarationCS

In the variable declaration, the type and init expression are optional. When these are required, this is defined in the production rule where the variable declaration is used.

VariableDeclarationCS ::= simpleNameCS (':' typeCS)?
( '=' OclExpressionCS )?

Abstract syntax mapping

VariableDeclarationCS.ast : VariableDeclaration

Synthesised attributes

VariableDeclarationCS.ast.name = simpleNameCS.ast
VariableDeclarationCS.ast.initExpression = OclExpressionCS.ast
-- A well-formed VariableDeclaration must have a type according to the abstract syntax.
-- The value OclUndefined is used when no type has been given in the concrete syntax.
-- Production rules that use this need to check on this type.
VariableDeclarationCS.ast.type = if typeCS->notEmpty() then
    typeCS.ast
else
    OclUndefined
endif

Inherited attributes

OclExpressionCS.env = VariableDeclarationCS.env
typeCS.env = VariableDeclarationCS.env

Disambiguating rules

-- none

TypeCS

A typename is either a Classifier, or a collection of some type.
  1.   typeCS ::= pathNameCS
  2.  typeCS ::= collectionTypeCS
  3.  typeCS ::= tupleTypeCS
Abstract syntax mapping

typeCS.ast : Classifier

Synthesised attributes

  1.  typeCS.ast =typeCS.env.lookupPathName(pathNameCS.ast).referredElement.oclAsType(Classifier)
  2.  typeCS.ast = CollectionTypeCS.ast
  3.  typeCS.ast = tupleTypeCS.ast
Inherited attributes
  1.   collectionTypeCS.env = typeCS.env
  2.  tupleTypeCS.env = typeCS.env
Disambiguating rules

[1] [A] pathName must be a name of a Classifier in current environment.
typeCS.env.lookupPathName(pathNameCS.ast).referredElement.oclIsKindOf (Classifier)

collectionTypeCS

A typename is either a Classifier, or a collection of some type.

collectionTypeCS ::= collectionTypeIdentifierCS '(' typeCS ')'

Abstract syntax mapping

typeCS.ast : CollectionType

Synthesised attributes

collectionTypeCS.ast.elementType = typeCS.ast
-- We know that the 'ast' is a collectiontype, all we need to state now is which
-- specific collection type it is.
kind = CollectionKind::Set implies collectionTypeCS.ast.oclIsKindOf (SetType )
kind = CollectionKind::Sequence implies collectionTypeCS.ast.oclIsKindOf (SequenceType)
kind = CollectionKind::Bag implies collectionTypeCS.ast.oclIsKindOf (BagType )
kind = CollectionKind::Collection implies collectionTypeCS.ast.oclIsKindOf
                                        (CollectionType)
kind = CollectionKind::OrderedSet implies collectionTypeCS.ast.oclIsKindOf
                                        (OrderedSetType)

Inherited attributes

typeCS.env = collectionTypeCS.env

Disambiguating rules

-- none

tupleTypeCS

This represents a tuple type declaration.

tupleTypeCS ::= 'Tuple' '(' variableDeclarationListCS? ')'

Abstract syntax mapping

typeCS.ast : TupleType

Synthesised attributes

typeCS.ast = TupleType::make( variableDeclarationListCS->collect( v | v.asAttribute() ))

Inherited attributes

variableDeclarationListCS.env = tupleTypeCS.env

Disambiguating rules

  1.   Of all VariableDeclarations the initExpression must be empty and the type must exist.

  2. variableDeclarationListCS.ast->forAll( varDecl |
    varDecl.initExpression->notEmpty() and varDecl.type->notEmpty() )

variableDeclarationListCS

This production rule represents the formal parameters of a tuple or attribute definition.

variableDeclarationListCS[1] = VariableDeclarationCS
    (','variableDeclarationListCS[2] )?

Abstract syntax mapping

variableDeclarationListCS[1].ast : Sequence( VariableDeclaration )

Synthesized attributes

variableDeclarationListCS[1].ast = Sequence{VariableDeclarationCS.ast}
    ->union(variableDeclarationListCS[2].ast)

Inherited attributes

VariableDeclarationCS.env = variableDeclarationListCS[1].env
variableDeclarationListCS[2].env = variableDeclarationListCS[1].env

Disambiguating rules

-- none

ModelPropertyCallExpCS

A ModelPropertCall expression may have three different productions. Which one is chosen depends on the disambiguating rules defined in each of the alternatives.
  1.   ModelPropertyCallExpCS ::= OperationCallExpCS
  2.   ModelPropertyCallExpCS ::= AttributeCallExpCS
  3.   ModelPropertyCallExpCS ::= NavigationCallExpCS
Abstract syntax mapping

ModelPropertyCallExpCS.ast : ModelPropertyCallExp

Synthesised attributes

The value of this production is the value of its child production.
  1.   ModelPropertyCallExpCS.ast = OperationCallExpCS.ast
  2.  ModelPropertyCallExpCS.ast = AttributeCallExpCS.ast
  3.  ModelPropertyCallExpCS.ast = NavigationCallExpCS.ast
Inherited attributes
  1.   OperationCallExpCS.env = ModelPropertyCallExpCS.env
  2.  AttributeCallExpCS.env = ModelPropertyCallExpCS.env
  3.  NavigationCallExpCS.env = ModelPropertyCallExpCS.env

Disambiguating rules

These are defined in the children.

OperationCallExpCS

An operation call has many different forms. A is used for infix, B for using an object as an implicit collection. C is a straightforward operation call, while D has an implicit source expression. E and F are like C and D, with the @pre addition. G covers the class operation call. Rule H is for unary prefix expressions.

  1. OperationCallExpCS ::= OclExpressionCS[1]
  2. simpleNameCS OclExpressionCS[2]
  3. OperationCallExpCS ::= OclExpressionCS '->' simpleNameCS '('
  4. argumentsCS? ')'
  5. OperationCallExpCS ::= OclExpressionCS '.' simpleNameCS
  6. '(' argumentsCS? ')'
  7. OperationCallExpCS ::= simpleNameCS '(' argumentsCS? ')'
  8. OperationCallExpCS ::= OclExpressionCS '.' simpleNameCS
  9. isMarkedPreCS '(' argumentsCS? ')'
  10. OperationCallExpCS ::= simpleNameCS isMarkedPreCS '(' argumentsCS? ')'
  11. OperationCallExpCS ::= pathNameCS '(' argumentsCS? ')'
  12. OperationCallExpCS ::= simpleNameCS OclExpressionCS

Abstract syntax mapping

OperationCallExpCS.ast : OperationCallExp

Synthesised attributes

    -- this rule is for binary operators as '+', '-', '*' etc. It has only one argument.
[A] OperationCallExpCS.ast.arguments = Sequence{OclExpression2[2].ast}
    OperationCallExpCS.ast.source = OclExpressionCS[1].ast
    OperationCallExpCS.ast.referredOperation =
         OclExpressionCS.ast.type.lookupOperation (
            simpleNameCS.ast,
            Sequence{OclExpression[2].ast.type} )
    -- The source is either a collection or a single object used as a collection.
[B] OperationCallExpCS.ast.arguments = argumentsCS.ast
    -- if the OclExpressionCS is a collectiontype, then the source is this OclExpressionCS.
    -- Otherwise, the source must be build up by defining a singleton set containing
    -- the OclExpressionCS. This is done though inserting a call to the standard
    -- operation "asSet()"
    OperationCallExpCS.ast.source =
            if OclExpressionCS.ast.type.oclIsKindOf(CollectionType)
            then OclExpressionCS.ast
            else OclExpressionCS.ast.withAsSet()
            endif
    ---- The referred operation:
    OperationCallExpCS.ast.referredOperation =
            if OclExpressionCS.ast.type.oclIsKindOf (CollectionType)
            then -- this is a collection operation called on a collection
                OclExpressionCS.ast.type.lookupOperation (simpleNameCS.ast,
                if (argumentsCS->notEmpty())
                    then argumentsCS.ast->collect(type)
                else Sequence{} endif )
            else
                -- this is a set operation called on an object => implicit Set with one element
                SetType.allInstances()->any (st |
                    st.elementType = OclExpressionCS.ast.type).lookupOperation (
                        simpleNameCS.ast,
                        if (argumentsCS->notEmpty())
                        then argumentsCS.ast->collect(type)
                        else Sequence{} endif )
            endif
[C] OperationCallExpCS.ast.referredOperation =
        OclExpressionCS.ast.type.lookupOperation (simpleNameCS.ast,
            if argumentsCS->notEmpty()
            then arguments.ast->collect(type)
            else Sequence{} endif)
    OperationCallExpCS.ast.arguments = argumentsCS.ast
    OperationCallExpCS.ast.source = OclExpressionCS.ast  
[D] OperationCallExpCS.ast.arguments = argumentsCS.ast and
    OperationCallExpCS.ast.referredOperation =
        env.lookupImplicitOperation(simpleName.ast,
            if argumentsCS->notEmpty()
            then arguments.ast->collect(type)
            else Sequence{} endif)  
     OperationCallExpCS.ast.source = env.lookupImplicitSourceForOperation(
            simpleName.ast,
            if argumentsCS->notEmpty()
            then arguments.ast->collect(type)
            else Sequence{} endif)
[E] -- incorporate the isPre() operation.
     OperationCallExpCS.ast.referredOperation =
            OclExpressionCS.ast.type.lookupOperation (simpleNameCS.ast,
                if argumentsCS->notEmpty()
                then arguments.ast->collect(type)
                else Sequence{} endif)
    OperationCallExpCS.ast.arguments = argumentsCS.ast
    OperationCallExpCS.ast.source = OclExpressionCS.ast.withAtPre()
[F] -- incorporate atPre() operation with the implicit source
    OperationCallExpCS.ast.arguments = argumentsCS.ast and
    OperationCallExpCS.ast.referredOperation =
            env.lookupImplicitOperation(simpleName.ast,
                if argumentsCS->notEmpty()
                then arguments.ast->collect(type)
                else Sequence{} endif)
                )
     OperationCallExpCS.ast.source =
        env.lookupImplicitSourceForOperation(simpleName.ast,
                if argumentsCS->notEmpty()
                then arguments.ast->collect(type)
                else Sequence{} endif)
        ).withAtPre()
[G] OperationCallExpCS.ast.arguments = argumentsCS.ast and
    OperationCallExpCS.ast.referredOperation =
            env.lookupPathName(pathName.ast,
                if argumentsCS->notEmpty()
                then arguments.ast->collect(type)
                else Sequence{} endif)
    OperationCallExpCS.ast.source->isEmpty()
-- this rule is for unary operators as '-' and 'not' etc. It has no argument.
[H] OperationCallExpCS.ast.arguments->isEmpty()
    OperationCallExpCS.ast.source = OclExpressionCS.ast
    OperationCallExpCS.ast.referredOperation =
            OclExpressionCS.ast.type.lookupOperation (
                simpleNameCS.ast,
                Sequence{} )

Inherited attributes

[A] OclExpressionCS[1].env = OperationCallExpCS.env
[A] OclExpressionCS[2].env = OperationCallExpCS.env
[B] OclExpressionCS.env = OperationCallExpCS.env
[B] argumentsCS.env = OperationCallExpCS.env
[C] OclExpressionCS.env = OperationCallExpCS.env
[C] argumentsCS.env = OperationCallExpCS.env
[D] argumentsCS.env = OperationCallExpCS.env
[E] OclExpressionCS.env = OperationCallExpCS.env
[E] argumentsCS.env = OperationCallExpCS.env
[F] argumentsCS.env = OperationCallExpCS.env

Disambiguating rules

[1] [A] The name of the referred Operation must be an operator
Set{'+','-','*','/','and','or','xor','=','<=','>=','<','>'}->includes(simpleNameCS.ast)

[2] [A,B,C,D,E,F] The referred Operation must be defined for the type of source
not OperationCallExpCS.ast.referredOperation.oclIsUndefined()

[3] [C] The name of the referred Operation cannot be an operator.
Set{'+','-','*','/','and','or','xor','=','<=','>=','<','>'}->excludes(simpleNameCS.ast)

AttributeCallExpCS

This production rule results in an AttributeCallExp. In production [A] the source is explicit, while production [B] is used for an implicit source. Alternative C covers the use of a classifier scoped attribute.

  1.   AttributeCallExpCS ::= OclExpressionCS '.' simpleNameCS isMarkedPreCS?
  2.  AttributeCallExpCS ::= simpleNameCS isMarkedPreCS?
  3.  AttributeCallExpCS ::= pathNameCS
Abstract syntax mapping

AttributeCallExpCS.ast : AttributeCallExp

Synthesised attributes

[A] AttributeCallExpCS.ast.referredAttribute =
    OclExpressionCS.ast.type.lookupAttribute(simpleNameCS.ast)
[A] AttributeCallExpCS.ast.source = if isMarkedPreCS->isEmpty()
        then OclExpressionCS.ast
        else OclExpressionCS.ast.withAtPre()
        endif
[B] AttributeCallExpCS.ast.referredAttribute =
        env.lookupImplicitAttribute(simpleNameCS.ast)
[B] AttributeCallExpCS.ast.source =
        if isMarkedPreCS->isEmpty()
        then env.findImplicitSourceForAttribute(simpleNameCS.ast)
        else env.findImplicitSourceForAttribute(simpleNameCS.ast).withAtPre()
        endif
[C] AttributeCallExpCS.ast.referredAttribute =
        env.lookupPathName(pathNameCS.ast).oclAsType(Attribute)

Inherited attributes

[A] OclExpressionCS.env = AttributeCallExpCS.env

Disambiguating rules

[1] [A, B] 'simpleName' is name of an Attribute of the type of source or if source is empty the name of an attribute of 'self' or any of the iterator variables in (nested) scope. In OCL:
not AttributeCallExpCS.ast.referredAttribute.oclIsUndefined()

[2] [C] The pathName refers to a class attribute.
env.lookupPathName(pathNameCS.ast).oclIsKindOf(Attribute)
and
AttributeCallExpCS.ast.referredAttribute.ownerscope = ScopeKind::instance


NavigationCallExpCS

This production rule represents a navigation call expression.
  1.   NavigationCallExpCS ::= AssociationEndCallExpCS
  2.  NavigationCallExpCS ::= AssociationClassCallExpCS
Abstract syntax mapping

NavigationCallExpCS.ast : NavigationCallExp

Synthesised attributes

The value of this production is the value of its child production.
  1. NavigationCallExpCS.ast = AssociationEndCallExpCS.ast
  2. NavigationCallExpCS.ast = AssociationClassCallExpCS.ast
Inherited attributes
  1.   AssociationEndCallExpCS.env = NavigationCallExpCS.env
  2.  AssociationClassCallExpCS.env = NavigationCallExpCS.env
Disambiguating rules

These are defined in the children.

AssociationEndCallExpCS

This production rule represents a navigation through an association end. Rule A is the default, rule B is used with an implicit source, while rule C is used with qualifiers.

  1.   AssociationEndCallExpCS ::= OclExpressionCS '.' simpleNameCS ('[' argumentsCS ']')? isMarkedPreCS?
  2.   AssociationEndCallExpCS ::= simpleNameCS ('[' argumentsCS ']')? isMarkedPreCS?
Abstract syntax mapping

AssociationEndCallExpCS.ast : AssociationEndCallExp

Synthesised attributes
[A] AssociationEndCallExpCS.ast.referredAssociationEnd =
        OclExpressionCS.ast.type.lookupAssociationEnd(simpleNameCS.ast)
    AssociationEndCallExpCS.ast.source = if isMarkedPreCS->isEmpty()
                        then OclExpressionCS.ast
                        else OclExpressionCS.ast.withAtPre()
            endif
[A] AssociationEndCallExpCS.ast.qualifiers = argumentsCS.ast
[B] AssociationEndCallExpCS.ast.referredAssociationEnd =
        env.lookupImplicitAssociationEnd(simpleNameCS.ast)
    AssociationEndCallExpCS.ast.source =
                        if isMarkedPreCS->isEmpty()
                        then env.findImplicitSourceForAssociationEnd(simpleNameCS.ast)
                        else env.findImplicitSourceForAssociationEnd(simpleNameCS.ast).withAtPre()
                        endif
[B] AssociationEndCallExpCS.ast.qualifiers = argumentsCS.ast

Inherited attributes

[A] OclExpressionCS.env = AssociationEndCallExpCS.env
[A, B] argumentsCS.env = AssociationEndCallExpCS.env

Disambiguating rules

[1] [A,B] 'simpleName' is name of an AssociationEnd of the type of source or if source is empty the name of an Associatio-
nEnd of 'self' or any of the iterator variables in (nested) scope. In OCL:

not AssociationEndCallExpCS.ast.referredAssociationEnd.oclIsUndefined()

AssociationClassCallExpCS

This production rule represents a navigation to an association class.

[A] AssociationClassCallExpCS ::= OclExpressionCS '.' simpleNameCS
('[' argumentsCS ']')? isMarkedPreCS?
[B] AssociationClassCallExpCS ::= simpleNameCS
('[' argumentsCS ']')? isMarkedPreCS?

Abstract syntax mapping

AssociationClassCallExpCS.ast : AssociationClassCallExp

Synthesised attributes

[A] AssociationClassCallExpCS.ast.referredAssociationClass =
        OclExpressionCS.ast.type.lookupAssociationClass(simpleNameCS.ast)
    AssociationClassCallExpCS.ast.source = if isMarkedPreCS->isEmpty()
            then OclExpressionCS.ast
            else OclExpressionCS.ast.withAtPre()
            endif
[A] AssociationClassCallExpCS.ast.qualifiers = argumentsCS.ast
[B] AssociationClassCallExpCS.ast.referredAssociationClass =
            env.lookupImplicitAssociationClass(simpleNameCS.ast)
    AssociationClassCallExpCS.ast.source =
            if isMarkedPreCS->isEmpty()
            then env.findImplicitSourceForAssociationClass(simpleNameCS.ast)
            else env.findImplicitSourceForAssociationClass(simpleNameCS.ast).withAtPre()
            endif
[B] AssociationClassCallExpCS.ast.qualifiers = argumentsCS.ast

Inherited attributes

[A] OclExpressionCS.env = AssociationClassCallExpCS.env
[A, B] argumentsCS.env = AssociationClassCallExpCS.env

Disambiguating rules

[1] 'simpleName' is name of an AssociationClass of the type of source.
not AssociationClassCallExpCS.ast.referredAssociationClass.oclIsUndefined()

isMarkedPreCS

This production rule represents the marking @pre in an ocl expression.
isMarkedPreCS ::= '@' 'pre'

Abstract syntax mapping

isMarkedPreCS.ast : Boolean

Synthesised attributes

self.ast = true

Inherited attributes

-- none

Disambiguating rules

-- none

argumentsCS

This production rule represents a sequence of arguments.
argumentsCS[1] ::= OclExpressionCS ( ',' argumentsCS[2] )?

Abstract syntax mapping

argumentsCS[1].ast : Sequence(OclExpression)

Synthesised attributes

argumentsCS[1].ast = Sequence{OclExpressionCS.ast}->union(argumentsCS[2].ast)

Inherited attributes

OclExpressionCS.env = argumentsCS[1].env
argumentsCS[2].env = argumentsCS[1].env

Disambiguating rules

-- none

LetExpCS

This production rule represents a let expression. The LetExpSubCS nonterminal has the purpose of allowing directly nested let expressions with the shorthand syntax, i.e. ending with one 'in' keyword.

LetExpCS ::= 'let' VariableDeclarationCS
LetExpSubCS

Abstract syntax mapping

LetExpCS.ast : LetExp

Synthesised attributes

LetExpCS.ast.variable = VariableDeclarationCS.ast
LetExpCS.ast.in = LetExpSubCS.ast

Inherited attributes

LetExpSubCS.env = LetExpCS.env.nestedEnvironment().addElement(
        VariableDeclarationCS.ast.varName,
        VariableDeclarationCS.ast,
        false)

Disambiguating rules

[1] The variable name must be unique in the current scope
LetExpCS.env.lookup (VariableDeclarationCS.ast.varName).oclIsUndefined()

[2] A variable declaration inside a let must have a declared type and an initial value.
not VariableDeclarationCS.ast.type.oclIsUndefined() and
VariableDeclarationCS.ast.initExpression->notEmpty()

LetExpSubCS

[A] LetExpSubCS[1] ::= ',' VariableDeclarationCS LetExpSubCS[2]
[B] LetExpSubCS ::= 'in' OclExpressionCS

Abstract syntax mapping

LetExpSubCS.ast : OclExpression

Synthesised attributes

[A] LetExpSubCS[1].ast.oclAsType(LetExp).variable = VariableDeclarationCS.ast
[A] LetExpSubCS[1].ast.oclAsType(LetExp).OClExpression = LetExpSubCS[2].ast
[B] LetExpSubCS.ast = OclExpressionCS.ast

Inherited attributes

[A] VariableDeclarationCS.env = LetExpSubCS[1].env
[A] LetExpSubCS[2].env = LetExpSubCS[1].env.nestedEnvironment().addElement(
        VariableDeclarationCS.ast.varName,
        VariableDeclarationCS.ast,
        false)
[B] OClExpressionCS.env = LetExpSubCS.env

Disambiguating rules

[A] The variable name must be unique in the current scope
    LetExpSubCS[1].env.lookup (VariableDeclarationCS.ast.varName).oclIsUndefined()

[A] A variable declaration inside a let must have a declared type and an initial value.
    not VariableDeclarationCS.ast.type.oclIsUndefined() and
  VariableDeclarationCS.ast.initExpression->notEmpty()

OclMessageExpCS

The message Name must either be the name of a Signal, or the name of an Operation belonging to the target object(s).

[A] OclMessageExpCS ::= OclExpressionCS '^^'
simpleNameCS '(' OclMessageArgumentsCS? ')'
[B] OclMessageExpCS ::= OclExpressionCS '^'
simpleNameCS '(' OclMessageArgumentsCS? ')'

Abstract syntax mapping

[A] OclMessageExpCS.ast : OclMessageExp
[B] OclMessageExpCS.ast : OclMessageExp

Synthesised attributes

[A] OclMessageExpCS.ast.target = OclExpressionCS.ast
[A] OclMessageExpCS.ast.arguments = OclMessageArgumentsCS.ast
    -- first, find the sequence of types of the operation/signal parameters
[A] let params : Sequence(Classifier) = OclMessageArguments.ast->collect(messArg |
        messArg.getType() ),
    -- try to find either the called operation or the sent signal
[A] operation : Operation = OclMessageExpCS.ast.target.type.
        lookupOperation(simpleNameCS.ast, params),
    signal : Signal = OclMessageExpCS.ast.target.type.
            lookupSignal(simpleNameCS.ast, params)
    in
    OclMessageExpCS.ast.calledOperation = if operation->isEmpty()
                then OclUndefined
                else = operation
                endif
    OclMessageExpCS.ast.sentSignal = if signal->isEmpty()
                then OclUndefined
                else signal
                endif  
[B]
    -- OclExpression^simpleNameCS(OclMessageArguments) is identical to
    -- OclExpression^^simpleNameCS(OclMessageArguments)->size() = 1
    -- actual mapping: straigthforward, TBD...

Inherited attributes

OclExpressionCS.env = OclMessageExpCS.env
OclMessageArgumentsCS.env = OclMessageExpCS.env

Disambiguating rules

-- none

OclMessageArgumentsCS

OclMessageArgumentsCS[1] ::= OclMessageArgCS
( ',' OclMessageArgumentsCS[2] )?

Abstract syntax mapping

OclMessageArgumentsCS[1].ast : Sequence(OclMessageArg)

Synthesised attributes

OclMessageArgumentsCS[1].ast =
Sequence{OclMessageArgCS.ast}->union(OclMessageArgumentsCS[2].ast)

Inherited attributes

OclMessageArgCS.env = OclMessageArgumentsCS[1].env
OclMessageArgumentsCS[2].env = OclMessageArgumentsCS[1].env

Disambiguating rules

-- none

OclMessageArgCS

[A] OclMessageArgCS ::= '?' (':' typeCS)?
[B] OclMessageArgCS ::= OclExpressionCS

Abstract syntax mapping

OclMessageArgCS.ast : OclMessageArg

Synthesised attributes

[A] OclMessageArgCS.ast.expression->isEmpty()
[A] OclMessageArgCS.ast.unspecified->notEmpty()
[A] OclMessageArgCS.ast.type = typeCS.ast
[B] OclMessageArgCS.ast.unspecified->isEmpty()
[B] OclMessageArgCS.ast.expression = OclExpressionCS.ast

Inherited attributes

OclExpressionCS.env = OclMessageArgCS.env

Disambiguating rules

-- none

IfExpCS

IfExpCS ::= 'if' OclExpression[1]
'then' OclExpression[2]
'else' OclExpression[3]
'endif'

Abstract syntax mapping

IfExpCS.ast : IfExp

Synthesised attributes

IfExpCS.ast.condition = OclExpression[1].ast
IfExpCS.ast.thenExpression = OclExpression[2].ast
IfExpCS.ast.elseExpression = OclExpression[3].ast

Inherited attributes

OclExpression[1].env = IfExpCS.env
OclExpression[2].env = IfExpCS.env
OclExpression[3].env = IfExpCS.env

Disambiguating rules
-- none

Comments

It is possible to include comments anywhere in a text composed according to the above concrete syntax. There will be no mapping of any comments to the abstract syntax. Comments are simply skipped when the text is being parsed. There are two forms of comments, a line comment and a paragraph comment. The line comment starts with the string `--' and ends with the next newline. The paragraph comment starts with the string `/*', and ends with the string `*/'. Paragraph comments may be nested.

Operator Precedence

In the grammar, the precedence of the operators from highest to lowest is as follows:
Parentheses `(' and `)' can be used to change precedence.