import re
from copy import copy
-from pyparsing import Keyword, Literal, Word, OneOrMore, Combine, Regex, Forward, Optional, Group, Suppress, delimitedList, cStyleComment, nums, alphanums, empty, srange
+from pyparsing import Keyword, Literal, Word, OneOrMore, ZeroOrMore, Combine, Regex, Forward, Optional, Group, Suppress, delimitedList, cStyleComment, nums, alphanums, empty, srange, dblQuotedString
__all__ = ['parse_asn1', 'AnnotatedToken']
-def parse_asn1(asn1_payload):
- """ Parse a string containing an ASN.1 module definition
- and return a syntax tree in the form of a list of
+def parse_asn1(asn1_definition):
+ """ Parse a string containing one or more ASN.1 module definitions.
+ Returns a list of module syntax trees represented as nested lists of
AnnotatedToken objects.
"""
grammar = _build_asn1_grammar()
- parse_result = grammar.parseString(asn1_payload)
+ parse_result = grammar.parseString(asn1_definition)
parse_tree = parse_result.asList()
return parse_tree
SIZE = Keyword('SIZE')
OF = Keyword('OF')
IMPORTS = Keyword('IMPORTS')
+ EXPORTS = Keyword('EXPORTS')
FROM = Keyword('FROM')
# Built-in types
VideotexString = Keyword('VideotexString')
VisibleString = Keyword('VisibleString')
+ # Useful types
+ GeneralizedTime = Keyword('GeneralizedTime')
+ UTCTime = Keyword('UTCTime')
+ ObjectDescriptor = Keyword('ObjectDescriptor')
+
# Literals
number = Word(nums)
signed_number = Combine(Optional('-') + number) # todo: consider defined values from 18.1
bitstring_value = bstring | hstring # todo: consider more forms from 21.9
integer_value = signed_number
null_value = NULL
+ cstring_value = dblQuotedString
- builtin_value = boolean_value | bitstring_value | real_value | integer_value | null_value
+ builtin_value = boolean_value | bitstring_value | real_value | integer_value | null_value | cstring_value
defined_value = valuereference # todo: more options from 13.1
# object identifier value
sequenceof_type = Suppress(SEQUENCE) + Optional(size_constraint) + Suppress(OF) + (type_ | named_type)
setof_type = Suppress(SET) + Optional(size_constraint) + Suppress(OF) + (type_ | named_type)
choice_type = CHOICE + braced_list(named_type | extension_marker)
- enumerated_type = ENUMERATED + braced_list(enumeration)
+ enumerated_type = ENUMERATED + braced_list(enumeration | extension_marker)
bitstring_type = BIT_STRING + braced_list(named_number)
plain_integer_type = INTEGER
restricted_integer_type = INTEGER + braced_list(named_number)
T61String | UniversalString | \
UTF8String | VideotexString | VisibleString
characterstring_type = restricted_characterstring_type | unrestricted_characterstring_type
+ useful_type = GeneralizedTime | UTCTime | ObjectDescriptor
# todo: consider other builtins from 16.2
- simple_type = (boolean_type | null_type | octetstring_type | characterstring_type | real_type | plain_integer_type | object_identifier_type) + Optional(constraint)
+ simple_type = (boolean_type | null_type | octetstring_type | characterstring_type | real_type | plain_integer_type | object_identifier_type | useful_type) + Optional(constraint)
constructed_type = choice_type | sequence_type | set_type
value_list_type = restricted_integer_type | enumerated_type
- builtin_type = tagged_type | simple_type | constructed_type | sequenceof_type | setof_type | value_list_type | bitstring_type
+ builtin_type = value_list_type | tagged_type | simple_type | constructed_type | sequenceof_type | setof_type | bitstring_type
type_ << (builtin_type | referenced_type)
- # BUG: identifier should not be Optional here,
- # but our ASN.1 interpreter supports unnamed members,
+ # EXT: identifier should not be Optional here, but
+ # our other ASN.1 code generator supports unnamed members,
# and we use them.
named_type << (Optional(identifier) + type_)
- # BUG: Trailing semi-colon is not allowed by standard grammar, but our ASN.1 interpreter accepts it
- # and we happen to use it.
- type_assignment = typereference + '::=' + type_ + Suppress(Optional(';'))
+ type_assignment = typereference + '::=' + type_
value_assignment = valuereference + type_ + '::=' + value
assignment = type_assignment | value_assignment
- assignment_list = OneOrMore(assignment)
+ assignment_list = ZeroOrMore(assignment)
assigned_identifier = Optional(object_identifier_value | defined_value)
global_module_reference = module_reference + assigned_identifier
symbol = Unique(reference) # TODO: parameterized reference?
symbol_list = Group(delimitedList(symbol))
-
symbols_from_module = symbol_list + Suppress(FROM) + global_module_reference
symbols_from_module_list = OneOrMore(symbols_from_module)
symbols_imported = Optional(symbols_from_module_list)
+ exports = Optional(Suppress(EXPORTS) + symbol_list + Suppress(';'))
imports = Optional(Suppress(IMPORTS) + symbols_imported + Suppress(';'))
- module_body = (imports + assignment_list) | empty
+ module_body = (exports + imports + assignment_list)
module_defaults = Suppress(tag_default + extension_default) # we don't want these in the AST
module_identifier = module_reference + definitive_identifier
module_definition = module_identifier + DEFINITIONS + module_defaults + '::=' + BEGIN + module_body + END
definitive_number_form.setParseAction(annotate('DefinitiveNumberForm'))
definitive_name_and_number_form.setParseAction(annotate('DefinitiveNameAndNumberForm'))
imports.setParseAction(annotate('Imports'))
+ exports.setParseAction(annotate('Exports'))
assignment_list.setParseAction(annotate('AssignmentList'))
- return module_definition
+ start = ZeroOrMore(module_definition)
+ return start
def Unique(token):