ASN.1 provides a mechanizm whereby users can extend the notation for their own use, or for use by others. A user does so by defining one or more macros using the macro definition notation. A macro can be imported and exported just like any type or value definitions. To the macro user, the macro appears as a new ASN.1 type with its own notation which can be used wherever a type can be placed, and similarly with value notation. In case of encoding, the macro is turned into equivalent value of ASN.1 types, so it can be !!!pokladane!!! as a delivered value. Macros are not used very commonly, so if you a re not very keen on ASN.1, you can skip this section without loosing too much information.
Each macro has its own reference name. It is like a type reference, but typed with all caps and followed by keyword MACRO. Its borders are signed with keywords BEGIN and END and between them are two sections called productions for type and value notation and optionaly the third one containing the other productions equal to type definitions. Each production starts with its reference name, first two are keywords TYPE NOTATION and VALUE NOTATION:
MY1STMACRO MACRO ::=
BEGIN
TYPE NOTATION ::= ...
VALUE NOTATION ::= ...
...
END
One production consists of its reference name, assignment sign (::=) and one or more alternatives separated by pipe sign (|). Each alternative is a list of items and/or embedded definition and/or name of the subsidiary productions. Each item has a corresponding character string, which it recognises, as follows:
"aaaa" | the string of characters "aaaa" excluding the double quotes |
string | any sequence of characters (delimited by the following item) |
identifier | a string obeying the rules for identifiers or references |
number | a string of digits |
empty | null string (always recognised) |
type | any string which can be recognised as ASN.1 type notation |
type (typeref) | as above, but as a side effect of recognition, the type is assigned to the typeref |
value (type) | any string which can be recognised as ASN.1 value notation for the type |
value (valueref type) | as above, but as a side effect of recognition, the value is assigned to the valueref |
Items may be separated by spaces and newlines.
Embedded definitions are simply a series of ASN.1 type and value assignments enclosed within "<>". They come into effect at the point in the alternative where they appear.
So, that' for theory, now let's have a look at some examples. The first one is macro POSSIBLE, which is very strange and probably unusable in praxis, but demonstrates most of macro possibilities:
POSSIBLE MACRO ::=
BEGIN
TYPE NOTATION ::=
type(X)
<PossibleX :: CHOICE {present X, omitted NULL}>
VALUE NOTATION ::=
"OMITTED"
<VALUE PossibleX ::= omitted NULL> |
value (x X)
<VALUE PossibleX ::= present x>
END
Before explaining all that happens, let's have these assignments:
A ::= POSSIBLE SEQUENCE OF INTEGER
a1 A ::= OMITTED
a2 A ::= {1, 2, 0}
First of them assignes an A instance of macro POSSIBLE with 'parameter' that is a type, values of which possibly can be assined to a variable in following value notation.
Assignment of a1 contains string OMITTED, that means, supported value for omitted from macro, which results in assigning NULL to a1.
The last assignment contains a sequence of tree numbers, which is valid for type SEQUENCE OF INTEGER. Because as a 'parameter' of assignment is this sequence, the second branch of VALUE NOTATION is taken and results in assigning this sequence to a2.
As you can see, this macro can be easily substituted by:
A ::= CHOICE {SEQUENCE OF INTEGER, NULL}
The only diference is that NULL must be then assigned to a1.
But, here is another example of macro which is more usable. It is taken from standard for Remote Operation.
OPERATION MACRO ::=
BEGIN
TYPE NOTATION ::= Argument Result Errors
VALUE NOTATION ::= value (VALUE OperationCode)
Argument ::= "ARGUMENT" ResultType | empty
Result ::= "RESULT" ResultType | empty
Errors ::= "ERRORS" "{" ErrorName "}" | empty
ResultType ::= type | empty
ErrorNames ::= ErrorList | empty
ErrorList ::= Error | ErrorList "," Error
Error ::= value (ERROR)
END
OperationCode ::= INTEGER
A typical example of the use of this macro is as follows:
get OPERATION
ARGUMENT AttributeType
RESULT ArgumentValue
ERRORS {noSuchAttribute, accessBarred}
::= 5
The last examle is more funny. At compile time it 'eats' the rest of any module within used until any other macro is reached:
VOCAIOUS MACRO ::=
BEGIN
TYPE NOTATION ::= Eat
VALUE NOTATION ::= empty
Eat ::= "END" | "MACRO" | EatSomething Eat
EatSomething ::= type | identifier | number | Keyword | Special
Keyword ::= "NULL" | "TRUE" | "FALSE" | "PLUS-INFINITY" | "MINUS-INFINITY"
Special ::= "::=" | "," | "{" | "}" | "." | "(" | ")" | "'" string "'B" | "'" string "'H" | """" string """"
END