QSIG fully implemented
[obnox/wireshark/wip.git] / tools / asn2wrs.py
index de09ddfc978fedc864590d7b2e679e8567275024..e4757202d37d32e5e30309f6a16e2d09968521b6 100755 (executable)
@@ -17,7 +17,7 @@
 # http://www.pobox.com/~asl2/software/PyZ3950/
 # (ASN.1 to Python compiler functionality is broken but not removed, it could be revived if necessary)
 #
-# It requires Dave Beazley's PLY parsing package licensed under the LGPL (tested with version 1.6)
+# It requires Dave Beazley's PLY parsing package licensed under the LGPL (tested with version 2.3)
 # http://www.dabeaz.com/ply/
 # 
 # 
@@ -33,6 +33,9 @@
 # ITU-T Recommendation X.683 (07/2002), 
 #   Information technology - Abstract Syntax Notation One (ASN.1): Parameterization of ASN.1 specifications
 #
+# ITU-T Recommendation X.880 (07/1994), 
+#   Information technology - Remote Operations: Concepts, model and notation
+#
 
 from __future__ import nested_scopes
 
@@ -44,8 +47,8 @@ import os
 import os.path
 import time
 import getopt
+import traceback
 
-import __main__ # XXX blech!
 import lex
 import yacc
 
@@ -140,11 +143,43 @@ oid_names = {
 }
 
 def asn2c(id):
-  return id.replace('-', '_').replace('.', '_')
-
-class LexError(Exception): pass
-class ParseError(Exception): pass
-
+  return id.replace('-', '_').replace('.', '_').replace('&', '_')
+
+input_file = None
+g_conform = None
+lexer = None
+in_oid = False
+
+class LexError(Exception):
+  def __init__(self, tok, filename=None):
+    self.tok = tok
+    self.filename = filename
+    self.msg =  "Unexpected character %r" % (self.tok.value[0])
+    Exception.__init__(self, self.msg)
+  def __repr__(self):
+    return "%s:%d: %s" % (self.filename, self.tok.lineno, self.msg)
+  __str__ = __repr__
+
+
+class ParseError(Exception):
+  def __init__(self, tok, filename=None):
+    self.tok = tok
+    self.filename = filename
+    self.msg =  "Unexpected token %s(%r)" % (self.tok.type, self.tok.value)
+    Exception.__init__(self, self.msg)
+  def __repr__(self):
+    return "%s:%d: %s" % (self.filename, self.tok.lineno, self.msg)
+  __str__ = __repr__
+
+
+states = (
+  ('braceignore','exclusive'),
+)
+
+precedence = (
+  ('left', 'UNION', 'BAR'),
+  ('left', 'INTERSECTION', 'CIRCUMFLEX'),
+)
 # 11 ASN.1 lexical items
 
 static_tokens = {
@@ -170,110 +205,91 @@ static_tokens = {
   #r'"'  : 'QUOTATION',
   #r"'"  : 'APOSTROPHE',
   r';'  : 'SEMICOLON',
-  #r'@'  : 'AT',
-  #r'\!' : 'EXCLAMATION',
+  r'@'  : 'AT',
+  r'\!' : 'EXCLAMATION',
   r'\^' : 'CIRCUMFLEX',
-  r'\&' : 'AMPERSAND'
+  r'\&' : 'AMPERSAND',
+  r'\|' : 'BAR'
 }
 
 # 11.27 Reserved words
 
 # all keys in reserved_words must start w/ upper case
 reserved_words = {
-    'TAGS' : 'TAGS',
-    'BOOLEAN' : 'BOOLEAN',
-    'INTEGER' : 'INTEGER',
-    'BIT'     : 'BIT',
-    'CHARACTER' : 'CHARACTER',
-    'STRING'  : 'STRING',
-    'OCTET'   : 'OCTET',
-    'NULL'    : 'NULL',
-    'SEQUENCE': 'SEQUENCE',
-    'OF'      : 'OF',
-    'SET'     : 'SET',
-    'IMPLICIT': 'IMPLICIT',
-    'CHOICE'  : 'CHOICE',
-    'ANY'     : 'ANY',
-#    'EXTERNAL' : 'EXTERNAL', # XXX added over base
-    'OPTIONAL':'OPTIONAL',
-    'DEFAULT' : 'DEFAULT',
-    'COMPONENTS': 'COMPONENTS',
-    'UNIVERSAL' : 'UNIVERSAL',
-    'APPLICATION' : 'APPLICATION',
-    'PRIVATE'   : 'PRIVATE',
-    'TRUE' : 'TRUE',
-    'FALSE' : 'FALSE',
-    'BEGIN' : 'BEGIN',
-    'END' : 'END',
-    'DEFINITIONS' : 'DEFINITIONS',
-    'EXPLICIT' : 'EXPLICIT',
-    'ENUMERATED' : 'ENUMERATED',
-    'EXPORTS' : 'EXPORTS',
-    'IMPORTS' : 'IMPORTS',
-    'REAL'    : 'REAL',
-    'INCLUDES': 'INCLUDES',
-    'MIN'     : 'MIN',
-    'MAX'     : 'MAX',
-    'SIZE'    : 'SIZE',
-    'FROM'    : 'FROM',
-    'INTERSECTION' : 'INTERSECTION',
-#    'UNION'   : 'UNION',
-    'PATTERN'    : 'PATTERN',
-    'WITH'    : 'WITH',
-    'COMPONENT': 'COMPONENT',
-    'PRESENT'  : 'PRESENT',
-    'ABSENT'   : 'ABSENT',
-#    'DEFINED'  : 'DEFINED',
-    'CONSTRAINED' : 'CONSTRAINED',
-    'BY'       : 'BY',
-    'PLUS-INFINITY'   : 'PLUS_INFINITY',
-    'MINUS-INFINITY'  : 'MINUS_INFINITY',
-    'GeneralizedTime' : 'GeneralizedTime',
-    'UTCTime'         : 'UTCTime',
-    'ObjectDescriptor': 'ObjectDescriptor',
-    'AUTOMATIC': 'AUTOMATIC',
-    'OBJECT': 'OBJECT',
-    'IDENTIFIER': 'IDENTIFIER',
-    'TYPE-IDENTIFIER' : 'TYPE_IDENTIFIER',
-    'ABSTRACT-SYNTAX' : 'ABSTRACT_SYNTAX',
-#      'OPERATION'       : 'OPERATION',
-#      'ARGUMENT'        : 'ARGUMENT',
-#      'RESULT'          : 'RESULT',
-#      'ERRORS'          : 'ERRORS',
-#      'LINKED'          : 'LINKED',
-#      'ERROR'           : 'ERROR',
-#      'PARAMETER'       : 'PARAMETER',
-#      'BIND'            : 'BIND',
-#      'BIND-ERROR'      : 'BIND_ERROR',
-#      'UNBIND'          : 'UNBIND',
-#      'APPLICATION-CONTEXT' : 'AC',
-#      'APPLICATON-SERVICE-ELEMENTS' : 'ASES',
-#      'REMOTE' : 'REMOTE',
-#      'INITIATOR' : 'INITIATOR',
-#      'RESPONDER' : 'RESPONDER',
-#      'APPLICATION-SERVICE-ELEMENT' : 'ASE',
-#      'OPERATIONS' : None,
-#      'EXTENSION-ATTRIBUTE' : 'EXTENSION_ATTRIBUTE',
-#      'EXTENSIONS' : None,
-#      'CHOSEN' : None,
-#      'EXTENSION' : None,
-#      'CRITICAL': None,
-#      'FOR' : None,
-#      'SUBMISSION' : None,
-#      'DELIVERY' : None,
-#      'TRANSFER' : None,
-#      'OBJECT' : None,
-#      'PORTS' : None,
-#      'PORT'  : None,
-#      r'ABSTRACT\s*OPERATIONS' : 'ABSTR_OPS',
-#      'REFINE' : None,
-#      'AS' : None,
-#      'RECURRING' : None
-    }
+  'ABSENT'      : 'ABSENT',
+  'ABSTRACT-SYNTAX' : 'ABSTRACT_SYNTAX',
+  'ALL'         : 'ALL',
+  'APPLICATION' : 'APPLICATION',
+  'AUTOMATIC'   : 'AUTOMATIC',
+  'BEGIN'       : 'BEGIN',
+  'BIT'         : 'BIT',
+  'BOOLEAN'     : 'BOOLEAN',
+  'BY'          : 'BY',
+  'CHARACTER'   : 'CHARACTER',
+  'CHOICE'      : 'CHOICE',
+  'CLASS'       : 'CLASS',
+  'COMPONENT'   : 'COMPONENT',
+  'COMPONENTS'  : 'COMPONENTS',
+  'CONSTRAINED' : 'CONSTRAINED',
+  'CONTAINING'  : 'CONTAINING',
+  'DEFAULT'     : 'DEFAULT',
+  'DEFINITIONS' : 'DEFINITIONS',
+  'EMBEDDED'    : 'EMBEDDED',
+#  'ENCODED'     : 'ENCODED',
+  'END'         : 'END',
+  'ENUMERATED'  : 'ENUMERATED',
+#  'EXCEPT'      : 'EXCEPT',
+  'EXPLICIT'    : 'EXPLICIT',
+  'EXPORTS'     : 'EXPORTS',
+#  'EXTENSIBILITY' : 'EXTENSIBILITY',
+  'EXTERNAL'    : 'EXTERNAL',
+  'FALSE'       : 'FALSE',
+  'FROM'        : 'FROM',
+  'GeneralizedTime' : 'GeneralizedTime',
+  'IDENTIFIER'  : 'IDENTIFIER',
+  'IMPLICIT'    : 'IMPLICIT',
+#  'IMPLIED'     : 'IMPLIED',
+  'IMPORTS'     : 'IMPORTS',
+  'INCLUDES'    : 'INCLUDES',
+  'INSTANCE'    : 'INSTANCE',
+  'INTEGER'     : 'INTEGER',
+  'INTERSECTION' : 'INTERSECTION',
+  'MAX'         : 'MAX',
+  'MIN'         : 'MIN',
+  'MINUS-INFINITY' : 'MINUS_INFINITY',
+  'NULL'        : 'NULL',
+  'OBJECT'      : 'OBJECT',
+  'ObjectDescriptor' : 'ObjectDescriptor',
+  'OCTET'       : 'OCTET',
+  'OF'          : 'OF',
+  'OPTIONAL'    : 'OPTIONAL',
+  'PATTERN'     : 'PATTERN',
+  'PDV'         : 'PDV',
+  'PLUS-INFINITY' : 'PLUS_INFINITY',
+  'PRESENT'     : 'PRESENT',
+  'PRIVATE'     : 'PRIVATE',
+  'REAL'        : 'REAL',
+#  'RELATIVE-OID' : 'RELATIVE-OID',
+  'SEQUENCE'    : 'SEQUENCE',
+  'SET'         : 'SET',
+  'SIZE'        : 'SIZE',
+  'STRING'      : 'STRING',
+  'SYNTAX'      : 'SYNTAX',
+  'TAGS'        : 'TAGS',
+  'TRUE'        : 'TRUE',
+  'TYPE-IDENTIFIER' : 'TYPE_IDENTIFIER',
+  'UNION'       : 'UNION',
+  'UNIQUE'      : 'UNIQUE',
+  'UNIVERSAL'   : 'UNIVERSAL',
+  'UTCTime'     : 'UTCTime',
+  'WITH'        : 'WITH',
+# obsolete but still used
+  'ANY'         : 'ANY',
+}
 
-for k in static_tokens.keys ():
-    if static_tokens [k] == None:
-        static_tokens [k] = k
+for k in static_tokens.keys():
+  if static_tokens [k] == None:
+    static_tokens [k] = k
 
 StringTypes = ['Numeric', 'Printable', 'IA5', 'BMP', 'Universal', 'UTF8',
                'Teletex', 'T61', 'Videotex', 'Graphic', 'ISO646', 'Visible',
@@ -285,12 +301,14 @@ for s in StringTypes:
 tokens = static_tokens.values() \
          + reserved_words.values() \
          + ['BSTRING', 'HSTRING', 'QSTRING',
-            'UCASE_IDENT', 'LCASE_IDENT',
-            'NUMBER', 'PYQUOTE']
+            'UCASE_IDENT', 'LCASE_IDENT', 'LCASE_IDENT_ASSIGNED', 'CLASS_IDENT',
+            'REAL_NUMBER', 'NUMBER', 'PYQUOTE']
+
 
+cur_mod = __import__ (__name__) # XXX blech!
 
 for (k, v) in static_tokens.items ():
-  __main__.__dict__['t_' + v] = k
+    cur_mod.__dict__['t_' + v] = k
 
 # 11.10 Binary strings
 def t_BSTRING (t):
@@ -304,15 +322,24 @@ def t_HSTRING (t):
 
 def t_QSTRING (t):
     r'"([^"]|"")*"'
-    return t # XXX might want to un-""
+    return t 
 
 def t_UCASE_IDENT (t):
     r"[A-Z](-[a-zA-Z0-9]|[a-zA-Z0-9])*" # can't end w/ '-'
-    t.type = reserved_words.get(t.value, "UCASE_IDENT")
+    if (is_class_ident(t.value)): t.type = 'CLASS_IDENT'
+    if (is_class_syntax(t.value)): t.type = t.value
+    t.type = reserved_words.get(t.value, t.type)
     return t
 
+lcase_ident_assigned = {}
 def t_LCASE_IDENT (t):
     r"[a-z](-[a-zA-Z0-9]|[a-zA-Z0-9])*" # can't end w/ '-'
+    if (not in_oid and lcase_ident_assigned.has_key(t.value)): t.type = 'LCASE_IDENT_ASSIGNED'
+    return t
+
+# 11.9 Real numbers
+def t_REAL_NUMBER (t):
+    r"[0-9]+\.[0-9]*(?!\.)"
     return t
 
 # 11.8 Numbers
@@ -320,14 +347,11 @@ def t_NUMBER (t):
     r"0|([1-9][0-9]*)"
     return t
 
-# 11.9 Real numbers
-# not supported yet
-
 # 11.6 Comments
 pyquote_str = 'PYQUOTE'
 def t_COMMENT(t):
     r"--(-[^\-\n]|[^\-\n])*(--|\n|-\n|$|-$)"
-    if (t.value.find("\n") >= 0) : t.lineno += 1
+    if (t.value.find("\n") >= 0) : t.lexer.lineno += 1
     if t.value[2:2+len (pyquote_str)] == pyquote_str:
         t.value = t.value[2+len(pyquote_str):]
         t.value = t.value.lstrip ()
@@ -339,13 +363,45 @@ t_ignore = " \t\r"
 
 def t_NEWLINE(t):
     r'\n+'
-    t.lineno += t.value.count("\n")
+    t.lexer.lineno += t.value.count("\n")
 
 def t_error(t):
-    print "Error", t.value[:100], t.lineno
-    raise LexError
+  global input_file
+  raise LexError(t, input_file)
 
-    
+# state 'braceignore'
+
+def t_braceignore_lbrace(t):     
+  r'\{'
+  t.lexer.level +=1                
+
+def t_braceignore_rbrace(t):
+  r'\}'
+  t.lexer.level -=1
+  # If closing brace, return token
+  if t.lexer.level == 0:
+    t.type = 'RBRACE'
+    return t
+
+def t_braceignore_QSTRING (t):
+  r'"([^"]|"")*"'
+  t.lexer.lineno += t.value.count("\n")
+
+def t_braceignore_COMMENT(t):
+  r"--(-[^\-\n]|[^\-\n])*(--|\n|-\n|$|-$)"
+  if (t.value.find("\n") >= 0) : t.lexer.lineno += 1
+
+def t_braceignore_nonspace(t):
+   r'[^\s\{\}\"-]+|-(?!-)'
+
+t_braceignore_ignore = " \t\r"
+
+def t_braceignore_NEWLINE(t):
+  r'\n+'
+  t.lexer.lineno += t.value.count("\n")
+
+def t_braceignore_error(t):
+  t.lexer.skip(1)
 
 class Ctx:
     def __init__ (self, defined_dict, indent = 0):
@@ -421,11 +477,86 @@ class Ctx:
         self.name_ctr += 1
         return "_compiler_generated_name_%d" % (self.name_ctr,)
 
+#--- Flags for EXPORT, USER_DEFINED, NO_EMIT, MAKE_ENUM -------------------------------
+EF_TYPE    = 0x0001
+EF_VALS    = 0x0002
+EF_ENUM    = 0x0004
+EF_WS_VAR  = 0x0010
+EF_EXTERN  = 0x0020
+EF_NO_PROT = 0x0040
+EF_NO_TYPE = 0x0080
+EF_UCASE   = 0x0100
+EF_TABLE   = 0x0400
+EF_DEFINE  = 0x0800
+
+#--- common dependency computation ---
+# Input  : list of items
+#          dictionary with lists of dependency
+#
+#           
+# Output : list of two outputs:
+#          [0] list of items in dependency
+#          [1] list of cycle dependency cycles
+def dependency_compute(items, dependency, map_fn = lambda t: t, ignore_fn = lambda t: False):
+  item_ord = []
+  item_cyc = []
+  x = {}  # already emitted
+  #print '# Dependency computation'
+  for t in items:
+    if x.has_key(map_fn(t)):
+      #print 'Continue: %s : %s' % (t, (map_fn(t))
+      continue
+    stack = [t]
+    stackx = {t : dependency.get(t, [])[:]}
+    #print 'Push: %s : %s' % (t, str(stackx[t]))
+    while stack:
+      if stackx[stack[-1]]:  # has dependencies
+        d = stackx[stack[-1]].pop(0)
+        if x.has_key(map_fn(d)) or ignore_fn(d):
+          continue
+        if stackx.has_key(d):  # cyclic dependency
+          c = stack[:]
+          c.reverse()
+          c = [d] + c[0:c.index(d)+1]
+          c.reverse()
+          item_cyc.append(c)
+          #print 'Cyclic: %s ' % (' -> '.join(c))
+          continue
+        stack.append(d)
+        stackx[d] = dependency.get(d, [])[:]
+        #print 'Push: %s : %s' % (d, str(stackx[d]))
+      else:
+        #print 'Pop: %s' % (stack[-1])
+        del stackx[stack[-1]]
+        e = map_fn(stack.pop())
+        if x.has_key(e):
+          continue
+        #print 'Add: %s' % (e)
+        item_ord.append(e)
+        x[e] = True
+  return (item_ord, item_cyc)
+
 #--- EthCtx -------------------------------------------------------------------
 class EthCtx:
   def __init__(self, conform, output, indent = 0):
     self.conform = conform
     self.output = output
+    self.conform.ectx = self
+    self.output.ectx = self
+    self.encoding = 'per'
+    self.aligned = False
+    self.new_ber = False
+    self.default_oid_variant = ''
+    self.default_opentype_variant = ''
+    self.default_containing_variant = '_pdu_new'
+    self.default_embedded_pdv_cb = None
+    self.default_external_type_cb = None
+    self.emitted_pdu = {}
+    self.module = {}
+    self.module_ord = []
+    self.all_type_attr = {}
+    self.all_tags = {}
+    self.all_vals = {}
 
   def encp(self):  # encoding protocol
     encp = self.encoding
@@ -434,16 +565,78 @@ class EthCtx:
   # Encoding
   def Per(self): return self.encoding == 'per'
   def Ber(self): return self.encoding == 'ber'
+  def NewBer(self): return self.new_ber
   def Aligned(self): return self.aligned
   def Unaligned(self): return not self.aligned
+  def Fld(self, tnm='*'): return self.fld_opt.get('*', False) or self.fld_opt.get(tnm, False) or (self.Ber() and not self.NewBer())
+  def Tag(self): return self.tag_opt # or self.Ber() - temporary comment out (experimental feature)
   def NAPI(self): return False  # disable planned features
 
+  def Module(self):  # current module name
+    return self.modules[-1][0]
+
+  def groups(self):
+    return self.group_by_prot or (self.conform.last_group > 0)
+
   def dbg(self, d):
     if (self.dbgopt.find(d) >= 0):
       return True
     else:
       return False
 
+  def value_max(self, a, b):
+    if (a == 'MAX') or (b == 'MAX'): return 'MAX';
+    if a == 'MIN': return b;
+    if b == 'MIN': return a;
+    try:
+      if (int(a) > int(b)):
+        return a
+      else:
+        return b
+    except (ValueError, TypeError):
+      pass
+    return "MAX((%s),(%s))" % (a, b) 
+
+  def value_min(self, a, b):
+    if (a == 'MIN') or (b == 'MIN'): return 'MIN';
+    if a == 'MAX': return b;
+    if b == 'MAX': return a;
+    try:
+      if (int(a) < int(b)):
+        return a
+      else:
+        return b
+    except (ValueError, TypeError):
+      pass
+    return "MIN((%s),(%s))" % (a, b) 
+
+  def value_get_eth(self, val):
+    if isinstance(val, Value):
+      return val.to_str(self)
+    ethname = val
+    if self.value.has_key(val):
+      ethname = self.value[val]['ethname']
+    return ethname
+
+  def value_get_val(self, nm):
+    val = asn2c(nm)
+    if self.value.has_key(nm):
+      if self.value[nm]['import']:
+        v = self.get_val_from_all(nm, self.value[nm]['import'])
+        if v is None:
+          msg = 'Need value of imported value identifier %s from %s (%s)' % (nm, self.value[nm]['import'], self.value[nm]['proto'])
+          warnings.warn_explicit(msg, UserWarning, '', '')
+        else:
+          val = v
+      else:
+        val = self.value[nm]['value']
+        if isinstance (val, Value):
+          val = val.to_str(self)
+    else:
+      msg = 'Need value of unknown value identifier %s' % (nm)
+      warnings.warn_explicit(msg, UserWarning, '', '')
+    return val
+
   def eth_get_type_attr(self, type):
     types = [type]
     while (not self.type[type]['import'] 
@@ -453,10 +646,108 @@ class EthCtx:
     attr = {}
     while len(types):
       t = types.pop()
-      attr.update(self.type[t]['attr'])
-      attr.update(self.eth_type[self.type[t]['ethname']]['attr'])
+      if (self.type[t]['import']):
+        attr.update(self.type[t]['attr'])
+        attr.update(self.eth_get_type_attr_from_all(t, self.type[t]['import']))
+      elif (self.type[t]['val'].type == 'SelectionType'):
+        val = self.type[t]['val']
+        (ftype, display) = val.eth_ftype(self)
+        attr.update({ 'TYPE' : ftype, 'DISPLAY' : display,
+                      'STRINGS' : val.eth_strings(), 'BITMASK' : '0' });
+      else:
+        attr.update(self.type[t]['attr'])
+        attr.update(self.eth_type[self.type[t]['ethname']]['attr'])
+    return attr
+
+  def eth_get_type_attr_from_all(self, type, module):
+    attr = {}
+    if self.all_type_attr.has_key(module) and self.all_type_attr[module].has_key(type):
+      attr = self.all_type_attr[module][type]
     return attr
 
+  def get_ttag_from_all(self, type, module):
+    ttag = None
+    if self.all_tags.has_key(module) and self.all_tags[module].has_key(type):
+      ttag = self.all_tags[module][type]
+    return ttag
+
+  def get_val_from_all(self, nm, module):
+    val = None
+    if self.all_vals.has_key(module) and self.all_vals[module].has_key(nm):
+      val = self.all_vals[module][nm]
+    return val
+
+  def get_obj_repr(self, ident, restr):
+    def set_type_fn(cls, field, fnfield):
+      obj[fnfield + '_fn'] = 'NULL'
+      obj[fnfield + '_pdu'] = 'NULL'
+      if val.has_key(field) and isinstance(val[field], Type_Ref):
+        p = val[field].eth_type_default_pars(self, '')
+        obj[fnfield + '_fn'] = p['TYPE_REF_FN']
+        obj[fnfield + '_fn'] = obj[fnfield + '_fn'] % p  # one iteration
+        if (self.conform.check_item('PDU', cls + '.' + field)):
+          obj[fnfield + '_pdu'] = 'dissect_' + self.field[val[field].val]['ethname']
+      return
+    # end of get_type_fn()
+    obj = { '_name' : ident, '_ident' : asn2c(ident)}
+    obj['_class'] = self.oassign[ident].cls
+    val = self.oassign[ident].val
+    fld = None
+    fld_neg = False
+    if len(restr) > 0:
+      fld = restr[0]
+      if fld[0] == '!':
+        fld_neg = True
+        fld = fld[1:]
+    if fld:
+      if fld_neg:
+        if val.has_key(fld):
+          return None
+      else:
+        if not val.has_key(fld):
+          return None
+    for f in val.keys():
+      if isinstance(val[f], Node):
+        obj[f] = val[f].fld_obj_repr(self)
+      else:
+        obj[f] = str(val[f])
+    if (obj['_class'] == 'TYPE-IDENTIFIER') or (obj['_class'] == 'ABSTRACT-SYNTAX'):
+      set_type_fn(obj['_class'], '&Type', '_type')
+    if (obj['_class'] == 'OPERATION'):
+      set_type_fn(obj['_class'], '&ArgumentType', '_argument')
+      set_type_fn(obj['_class'], '&ResultType', '_result')
+    if (obj['_class'] == 'ERROR'):
+      set_type_fn(obj['_class'], '&ParameterType', '_parameter')
+    return obj
+
+  #--- eth_reg_module -----------------------------------------------------------
+  def eth_reg_module(self, module):
+    #print "eth_reg_module(module='%s')" % (module)
+    name = module.get_name()
+    self.modules.append([name, module.get_proto(self)])
+    if self.module.has_key(name):
+      raise "Duplicate module for " + name
+    self.module[name] = []
+    self.module_ord.append(name)
+
+  #--- eth_module_dep_add ------------------------------------------------------------
+  def eth_module_dep_add(self, module, dep):
+    self.module[module].append(dep)
+
+  #--- eth_exports ------------------------------------------------------------
+  def eth_exports(self, exports):
+    self.exports_all = False
+    if ((len(exports) == 1) and (exports[0] == 'ALL')):
+      self.exports_all = True
+      return
+    for e in (exports):
+      if isinstance(e, Type_Ref):
+        self.exports.append(e.val)
+      elif isinstance(e, Class_Ref):
+        self.cexports.append(e.val)
+      else:
+        self.vexports.append(e)
+
   #--- eth_reg_assign ---------------------------------------------------------
   def eth_reg_assign(self, ident, val, virt=False):
     #print "eth_reg_assign(ident='%s')" % (ident)
@@ -464,6 +755,8 @@ class EthCtx:
       raise "Duplicate assignment for " + ident
     self.assign[ident] = { 'val' : val , 'virt' : virt }
     self.assign_ord.append(ident)
+    if  (self.exports_all):
+      self.exports.append(ident)
 
   #--- eth_reg_vassign --------------------------------------------------------
   def eth_reg_vassign(self, vassign):
@@ -473,12 +766,33 @@ class EthCtx:
       raise "Duplicate value assignment for " + ident
     self.vassign[ident] = vassign
     self.vassign_ord.append(ident)
+    if  (self.exports_all):
+      self.vexports.append(ident)
+
+  #--- eth_reg_oassign --------------------------------------------------------
+  def eth_reg_oassign(self, oassign):
+    ident = oassign.ident
+    #print "eth_reg_oassign(ident='%s')" % (ident)
+    if self.oassign.has_key(ident):
+      if self.oassign[ident] == oassign:
+        return  # OK - already defined
+      else:
+        raise "Duplicate information object assignment for " + ident
+    self.oassign[ident] = oassign
+    self.oassign_ord.append(ident)
+    self.oassign_cls.setdefault(oassign.cls, []).append(ident)
 
   #--- eth_import_type --------------------------------------------------------
   def eth_import_type(self, ident, mod, proto):
-    #print "eth_import_type(ident='%s', mod='%s', prot='%s')" % (ident, mod, prot)
+    #print "eth_import_type(ident='%s', mod='%s', prot='%s')" % (ident, mod, proto)
     if self.type.has_key(ident):
-      raise "Duplicate type for " + ident
+      #print "already defined import=%s, module=%s" % (str(self.type[ident]['import']), self.type[ident]['module'])
+      if not self.type[ident]['import'] and (self.type[ident]['module'] == mod) :
+        return  # OK - already defined
+      elif self.type[ident]['import'] and (self.type[ident]['import'] == mod) :
+        return  # OK - already imported
+      else:
+        raise "Duplicate type for " + ident
     self.type[ident] = {'import'  : mod, 'proto' : proto,
                         'ethname' : '' }
     self.type[ident]['attr'] = { 'TYPE' : 'FT_NONE', 'DISPLAY' : 'BASE_NONE',
@@ -486,38 +800,92 @@ class EthCtx:
     self.type[ident]['attr'].update(self.conform.use_item('TYPE_ATTR', ident))
     self.type_imp.append(ident)
 
+  #--- dummy_import_type --------------------------------------------------------
+  def dummy_import_type(self, ident):
+    # dummy imported
+    if self.type.has_key(ident):
+        raise "Try to dummy import for existing type :" + ident
+    ethtype = asn2c(ident)
+    self.type[ident] = {'import'  : 'xxx', 'proto' : 'xxx',
+                        'ethname' : ethtype }
+    self.type[ident]['attr'] = { 'TYPE' : 'FT_NONE', 'DISPLAY' : 'BASE_NONE',
+                                 'STRINGS' : 'NULL', 'BITMASK' : '0' }
+    self.eth_type[ethtype] = { 'import' : 'xxx', 'proto' : 'xxx' , 'attr' : {}, 'create_field' : False, 'ref' : []}
+    print "Dummy imported: %s (%s)" % (ident, ethtype)
+    return ethtype
+
+  #--- eth_import_class --------------------------------------------------------
+  def eth_import_class(self, ident, mod, proto):
+    #print "eth_import_class(ident='%s', mod='%s', prot='%s')" % (ident, mod, proto)
+    if self.objectclass.has_key(ident):
+      #print "already defined import=%s, module=%s" % (str(self.objectclass[ident]['import']), self.objectclass[ident]['module'])
+      if not self.objectclass[ident]['import'] and (self.objectclass[ident]['module'] == mod) :
+        return  # OK - already defined
+      elif self.objectclass[ident]['import'] and (self.objectclass[ident]['import'] == mod) :
+        return  # OK - already imported
+      else:
+        raise "Duplicate object class for " + ident
+    self.objectclass[ident] = {'import'  : mod, 'proto' : proto,
+                        'ethname' : '' }
+    self.objectclass_imp.append(ident)
+
   #--- eth_import_value -------------------------------------------------------
   def eth_import_value(self, ident, mod, proto):
     #print "eth_import_value(ident='%s', mod='%s', prot='%s')" % (ident, mod, prot)
-    if self.type.has_key(ident):
-      raise "Duplicate value for " + ident
+    if self.value.has_key(ident):
+      #print "already defined import=%s, module=%s" % (str(self.value[ident]['import']), self.value[ident]['module'])
+      if not self.value[ident]['import'] and (self.value[ident]['module'] == mod) :
+        return  # OK - already defined
+      elif self.value[ident]['import'] and (self.value[ident]['import'] == mod) :
+        return  # OK - already imported
+      else:
+        raise "Duplicate value for " + ident
     self.value[ident] = {'import'  : mod, 'proto' : proto,
                          'ethname' : ''}
     self.value_imp.append(ident)
 
+  #--- eth_sel_req ------------------------------------------------------------
+  def eth_sel_req(self, typ, sel):
+    key = typ + '.' + sel
+    if not self.sel_req.has_key(key):
+      self.sel_req[key] = { 'typ' : typ , 'sel' : sel}
+      self.sel_req_ord.append(key)
+    return key
+
+  #--- eth_comp_req ------------------------------------------------------------
+  def eth_comp_req(self, type):
+    self.comp_req_ord.append(type)
+
   #--- eth_dep_add ------------------------------------------------------------
   def eth_dep_add(self, type, dep):
-    if self.type_dep.has_key(type):
-      self.type_dep[type].append(dep)
-    else:
-      self.type_dep[type] = [dep]
+    if not self.type_dep.has_key(type): 
+      self.type_dep[type] = []
+    self.type_dep[type].append(dep)
 
   #--- eth_reg_type -----------------------------------------------------------
   def eth_reg_type(self, ident, val):
     #print "eth_reg_type(ident='%s', type='%s')" % (ident, val.type)
     if self.type.has_key(ident):
-      raise "Duplicate type for " + ident
+      if self.type[ident]['import'] and (self.type[ident]['import'] == self.Module()) :
+        # replace imported type
+        del self.type[ident]
+        self.type_imp.remove(ident)
+      else:
+        raise "Duplicate type for " + ident
     self.type[ident] = { 'val' : val, 'import' : None }
+    self.type[ident]['module'] = self.Module()
+    self.type[ident]['proto'] = self.proto
     if len(ident.split('/')) > 1:
       self.type[ident]['tname'] = val.eth_tname()
     else:
       self.type[ident]['tname'] = asn2c(ident)
     self.type[ident]['export'] = self.conform.use_item('EXPORTS', ident)
+    self.type[ident]['enum'] = self.conform.use_item('MAKE_ENUM', ident)
     self.type[ident]['user_def'] = self.conform.use_item('USER_DEFINED', ident)
     self.type[ident]['no_emit'] = self.conform.use_item('NO_EMIT', ident)
     self.type[ident]['tname'] = self.conform.use_item('TYPE_RENAME', ident, val_dflt=self.type[ident]['tname'])
     self.type[ident]['ethname'] = ''
-    if val.type == 'Type_Ref':
+    if (val.type == 'Type_Ref') or (val.type == 'SelectionType') :
       self.type[ident]['attr'] = {}
     else:
       (ftype, display) = val.eth_ftype(self)
@@ -525,25 +893,60 @@ class EthCtx:
                                    'STRINGS' : val.eth_strings(), 'BITMASK' : '0' }
     self.type[ident]['attr'].update(self.conform.use_item('TYPE_ATTR', ident))
     self.type_ord.append(ident)
+    # PDU
+    if (self.conform.check_item('PDU', ident)):
+      self.eth_reg_field(ident, ident, impl=val.HasImplicitTag(self), pdu=self.conform.use_item('PDU', ident))
+
+  #--- eth_reg_objectclass ----------------------------------------------------------
+  def eth_reg_objectclass(self, ident, val):
+    #print "eth_reg_objectclass(ident='%s')" % (ident)
+    if self.objectclass.has_key(ident):
+      if self.objectclass[ident]['import'] and (self.objectclass[ident]['import'] == self.Module()) :
+        # replace imported object class
+        del self.objectclass[ident]
+        self.objectclass_imp.remove(ident)
+      elif isinstance(self.objectclass[ident]['val'], Class_Ref) and \
+           isinstance(val, Class_Ref) and \
+           (self.objectclass[ident]['val'].val == val.val):
+        pass  # ignore duplicated CLASS1 ::= CLASS2
+      else:
+        raise "Duplicate object class for " + ident
+    self.objectclass[ident] = { 'import' : None, 'module' : self.Module(), 'proto' : self.proto }
+    self.objectclass[ident]['val'] = val
+    self.objectclass[ident]['export'] = self.conform.use_item('EXPORTS', ident)
+    self.objectclass_ord.append(ident)
 
   #--- eth_reg_value ----------------------------------------------------------
-  def eth_reg_value(self, ident, type, value):
+  def eth_reg_value(self, ident, type, value, ethname=None):
     #print "eth_reg_value(ident='%s')" % (ident)
     if self.value.has_key(ident):
-      raise "Duplicate value for " + ident
-    self.value[ident] = { 'import' : None, 'proto' : self.proto,
-                          'type' : type, 'value' : value }
+      if self.value[ident]['import'] and (self.value[ident]['import'] == self.Module()) :
+        # replace imported value
+        del self.value[ident]
+        self.value_imp.remove(ident)
+      elif ethname:
+        self.value[ident]['ethname'] = ethname
+        return
+      else:
+        raise "Duplicate value for " + ident
+    self.value[ident] = { 'import' : None, 'module' : self.Module(), 'proto' : self.proto,
+                          'type' : type, 'value' : value,
+                          'no_emit' : False }
     self.value[ident]['export'] = self.conform.use_item('EXPORTS', ident)
     self.value[ident]['ethname'] = ''
+    if (ethname): self.value[ident]['ethname'] = ethname
     self.value_ord.append(ident)
 
   #--- eth_reg_field ----------------------------------------------------------
   def eth_reg_field(self, ident, type, idx='', parent=None, impl=False, pdu=None):
     #print "eth_reg_field(ident='%s', type='%s')" % (ident, type)
     if self.field.has_key(ident):
-      raise "Duplicate field for " + ident
+      if pdu and (type == self.field[ident]['type']):
+        pass  # OK already created PDU
+      else:
+        raise "Duplicate field for " + ident
     self.field[ident] = {'type' : type, 'idx' : idx, 'impl' : impl, 'pdu' : pdu,
-                         'modified' : '', 'attr' : {} }
+                         'modified' : '', 'attr' : {} , 'create_field' : False }
     name = ident.split('/')[-1]
     if len(ident.split('/')) > 1 and name == '_item':  # Sequnce/Set of type
       self.field[ident]['attr']['NAME'] = '"Item"'
@@ -558,7 +961,9 @@ class EthCtx:
       self.pdu_ord.append(ident)
     else:
       self.field_ord.append(ident)
-    if parent: self.eth_dep_add(parent, type)
+    if parent:
+      self.field[ident]['create_field'] = self.Fld(parent)
+      self.eth_dep_add(parent, type)
 
   #--- eth_clean --------------------------------------------------------------
   def eth_clean(self):
@@ -573,13 +978,26 @@ class EthCtx:
     self.type_ord = []
     self.type_imp = []
     self.type_dep = {}
+    self.sel_req = {}
+    self.sel_req_ord = []
+    self.comp_req_ord = []
     self.vassign = {}
     self.vassign_ord = []
     self.value = {}
     self.value_ord = []
     self.value_imp = []
+    self.objectclass = {}
+    self.objectclass_ord = []
+    self.objectclass_imp = []
+    self.oassign = {}
+    self.oassign_ord = []
+    self.oassign_cls = {}
     #--- Modules ------------
     self.modules = []
+    self.exports_all = False
+    self.exports = []
+    self.cexports = []
+    self.vexports = []
     #--- types -------------------
     self.eth_type = {}
     self.eth_type_ord = []
@@ -614,12 +1032,55 @@ class EthCtx:
       self.eth_reg_type('_dummy/'+nm, NullType())
       self.eth_reg_field(nm, '_dummy/'+nm, pdu=self.conform.use_item('PDU', nm))
 
+    #--- required PDUs ----------------------------
+    for t in self.type_ord:
+      pdu = self.type[t]['val'].eth_need_pdu(self)
+      if not pdu: continue
+      f = pdu['type']
+      pdu['reg'] = None
+      pdu['hidden'] = False
+      pdu['need_decl'] = True
+      if not self.field.has_key(f):
+        self.eth_reg_field(f, f, pdu=pdu)
+
+    #--- values -> named values -------------------
+    t_for_update = {}
+    for v in self.value_ord:
+      if (self.value[v]['type'].type == 'Type_Ref'):
+        tnm = self.value[v]['type'].val
+        if self.type.has_key(tnm) \
+           and not self.type[tnm]['import'] \
+           and (self.type[tnm]['val'].type == 'IntegerType'):
+          self.type[tnm]['val'].add_named_value(v, self.value[v]['value'])
+          self.value[v]['no_emit'] = True
+          t_for_update[tnm] = True
+    for t in t_for_update.keys():
+      self.type[t]['attr']['STRINGS'] = self.type[t]['val'].eth_strings()
+      self.type[t]['attr'].update(self.conform.use_item('TYPE_ATTR', t))
+
+    #--- required components of ---------------------------
+    #print "self.comp_req_ord = ", self.comp_req_ord
+    for t in self.comp_req_ord:
+      self.type[t]['val'].eth_reg_sub(t, self, components_available=True)
+
+    #--- required selection types ---------------------------
+    #print "self.sel_req_ord = ", self.sel_req_ord
+    for t in self.sel_req_ord:
+      tt = self.sel_req[t]['typ']
+      if not self.type.has_key(tt):
+        self.dummy_import_type(t)
+      elif self.type[tt]['import']:
+        self.eth_import_type(t, self.type[tt]['import'], self.type[tt]['proto'])
+      else:
+        self.type[tt]['val'].sel_req(t, self.sel_req[t]['sel'], self)
+
     #--- types -------------------
     for t in self.type_imp:
       nm = asn2c(t)
       self.eth_type[nm] = { 'import' : self.type[t]['import'], 
                             'proto' : asn2c(self.type[t]['proto']),
-                            'attr' : {}, 'ref' : []}
+                            'attr' : {}, 'create_field' : False, 'ref' : []}
+      self.eth_type[nm]['attr'].update(self.conform.use_item('ETYPE_ATTR', nm))
       self.type[t]['ethname'] = nm
     for t in self.type_ord:
       nm = self.type[t]['tname']
@@ -629,8 +1090,10 @@ class EthCtx:
            not self.conform.check_item('TYPE_RENAME', t))):
         if len(t.split('/')) == 2 and t.split('/')[1] == '_item':  # Sequnce of type at the 1st level
           nm = t.split('/')[0] + t.split('/')[1]
-        elif t.split('/')[-1] == '_item':  # Sequnce of type at next levels
+        elif t.split('/')[-1] == '_item':  # Sequnce/Set of type at next levels
           nm = 'T_' + self.conform.use_item('FIELD_RENAME', '/'.join(t.split('/')[0:-1]), val_dflt=t.split('/')[-2]) + t.split('/')[-1]
+        elif t.split('/')[-1] == '_untag':  # Untagged type
+          nm = self.type['/'.join(t.split('/')[0:-1])]['ethname'] + '_U'
         else:
           nm = 'T_' + self.conform.use_item('FIELD_RENAME', t, val_dflt=t.split('/')[-1])
         nm = asn2c(nm)
@@ -639,25 +1102,26 @@ class EthCtx:
             self.eth_type_dupl[nm].append(t)
           else:
             self.eth_type_dupl[nm] = [self.eth_type[nm]['ref'][0], t]
-          nm += str(len(self.eth_type_dupl[nm])-1)
+          nm += '_%02d' % (len(self.eth_type_dupl[nm])-1)
       if self.eth_type.has_key(nm):
         self.eth_type[nm]['ref'].append(t)
       else:
         self.eth_type_ord.append(nm)
-        self.eth_type[nm] = { 'import' : None, 'proto' : self.eproto, 'export' : 0,
-                              'user_def' : 0x03, 'no_emit' : 0x03
+        self.eth_type[nm] = { 'import' : None, 'proto' : self.eproto, 'export' : 0, 'enum' : 0,
+                              'user_def' : EF_TYPE|EF_VALS, 'no_emit' : EF_TYPE|EF_VALS
                               'val' : self.type[t]['val'], 
                               'attr' : {}, 
-                              'ref' : [t]}
-        self.eth_type[nm]['attr'].update(self.conform.use_item('ETYPE_ATTR', nm))
+                              'create_field' : False, 'ref' : [t]}
       self.type[t]['ethname'] = nm
       if (not self.eth_type[nm]['export'] and self.type[t]['export']):  # new export
         self.eth_export_ord.append(nm)
       self.eth_type[nm]['export'] |= self.type[t]['export']
+      self.eth_type[nm]['enum'] |= self.type[t]['enum']
       self.eth_type[nm]['user_def'] &= self.type[t]['user_def']
       self.eth_type[nm]['no_emit'] &= self.type[t]['no_emit']
       if self.type[t]['attr'].get('STRINGS') == '$$':
         self.eth_type[nm]['attr']['STRINGS'] = 'VALS(%s)' % (self.eth_vals_nm(nm))
+      self.eth_type[nm]['attr'].update(self.conform.use_item('ETYPE_ATTR', nm))
     for t in self.eth_type_ord:
       bits = self.eth_type[t]['val'].eth_named_bits()
       if (bits):
@@ -672,6 +1136,11 @@ class EthCtx:
       else:
         self.eth_type[t]['tree'] = None
 
+    #--- register values from enums ------------
+    for t in self.eth_type_ord:
+      if (self.eth_type[t]['val'].eth_has_enum(t, self)):
+        self.eth_type[t]['val'].reg_enum_vals(t, self)
+
     #--- value dependencies -------------------
     for v in self.value_ord:
       if isinstance (self.value[v]['value'], Value):
@@ -689,7 +1158,7 @@ class EthCtx:
         d = deparr.pop()
         if not self.value[d]['import']:
           if not self.value[d]['export']:
-            self.value[d]['export'] = 0x01
+            self.value[d]['export'] = EF_TYPE
             deparr.extend(self.value_dep.get(d, []))
 
     #--- values -------------------
@@ -700,14 +1169,15 @@ class EthCtx:
                              'ref' : []}
       self.value[v]['ethname'] = nm
     for v in self.value_ord:
+      if (self.value[v]['ethname']):
+        continue
+      if (self.value[v]['no_emit']):
+        continue
       nm = asn2c(v)
       self.eth_value[nm] = { 'import' : None, 
                              'proto' : asn2c(self.value[v]['proto']),
                              'export' : self.value[v]['export'], 'ref' : [v] }
-      if isinstance (self.value[v]['value'], Value):
-        self.eth_value[nm]['value'] = self.value[v]['value'].to_str()
-      else:
-        self.eth_value[nm]['value'] = self.value[v]['value']
+      self.eth_value[nm]['value'] = self.value[v]['value']
       self.eth_value_ord.append(nm)
       self.value[v]['ethname'] = nm
 
@@ -721,44 +1191,44 @@ class EthCtx:
       nm = asn2c(nm)
       if (self.field[f]['pdu']): 
         nm += '_PDU'
+        if (not self.merge_modules):
+          nm = self.eproto + '_' + nm
       t = self.field[f]['type']
       if self.type.has_key(t):
         ethtype = self.type[t]['ethname']
       else:  # undefined type
-        # dummy imported
-        print "Dummy imported: ", t
-        self.type[t] = {'import'  : 'xxx', 'proto' : 'xxx',
-                        'ethname' : t }
-        self.type[t]['attr'] = { 'TYPE' : 'FT_NONE', 'DISPLAY' : 'BASE_NONE',
-                                 'STRINGS' : 'NULL', 'BITMASK' : '0' }
-        self.eth_type[t] = { 'import' : 'xxx', 'proto' : 'xxx' , 'attr' : {}, 'ref' : []}
-        ethtype = t
+        ethtype = self.dummy_import_type(t)
       ethtypemod = ethtype + self.field[f]['modified']
       if self.eth_hf.has_key(nm):
         if self.eth_hf_dupl.has_key(nm):
           if self.eth_hf_dupl[nm].has_key(ethtypemod):
             nm = self.eth_hf_dupl[nm][ethtypemod]
+            self.eth_hf[nm]['create_field'] = self.eth_hf[nm]['create_field'] or self.field[f]['create_field']
             self.eth_hf[nm]['ref'].append(f)
             self.field[f]['ethname'] = nm
+            self.eth_type[ethtype]['create_field'] = self.eth_type[ethtype]['create_field'] or self.eth_hf[nm]['create_field']
             continue
           else:
-            nmx = nm + str(len(self.eth_hf_dupl[nm]))
+            nmx = nm + ('_%02d' % (len(self.eth_hf_dupl[nm])))
             self.eth_hf_dupl[nm][ethtype] = nmx
             nm = nmx
         else:
           if (self.eth_hf[nm]['ethtype']+self.eth_hf[nm]['modified']) == ethtypemod:
+            self.eth_hf[nm]['create_field'] = self.eth_hf[nm]['create_field'] or self.field[f]['create_field']
             self.eth_hf[nm]['ref'].append(f)
             self.field[f]['ethname'] = nm
+            self.eth_type[ethtype]['create_field'] = self.eth_type[ethtype]['create_field'] or self.eth_hf[nm]['create_field']
             continue
           else:
+            nmx = nm + '_01'
             self.eth_hf_dupl[nm] = {self.eth_hf[nm]['ethtype']+self.eth_hf[nm]['modified'] : nm, \
-                                    ethtypemod : nm+'1'}
-            nm += '1'
+                                    ethtypemod : nmx}
+            nm = nmx
       if (self.field[f]['pdu']):
         self.eth_hfpdu_ord.append(nm)
       else:
         self.eth_hf_ord.append(nm)
-      fullname = "hf_%s_%s" % (self.eproto, nm)
+      fullname = 'hf_%s_%s' % (self.eproto, nm)
       attr = self.eth_get_type_attr(self.field[f]['type']).copy()
       attr.update(self.field[f]['attr'])
       if (self.NAPI() and attr.has_key('NAME')):
@@ -766,43 +1236,13 @@ class EthCtx:
       attr.update(self.conform.use_item('EFIELD_ATTR', nm))
       self.eth_hf[nm] = {'fullname' : fullname, 'pdu' : self.field[f]['pdu'],
                          'ethtype' : ethtype, 'modified' : self.field[f]['modified'],
-                         'attr' : attr.copy(), 'ref' : [f]}
+                         'attr' : attr.copy(), 
+                         'create_field' : self.field[f]['create_field'],
+                         'ref' : [f]}
       self.field[f]['ethname'] = nm
+      self.eth_type[ethtype]['create_field'] = self.eth_type[ethtype]['create_field'] or self.eth_hf[nm]['create_field']
     #--- type dependencies -------------------
-    x = {}  # already emitted
-    #print '# Dependency computation'
-    for t in self.type_ord:
-      if x.has_key(self.type[t]['ethname']):
-        #print 'Continue: %s : %s' % (t, self.type[t]['ethname'])
-        continue
-      stack = [t]
-      stackx = {t : self.type_dep.get(t, [])[:]}
-      #print 'Push: %s : %s' % (t, str(stackx[t]))
-      while stack:
-        if stackx[stack[-1]]:  # has dependencies
-          d = stackx[stack[-1]].pop(0)
-          if x.has_key(self.type[d]['ethname']) or self.type[d]['import']:
-            continue
-          if stackx.has_key(d):  # cyclic dependency
-            c = stack[:]
-            c.reverse()
-            c = [d] + c[0:c.index(d)+1]
-            c.reverse()
-            self.eth_dep_cycle.append(c)
-            #print 'Cyclic: %s ' % (' -> '.join(c))
-            continue
-          stack.append(d)
-          stackx[d] = self.type_dep.get(d, [])[:]
-          #print 'Push: %s : %s' % (d, str(stackx[d]))
-        else:
-          #print 'Pop: %s' % (stack[-1])
-          del stackx[stack[-1]]
-          e = self.type[stack.pop()]['ethname']
-          if x.has_key(e):
-            continue
-          #print 'Add: %s' % (e)
-          self.eth_type_ord1.append(e)
-          x[e] = True
+    (self.eth_type_ord1, self.eth_dep_cycle) = dependency_compute(self.type_ord, self.type_dep, map_fn = lambda t: self.type[t]['ethname'], ignore_fn = lambda t: self.type[t]['import'])
     i = 0
     while i < len(self.eth_dep_cycle):
       t = self.type[self.eth_dep_cycle[i][0]]['ethname']
@@ -816,10 +1256,36 @@ class EthCtx:
       else:
         self.eth_value_ord1.append(v)
 
+    #--- export tags, values, ... ---
+    for t in self.exports:
+      if not self.type.has_key(t):
+        continue
+      if self.type[t]['import']:
+        continue
+      m = self.type[t]['module']
+      if not self.all_tags.has_key(m):
+        self.all_tags[m] = {}
+      self.all_tags[m][t] = self.type[t]['val'].GetTTag(self)
+      if not self.all_type_attr.has_key(m):
+        self.all_type_attr[m] = {}
+      self.all_type_attr[m][t] = self.eth_get_type_attr(t).copy()
+    for v in self.vexports:
+      if not self.value.has_key(v):
+        continue
+      if self.value[v]['import']:
+        continue
+      m = self.value[v]['module']
+      if not self.all_vals.has_key(m):
+        self.all_vals[m] = {}
+      vv = self.value[v]['value']
+      if isinstance (vv, Value):
+        vv = vv.to_str(self)
+      self.all_vals[m][v] = vv
+
   #--- eth_vals_nm ------------------------------------------------------------
   def eth_vals_nm(self, tname):
     out = ""
-    if (not self.eth_type[tname]['export'] & 0x10):
+    if (not self.eth_type[tname]['export'] & EF_NO_PROT):
       out += "%s_" % (self.eproto)
     out += "%s_vals" % (tname)
     return out
@@ -827,14 +1293,71 @@ class EthCtx:
   #--- eth_vals ---------------------------------------------------------------
   def eth_vals(self, tname, vals):
     out = ""
-    if (not self.eth_type[tname]['export'] & 0x02):
+    has_enum = self.eth_type[tname]['enum'] & EF_ENUM
+    if (not self.eth_type[tname]['export'] & EF_VALS):
+      out += "static "
+    if (self.eth_type[tname]['export'] & EF_VALS) and (self.eth_type[tname]['export'] & EF_TABLE):
       out += "static "
     out += "const value_string %s[] = {\n" % (self.eth_vals_nm(tname))
     for (val, id) in vals:
-      out += '  { %3s, "%s" },\n' % (val, id)
+      if (has_enum):
+        vval = self.eth_enum_item(tname, id)
+      else:
+        vval = val
+      out += '  { %3s, "%s" },\n' % (vval, id)
     out += "  { 0, NULL }\n};\n"
     return out
 
+  #--- eth_enum_prefix ------------------------------------------------------------
+  def eth_enum_prefix(self, tname, type=False):
+    out = ""
+    if (self.eth_type[tname]['export'] & EF_ENUM):
+      no_prot = self.eth_type[tname]['export'] & EF_NO_PROT
+    else:
+      no_prot = self.eth_type[tname]['enum'] & EF_NO_PROT
+    if (not no_prot):
+      out += self.eproto
+    if ((not self.eth_type[tname]['enum'] & EF_NO_TYPE) or type):
+      if (out): out += '_'
+      out += tname
+    if (self.eth_type[tname]['enum'] & EF_UCASE):
+      out = out.upper()
+    if (out): out += '_'
+    return out
+
+  #--- eth_enum_nm ------------------------------------------------------------
+  def eth_enum_nm(self, tname):
+    out = self.eth_enum_prefix(tname, type=True)
+    out += "enum"
+    return out
+
+  #--- eth_enum_item ---------------------------------------------------------------
+  def eth_enum_item(self, tname, ident):
+    out = self.eth_enum_prefix(tname)
+    out += asn2c(ident)
+    if (self.eth_type[tname]['enum'] & EF_UCASE):
+      out = out.upper()
+    return out
+
+  #--- eth_enum ---------------------------------------------------------------
+  def eth_enum(self, tname, vals):
+    out = ""
+    if (self.eth_type[tname]['enum'] & EF_DEFINE):
+      out += "/* enumerated values for %s */\n" % (tname)
+      for (val, id) in vals:
+        out += '#define %-12s %3s\n' % (self.eth_enum_item(tname, id), val)
+    else:
+      out += "typedef enum _%s {\n" % (self.eth_enum_nm(tname))
+      first_line = 1
+      for (val, id) in vals:
+        if (first_line == 1):
+          first_line = 0
+        else:
+          out += ",\n"  
+        out += '  %-12s = %3s' % (self.eth_enum_item(tname, id), val)
+      out += "\n} %s;\n" % (self.eth_enum_nm(tname))
+    return out
+
   #--- eth_bits ---------------------------------------------------------------
   def eth_bits(self, tname, bits):
     out = ""
@@ -848,13 +1371,13 @@ class EthCtx:
   #--- eth_type_fn_h ----------------------------------------------------------
   def eth_type_fn_h(self, tname):
     out = ""
-    if (not self.eth_type[tname]['export'] & 0x01):
+    if (not self.eth_type[tname]['export'] & EF_TYPE):
       out += "static "
     out += "int "
     if (self.Ber()):
-      out += "dissect_%s_%s(gboolean implicit_tag, tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, int hf_index)" % (self.eth_type[tname]['proto'], tname)
+      out += "dissect_%s_%s(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_)" % (self.eth_type[tname]['proto'], tname)
     elif (self.Per()):
-      out += "dissect_%s_%s(tvbuff_t *tvb, int offset, asn_ctx_t *actx, proto_tree *tree, int hf_index)" % (self.eth_type[tname]['proto'], tname)
+      out += "dissect_%s_%s(tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_)" % (self.eth_type[tname]['proto'], tname)
     out += ";\n"
     return out
 
@@ -878,25 +1401,27 @@ class EthCtx:
   #--- eth_type_fn_hdr --------------------------------------------------------
   def eth_type_fn_hdr(self, tname):
     out = '\n'
-    if (not self.eth_type[tname]['export'] & 0x01):
+    if (not self.eth_type[tname]['export'] & EF_TYPE):
       out += "static "
     out += "int\n"
     if (self.Ber()):
-      out += "dissect_%s_%s(gboolean implicit_tag _U_, tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree, int hf_index _U_) {\n" % (self.eth_type[tname]['proto'], tname)
+      out += "dissect_%s_%s(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {\n" % (self.eth_type[tname]['proto'], tname)
     elif (self.Per()):
-      out += "dissect_%s_%s(tvbuff_t *tvb, int offset, asn_ctx_t *actx _U_, proto_tree *tree, int hf_index) {\n" % (self.eth_type[tname]['proto'], tname)
-    if self.conform.get_fn_presence(tname):
-      out += self.conform.get_fn_text(tname, 'FN_HDR')
-    elif self.conform.get_fn_presence(self.eth_type[tname]['ref'][0]):
+      out += "dissect_%s_%s(tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_, int hf_index _U_) {\n" % (self.eth_type[tname]['proto'], tname)
+    #if self.conform.get_fn_presence(tname):
+    #  out += self.conform.get_fn_text(tname, 'FN_HDR')
+    #el
+    if self.conform.get_fn_presence(self.eth_type[tname]['ref'][0]):
       out += self.conform.get_fn_text(self.eth_type[tname]['ref'][0], 'FN_HDR')
     return out
 
   #--- eth_type_fn_ftr --------------------------------------------------------
   def eth_type_fn_ftr(self, tname):
     out = '\n'
-    if self.conform.get_fn_presence(tname):
-      out += self.conform.get_fn_text(tname, 'FN_FTR')
-    elif self.conform.get_fn_presence(self.eth_type[tname]['ref'][0]):
+    #if self.conform.get_fn_presence(tname):
+    #  out += self.conform.get_fn_text(tname, 'FN_FTR')
+    #el
+    if self.conform.get_fn_presence(self.eth_type[tname]['ref'][0]):
       out += self.conform.get_fn_text(self.eth_type[tname]['ref'][0], 'FN_FTR')
     out += "  return offset;\n"
     out += "}\n"
@@ -905,9 +1430,10 @@ class EthCtx:
   #--- eth_type_fn_body -------------------------------------------------------
   def eth_type_fn_body(self, tname, body, pars=None):
     out = body
-    if self.conform.get_fn_body_presence(tname):
-      out = self.conform.get_fn_text(tname, 'FN_BODY')
-    elif self.conform.get_fn_body_presence(self.eth_type[tname]['ref'][0]):
+    #if self.conform.get_fn_body_presence(tname):
+    #  out = self.conform.get_fn_text(tname, 'FN_BODY')
+    #el
+    if self.conform.get_fn_body_presence(self.eth_type[tname]['ref'][0]):
       out = self.conform.get_fn_text(self.eth_type[tname]['ref'][0], 'FN_BODY')
     if pars:
       try:
@@ -933,10 +1459,8 @@ class EthCtx:
     if not len(self.eth_hf_ord) and not len(self.eth_hfpdu_ord) and not len(self.named_bit): return
     fx = self.output.file_open('hfarr')
     for f in (self.eth_hfpdu_ord + self.eth_hf_ord):
-      if len(self.eth_hf[f]['ref']) == 1:
-        blurb = '"' + self.eth_hf[f]['ref'][0] + '"'
-      else:
-        blurb = '""'
+      t = self.eth_hf[f]['ethtype']
+      blurb = '"%s.%s"' % (self.eth_type[t]['proto'], t)
       attr = self.eth_hf[f]['attr'].copy()
       attr['ABBREV'] = '"%s.%s"' % (self.proto, attr['ABBREV'])
       if not attr.has_key('BLURB'):
@@ -980,14 +1504,21 @@ class EthCtx:
     if (not len(self.eth_export_ord)): return
     fx = self.output.file_open('exp', ext='h')
     for t in self.eth_export_ord:  # vals
-      if (self.eth_type[t]['export'] & 0x02) and self.eth_type[t]['val'].eth_has_vals():
-        if self.eth_type[t]['export'] & 0x08:
-          fx.write("WS_VAR_IMPORT ")
+      if (self.eth_type[t]['export'] & EF_ENUM) and self.eth_type[t]['val'].eth_has_enum(t, self):
+        fx.write(self.eth_type[t]['val'].eth_type_enum(t, self))
+      if (self.eth_type[t]['export'] & EF_VALS) and self.eth_type[t]['val'].eth_has_vals():
+        if not self.eth_type[t]['export'] & EF_TABLE:
+          if self.eth_type[t]['export'] & EF_WS_VAR:
+            fx.write("WS_VAR_IMPORT ")
+          else:
+            fx.write("extern ")
+          fx.write("const value_string %s[];\n" % (self.eth_vals_nm(t)))
         else:
-          fx.write("extern ")
-        fx.write("const value_string %s[];\n" % (self.eth_vals_nm(t)))
+          fx.write(self.eth_type[t]['val'].eth_type_vals(t, self))
     for t in self.eth_export_ord:  # functions
-      if (self.eth_type[t]['export'] & 0x01):
+      if (self.eth_type[t]['export'] & EF_TYPE):
+        if self.eth_type[t]['export'] & EF_EXTERN:
+          fx.write("extern ")
         fx.write(self.eth_type_fn_h(t))
     self.output.file_close(fx)
 
@@ -1001,16 +1532,27 @@ class EthCtx:
     for (m, p) in self.modules:
       fx.write("%-*s  %s\n" % (maxw, m, p))
     fx.write('#.END\n\n')
+    for cls in self.objectclass_ord:
+      if self.objectclass[cls]['export']:
+        fx.write('#.CLASS %s\n' % (cls))
+        maxw = 2
+        for fld in self.objectclass[cls]['val'].fields:
+          w = len(fld.fld_repr()[0])  
+          if (w > maxw): maxw = w
+        for fld in self.objectclass[cls]['val'].fields:
+          repr = fld.fld_repr()
+          fx.write('%-*s  %s\n' % (maxw, repr[0], ' '.join(repr[1:])))
+        fx.write('#.END\n\n')
     if self.Ber():
       fx.write('#.IMPORT_TAG\n')
       for t in self.eth_export_ord:  # tags
-        if (self.eth_type[t]['export'] & 0x01):
+        if (self.eth_type[t]['export'] & EF_TYPE):
           fx.write('%-24s ' % self.eth_type[t]['ref'][0])
           fx.write('%s %s\n' % self.eth_type[t]['val'].GetTag(self))
       fx.write('#.END\n\n')
     fx.write('#.TYPE_ATTR\n')
     for t in self.eth_export_ord:  # attributes
-      if (self.eth_type[t]['export'] & 0x01):
+      if (self.eth_type[t]['export'] & EF_TYPE):
         fx.write('%-24s ' % self.eth_type[t]['ref'][0])
         attr = self.eth_get_type_attr(self.eth_type[t]['ref'][0]).copy()
         fx.write('TYPE = %(TYPE)-9s  DISPLAY = %(DISPLAY)-9s  STRINGS = %(STRINGS)s  BITMASK = %(BITMASK)s\n' % attr)
@@ -1022,7 +1564,15 @@ class EthCtx:
     if (not len(self.eth_value_ord1)): return
     fx = self.output.file_open('val', ext='h')
     for v in self.eth_value_ord1:
-      fx.write("#define %-30s %s\n" % (v, self.eth_value[v]['value']))
+      vv = self.eth_value[v]['value']
+      if isinstance (vv, Value):
+        vv = vv.to_str(self)
+      fx.write("#define %-30s %s\n" % (v, vv))
+    for t in self.eth_type_ord1:
+      if self.eth_type[t]['import']:
+        continue
+      if self.eth_type[t]['val'].eth_has_enum(t, self) and not (self.eth_type[t]['export'] & EF_ENUM):
+        fx.write(self.eth_type[t]['val'].eth_type_enum(t, self))
     self.output.file_close(fx)
 
   #--- eth_output_valexp ------------------------------------------------------
@@ -1030,7 +1580,10 @@ class EthCtx:
     if (not len(self.eth_vexport_ord)): return
     fx = self.output.file_open('valexp', ext='h')
     for v in self.eth_vexport_ord:
-      fx.write("#define %-30s %s\n" % (v, self.eth_value[v]['value']))
+      vv = self.eth_value[v]['value']
+      if isinstance (vv, Value):
+        vv = vv.to_str(self)
+      fx.write("#define %-30s %s\n" % (v, vv))
     self.output.file_close(fx)
 
   #--- eth_output_types -------------------------------------------------------
@@ -1056,50 +1609,79 @@ class EthCtx:
         if (self.Ber()):
           if (i): postfix = '_impl'; impl = 'TRUE'
           else:   postfix = '';      impl = 'FALSE'
-          out += 'static int dissect_'+f+postfix+'(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int offset) {\n'
-          par=((impl, 'tvb', 'offset', 'pinfo', 'tree', self.eth_hf[f]['fullname']),)
+          out += 'static int dissect_'+f+postfix+'(proto_tree *tree _U_, tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_) {\n'
+          par=((impl, 'tvb', 'offset', 'actx', 'tree', self.eth_hf[f]['fullname']),)
         else:
-          out += 'static int dissect_'+f+'(tvbuff_t *tvb, int offset, asn_ctx_t *actx, proto_tree *tree) {\n'
+          out += 'static int dissect_'+f+'(tvbuff_t *tvb _U_, int offset _U_, asn1_ctx_t *actx _U_, proto_tree *tree _U_) {\n'
           par=(('tvb', 'offset', 'actx', 'tree', self.eth_hf[f]['fullname']),)
         out += self.eth_fn_call('dissect_%s_%s' % (self.eth_type[t]['proto'], t), ret='return',
                                 par=par)
         out += '}\n'
       return out
     #end out_field()
-    def out_pdu(f):
+    def out_pdu_decl(f):
       t = self.eth_hf[f]['ethtype']
       is_new = self.eth_hf[f]['pdu']['new']
-      if self.field[self.eth_hf[f]['ref'][0]]['impl']:
-        impl = 'TRUE'
+      out = 'static '
+      if (is_new):
+        out += 'int'
       else:
-        impl = 'FALSE'
+        out += 'void'
+      out += ' dissect_'+f+'(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_);\n'
+      return out
+    #end out_pdu_decl()
+    def out_pdu(f):
+      t = self.eth_hf[f]['ethtype']
+      is_new = self.eth_hf[f]['pdu']['new']
+      impl = 'FALSE'
       out = 'static '
       if (is_new):
         out += 'int'
       else:
         out += 'void'
-      out += ' dissect_'+f+'(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {\n'
+      out += ' dissect_'+f+'(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_) {\n'
+      if (is_new):
+        out += '  int offset = 0;\n'
+        off_par = 'offset'
+        ret_par = 'offset'
+      else:
+        off_par = '0'
+        ret_par = None
       if (self.Per()):
         if (self.Aligned()):
           aligned = 'TRUE'
         else:
           aligned = 'FALSE'
-        out += "  asn_ctx_t asn_ctx;\n"
-        out += self.eth_fn_call('asn_ctx_init', par=(('&asn_ctx', 'ASN_ENC_PER', aligned, 'pinfo'),))
+        out += "  asn1_ctx_t asn1_ctx;\n"
+        out += self.eth_fn_call('asn1_ctx_init', par=(('&asn1_ctx', 'ASN1_ENC_PER', aligned, 'pinfo'),))
       if (self.Ber()):
-        par=((impl, 'tvb', '0', 'pinfo', 'tree', self.eth_hf[f]['fullname']),)
+        out += "  asn1_ctx_t asn1_ctx;\n"
+        out += self.eth_fn_call('asn1_ctx_init', par=(('&asn1_ctx', 'ASN1_ENC_BER', 'TRUE', 'pinfo'),))
+        par=((impl, 'tvb', off_par,'&asn1_ctx', 'tree', self.eth_hf[f]['fullname']),)
       elif (self.Per()):
-        par=(('tvb', '0', '&asn_ctx', 'tree', self.eth_hf[f]['fullname']),)
+        par=(('tvb', off_par, '&asn1_ctx', 'tree', self.eth_hf[f]['fullname']),)
       else:
         par=((),)
-      ret = None
-      if (is_new): ret = 'return'
-      out += self.eth_fn_call('dissect_%s_%s' % (self.eth_type[t]['proto'], t), ret=ret, par=par)
+      out += self.eth_fn_call('dissect_%s_%s' % (self.eth_type[t]['proto'], t), ret=ret_par, par=par)
+      if (self.Per() and is_new):
+        out += '  offset += 7; offset >>= 3;\n'
+      if (is_new):
+        out += '  return offset;\n'
       out += '}\n'
       return out
     #end out_pdu()
     fx = self.output.file_open('fn')
     pos = fx.tell()
+    if (len(self.eth_hfpdu_ord)):
+      first_decl = True
+      for f in self.eth_hfpdu_ord:
+        if (self.eth_hf[f]['pdu'] and self.eth_hf[f]['pdu']['need_decl']):
+          if first_decl:
+            fx.write('/*--- PDUs declarations ---*/\n')
+            first_decl = False
+          fx.write(out_pdu_decl(f))
+      if not first_decl:
+        fx.write('\n')
     if self.eth_dep_cycle:
       fx.write('/*--- Cyclic dependencies ---*/\n\n')
       i = 0
@@ -1108,15 +1690,15 @@ class EthCtx:
         if self.dep_cycle_eth_type[t][0] != i: i += 1; continue
         fx.write(''.join(map(lambda i: '/* %s */\n' % ' -> '.join(self.eth_dep_cycle[i]), self.dep_cycle_eth_type[t])))
         fx.write(self.eth_type_fn_h(t))
-        if (not self.NAPI()):
+        if (self.Fld() or self.eth_type[t]['create_field']):
           fx.write('\n')
           for f in self.eth_hf_ord:
-            if (self.eth_hf[f]['ethtype'] == t):
+            if ((self.eth_hf[f]['ethtype'] == t) and (self.Fld() or self.eth_hf[f]['create_field'])):
               fx.write(out_field(f))
         fx.write('\n')
         i += 1
       fx.write('\n')
-    if (not self.NAPI()):  # fields for imported types
+    if (self.Fld()):  # fields for imported types
       fx.write('/*--- Fields for imported types ---*/\n\n')
       for f in self.eth_hf_ord:
         if (self.eth_type[self.eth_hf[f]['ethtype']]['import']):
@@ -1126,28 +1708,34 @@ class EthCtx:
       if self.eth_type[t]['import']:
         continue
       if self.eth_type[t]['val'].eth_has_vals():
-        if self.eth_type[t]['no_emit'] & 0x02:
+        if self.eth_type[t]['no_emit'] & EF_VALS:
           pass
-        elif self.eth_type[t]['user_def'] & 0x02:
+        elif self.eth_type[t]['user_def'] & EF_VALS:
           fx.write("extern const value_string %s[];\n" % (self.eth_vals_nm(t)))
+        elif (self.eth_type[t]['export'] & EF_VALS) and (self.eth_type[t]['export'] & EF_TABLE):
+          pass
         else:
           fx.write(self.eth_type[t]['val'].eth_type_vals(t, self))
-      if self.eth_type[t]['no_emit'] & 0x01:
+      if self.eth_type[t]['no_emit'] & EF_TYPE:
         pass
-      elif self.eth_type[t]['user_def'] & 0x01:
+      elif self.eth_type[t]['user_def'] & EF_TYPE:
         fx.write(self.eth_type_fn_h(t))
       else:
         fx.write(self.eth_type[t]['val'].eth_type_fn(self.eth_type[t]['proto'], t, self))
-      if (not self.NAPI() and not self.dep_cycle_eth_type.has_key(t)):
+      if ((self.Fld() or self.eth_type[t]['create_field']) and not self.dep_cycle_eth_type.has_key(t)):
         for f in self.eth_hf_ord:
-          if (self.eth_hf[f]['ethtype'] == t):
+          if ((self.eth_hf[f]['ethtype'] == t) and (self.Fld() or self.eth_hf[f]['create_field'])):
             fx.write(out_field(f))
       fx.write('\n')
     if (len(self.eth_hfpdu_ord)):
       fx.write('/*--- PDUs ---*/\n\n')
       for f in self.eth_hfpdu_ord:
         if (self.eth_hf[f]['pdu']):
-          fx.write(out_pdu(f))
+          if (self.emitted_pdu.has_key(f)):
+            fx.write("  /* %s already emitted */\n" % (f))
+          else:
+            fx.write(out_pdu(f))
+            self.emitted_pdu[f] = True
       fx.write('\n')
     fempty = pos == fx.tell()
     self.output.file_close(fx, discard=fempty)
@@ -1208,13 +1796,47 @@ class EthCtx:
             hnd = 'find_dissector("%s")' % (dis)
         else:
           hnd = '%screate_dissector_handle(dissect_%s, proto_%s)' % (new_prefix, f, self.eproto)
-        fx.write('  dissector_add%s("%s", %s, %s);\n' % (rstr, reg['rtable'], reg['rport'], hnd))
+        rport = self.value_get_eth(reg['rport'])
+        fx.write('  dissector_add%s("%s", %s, %s);\n' % (rstr, reg['rtable'], rport, hnd))
       elif (reg['rtype'] in ('BER', 'PER')):
-        fx.write('  %sregister_%s_oid_dissector(%s, dissect_%s, proto_%s, %s);\n' % (new_prefix, reg['rtype'].lower(), reg['roid'], f, self.eproto, reg['roidname']))
+        roid = self.value_get_eth(reg['roid'])
+        fx.write('  %sregister_%s_oid_dissector(%s, dissect_%s, proto_%s, %s);\n' % (new_prefix, reg['rtype'].lower(), roid, f, self.eproto, reg['roidname']))
       fempty = False
     fx.write('\n')
     self.output.file_close(fx, discard=fempty)
 
+  #--- eth_output_table -----------------------------------------------------
+  def eth_output_table(self):
+    for num in self.conform.report.keys():
+      fx = self.output.file_open('table' + num)
+      for rep in self.conform.report[num]:
+        if rep['type'] == 'HDR':
+          fx.write('\n')
+        if rep['var']:
+          var = rep['var']
+          var_list = var.split('.')
+          cls = var_list[0]
+          del var_list[0]
+          if (self.oassign_cls.has_key(cls)):
+            for ident in self.oassign_cls[cls]:
+             obj = self.get_obj_repr(ident, var_list)
+             if not obj:
+               continue
+             obj['_LOOP'] = var
+             obj['_DICT'] = str(obj)
+             try:
+               text = rep['text'] % obj
+             except (KeyError):
+               raise sys.exc_type, "%s:%s invalid key %s for information object %s of %s" % (rep['fn'], rep['lineno'], sys.exc_value, ident, var)
+             fx.write(text)
+          else:
+            fx.write("/* Unknown or empty loop list %s */\n" % (var))
+        else:
+          fx.write(rep['text'])
+        if rep['type'] == 'FTR':
+          fx.write('\n')
+      self.output.file_close(fx)
+
   #--- dupl_report -----------------------------------------------------
   def dupl_report(self):
     # types
@@ -1223,11 +1845,8 @@ class EthCtx:
     for t in tmplist:
       msg = "The same type names for different types. Explicit type renaming is recommended.\n"
       msg += t + "\n"
-      x = ''
       for tt in self.eth_type_dupl[t]:
-        msg += " %-20s %s\n" % (t+str(x), tt)
-        if not x: x = 1
-        else: x += 1
+        msg += " %-20s %s\n" % (self.type[tt]['ethname'], tt)
       warnings.warn_explicit(msg, UserWarning, '', '')
     # fields
     tmplist = self.eth_hf_dupl.keys()
@@ -1250,7 +1869,11 @@ class EthCtx:
         if (self.assign[a]['virt']): v = '*'
         print v, a
       print "\n# Value assignments"
-      print "\n".join(self.vassign_ord)
+      for a in self.vassign_ord:
+        print ' ', a
+      print "\n# Information object assignments"
+      for a in self.oassign_ord:
+        print " %-12s (%s)" % (a, self.oassign[a].cls)
     if self.dbg('t'):
       print "\n# Imported Types"
       print "%-40s %-24s %-24s" % ("ASN.1 name", "Module", "Protocol")
@@ -1262,6 +1885,11 @@ class EthCtx:
       print "-" * 100
       for t in self.value_imp:
         print "%-40s %-24s %-24s" % (t, self.value[t]['import'], self.value[t]['proto'])
+      print "\n# Imported Object Classes"
+      print "%-40s %-24s %-24s" % ("ASN.1 name", "Module", "Protocol")
+      print "-" * 100
+      for t in self.objectclass_imp:
+        print "%-40s %-24s %-24s" % (t, self.objectclass[t]['import'], self.objectclass[t]['proto'])
       print "\n# Exported Types"
       print "%-31s %s" % ("Wireshark type", "Export Flag")
       print "-" * 100
@@ -1271,7 +1899,15 @@ class EthCtx:
       print "%-40s %s" % ("Wireshark name", "Value")
       print "-" * 100
       for v in self.eth_vexport_ord:
-        print "%-40s %s" % (v, self.eth_value[v]['value'])
+        vv = self.eth_value[v]['value']
+        if isinstance (vv, Value):
+          vv = vv.to_str(self)
+        print "%-40s %s" % (v, vv)
+      print "\n# ASN.1 Object Classes"
+      print "%-40s %-24s %-24s" % ("ASN.1 name", "Module", "Protocol")
+      print "-" * 100
+      for t in self.objectclass_ord:
+        print "%-40s " % (t)
       print "\n# ASN.1 Types"
       print "%-49s %-24s %-24s" % ("ASN.1 unique name", "'tname'", "Wireshark type")
       print "-" * 100
@@ -1284,18 +1920,21 @@ class EthCtx:
         print "%-31s %d" % (t, len(self.eth_type[t]['ref'])),
         print ', '.join(self.eth_type[t]['ref'])
       print "\n# ASN.1 Values"
-      print "%-40s %-18s %s" % ("ASN.1 unique name", "Type", "Value")
+      print "%-40s %-18s %-20s %s" % ("ASN.1 unique name", "Type", "Value", "Wireshark value")
       print "-" * 100
       for v in self.value_ord:
-        if isinstance (self.value[v]['value'], Value):
-          print "%-40s %-18s %s" % (v, self.value[v]['type'].eth_tname(), self.value[v]['value'].to_str())
-        else:
-          print "%-40s %-18s %s" % (v, self.value[v]['type'].eth_tname(), self.value[v]['value'])
-      print "\n# Wireshark Values"
-      print "%-40s %s" % ("Wireshark name", "Value")
-      print "-" * 100
-      for v in self.eth_value_ord:
-        print "%-40s %s" % (v, self.eth_value[v]['value'])
+        vv = self.value[v]['value']
+        if isinstance (vv, Value):
+          vv = vv.to_str(self)
+        print "%-40s %-18s %-20s %s" % (v, self.value[v]['type'].eth_tname(), vv, self.value[v]['ethname'])
+      #print "\n# Wireshark Values"
+      #print "%-40s %s" % ("Wireshark name", "Value")
+      #print "-" * 100
+      #for v in self.eth_value_ord:
+      #  vv = self.eth_value[v]['value']
+      #  if isinstance (vv, Value):
+      #    vv = vv.to_str(self)
+      #  print "%-40s %s" % (v, vv)
       print "\n# ASN.1 Fields"
       print "ASN.1 unique name                        Wireshark name        ASN.1 type"
       print "-" * 100
@@ -1316,6 +1955,7 @@ class EthCtx:
     self.output.outnm = self.outnm_opt
     if (not self.output.outnm):
       self.output.outnm = self.proto
+      self.output.outnm = self.output.outnm.replace('.', '-')
     self.eth_output_hf()
     self.eth_output_ett()
     self.eth_output_types()
@@ -1329,22 +1969,58 @@ class EthCtx:
     self.eth_output_dis_hnd()
     self.eth_output_dis_reg()
     self.eth_output_dis_tab()
+    self.eth_output_table()
+
+  def dbg_modules(self):
+    def print_mod(m):
+      print "%-30s " % (m),
+      dep = self.module[m][:]
+      for i in range(len(dep)):
+        if not self.module.has_key(dep[i]): 
+          dep[i] = '*' + dep[i]
+      print ', '.join(dep)
+    # end of print_mod()
+    (mod_ord, mod_cyc) = dependency_compute(self.module_ord, self.module, ignore_fn = lambda t: not self.module.has_key(t))
+    print "\n# ASN.1 Moudules"
+    print "Module name                     Dependency"
+    print "-" * 100
+    new_ord = False
+    for m in (self.module_ord):
+      print_mod(m)
+      new_ord = new_ord or (self.module_ord.index(m) != mod_ord.index(m))
+    if new_ord:
+      print "\n# ASN.1 Moudules - in dependency order"
+      print "Module name                     Dependency"
+      print "-" * 100
+      for m in (mod_ord):
+        print_mod(m)
+    if mod_cyc:
+      print "\nCyclic dependencies:"
+      for i in (range(len(mod_cyc))):
+        print "%02d: %s" % (i + 1, str(mod_cyc[i]))
+
 
 #--- EthCnf -------------------------------------------------------------------
 class EthCnf:
   def __init__(self):
+    self.ectx = None
     self.tblcfg = {}
     self.table = {}
     self.order = {}
     self.fn = {}
+    self.report = {}
+    self.suppress_line = False
+    self.include_path = []
     #                                   Value name             Default value       Duplicity check   Usage check
     self.tblcfg['EXPORTS']         = { 'val_nm' : 'flag',     'val_dflt' : 0,     'chk_dup' : True, 'chk_use' : True }
+    self.tblcfg['MAKE_ENUM']       = { 'val_nm' : 'flag',     'val_dflt' : 0,     'chk_dup' : True, 'chk_use' : True }
     self.tblcfg['PDU']             = { 'val_nm' : 'attr',     'val_dflt' : None,  'chk_dup' : True, 'chk_use' : True }
     self.tblcfg['REGISTER']        = { 'val_nm' : 'attr',     'val_dflt' : None,  'chk_dup' : True, 'chk_use' : True }
     self.tblcfg['USER_DEFINED']    = { 'val_nm' : 'flag',     'val_dflt' : 0,     'chk_dup' : True, 'chk_use' : True }
     self.tblcfg['NO_EMIT']         = { 'val_nm' : 'flag',     'val_dflt' : 0,     'chk_dup' : True, 'chk_use' : True }
     self.tblcfg['MODULE']          = { 'val_nm' : 'proto',    'val_dflt' : None,  'chk_dup' : True, 'chk_use' : False }
     self.tblcfg['OMIT_ASSIGNMENT'] = { 'val_nm' : 'omit',     'val_dflt' : False, 'chk_dup' : True, 'chk_use' : True }
+    self.tblcfg['NO_OMIT_ASSGN']   = { 'val_nm' : 'omit',     'val_dflt' : True,  'chk_dup' : True, 'chk_use' : True }
     self.tblcfg['VIRTUAL_ASSGN']   = { 'val_nm' : 'name',     'val_dflt' : None,  'chk_dup' : True, 'chk_use' : True }
     self.tblcfg['SET_TYPE']        = { 'val_nm' : 'type',     'val_dflt' : None,  'chk_dup' : True, 'chk_use' : True }
     self.tblcfg['TYPE_RENAME']     = { 'val_nm' : 'eth_name', 'val_dflt' : None,  'chk_dup' : True, 'chk_use' : True }
@@ -1355,6 +2031,7 @@ class EthCnf:
     self.tblcfg['ETYPE_ATTR']      = { 'val_nm' : 'attr',     'val_dflt' : {},    'chk_dup' : True, 'chk_use' : False }
     self.tblcfg['FIELD_ATTR']      = { 'val_nm' : 'attr',     'val_dflt' : {},    'chk_dup' : True, 'chk_use' : True }
     self.tblcfg['EFIELD_ATTR']     = { 'val_nm' : 'attr',     'val_dflt' : {},    'chk_dup' : True, 'chk_use' : True }
+    self.tblcfg['ASSIGNED_ID']     = { 'val_nm' : 'ids',      'val_dflt' : {},    'chk_dup' : False,'chk_use' : False }
 
 
     for k in self.tblcfg.keys() :
@@ -1371,6 +2048,13 @@ class EthCnf:
     self.table[table][key].update(kw)
     self.order[table].append(key)
 
+  def update_item(self, table, key, fn, lineno, **kw):
+    if not self.table[table].has_key(key):
+      self.table[table][key] = {'fn' : fn, 'lineno' : lineno, 'used' : False}
+      self.order[table].append(key)
+      self.table[table][key][self.tblcfg[table]['val_nm']] = {}
+    self.table[table][key][self.tblcfg[table]['val_nm']].update(kw[self.tblcfg[table]['val_nm']])
+
   def get_order(self, table):
     return self.order[table]
 
@@ -1388,6 +2072,16 @@ class EthCnf:
     self.table[table][key]['used'] = True
     return self.table[table][key].get(vname, vdflt)
 
+  def omit_assignment(self, type, ident, module):
+    if self.ectx.conform.use_item('OMIT_ASSIGNMENT', ident): 
+      return True
+    if self.ectx.conform.use_item('OMIT_ASSIGNMENT', '*') or \
+       self.ectx.conform.use_item('OMIT_ASSIGNMENT', '*'+type) or \
+       self.ectx.conform.use_item('OMIT_ASSIGNMENT', '*/'+module) or \
+       self.ectx.conform.use_item('OMIT_ASSIGNMENT', '*'+type+'/'+module):
+      return self.ectx.conform.use_item('NO_OMIT_ASSGN', ident)
+    return False
+
   def add_fn_line(self, name, ctx, line, fn, lineno):
     if not self.fn.has_key(name):
       self.fn[name] = {'FN_HDR' : None, 'FN_FTR' : None, 'FN_BODY' : None}
@@ -1408,14 +2102,17 @@ class EthCnf:
     if (not self.fn[name][ctx]):
       return '';
     self.fn[name][ctx]['used'] = True
-    return '#line %u "%s"\n%s\n' % (self.fn[name][ctx]['lineno'],self.fn[name][ctx]['fn'],self.fn[name][ctx]['text']);
+    out = self.fn[name][ctx]['text']
+    if (not self.suppress_line): 
+      out = '#line %u "%s"\n%s\n' % (self.fn[name][ctx]['lineno'], self.fn[name][ctx]['fn'], out);
+    return out
 
   def add_pdu(self, par, is_new, fn, lineno):
     #print "add_pdu(par=%s, %s, %d)" % (str(par), fn, lineno)
     (reg, hidden) = (None, False)
     if (len(par) > 1): reg = par[1]
     if (reg and reg[0]=='@'): (reg, hidden) = (reg[1:], True)
-    attr = {'new' : is_new, 'reg' : reg, 'hidden' : hidden}
+    attr = {'new' : is_new, 'reg' : reg, 'hidden' : hidden, 'need_decl' : False}
     self.add_item('PDU', par[0], attr=attr, fn=fn, lineno=lineno)
     return
 
@@ -1439,26 +2136,33 @@ class EthCnf:
     elif (rtype in ('BER', 'PER')): 
       attr['roid'] = par[1]
       attr['roidname'] = '""'
-      if (len(par)>=3): attr['roidname'] = par[2]
+      if (len(par)>=3): 
+        attr['roidname'] = par[2]
+      elif attr['roid'][0] != '"':
+        attr['roidname'] = '"' + attr['roid'] + '"'
       rkey = '/'.join([rtype, attr['roid']])
     self.add_item('REGISTER', rkey, attr=attr, fn=fn, lineno=lineno)
 
+  def check_par(self, par, pmin, pmax, fn, lineno):
+    for i in range(len(par)):
+      if par[i] == '-':
+        par[i] = None
+        continue
+      if par[i][0] == '#':
+        par[i:] = []
+        break
+    if len(par) < pmin:
+      warnings.warn_explicit("Too few parameters. At least %d parameters are required" % (pmin), UserWarning, fn, lineno)
+      return None
+    if (pmax >= 0) and (len(par) > pmax):
+      warnings.warn_explicit("Too many parameters. Only %d parameters are allowed" % (pmax), UserWarning, fn, lineno)
+      return par[0:pmax]
+    return par
+
   def read(self, fn):
     def get_par(line, pmin, pmax, fn, lineno):
       par = line.split(None, pmax)
-      for i in range(len(par)):
-        if par[i] == '-':
-          par[i] = None
-          continue
-        if par[i][0] == '#':
-          par[i:] = []
-          break
-      if len(par) < pmin:
-        warnings.warn_explicit("Too few parameters. At least %d parameters are required" % (pmin), UserWarning, fn, lineno)
-        return None
-      if (pmax >= 0) and (len(par) > pmax):
-        warnings.warn_explicit("Too many parameters. Only %d parameters are allowed" % (pmax), UserWarning, fn, lineno)
-        return par[0:pmax]
+      par = self.check_par(par, pmin, pmax, fn, lineno)
       return par
 
     def get_par_nm(line, pmin, pmax, fn, lineno):
@@ -1499,18 +2203,24 @@ class EthCnf:
       return par
 
     f = open(fn, "r")
-    directive = re.compile(r'^\s*#\.(?P<name>[A-Z_]+)\s+')
+    directive = re.compile(r'^\s*#\.(?P<name>[A-Z_][A-Z_0-9]*)\s+')
+    report = re.compile(r'^TABLE(?P<num>\d*)_(?P<type>HDR|BODY|FTR)$')
     comment = re.compile(r'^\s*#[^.]')
     empty = re.compile(r'^\s*$')
     lineno = 0
     ctx = None
     name = ''
+    default_flags = 0x00
     stack = []
     while 1:
-      line = f.readline()
-      lineno += 1
+      if not f.closed:
+        line = f.readline()
+        lineno += 1
+      else:
+        line = None
       if not line:
-        f.close()
+        if not f.closed:
+          f.close()
         if stack:
           frec = stack.pop()
           fn, f, lineno = frec['fn'], frec['f'], frec['lineno']
@@ -1520,12 +2230,73 @@ class EthCnf:
       if comment.search(line): continue
       result = directive.search(line)
       if result:  # directive
-        if result.group('name') in ('EXPORTS', 'PDU', 'PDU_NEW', 'REGISTER', 'REGISTER_NEW', 
-                                    'USER_DEFINED', 'NO_EMIT', 'MODULE', 'MODULE_IMPORT', 
-                                    'OMIT_ASSIGNMENT', 'VIRTUAL_ASSGN', 'SET_TYPE',
+        rep_result = report.search(result.group('name'))
+        if result.group('name') == 'END_OF_CNF':
+          f.close()
+        elif result.group('name') == 'OPT':
+          ctx = result.group('name')
+          par = get_par(line[result.end():], 0, -1, fn=fn, lineno=lineno)
+          if not par: continue
+          self.set_opt(par[0], par[1:], fn, lineno)
+          ctx = None
+        elif result.group('name') in ('PDU', 'PDU_NEW', 'REGISTER', 'REGISTER_NEW', 
+                                    'MODULE', 'MODULE_IMPORT', 
+                                    'OMIT_ASSIGNMENT', 'NO_OMIT_ASSGN', 
+                                    'VIRTUAL_ASSGN', 'SET_TYPE',
                                     'TYPE_RENAME', 'FIELD_RENAME', 'TF_RENAME', 'IMPORT_TAG',
                                     'TYPE_ATTR', 'ETYPE_ATTR', 'FIELD_ATTR', 'EFIELD_ATTR'):
           ctx = result.group('name')
+        elif result.group('name') in ('OMIT_ALL_ASSIGNMENTS', 'OMIT_ASSIGNMENTS_EXCEPT',
+                                      'OMIT_ALL_TYPE_ASSIGNMENTS', 'OMIT_TYPE_ASSIGNMENTS_EXCEPT',
+                                      'OMIT_ALL_VALUE_ASSIGNMENTS', 'OMIT_VALUE_ASSIGNMENTS_EXCEPT'):
+          ctx = result.group('name')
+          key = '*'
+          if ctx in ('OMIT_ALL_TYPE_ASSIGNMENTS', 'OMIT_TYPE_ASSIGNMENTS_EXCEPT'):
+            key += 'T'
+          if ctx in ('OMIT_ALL_VALUE_ASSIGNMENTS', 'OMIT_VALUE_ASSIGNMENTS_EXCEPT'):
+            key += 'V'
+          par = get_par(line[result.end():], 0, 1, fn=fn, lineno=lineno)
+          if par: 
+            key += '/' + par[0]
+          self.add_item('OMIT_ASSIGNMENT', key, omit=True, fn=fn, lineno=lineno)
+          if ctx in ('OMIT_ASSIGNMENTS_EXCEPT', 'OMIT_TYPE_ASSIGNMENTS_EXCEPT', 'OMIT_VALUE_ASSIGNMENTS_EXCEPT'):
+            ctx = 'NO_OMIT_ASSGN'
+          else:
+            ctx = None
+        elif result.group('name') in ('EXPORTS', 'USER_DEFINED', 'NO_EMIT'):
+          ctx = result.group('name')
+          default_flags = EF_TYPE|EF_VALS
+          if ctx == 'EXPORTS':
+            par = get_par(line[result.end():], 0, 5, fn=fn, lineno=lineno)
+          else:
+            par = get_par(line[result.end():], 0, 1, fn=fn, lineno=lineno)
+          if not par: continue
+          p = 1
+          if (par[0] == 'WITH_VALS'):      default_flags |= EF_TYPE|EF_VALS
+          elif (par[0] == 'WITHOUT_VALS'): default_flags |= EF_TYPE; default_flags &= ~EF_TYPE
+          elif (par[0] == 'ONLY_VALS'):    default_flags &= ~EF_TYPE; default_flags |= EF_VALS
+          elif (ctx == 'EXPORTS'): p = 0
+          else: warnings.warn_explicit("Unknown parameter value '%s'" % (par[0]), UserWarning, fn, lineno)
+          for i in range(p, len(par)):
+            if (par[i] == 'ONLY_ENUM'):   default_flags &= ~(EF_TYPE|EF_VALS); default_flags |= EF_ENUM
+            elif (par[i] == 'WITH_ENUM'): default_flags |= EF_ENUM
+            elif (par[i] == 'VALS_WITH_TABLE'):  default_flags |= EF_TABLE
+            elif (par[i] == 'WS_VAR'):    default_flags |= EF_WS_VAR
+            elif (par[i] == 'EXTERN'):    default_flags |= EF_EXTERN
+            elif (par[i] == 'NO_PROT_PREFIX'): default_flags |= EF_NO_PROT
+            else: warnings.warn_explicit("Unknown parameter value '%s'" % (par[i]), UserWarning, fn, lineno)
+        elif result.group('name') in ('MAKE_ENUM', 'MAKE_DEFINES'):
+          ctx = result.group('name')
+          default_flags = EF_ENUM
+          if ctx == 'MAKE_ENUM': default_flags |= EF_NO_PROT|EF_NO_TYPE
+          if ctx == 'MAKE_DEFINES': default_flags |= EF_DEFINE|EF_UCASE|EF_NO_TYPE
+          par = get_par(line[result.end():], 0, 3, fn=fn, lineno=lineno)
+          for i in range(0, len(par)):
+            if (par[i] == 'NO_PROT_PREFIX'):   default_flags |= EF_NO_PROT
+            elif (par[i] == 'NO_TYPE_PREFIX'): default_flags |= EF_NO_TYPE
+            elif (par[i] == 'UPPER_CASE'):     default_flags |= EF_UCASE
+            elif (par[i] == 'NO_UPPER_CASE'):  default_flags &= ~EF_UCASE
+            else: warnings.warn_explicit("Unknown parameter value '%s'" % (par[i]), UserWarning, fn, lineno)
         elif result.group('name') in ('FN_HDR', 'FN_FTR'):
           par = get_par(line[result.end():], 1, 1, fn=fn, lineno=lineno)
           if not par: continue
@@ -1543,18 +2314,54 @@ class EthCnf:
           ctx = result.group('name')
           if not par:
             name = None
-          else:
+          elif len(par) == 1:
             name = par[0]
-          if len(par) > 1:
-            self.add_item(ctx, name, pars=par[1], fn=fn, lineno=lineno)
+            self.add_item(ctx, name, pars={}, fn=fn, lineno=lineno)
+          elif len(par) > 1:
+            self.add_item(ctx, par[0], pars=par[1], fn=fn, lineno=lineno)
             ctx = None
-            name = None
+        elif result.group('name') == 'CLASS':
+          par = get_par(line[result.end():], 1, 1, fn=fn, lineno=lineno)
+          if not par: continue
+          ctx = result.group('name')
+          name = par[0]
+          add_class_ident(name)
+          if not name.isupper():
+            warnings.warn_explicit("No lower-case letters shall be included in information object class name (%s)" % (name),
+                                    UserWarning, fn, lineno)
+        elif result.group('name') == 'ASSIGNED_OBJECT_IDENTIFIER':
+          par = get_par(line[result.end():], 1, 1, fn=fn, lineno=lineno)
+          if not par: continue
+          self.update_item('ASSIGNED_ID', 'OBJECT_IDENTIFIER', ids={par[0] : par[0]}, fn=fn, lineno=lineno)
+        elif rep_result:  # Reports
+          num = rep_result.group('num')
+          type = rep_result.group('type')
+          if type == 'BODY':
+            par = get_par(line[result.end():], 1, 1, fn=fn, lineno=lineno)
+            if not par: continue
+          else:
+            par = get_par(line[result.end():], 0, 0, fn=fn, lineno=lineno)
+          rep = { 'type' : type, 'var' : None, 'text' : '', 'fn' : fn, 'lineno' : lineno }
+          if len(par) > 0:
+            rep['var'] = par[0]
+          self.report.setdefault(num, []).append(rep)
+          ctx = 'TABLE'
+          name = num
         elif result.group('name') == 'INCLUDE':
           par = get_par(line[result.end():], 1, 1, fn=fn, lineno=lineno)
           if not par: 
             warnings.warn_explicit("INCLUDE requires parameter", UserWarning, fn, lineno)
             continue
-          fname = os.path.join(os.path.split(fn)[0], par[0])
+          fname = par[0]
+          #print "Try include: %s" % (fname)
+          if (not os.path.exists(fname)):
+            fname = os.path.join(os.path.split(fn)[0], par[0])
+          #print "Try include: %s" % (fname)
+          i = 0
+          while not os.path.exists(fname) and (i < len(self.include_path)):
+            fname = os.path.join(self.include_path[i], par[0])
+            #print "Try include: %s" % (fname)
+            i += 1
           if (not os.path.exists(fname)):
             fname = par[0]
           fnew = open(fname, "r")
@@ -1568,26 +2375,47 @@ class EthCnf:
       if not ctx:
         if not empty.match(line):
           warnings.warn_explicit("Non-empty line in empty context", UserWarning, fn, lineno)
+      elif ctx == 'OPT':
+        if empty.match(line): continue
+        par = get_par(line, 1, -1, fn=fn, lineno=lineno)
+        if not par: continue
+        self.set_opt(par[0], par[1:], fn, lineno)
       elif ctx in ('EXPORTS', 'USER_DEFINED', 'NO_EMIT'):
         if empty.match(line): continue
         if ctx == 'EXPORTS':
-          par = get_par(line, 1, 4, fn=fn, lineno=lineno)
+          par = get_par(line, 1, 6, fn=fn, lineno=lineno)
         else:
           par = get_par(line, 1, 2, fn=fn, lineno=lineno)
         if not par: continue
-        flag = 0x03
+        flags = default_flags
         p = 2
         if (len(par)>=2):
-          if (par[1] == 'WITH_VALS'):      flag = 0x03
-          elif (par[1] == 'WITHOUT_VALS'): flag = 0x01
-          elif (par[1] == 'ONLY_VALS'):    flag = 0x02
+          if (par[1] == 'WITH_VALS'):      flags |= EF_TYPE|EF_VALS
+          elif (par[1] == 'WITHOUT_VALS'): flags |= EF_TYPE; flags &= ~EF_TYPE
+          elif (par[1] == 'ONLY_VALS'):    flags &= ~EF_TYPE; flags |= EF_VALS
           elif (ctx == 'EXPORTS'): p = 1
           else: warnings.warn_explicit("Unknown parameter value '%s'" % (par[1]), UserWarning, fn, lineno)
         for i in range(p, len(par)):
-          if (par[i] == 'WS_VAR'):          flag |= 0x08
-          elif (par[i] == 'NO_PROT_PREFIX'): flag |= 0x10
+          if (par[i] == 'ONLY_ENUM'):        flags &= ~(EF_TYPE|EF_VALS); flags |= EF_ENUM
+          elif (par[i] == 'WITH_ENUM'):      flags |= EF_ENUM
+          elif (par[i] == 'VALS_WITH_TABLE'):  flags |= EF_TABLE
+          elif (par[i] == 'WS_VAR'):         flags |= EF_WS_VAR
+          elif (par[i] == 'EXTERN'):         flags |= EF_EXTERN
+          elif (par[i] == 'NO_PROT_PREFIX'): flags |= EF_NO_PROT
+          else: warnings.warn_explicit("Unknown parameter value '%s'" % (par[i]), UserWarning, fn, lineno)
+        self.add_item(ctx, par[0], flag=flags, fn=fn, lineno=lineno)
+      elif ctx in ('MAKE_ENUM', 'MAKE_DEFINES'):
+        if empty.match(line): continue
+        par = get_par(line, 1, 4, fn=fn, lineno=lineno)
+        if not par: continue
+        flags = default_flags
+        for i in range(1, len(par)):
+          if (par[i] == 'NO_PROT_PREFIX'):   flags |= EF_NO_PROT
+          elif (par[i] == 'NO_TYPE_PREFIX'): flags |= EF_NO_TYPE
+          elif (par[i] == 'UPPER_CASE'):     flags |= EF_UCASE
+          elif (par[i] == 'NO_UPPER_CASE'):  flags &= ~EF_UCASE
           else: warnings.warn_explicit("Unknown parameter value '%s'" % (par[i]), UserWarning, fn, lineno)
-        self.add_item(ctx, par[0], flag=flag, fn=fn, lineno=lineno)
+        self.add_item('MAKE_ENUM', par[0], flag=flags, fn=fn, lineno=lineno)
       elif ctx in ('PDU', 'PDU_NEW'):
         if empty.match(line): continue
         par = get_par(line, 1, 5, fn=fn, lineno=lineno)
@@ -1615,12 +2443,17 @@ class EthCnf:
         if empty.match(line): continue
         par = get_par(line, 3, 3, fn=fn, lineno=lineno)
         if not par: continue
-        self.add_item('IMPORT_TAG', par[0], ttag=(par[1], par[2]), fn=fn, lineno=lineno)
+        self.add_item(ctx, par[0], ttag=(par[1], par[2]), fn=fn, lineno=lineno)
       elif ctx == 'OMIT_ASSIGNMENT':
         if empty.match(line): continue
         par = get_par(line, 1, 1, fn=fn, lineno=lineno)
         if not par: continue
-        self.add_item('OMIT_ASSIGNMENT', par[0], omit=True, fn=fn, lineno=lineno)
+        self.add_item(ctx, par[0], omit=True, fn=fn, lineno=lineno)
+      elif ctx == 'NO_OMIT_ASSGN':
+        if empty.match(line): continue
+        par = get_par(line, 1, 1, fn=fn, lineno=lineno)
+        if not par: continue
+        self.add_item(ctx, par[0], omit=False, fn=fn, lineno=lineno)
       elif ctx == 'VIRTUAL_ASSGN':
         if empty.match(line): continue
         par = get_par(line, 2, -1, fn=fn, lineno=lineno)
@@ -1685,11 +2518,97 @@ class EthCnf:
           par = get_par_nm(line, 1, 1, fn=fn, lineno=lineno)
         if not par: continue
         if name:
-          self.add_item(ctx, name, pars=par[0], fn=fn, lineno=lineno)
+          self.update_item(ctx, name, pars=par[0], fn=fn, lineno=lineno)
         else:
           self.add_item(ctx, par[0], pars=par[1], fn=fn, lineno=lineno)
       elif ctx in ('FN_HDR', 'FN_FTR', 'FN_BODY'):
         self.add_fn_line(name, ctx, line, fn=fn, lineno=lineno)
+      elif ctx == 'CLASS':
+        if empty.match(line): continue
+        par = get_par(line, 1, 3, fn=fn, lineno=lineno)
+        if not par: continue
+        if not set_type_to_class(name, par[0], par[1:]):
+          warnings.warn_explicit("Could not set type of class member %s.&%s to %s" % (name, par[0], par[1]),
+                                  UserWarning, fn, lineno)
+      elif ctx == 'TABLE':
+        self.report[name][-1]['text'] += line
+
+  def set_opt(self, opt, par, fn, lineno):
+    #print "set_opt: %s, %s" % (opt, par)
+    if opt in ("-I",):
+      par = self.check_par(par, 1, 1, fn, lineno)
+      if not par: return
+      self.include_path.append(par[0])
+    elif opt in ("-b", "BER", "CER", "DER"):
+      par = self.check_par(par, 0, 0, fn, lineno)
+      self.ectx.encoding = 'ber'
+    elif opt in ("-X", "NEW_BER"):
+      par = self.check_par(par, 0, 0, fn, lineno)
+      self.ectx.new_ber = True
+    elif opt in ("PER",):
+      par = self.check_par(par, 0, 0, fn, lineno)
+      self.ectx.encoding = 'per'
+    elif opt in ("-p", "PROTO"):
+      par = self.check_par(par, 1, 1, fn, lineno)
+      if not par: return
+      self.ectx.proto_opt = par[0]
+      self.ectx.merge_modules = True
+    elif opt in ("-F", "CREATE_FIELDS"):
+      par = self.check_par(par, 0, 1, fn, lineno)
+      tnm = '*'
+      if (len(par) > 0): tnm = par[0]
+      self.ectx.fld_opt[tnm] = True
+    elif opt in ("-T",):
+      par = self.check_par(par, 0, 0, fn, lineno)
+      self.ectx.tag_opt = True
+    elif opt in ("ALIGNED",):
+      par = self.check_par(par, 0, 0, fn, lineno)
+      self.ectx.aligned = True
+    elif opt in ("-u", "UNALIGNED"):
+      par = self.check_par(par, 0, 0, fn, lineno)
+      self.ectx.aligned = False
+    elif opt in ("-d",):
+      par = self.check_par(par, 1, 1, fn, lineno)
+      if not par: return
+      self.ectx.dbgopt = par[0]
+    elif opt in ("-e",):
+      par = self.check_par(par, 0, 0, fn, lineno)
+      self.ectx.expcnf = True
+    elif opt in ("-S",):
+      par = self.check_par(par, 0, 0, fn, lineno)
+      self.ectx.merge_modules = True
+    elif opt in ("GROUP_BY_PROT",):
+      par = self.check_par(par, 0, 0, fn, lineno)
+      self.ectx.group_by_prot = True
+    elif opt in ("-o",):
+      par = self.check_par(par, 1, 1, fn, lineno)
+      if not par: return
+      self.ectx.outnm_opt = par[0]
+    elif opt in ("-O",):
+      par = self.check_par(par, 1, 1, fn, lineno)
+      if not par: return
+      self.ectx.output.outdir = par[0]
+    elif opt in ("-s",):
+      par = self.check_par(par, 1, 1, fn, lineno)
+      if not par: return
+      self.ectx.output.single_file = par[0]
+    elif opt in ("-k",):
+      par = self.check_par(par, 0, 0, fn, lineno)
+      self.ectx.output.keep = True
+    elif opt in ("-L",):
+      par = self.check_par(par, 0, 0, fn, lineno)
+      self.suppress_line = True
+    elif opt in ("EMBEDDED_PDV_CB",):
+      par = self.check_par(par, 1, 1, fn, lineno)
+      if not par: return
+      self.ectx.default_embedded_pdv_cb = par[0]
+    elif opt in ("EXTERNAL_TYPE_CB",):
+      par = self.check_par(par, 1, 1, fn, lineno)
+      if not par: return
+      self.ectx.default_external_type_cb = par[0]
+    else:
+      warnings.warn_explicit("Unknown option %s" % (opt),
+                             UserWarning, fn, lineno)
 
   def dbg_print(self):
     print "\n# Conformance values"
@@ -1729,12 +2648,32 @@ class EthCnf:
 #--- EthOut -------------------------------------------------------------------
 class EthOut:
   def __init__(self):
+    self.ectx = None
     self.outnm = None
     self.outdir = '.'
     self.single_file = None
-    self.created_files = []
-    self.unique_created_files = []
+    self.created_files = {}
+    self.created_files_ord = []
     self.keep = False
+
+  def outcomment(self, ln, comment=None):
+    if comment:
+      return '%s %s\n' % (comment, ln)
+    else:
+      return '/* %-74s */\n' % (ln)
+
+  def created_file_add(self, name, keep_anyway):
+    name = os.path.normcase(os.path.abspath(name))
+    if not self.created_files.has_key(name):
+      self.created_files_ord.append(name)
+      self.created_files[name] = keep_anyway
+    else:
+      self.created_files[name] = self.created_files[name] or keep_anyway
+
+  def created_file_exists(self, name):
+    name = os.path.normcase(os.path.abspath(name))
+    return self.created_files.has_key(name)
+
   #--- output_fname -------------------------------------------------------
   def output_fname(self, ftype, ext='c'):
     fn = ''
@@ -1751,39 +2690,53 @@ class EthOut:
   #--- file_open -------------------------------------------------------
   def file_open(self, ftype, ext='c'):
     fn = self.output_fullname(ftype, ext=ext)
-    fx = file(fn, 'w')
+    if self.created_file_exists(fn):
+      fx = file(fn, 'a')
+    else:
+      fx = file(fn, 'w')
+    comment = None
     if ext in ('cnf',):
-      fx.write(self.fhdr(fn, comment = '#'))
+      comment = '#'
+      fx.write(self.fhdr(fn, comment = comment))
     else:
-      if (not self.single_file):
+      if (not self.single_file and not self.created_file_exists(fn)):
         fx.write(self.fhdr(fn))
+    if not self.ectx.merge_modules:
+      fx.write('\n')
+      mstr = "--- "
+      if self.ectx.groups():
+        mstr += "Module"
+        if (len(self.ectx.modules) > 1):
+          mstr += "s"
+        for (m, p) in self.ectx.modules:
+          mstr += " %s" % (m)
+      else:
+        mstr += "Module %s" % (self.ectx.Module())
+      mstr += " --- --- ---"
+      fx.write(self.outcomment(mstr, comment))
+      fx.write('\n')
     return fx
   #--- file_close -------------------------------------------------------
   def file_close(self, fx, discard=False, keep_anyway=False):
     fx.close()
-    if (discard): 
+    if discard and not self.created_file_exists(fx.name): 
       os.unlink(fx.name)
-    elif (not keep_anyway):
-      self.created_files.append(os.path.normcase(os.path.abspath(fx.name)))
+    else:
+      self.created_file_add(fx.name, keep_anyway)
   #--- fhdr -------------------------------------------------------
   def fhdr(self, fn, comment=None):
-    def outln(ln):
-      if comment:
-        return '# %s\n' % (ln)
-      else:
-        return '/* %-74s */\n' % (ln)
     out = ''
-    out += outln('Do not modify this file.')
-    out += outln('It is created automatically by the ASN.1 to Wireshark dissector compiler')
-    out += outln(fn)
-    out += outln(' '.join(sys.argv))
+    out += self.outcomment('Do not modify this file.', comment)
+    out += self.outcomment('It is created automatically by the ASN.1 to Wireshark dissector compiler', comment)
+    out += self.outcomment(fn, comment)
+    out += self.outcomment(' '.join(sys.argv), comment)
     out += '\n'
     return out
 
   #--- dbg_print -------------------------------------------------------
   def dbg_print(self):
     print "\n# Output files"
-    print "\n".join(self.created_files)
+    print "\n".join(self.created_files_ord)
     print "\n"
 
   #--- make_single_file -------------------------------------------------------
@@ -1797,16 +2750,15 @@ class EthOut:
       out_nm = self.output_fullname('', ext='h')
       self.do_include(out_nm, in_nm)
     if (not self.keep):
-      self.unique_created_files = []
-      [self.unique_created_files.append(wrd) for wrd in self.created_files if not self.unique_created_files.count(wrd)]
-      for fn in self.unique_created_files:
-        os.unlink(fn)
+      for fn in self.created_files_ord:
+        if not self.created_files[fn]:
+          os.unlink(fn)
 
   #--- do_include -------------------------------------------------------
   def do_include(self, out_nm, in_nm):
     def check_file(fn, fnlist):
       fnfull = os.path.normcase(os.path.abspath(fn))
-      if ((fnfull in fnlist) and os.path.exists(fnfull)):
+      if (fnlist.has_key(fnfull) and os.path.exists(fnfull)):
         return os.path.normpath(fn)
       return None
     fin = file(in_nm, "r")
@@ -1882,7 +2834,7 @@ class Node:
         l.append ("".join (map (lambda (k,v): self.str_child (k, v, depth + 1),
                                 self.__dict__.items ())))
         return "\n".join (l)
-    def __str__(self):
+    def __repr__(self):
         return "\n" + self.str_depth (0)
     def to_python (self, ctx):
         return self.str_depth (ctx.indent_lev)
@@ -1890,16 +2842,65 @@ class Node:
     def eth_reg(self, ident, ectx):
         pass
 
-#--- value_assign -------------------------------------------------------------
-class value_assign (Node):
+    def fld_obj_repr(self, ectx):
+        return "/* TO DO %s */" % (str(self))
+
+#--- ValueAssignment -------------------------------------------------------------
+class ValueAssignment (Node):
   def __init__(self,*args, **kw) :
     Node.__init__ (self,*args, **kw)
 
   def eth_reg(self, ident, ectx):
-    if ectx.conform.use_item('OMIT_ASSIGNMENT', self.ident): return # Assignment to omit
+    if ectx.conform.omit_assignment('V', self.ident, ectx.Module()): return # Assignment to omit
     ectx.eth_reg_vassign(self)
     ectx.eth_reg_value(self.ident, self.typ, self.val)
 
+#--- ObjectAssignment -------------------------------------------------------------
+class ObjectAssignment (Node):
+  def __init__(self,*args, **kw) :
+    Node.__init__ (self,*args, **kw)
+
+  def __eq__(self, other):
+    if self.cls != other.cls:
+      return False
+    if len(self.val) != len(other.val):
+      return False
+    for f in (self.val.keys()):
+      if not other.val.has_key(f):
+        return False
+      if isinstance(self.val[f], Node) and isinstance(other.val[f], Node):
+        if not self.val[f].fld_obj_eq(other.val[f]):
+          return False
+      else:
+        if str(self.val[f]) != str(other.val[f]):
+          return False
+    return True
+
+  def eth_reg(self, ident, ectx):
+    def make_virtual_type(cls, field, prefix):
+      if isinstance(self.val, str): return
+      if self.val.has_key(field) and not isinstance(self.val[field], Type_Ref):
+        vnm = prefix + '-' + self.ident
+        virtual_tr = Type_Ref(val = vnm)
+        t = self.val[field]
+        self.val[field] = virtual_tr
+        ectx.eth_reg_assign(vnm, t, virt=True)
+        ectx.eth_reg_type(vnm, t)
+        t.eth_reg_sub(vnm, ectx)
+      if self.val.has_key(field) and ectx.conform.check_item('PDU', cls + '.' + field):
+        ectx.eth_reg_field(self.val[field].val, self.val[field].val, impl=self.val[field].HasImplicitTag(ectx), pdu=ectx.conform.use_item('PDU', cls + '.' + field))
+      return
+    # end of make_virtual_type()
+    if ectx.conform.omit_assignment('V', self.ident, ectx.Module()): return # Assignment to omit
+    ectx.eth_reg_oassign(self)
+    if (self.cls == 'TYPE-IDENTIFIER') or (self.cls == 'ABSTRACT-SYNTAX'):
+      make_virtual_type(self.cls, '&Type', 'TYPE')
+    if (self.cls == 'OPERATION'):
+      make_virtual_type(self.cls, '&ArgumentType', 'ARG')
+      make_virtual_type(self.cls, '&ResultType', 'RES')
+    if (self.cls == 'ERROR'):
+      make_virtual_type(self.cls, '&ParameterType', 'PAR')
+
 
 #--- Type ---------------------------------------------------------------------
 class Type (Node):
@@ -1907,6 +2908,7 @@ class Type (Node):
     self.name = None
     self.constr = None
     self.tags = []
+    self.named_list = None
     Node.__init__ (self,*args, **kw)
 
   def IsNamed(self):
@@ -1921,6 +2923,18 @@ class Type (Node):
     else :
       return True
 
+  def HasSizeConstraint(self):
+    return self.HasConstraint() and self.constr.IsSize()
+
+  def HasValueConstraint(self):
+    return self.HasConstraint() and self.constr.IsValue()
+
+  def HasPermAlph(self):
+    return self.HasConstraint() and self.constr.IsPermAlph()
+
+  def HasContentsConstraint(self):
+    return self.HasConstraint() and self.constr.IsContents()
+
   def HasOwnTag(self):
     return len(self.tags) > 0
 
@@ -1945,7 +2959,7 @@ class Type (Node):
     print self.str_depth(1)
     return ('BER_CLASS_unknown', 'TAG_unknown')
 
-  def SetName(self, name) :
+  def SetName(self, name):
     self.name = name
 
   def AddConstraint(self, constr):
@@ -1969,30 +2983,55 @@ class Type (Node):
   def eth_has_vals(self):
     return False
 
+  def eth_has_enum(self, tname, ectx):
+    return self.eth_has_vals() and (ectx.eth_type[tname]['enum'] & EF_ENUM)
+
+  def eth_need_pdu(self, ectx):
+    return None
+
   def eth_named_bits(self):
     return None
 
   def eth_reg_sub(self, ident, ectx):
     pass
 
-  def eth_reg(self, ident, ectx, idx='', parent=None):
+  def get_components(self, ectx):
+    print "#Unhandled  get_components() in %s" % (self.type)
+    print self.str_depth(1)
+    return []
+
+  def sel_req(self, sel, ectx):
+    print "#Selection '%s' required for non-CHOICE type %s" % (sel, self.type)
+    print self.str_depth(1)
+    
+  def fld_obj_eq(self, other):
+    return isinstance(other, Type) and (self.eth_tname() == other.eth_tname())
+
+  def eth_reg(self, ident, ectx, tstrip=0, tagflag=False, selflag=False, idx='', parent=None):
+    #print "eth_reg(): %s, ident=%s, tstrip=%d, tagflag=%s, selflag=%s, parent=%s" %(self.type, ident, tstrip, str(tagflag), str(selflag), str(parent))
+    if (ectx.Tag() and (len(self.tags) > tstrip)):
+      tagged_type = TaggedType(val=self, tstrip=tstrip)
+      tagged_type.AddTag(self.tags[tstrip])
+      if not tagflag:  # 1st tagged level
+        if self.IsNamed() and not selflag:
+          tagged_type.SetName(self.name)
+      tagged_type.eth_reg(ident, ectx, tstrip=1, tagflag=tagflag, idx=idx, parent=parent)
+      return
     nm = ''
-    if ident and self.IsNamed ():
+    if ident and self.IsNamed() and not tagflag and not selflag:
       nm = ident + '/' + self.name
-    elif self.IsNamed():
-      nm = self.name
     elif ident:
       nm = ident
-    if not ident and ectx.conform.use_item('OMIT_ASSIGNMENT', nm): return # Assignment to omit
+    elif self.IsNamed():
+      nm = self.name
+    if not ident and ectx.conform.omit_assignment('T', nm, ectx.Module()): return # Assignment to omit
     if not ident:  # Assignment
       ectx.eth_reg_assign(nm, self)
       if self.type == 'Type_Ref':
         ectx.eth_reg_type(nm, self)
-      if (ectx.conform.check_item('PDU', nm)):
-        ectx.eth_reg_field(nm, nm, impl=self.HasImplicitTag(ectx), pdu=ectx.conform.use_item('PDU', nm))
     virtual_tr = Type_Ref(val=ectx.conform.use_item('SET_TYPE', nm))
     if (self.type == 'Type_Ref') or ectx.conform.check_item('SET_TYPE', nm):
-      if ectx.conform.check_item('TYPE_RENAME', nm) or ectx.conform.get_fn_presence(nm):
+      if ident and (ectx.conform.check_item('TYPE_RENAME', nm) or ectx.conform.get_fn_presence(nm) or selflag):
         if ectx.conform.check_item('SET_TYPE', nm):
           ectx.eth_reg_type(nm, virtual_tr)  # dummy Type Reference
         else:
@@ -2004,48 +3043,74 @@ class Type (Node):
         trnm = self.val
     else:
       ectx.eth_reg_type(nm, self)
+      trnm = nm
     if ectx.conform.check_item('VIRTUAL_ASSGN', nm):
       vnm = ectx.conform.use_item('VIRTUAL_ASSGN', nm)
       ectx.eth_reg_assign(vnm, self, virt=True)
       ectx.eth_reg_type(vnm, self)
       self.eth_reg_sub(vnm, ectx)
-    if ident:
-      if (self.type == 'Type_Ref') or ectx.conform.check_item('SET_TYPE', nm):
-        ectx.eth_reg_field(nm, trnm, idx=idx, parent=parent, impl=self.HasImplicitTag(ectx))
-      else:
-        ectx.eth_reg_field(nm, nm, idx=idx, parent=parent, impl=self.HasImplicitTag(ectx))
+    if parent and (ectx.type[parent]['val'].type == 'TaggedType'):
+      ectx.type[parent]['val'].eth_set_val_name(parent, trnm, ectx)
+    if ident and not tagflag:
+      ectx.eth_reg_field(nm, trnm, idx=idx, parent=parent, impl=self.HasImplicitTag(ectx))
     if ectx.conform.check_item('SET_TYPE', nm):
       virtual_tr.eth_reg_sub(nm, ectx)
     else:
       self.eth_reg_sub(nm, ectx)
 
-  def eth_get_size_constr(self):
-    (minv, maxv, ext) = ('NO_BOUND', 'NO_BOUND', 'FALSE')
-    if not self.HasConstraint():
-      (minv, maxv, ext) = ('NO_BOUND', 'NO_BOUND', 'FALSE')
-    elif self.constr.IsSize():
-      (minv, maxv, ext) = self.constr.GetSize()
-    elif (self.constr.type == 'Intersection'):
-      if self.constr.subtype[0].IsSize():
-        (minv, maxv, ext) = self.constr.subtype[0].GetSize()
-      elif self.constr.subtype[1].IsSize():
-        (minv, maxv, ext) = self.constr.subtype[1].GetSize()
+  def eth_get_size_constr(self, ectx):
+    (minv, maxv, ext) = ('MIN', 'MAX', False)
+    if self.HasSizeConstraint():
+      if self.constr.IsSize():
+        (minv, maxv, ext) = self.constr.GetSize(ectx)
+      if (self.constr.type == 'Intersection'):
+        if self.constr.subtype[0].IsSize():
+          (minv, maxv, ext) = self.constr.subtype[0].GetSize(ectx)
+        elif self.constr.subtype[1].IsSize():
+          (minv, maxv, ext) = self.constr.subtype[1].GetSize(ectx)
+    if minv == 'MIN': minv = 'NO_BOUND'
+    if maxv == 'MAX': maxv = 'NO_BOUND'
+    if (ext): ext = 'TRUE'
+    else: ext = 'FALSE'
     return (minv, maxv, ext)
 
-  def eth_get_value_constr(self):
-    (minv, maxv, ext) = ('NO_BOUND', 'NO_BOUND', 'FALSE')
-    if not self.HasConstraint():
-      (minv, maxv, ext) = ('NO_BOUND', 'NO_BOUND', 'FALSE')
-    elif self.constr.IsValue():
-      (minv, maxv, ext) = self.constr.GetValue()
+  def eth_get_value_constr(self, ectx):
+    (minv, maxv, ext) = ('MIN', 'MAX', False)
+    if self.HasValueConstraint():
+      (minv, maxv, ext) = self.constr.GetValue(ectx)
+    if minv == 'MIN': minv = 'NO_BOUND'
+    if maxv == 'MAX': maxv = 'NO_BOUND'
+    if str(minv).isdigit(): minv += 'U'
+    if str(maxv).isdigit(): maxv += 'U'
+    if (ext): ext = 'TRUE'
+    else: ext = 'FALSE'
     return (minv, maxv, ext)
 
+  def eth_get_alphabet_constr(self, ectx):
+    (alph, alphlen) = ('NULL', '0')
+    if self.HasPermAlph():
+      alph = self.constr.GetPermAlph(ectx)
+      if not alph:
+        alph = 'NULL'
+      if (alph != 'NULL'):
+        if (((alph[0] + alph[-1]) == '""') and (not alph.count('"', 1, -1))):
+          alphlen = str(len(alph) - 2)
+        else:
+          alphlen = 'strlen(%s)' % (alph)
+    return (alph, alphlen)
+
   def eth_type_vals(self, tname, ectx):
     if self.eth_has_vals():
       print "#Unhandled  eth_type_vals('%s') in %s" % (tname, self.type)
       print self.str_depth(1)
     return ''
 
+  def eth_type_enum(self, tname, ectx):
+    if self.eth_has_enum(tname, ectx):
+      print "#Unhandled  eth_type_enum('%s') in %s" % (tname, self.type)
+      print self.str_depth(1)
+    return ''
+
   def eth_type_default_table(self, ectx, tname):
     return ''
 
@@ -2069,8 +3134,10 @@ class Type (Node):
     }
     if (ectx.eth_type[tname]['tree']):
       pars['ETT_INDEX'] = ectx.eth_type[tname]['tree']
-    if (not ectx.Per()):
-      pars['PINFO'] = 'pinfo'
+    if (ectx.merge_modules):
+      pars['PROTOP'] = ''
+    else:
+      pars['PROTOP'] = ectx.eth_type[tname]['proto'] + '_'
     return pars
 
   def eth_type_fn(self, proto, tname, ectx):
@@ -2082,7 +3149,11 @@ class Type (Node):
       pars.update(ectx.conform.use_item('FN_PARS', ectx.eth_type[tname]['ref'][0]))
     pars['DEFAULT_BODY'] = body
     for i in range(4):
-      for k in pars.keys(): pars[k] = pars[k] % pars
+      for k in pars.keys(): 
+        try:
+          pars[k] = pars[k] % pars
+        except (TypeError):
+          raise sys.exc_type, "%s\n%s" % (str(pars), sys.exc_value)
     out = '\n'
     out += self.eth_type_default_table(ectx, tname) % pars
     out += ectx.eth_type_fn_hdr(tname)
@@ -2099,18 +3170,52 @@ class Value (Node):
   def SetName(self, name) :
     self.name = name
 
-  def to_str(self):
-    return str(self)
+  def to_str(self, ectx):
+    return str(self.val)
 
   def get_dep(self):
     return None
 
-#--- Tag ---------------------------------------------------------------
-class Tag (Node):
-  def to_python (self, ctx):
-    return 'asn1.TYPE(%s,%s)' % (mk_tag_str (ctx, self.tag.cls,
-                                                self.tag_typ,
-                                                self.tag.num),
+  def fld_obj_repr(self, ectx):
+    return self.to_str(ectx)
+
+#--- Value_Ref -----------------------------------------------------------------
+class Value_Ref (Value):
+  def to_str(self, ectx):
+    return asn2c(self.val)
+
+#--- ObjectClass ---------------------------------------------------------------------
+class ObjectClass (Node):
+  def __init__(self,*args, **kw) :
+    self.name = None
+    Node.__init__ (self,*args, **kw)
+
+  def SetName(self, name):
+    self.name = name
+    add_class_ident(self.name)
+
+  def eth_reg(self, ident, ectx):
+    if ectx.conform.omit_assignment('C', self.name, ectx.Module()): return # Assignment to omit
+    ectx.eth_reg_objectclass(self.name, self)
+
+#--- Class_Ref -----------------------------------------------------------------
+class Class_Ref (ObjectClass):
+  pass
+
+#--- ObjectClassDefn ---------------------------------------------------------------------
+class ObjectClassDefn (ObjectClass):
+  def reg_types(self):
+    for fld in self.fields:
+      repr = fld.fld_repr()
+      set_type_to_class(self.name, repr[0], repr[1:])
+
+
+#--- Tag ---------------------------------------------------------------
+class Tag (Node):
+  def to_python (self, ctx):
+    return 'asn1.TYPE(%s,%s)' % (mk_tag_str (ctx, self.tag.cls,
+                                                self.tag_typ,
+                                                self.tag.num),
                                     self.typ.to_python (ctx))
   def IsImplicit(self, ectx):
     return ((self.mode == 'IMPLICIT') or ((self.mode == 'default') and (ectx.tag_def == 'IMPLICIT')))
@@ -2122,6 +3227,14 @@ class Tag (Node):
     elif (self.cls == 'CONTEXT'): tc = 'BER_CLASS_CON'
     elif (self.cls == 'PRIVATE'): tc = 'BER_CLASS_PRI'
     return (tc, self.num)
+
+  def eth_tname(self):
+    n = ''
+    if (self.cls == 'UNIVERSAL'): n = 'U'
+    elif (self.cls == 'APPLICATION'): n = 'A'
+    elif (self.cls == 'CONTEXT'): n = 'C'
+    elif (self.cls == 'PRIVATE'): n = 'P'
+    return n + str(self.num)
  
 #--- Constraint ---------------------------------------------------------------
 class Constraint (Node):
@@ -2131,76 +3244,141 @@ class Constraint (Node):
   def __str__ (self):
     return "Constraint: type=%s, subtype=%s" % (self.type, self.subtype)
 
+  def eth_tname(self):
+    return '#' + self.type + '_' + str(id(self))
+
   def IsSize(self):
-    return self.type == 'Size' and (self.subtype.type == 'SingleValue' or self.subtype.type == 'ValueRange')
+    return (self.type == 'Size' and self.subtype.IsValue()) \
+           or (self.type == 'Intersection' and (self.subtype[0].IsSize() or self.subtype[1].IsSize())) \
 
-  def GetSize(self):
-    minv = 'NO_BOUND'
-    maxv = 'NO_BOUND'
-    ext = 'FALSE'
+  def GetSize(self, ectx):
+    (minv, maxv, ext) = ('MIN', 'MAX', False)
     if self.IsSize():
-      if self.subtype.type == 'SingleValue':
-        minv = self.subtype.subtype
-        maxv = self.subtype.subtype
-      else:
-        minv = self.subtype.subtype[0]
-        maxv = self.subtype.subtype[1]
-      if hasattr(self.subtype, 'ext') and self.subtype.ext:
-        ext = 'TRUE'
-      else:
-        ext = 'FALSE'
+      if self.type == 'Size':
+        (minv, maxv, ext) = self.subtype.GetValue(ectx)
+      elif self.type == 'Intersection':
+        if self.subtype[0].IsSize() and not self.subtype[1].IsSize():
+          (minv, maxv, ext) = self.subtype[0].GetSize(ectx)
+        elif not self.subtype[0].IsSize() and self.subtype[1].IsSize():
+          (minv, maxv, ext) = self.subtype[1].GetSize(ectx)
     return (minv, maxv, ext)
 
   def IsValue(self):
-    return self.type == 'SingleValue' or self.type == 'ValueRange'
+    return self.type == 'SingleValue' \
+           or self.type == 'ValueRange' \
+           or (self.type == 'Intersection' and (self.subtype[0].IsValue() or self.subtype[1].IsValue())) \
+           or (self.type == 'Union' and (self.subtype[0].IsValue() and self.subtype[1].IsValue()))
 
-  def GetValue(self):
-    minv = 'NO_BOUND'
-    maxv = 'NO_BOUND'
-    ext = 'FALSE'
+  def GetValue(self, ectx):
+    (minv, maxv, ext) = ('MIN', 'MAX', False)
     if self.IsValue():
       if self.type == 'SingleValue':
-        minv = self.subtype
-        maxv = self.subtype
-      else:
-        if self.subtype[0] == 'MIN':
-          minv = 'NO_BOUND'
-        else:
-          minv = self.subtype[0]
-        if self.subtype[1] == 'MAX':
-          maxv = 'NO_BOUND'
-        else:
-          maxv = self.subtype[1]
-      if str(minv).isdigit(): minv += 'U'
-      if str(maxv).isdigit(): maxv += 'U'
-      if hasattr(self, 'ext') and self.ext:
-        ext = 'TRUE'
-      else:
-        ext = 'FALSE'
+        minv = ectx.value_get_eth(self.subtype)
+        maxv = ectx.value_get_eth(self.subtype)
+        ext = hasattr(self, 'ext') and self.ext
+      elif self.type == 'ValueRange':
+        minv = ectx.value_get_eth(self.subtype[0])
+        maxv = ectx.value_get_eth(self.subtype[1])
+        ext = hasattr(self, 'ext') and self.ext
+      elif self.type == 'Intersection':
+        if self.subtype[0].IsValue() and not self.subtype[1].IsValue():
+          (minv, maxv, ext) = self.subtype[0].GetValue(ectx)
+        elif not self.subtype[0].IsValue() and self.subtype[1].IsValue():
+          (minv, maxv, ext) = self.subtype[1].GetValue(ectx)
+        elif self.subtype[0].IsValue() and self.subtype[1].IsValue():
+          v0 = self.subtype[0].GetValue(ectx)
+          v1 = self.subtype[1].GetValue(ectx)
+          (minv, maxv, ext) = (ectx.value_max(v0[0],v1[0]), ectx.value_min(v0[1],v1[1]), v0[2] and v1[2])
+      elif self.type == 'Union':
+        if self.subtype[0].IsValue() and self.subtype[1].IsValue():
+          v0 = self.subtype[0].GetValue(ectx)
+          v1 = self.subtype[1].GetValue(ectx)
+          (minv, maxv, ext) = (ectx.value_min(v0[0],v1[0]), ectx.value_max(v0[1],v1[1]), v0[2] or v1[2])
     return (minv, maxv, ext)
 
+  def IsAlphabet(self):
+    return self.type == 'SingleValue' \
+           or self.type == 'ValueRange' \
+           or (self.type == 'Intersection' and (self.subtype[0].IsAlphabet() or self.subtype[1].IsAlphabet())) \
+           or (self.type == 'Union' and (self.subtype[0].IsAlphabet() and self.subtype[1].IsAlphabet()))
+
+  def GetAlphabet(self, ectx):
+    alph = None
+    if self.IsAlphabet():
+      if self.type == 'SingleValue':
+        alph = ectx.value_get_eth(self.subtype)
+      elif self.type == 'ValueRange':
+        if ((len(self.subtype[0]) == 3) and ((self.subtype[0][0] + self.subtype[0][-1]) == '""') \
+            and (len(self.subtype[1]) == 3) and ((self.subtype[1][0] + self.subtype[1][-1]) == '""')):
+          alph = '"'
+          for c in range(ord(self.subtype[0][1]), ord(self.subtype[1][1]) + 1):
+            alph += chr(c)
+          alph += '"'
+      elif self.type == 'Union':
+        if self.subtype[0].IsAlphabet() and self.subtype[1].IsAlphabet():
+          a0 = self.subtype[0].GetAlphabet(ectx)
+          a1 = self.subtype[1].GetAlphabet(ectx)
+          if (((a0[0] + a0[-1]) == '""') and not a0.count('"', 1, -1) \
+              and ((a1[0] + a1[-1]) == '""') and not a1.count('"', 1, -1)):
+            alph = '"' + a0[1:-1] + a1[1:-1] + '"'
+          else:
+            alph = a0 + ' ' + a1
+    return alph
+
+  def IsPermAlph(self):
+    return self.type == 'From' and self.subtype.IsAlphabet() \
+           or (self.type == 'Intersection' and (self.subtype[0].IsPermAlph() or self.subtype[1].IsPermAlph())) \
+
+  def GetPermAlph(self, ectx):
+    alph = None
+    if self.IsPermAlph():
+      if self.type == 'From':
+        alph = self.subtype.GetAlphabet(ectx)
+      elif self.type == 'Intersection':
+        if self.subtype[0].IsPermAlph() and not self.subtype[1].IsPermAlph():
+          alph = self.subtype[0].GetPermAlph(ectx)
+        elif not self.subtype[0].IsPermAlph() and self.subtype[1].IsPermAlph():
+          alph = self.subtype[1].GetPermAlph(ectx)
+    return alph
+
+  def IsContents(self):
+    return self.type == 'Contents' \
+           or (self.type == 'Intersection' and (self.subtype[0].IsContents() or self.subtype[1].IsContents())) \
+
+  def GetContents(self, ectx):
+    contents = None
+    if self.IsContents():
+      if self.type == 'Contents':
+        if self.subtype.type == 'Type_Ref':
+          contents = self.subtype.val
+      elif self.type == 'Intersection':
+        if self.subtype[0].IsContents() and not self.subtype[1].IsContents():
+          contents = self.subtype[0].GetContents(ectx)
+        elif not self.subtype[0].IsContents() and self.subtype[1].IsContents():
+          contents = self.subtype[1].GetContents(ectx)
+    return contents
+
   def IsNegativ(self):
     def is_neg(sval):
-      return sval[0] == '-'
+      return isinstance(sval, str) and (sval[0] == '-')
     if self.type == 'SingleValue':
       return is_neg(self.subtype)
     elif self.type == 'ValueRange':
       if self.subtype[0] == 'MIN': return True
       return is_neg(self.subtype[0])
-    return FALSE
-
-  def IsPermAlph(self):
-    return self.type == 'From' and self.subtype.type == 'SingleValue'
+    return False
 
   def eth_constrname(self):
     def int2str(val):
+      if isinstance(val, Value_Ref):
+        return asn2c(val.val)
       try:
         if (int(val) < 0):
           return 'M' + str(-int(val))
         else:
           return str(val)
       except (ValueError, TypeError):
-        return str(val)
+        return asn2c(str(val))
 
     ext = ''
     if hasattr(self, 'ext') and self.ext:
@@ -2221,32 +3399,51 @@ class Module (Node):
     return """#%s
 %s""" % (self.ident, self.body.to_python (ctx))
 
-  def to_eth (self, ectx):
+  def get_name(self):
+    return self.ident.val
+
+  def get_proto(self, ectx):
+    if (ectx.proto):
+      prot = ectx.proto
+    else:
+      prot = ectx.conform.use_item('MODULE', self.get_name(), val_dflt=self.get_name())
+    return prot
+
+  def to_eth(self, ectx):
     ectx.tags_def = 'EXPLICIT' # default = explicit
-    if (not ectx.proto):
-      ectx.proto = ectx.conform.use_item('MODULE', self.ident.val, val_dflt=self.ident.val)
+    ectx.proto = self.get_proto(ectx)
     ectx.tag_def = self.tag_def.dfl_tag
-    ectx.modules.append((self.ident.val, ectx.proto))
+    ectx.eth_reg_module(self)
     self.body.to_eth(ectx)
 
 class Module_Body (Node):
-    def to_python (self, ctx):
-        # XXX handle exports, imports.
-        l = map (lambda x: x.to_python (ctx), self.assign_list)
-        l = [a for a in l if a <> '']
-        return "\n".join (l)
-
-    def to_eth(self, ectx):
-        for i in self.imports:
-          mod = i.module.val
-          proto = ectx.conform.use_item('MODULE', mod, val_dflt=mod)
-          for s in i.symbol_list:
-            if isinstance(s, Type_Ref):
-              ectx.eth_import_type(s.val, mod, proto)
-            else:
-              ectx.eth_import_value(s, mod, proto)
-        for a in self.assign_list:
-          a.eth_reg('', ectx)
+  def to_python (self, ctx):
+    # XXX handle exports, imports.
+    l = map (lambda x: x.to_python (ctx), self.assign_list)
+    l = [a for a in l if a <> '']
+    return "\n".join (l)
+
+  def to_eth(self, ectx):
+    # Exports
+    ectx.eth_exports(self.exports)
+    # Imports
+    for i in self.imports:
+      mod = i.module.val
+      proto = ectx.conform.use_item('MODULE', mod, val_dflt=mod)
+      ectx.eth_module_dep_add(ectx.Module(), mod)
+      for s in i.symbol_list:
+        if isinstance(s, Type_Ref):
+          ectx.eth_import_type(s.val, mod, proto)
+        elif isinstance(s, Value_Ref):
+          ectx.eth_import_value(s.val, mod, proto)
+        elif isinstance(s, Class_Ref):
+          ectx.eth_import_class(s.val, mod, proto)
+        else:
+          msg = 'Unknown kind of imported symbol %s from %s' % (str(s), mod)
+          warnings.warn_explicit(msg, UserWarning, '', '')
+    # AssignmentList
+    for a in self.assign_list:
+      a.eth_reg('', ectx)
 
 class Default_Tags (Node):
     def to_python (self, ctx): # not to be used directly
@@ -2305,14 +3502,27 @@ class Type_Ref (Type):
   def eth_tname(self):
     return asn2c(self.val)
 
+  def fld_obj_repr(self, ectx):
+    return self.val
+
+  def get_components(self, ectx):
+    if not ectx.type.has_key(self.val) or ectx.type[self.val]['import']:
+      msg = "Can not get COMPONENTS OF %s which is imported type" % (self.val)
+      warnings.warn_explicit(msg, UserWarning, '', '')
+      return []
+    else:
+      return ectx.type[self.val]['val'].get_components(ectx)
+
   def GetTTag(self, ectx):
     #print "GetTTag(%s)\n" % self.val;
     if (ectx.type[self.val]['import']):
       if not ectx.type[self.val].has_key('ttag'):
-        if not ectx.conform.check_item('IMPORT_TAG', self.val):
+        ttag = ectx.get_ttag_from_all(self.val, ectx.type[self.val]['import'])
+        if not ttag and not ectx.conform.check_item('IMPORT_TAG', self.val):
           msg = 'Missing tag information for imported type %s from %s (%s)' % (self.val, ectx.type[self.val]['import'], ectx.type[self.val]['proto'])
           warnings.warn_explicit(msg, UserWarning, '', '')
-        ectx.type[self.val]['ttag'] = ectx.conform.use_item('IMPORT_TAG', self.val, val_dflt=('-1 /*imported*/', '-1 /*imported*/'))
+          ttag = ('-1 /*imported*/', '-1 /*imported*/')
+        ectx.type[self.val]['ttag'] = ectx.conform.use_item('IMPORT_TAG', self.val, val_dflt=ttag)
       return ectx.type[self.val]['ttag']
     else:
       return ectx.type[self.val]['val'].GetTag(ectx)
@@ -2324,7 +3534,10 @@ class Type_Ref (Type):
       return ectx.type[self.val]['val'].IndetermTag(ectx)
 
   def eth_type_default_pars(self, ectx, tname):
-    pars = Type.eth_type_default_pars(self, ectx, tname)
+    if tname:
+      pars = Type.eth_type_default_pars(self, ectx, tname)
+    else:
+      pars = {}
     t = ectx.type[self.val]['ethname']
     pars['TYPE_REF_PROTO'] = ectx.eth_type[t]['proto']
     pars['TYPE_REF_TNAME'] = t
@@ -2334,7 +3547,62 @@ class Type_Ref (Type):
   def eth_type_default_body(self, ectx, tname):
     if (ectx.Ber()):
       body = ectx.eth_fn_call('%(TYPE_REF_FN)s', ret='offset',
-                              par=(('%(IMPLICIT_TAG)s', '%(TVB)s', '%(OFFSET)s', '%(PINFO)s', '%(TREE)s', '%(HF_INDEX)s'),))
+                              par=(('%(IMPLICIT_TAG)s', '%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),))
+    elif (ectx.Per()):
+      body = ectx.eth_fn_call('%(TYPE_REF_FN)s', ret='offset',
+                              par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),))
+    else:
+      body = '#error Can not decode %s' % (tname)
+    return body
+
+#--- SelectionType ------------------------------------------------------------
+class SelectionType (Type):
+  def to_python (self, ctx):
+    return self.val
+
+  def sel_of_typeref(self):
+    return self.typ.type == 'Type_Ref'
+
+  def eth_reg_sub(self, ident, ectx):
+    if not self.sel_of_typeref():
+      self.seltype = ''
+      return
+    self.seltype = ectx.eth_sel_req(self.typ.val, self.sel)
+    ectx.eth_dep_add(ident, self.seltype)
+
+  def eth_ftype(self, ectx):
+    (ftype, display) = ('FT_NONE', 'BASE_NONE')
+    if self.sel_of_typeref() and not ectx.type[self.seltype]['import']:
+      (ftype, display) = ectx.type[self.typ.val]['val'].eth_ftype_sel(self.sel, ectx)
+    return (ftype, display)
+
+  def GetTTag(self, ectx):
+    #print "GetTTag(%s)\n" % self.seltype;
+    if (ectx.type[self.seltype]['import']):
+      if not ectx.type[self.seltype].has_key('ttag'):
+        if not ectx.conform.check_item('IMPORT_TAG', self.seltype):
+          msg = 'Missing tag information for imported type %s from %s (%s)' % (self.seltype, ectx.type[self.seltype]['import'], ectx.type[self.seltype]['proto'])
+          warnings.warn_explicit(msg, UserWarning, '', '')
+        ectx.type[self.seltype]['ttag'] = ectx.conform.use_item('IMPORT_TAG', self.seltype, val_dflt=('-1 /*imported*/', '-1 /*imported*/'))
+      return ectx.type[self.seltype]['ttag']
+    else:
+      return ectx.type[self.typ.val]['val'].GetTTagSel(self.sel, ectx)
+
+  def eth_type_default_pars(self, ectx, tname):
+    pars = Type.eth_type_default_pars(self, ectx, tname)
+    if self.sel_of_typeref():
+      t = ectx.type[self.seltype]['ethname']
+      pars['TYPE_REF_PROTO'] = ectx.eth_type[t]['proto']
+      pars['TYPE_REF_TNAME'] = t
+      pars['TYPE_REF_FN'] = 'dissect_%(TYPE_REF_PROTO)s_%(TYPE_REF_TNAME)s'
+    return pars
+
+  def eth_type_default_body(self, ectx, tname):
+    if not self.sel_of_typeref():
+      body = '#error Can not decode %s' % (tname)
+    elif (ectx.Ber()):
+      body = ectx.eth_fn_call('%(TYPE_REF_FN)s', ret='offset',
+                              par=(('%(IMPLICIT_TAG)s', '%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),))
     elif (ectx.Per()):
       body = ectx.eth_fn_call('%(TYPE_REF_FN)s', ret='offset',
                               par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),))
@@ -2342,10 +3610,59 @@ class Type_Ref (Type):
       body = '#error Can not decode %s' % (tname)
     return body
 
+#--- TaggedType -----------------------------------------------------------------
+class TaggedType (Type):
+  def eth_tname(self):
+    tn = ''
+    for i in range(self.tstrip, len(self.val.tags)):
+      tn += self.val.tags[i].eth_tname()
+      tn += '_'
+    tn += self.val.eth_tname()
+    return tn
+
+  def eth_set_val_name(self, ident, val_name, ectx):
+    #print "TaggedType::eth_set_val_name(): ident=%s, val_name=%s" % (ident, val_name)
+    self.val_name = val_name
+    ectx.eth_dep_add(ident, self.val_name)
+
+  def eth_reg_sub(self, ident, ectx):
+    self.val_name = ident + '/' + '_untag'
+    self.val.eth_reg(self.val_name, ectx, tstrip=self.tstrip+1, tagflag=True, parent=ident)
+
+  def GetTTag(self, ectx):
+    #print "GetTTag(%s)\n" % self.seltype;
+    return self.GetTag(ectx)
+
+  def eth_ftype(self, ectx):
+    return self.val.eth_ftype(ectx)
+
+  def eth_type_default_pars(self, ectx, tname):
+    pars = Type.eth_type_default_pars(self, ectx, tname)
+    t = ectx.type[self.val_name]['ethname']
+    pars['TYPE_REF_PROTO'] = ectx.eth_type[t]['proto']
+    pars['TYPE_REF_TNAME'] = t
+    pars['TYPE_REF_FN'] = 'dissect_%(TYPE_REF_PROTO)s_%(TYPE_REF_TNAME)s'
+    (pars['TAG_CLS'], pars['TAG_TAG']) = self.GetTag(ectx)
+    if self.HasImplicitTag(ectx):
+      pars['TAG_IMPL'] = 'TRUE'
+    else:
+      pars['TAG_IMPL'] = 'FALSE'
+    return pars
+
+  def eth_type_default_body(self, ectx, tname):
+    if (ectx.Ber()):
+      body = ectx.eth_fn_call('dissect_%(ER)s_tagged_type', ret='offset',
+                              par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
+                                   ('%(HF_INDEX)s', '%(TAG_CLS)s', '%(TAG_TAG)s', '%(TAG_IMPL)s', '%(TYPE_REF_FN)s',),))
+    else:
+      body = '#error Can not decode %s' % (tname)
+    return body
+
 #--- SqType -----------------------------------------------------------
 class SqType (Type):
   def out_item(self, f, val, optional, ext, ectx):
     ef = ectx.field[f]['ethname']
+    t = ectx.eth_hf[ef]['ethtype']
     efd = ef
     if (ectx.Ber() and ectx.field[f]['impl']):
       efd += '_impl'
@@ -2372,21 +3689,69 @@ class SqType (Type):
         opt = 'ASN1_NOT_OPTIONAL'
     if (ectx.Ber()):
       (tc, tn) = val.GetTag(ectx)
-      out = '  { %-13s, %s, %s, dissect_%s },\n' \
-            % (tc, tn, opt, efd)
+      if (ectx.NewBer()):
+        out = '  { %-24s, %-13s, %s, %s, dissect_%s_%s },\n' \
+              % ('&'+ectx.eth_hf[ef]['fullname'], tc, tn, opt, ectx.eth_type[t]['proto'], t)
+      else:
+        out = '  { %-13s, %s, %s, dissect_%s },\n' \
+              % (tc, tn, opt, efd)
     elif (ectx.Per()):
-      out = '  { %-30s, %-23s, %-17s, dissect_%s },\n' \
-            % ('"'+(val.name or '')+'"', ext, opt, efd)
+      out = '  { %-24s, %-23s, %-17s, dissect_%s_%s },\n' \
+            % ('&'+ectx.eth_hf[ef]['fullname'], ext, opt, ectx.eth_type[t]['proto'], t)
     else:
       out = ''
     return out   
 
 #--- SeqType -----------------------------------------------------------
 class SeqType (SqType):
+
+  def need_components(self):
+    lst = self.elt_list[:]
+    if hasattr(self, 'ext_list'):
+      lst.extend(self.ext_list)
+    if hasattr(self, 'elt_list2'):
+      lst.extend(self.elt_list2)
+    for e in (lst):
+      if e.type == 'components_of':
+        return True
+    return False
+
+  def expand_components(self, ectx):
+    while self.need_components():
+      for i in range(len(self.elt_list)):
+        if self.elt_list[i].type == 'components_of':
+          comp = self.elt_list[i].typ.get_components(ectx)
+          self.elt_list[i:i+1] = comp
+          break
+      if hasattr(self, 'ext_list'):
+        for i in range(len(self.ext_list)):
+          if self.ext_list[i].type == 'components_of':
+            comp = self.ext_list[i].typ.get_components(ectx)
+            self.ext_list[i:i+1] = comp
+            break
+      if hasattr(self, 'elt_list2'):
+        for i in range(len(self.elt_list2)):
+          if self.elt_list2[i].type == 'components_of':
+            comp = self.elt_list2[i].typ.get_components(ectx)
+            self.elt_list2[i:i+1] = comp
+            break
+
+  def get_components(self, ectx):
+    lst = self.elt_list[:]
+    if hasattr(self, 'elt_list2'):
+      lst.extend(self.elt_list2)
+    return lst
+
   def eth_type_default_table(self, ectx, tname):
     #print "eth_type_default_table(tname='%s')" % (tname)
     fname = ectx.eth_type[tname]['ref'][0]
-    table = "static const %(ER)s_sequence_t %(TABLE)s[] = {\n"
+    if (ectx.Ber()):
+        if (ectx.NewBer()):
+            table = "static const %(ER)s_sequence_t %(TABLE)s[] = {\n"
+        else:
+            table = "static const %(ER)s_old_sequence_t %(TABLE)s[] = {\n"
+    else:
+        table = "static const %(ER)s_sequence_t %(TABLE)s[] = {\n"
     if hasattr(self, 'ext_list'):
       ext = 'ASN1_EXTENSION_ROOT'
     else:
@@ -2398,8 +3763,15 @@ class SeqType (SqType):
       for e in (self.ext_list):
         f = fname + '/' + e.val.name
         table += self.out_item(f, e.val, e.optional, 'ASN1_NOT_EXTENSION_ROOT', ectx)
+    if hasattr(self, 'elt_list2'):
+      for e in (self.elt_list2):
+        f = fname + '/' + e.val.name
+        table += self.out_item(f, e.val, e.optional, ext, ectx)
     if (ectx.Ber()):
-      table += "  { 0, 0, 0, NULL }\n};\n"
+      if (ectx.NewBer()):
+        table += "  { NULL, 0, 0, 0, NULL }\n};\n"
+      else:
+        table += "  { 0, 0, 0, NULL }\n};\n"
     else:
       table += "  { NULL, 0, 0, NULL }\n};\n"
     return table
@@ -2413,7 +3785,13 @@ class SeqOfType (SqType):
       f = fname + '/' + self.val.name
     else:
       f = fname + '/' + '_item'
-    table = "static const %(ER)s_sequence_t %(TABLE)s[1] = {\n"
+    if (ectx.Ber()):
+        if (ectx.NewBer()):
+            table = "static const %(ER)s_sequence_t %(TABLE)s[1] = {\n"
+        else:
+            table = "static const %(ER)s_old_sequence_t %(TABLE)s[1] = {\n"
+    else:
+        table = "static const %(ER)s_sequence_t %(TABLE)s[1] = {\n"
     table += self.out_item(f, self.val, False, 'ASN1_NO_EXTENSIONS', ectx)
     table += "};\n"
     return table
@@ -2434,7 +3812,7 @@ class SequenceOfType (SeqOfType):
     itmnm = ident
     if not self.val.IsNamed ():
       itmnm += '/' + '_item'
-    self.val.eth_reg(itmnm, ectx, idx='[##]', parent=ident)
+    self.val.eth_reg(itmnm, ectx, tstrip=1, idx='[##]', parent=ident)
 
   def eth_tname(self):
     if self.val.type != 'Type_Ref':
@@ -2457,14 +3835,19 @@ class SequenceOfType (SeqOfType):
 
   def eth_type_default_pars(self, ectx, tname):
     pars = Type.eth_type_default_pars(self, ectx, tname)
-    (pars['MIN_VAL'], pars['MAX_VAL'], pars['EXT']) = self.eth_get_size_constr()
-    pars['TABLE'] = '%(TNAME)s_sequence_of'
+    (pars['MIN_VAL'], pars['MAX_VAL'], pars['EXT']) = self.eth_get_size_constr(ectx)
+    pars['TABLE'] = '%(PROTOP)s%(TNAME)s_sequence_of'
     return pars
 
   def eth_type_default_body(self, ectx, tname):
     if (ectx.Ber()):
-      body = ectx.eth_fn_call('dissect_%(ER)s_sequence_of', ret='offset',
-                              par=(('%(IMPLICIT_TAG)s', '%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
+        if (ectx.NewBer()):
+            body = ectx.eth_fn_call('dissect_%(ER)s_sequence_of', ret='offset',
+                              par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
+                                   ('%(TABLE)s', '%(HF_INDEX)s', '%(ETT_INDEX)s',),))
+        else:            
+            body = ectx.eth_fn_call('dissect_%(ER)s_old_sequence_of', ret='offset',
+                              par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
                                    ('%(TABLE)s', '%(HF_INDEX)s', '%(ETT_INDEX)s',),))
     elif (ectx.Per() and not self.HasConstraint()):
       body = ectx.eth_fn_call('dissect_%(ER)s_sequence_of', ret='offset',
@@ -2486,7 +3869,7 @@ class SetOfType (SeqOfType):
     itmnm = ident
     if not self.val.IsNamed ():
       itmnm += '/' + '_item'
-    self.val.eth_reg(itmnm, ectx, idx='(##)', parent=ident)
+    self.val.eth_reg(itmnm, ectx, tstrip=1, idx='(##)', parent=ident)
 
   def eth_tname(self):
     if self.val.type != 'Type_Ref':
@@ -2509,14 +3892,19 @@ class SetOfType (SeqOfType):
 
   def eth_type_default_pars(self, ectx, tname):
     pars = Type.eth_type_default_pars(self, ectx, tname)
-    (pars['MIN_VAL'], pars['MAX_VAL'], pars['EXT']) = self.eth_get_size_constr()
-    pars['TABLE'] = '%(TNAME)s_set_of'
+    (pars['MIN_VAL'], pars['MAX_VAL'], pars['EXT']) = self.eth_get_size_constr(ectx)
+    pars['TABLE'] = '%(PROTOP)s%(TNAME)s_set_of'
     return pars
 
   def eth_type_default_body(self, ectx, tname):
     if (ectx.Ber()):
-      body = ectx.eth_fn_call('dissect_%(ER)s_set_of', ret='offset',
-                              par=(('%(IMPLICIT_TAG)s', '%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
+        if (ectx.NewBer()):
+            body = ectx.eth_fn_call('dissect_%(ER)s_set_of', ret='offset',
+                              par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
+                                   ('%(TABLE)s', '%(HF_INDEX)s', '%(ETT_INDEX)s',),))
+        else:    
+            body = ectx.eth_fn_call('dissect_%(ER)s_old_set_of', ret='offset',
+                              par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
                                    ('%(TABLE)s', '%(HF_INDEX)s', '%(ETT_INDEX)s',),))
     elif (ectx.Per() and not self.HasConstraint()):
       body = ectx.eth_fn_call('dissect_%(ER)s_set_of', ret='offset',
@@ -2586,12 +3974,21 @@ class SequenceType (SeqType):
       ctx.outdent ()
       return rv
 
-  def eth_reg_sub(self, ident, ectx):
-      for e in (self.elt_list):
-          e.val.eth_reg(ident, ectx, parent=ident)
-      if hasattr(self, 'ext_list'):
-          for e in (self.ext_list):
-              e.val.eth_reg(ident, ectx, parent=ident)
+  def eth_reg_sub(self, ident, ectx, components_available=False):
+    if self.need_components():
+      if components_available:
+        self.expand_components(ectx)
+      else:
+        ectx.eth_comp_req(ident)
+        return
+    for e in (self.elt_list):
+        e.val.eth_reg(ident, ectx, tstrip=1, parent=ident)
+    if hasattr(self, 'ext_list'):
+        for e in (self.ext_list):
+            e.val.eth_reg(ident, ectx, tstrip=1, parent=ident)
+    if hasattr(self, 'elt_list2'):
+        for e in (self.elt_list2):
+            e.val.eth_reg(ident, ectx, tstrip=1, parent=ident)
 
   def eth_need_tree(self):
     return True
@@ -2601,13 +3998,18 @@ class SequenceType (SeqType):
 
   def eth_type_default_pars(self, ectx, tname):
     pars = Type.eth_type_default_pars(self, ectx, tname)
-    pars['TABLE'] = '%(TNAME)s_sequence'
+    pars['TABLE'] = '%(PROTOP)s%(TNAME)s_sequence'
     return pars
 
   def eth_type_default_body(self, ectx, tname):
     if (ectx.Ber()):
-      body = ectx.eth_fn_call('dissect_%(ER)s_sequence', ret='offset',
-                              par=(('%(IMPLICIT_TAG)s', '%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
+        if(ectx.NewBer()):
+            body = ectx.eth_fn_call('dissect_%(ER)s_sequence', ret='offset',
+                              par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
+                                   ('%(TABLE)s', '%(HF_INDEX)s', '%(ETT_INDEX)s',),))
+        else:
+            body = ectx.eth_fn_call('dissect_%(ER)s_old_sequence', ret='offset',
+                              par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
                                    ('%(TABLE)s', '%(HF_INDEX)s', '%(ETT_INDEX)s',),))
     elif (ectx.Per()):
       body = ectx.eth_fn_call('dissect_%(ER)s_sequence', ret='offset',
@@ -2619,12 +4021,19 @@ class SequenceType (SeqType):
 
 #--- SetType ------------------------------------------------------------------
 class SetType(SeqType):
-  def eth_reg_sub(self, ident, ectx):
+
+  def eth_reg_sub(self, ident, ectx, components_available=False):
+    if self.need_components():
+      if components_available:
+        self.expand_components(ectx)
+      else:
+        ectx.eth_comp_req(ident)
+        return
     for e in (self.elt_list):
-      e.val.eth_reg(ident, ectx, parent=ident)
+      e.val.eth_reg(ident, ectx, tstrip=1, parent=ident)
     if hasattr(self, 'ext_list'):
       for e in (self.ext_list):
-        e.val.eth_reg(ident, ectx, parent=ident)
+        e.val.eth_reg(ident, ectx, tstrip=1, parent=ident)
 
   def eth_need_tree(self):
     return True
@@ -2634,13 +4043,18 @@ class SetType(SeqType):
 
   def eth_type_default_pars(self, ectx, tname):
     pars = Type.eth_type_default_pars(self, ectx, tname)
-    pars['TABLE'] = '%(TNAME)s_set'
+    pars['TABLE'] = '%(PROTOP)s%(TNAME)s_set'
     return pars
 
   def eth_type_default_body(self, ectx, tname):
     if (ectx.Ber()):
-      body = ectx.eth_fn_call('dissect_%(ER)s_set', ret='offset',
-                              par=(('%(IMPLICIT_TAG)s', '%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
+        if(ectx.NewBer()):
+            body = ectx.eth_fn_call('dissect_%(ER)s_set', ret='offset',
+                              par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
+                                   ('%(TABLE)s', '%(HF_INDEX)s', '%(ETT_INDEX)s',),))
+        else:
+            body = ectx.eth_fn_call('dissect_%(ER)s_old_set', ret='offset',
+                              par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
                                    ('%(TABLE)s', '%(HF_INDEX)s', '%(ETT_INDEX)s',),))
     elif (ectx.Per()):
       body = ectx.eth_fn_call('dissect_%(ER)s_set', ret='offset',
@@ -2690,16 +4104,46 @@ class ChoiceType (Type):
       return rv
 
   def eth_reg_sub(self, ident, ectx):
-      #print "eth_reg_sub(ident='%s')" % (ident)
-      for e in (self.elt_list):
-          e.eth_reg(ident, ectx, parent=ident)
-      if hasattr(self, 'ext_list'):
-          for e in (self.ext_list):
-              e.eth_reg(ident, ectx, parent=ident)
+    #print "eth_reg_sub(ident='%s')" % (ident)
+    for e in (self.elt_list):
+        e.eth_reg(ident, ectx, tstrip=1, parent=ident)
+        if ectx.conform.check_item('EXPORTS', ident + '.' + e.name):
+          ectx.eth_sel_req(ident, e.name)
+    if hasattr(self, 'ext_list'):
+        for e in (self.ext_list):
+            e.eth_reg(ident, ectx, tstrip=1, parent=ident)
+            if ectx.conform.check_item('EXPORTS', ident + '.' + e.name):
+              ectx.eth_sel_req(ident, e.name)
+
+  def sel_item(self, ident, sel, ectx):
+    lst = self.elt_list[:]
+    if hasattr(self, 'ext_list'):
+      lst.extend(self.ext_list)
+    ee = None
+    for e in (self.elt_list):
+      if e.IsNamed() and (e.name == sel):
+        ee = e
+        break
+    if not ee:
+      print "#CHOICE %s does not contain item %s" % (ident, sel)
+    return ee
+
+  def sel_req(self, ident, sel, ectx):
+    #print "sel_req(ident='%s', sel=%s)\n%s" % (ident, sel, str(self))
+    ee = self.sel_item(ident, sel, ectx)
+    if ee:
+      ee.eth_reg(ident, ectx, tstrip=0, selflag=True)
 
   def eth_ftype(self, ectx):
     return ('FT_UINT32', 'BASE_DEC')
 
+  def eth_ftype_sel(self, sel, ectx):
+    ee = self.sel_item('', sel, ectx)
+    if ee:
+      return ee.eth_ftype(ectx)
+    else:
+      return ('FT_NONE', 'BASE_NONE')
+
   def eth_strings(self):
     return '$$'
 
@@ -2721,15 +4165,21 @@ class ChoiceType (Type):
     #    cls = '-1/*choice*/'
     return (cls, '-1/*choice*/')
 
+  def GetTTagSel(self, sel, ectx):
+    ee = self.sel_item('', sel, ectx)
+    if ee:
+      return ee.GetTag(ectx)
+    else:
+      return ('BER_CLASS_ANY/*unknown selection*/', '-1/*unknown selection*/')
+
   def IndetermTag(self, ectx):
     #print "Choice IndetermTag()=%s" % (str(not self.HasOwnTag()))
     return not self.HasOwnTag()
 
-  def eth_type_vals(self, tname, ectx):
-    out = '\n'
+  def get_vals(self, ectx):
     tagval = False
     if (ectx.Ber()):
-      lst = self.elt_list
+      lst = self.elt_list[:]
       if hasattr(self, 'ext_list'):
         lst.extend(self.ext_list)
       if (len(lst) > 0):
@@ -2753,18 +4203,35 @@ class ChoiceType (Type):
         else: val = str(cnt)
         vals.append((val, e.name))
         cnt += 1
+    return vals
+
+  def eth_type_vals(self, tname, ectx):
+    out = '\n'
+    vals = self.get_vals(ectx)
     out += ectx.eth_vals(tname, vals)
     return out
 
+  def eth_type_enum(self, tname, ectx):
+    out = '\n'
+    vals = self.get_vals(ectx)
+    out += ectx.eth_enum(tname, vals)
+    return out
+
   def eth_type_default_pars(self, ectx, tname):
     pars = Type.eth_type_default_pars(self, ectx, tname)
-    pars['TABLE'] = '%(TNAME)s_choice'
+    pars['TABLE'] = '%(PROTOP)s%(TNAME)s_choice'
     return pars
 
   def eth_type_default_table(self, ectx, tname):
     def out_item(val, e, ext, ectx):
+      has_enum = ectx.eth_type[tname]['enum'] & EF_ENUM
+      if (has_enum):
+        vval = ectx.eth_enum_item(tname, e.name)
+      else:
+        vval = val
       f = fname + '/' + e.name
       ef = ectx.field[f]['ethname']
+      t = ectx.eth_hf[ef]['ethtype']
       efd = ef
       if (ectx.field[f]['impl']):
         efd += '_impl'
@@ -2772,17 +4239,21 @@ class ChoiceType (Type):
         opt = ''
         if (not e.HasOwnTag()):
           opt = 'BER_FLAGS_NOOWNTAG'
-        elif (val.HasImplicitTag(ectx)):
+        elif (e.HasImplicitTag(ectx)):
           if (opt): opt += '|'
           opt += 'BER_FLAGS_IMPLTAG'
         if (not opt): opt = '0'
       if (ectx.Ber()):
         (tc, tn) = e.GetTag(ectx)
-        out = '  { %3s, %-13s, %s, %s, dissect_%s },\n' \
-              % (val, tc, tn, opt, efd)
+        if (ectx.NewBer()):
+          out = '  { %3s, %-24s, %-13s, %s, %s, dissect_%s_%s },\n' \
+                % (vval, '&'+ectx.eth_hf[ef]['fullname'], tc, tn, opt, ectx.eth_type[t]['proto'], t)
+        else:
+          out = '  { %3s, %-13s, %s, %s, dissect_%s },\n' \
+                % (vval, tc, tn, opt, efd)
       elif (ectx.Per()):
-        out = '  { %3s, %-30s, %-23s, dissect_%s },\n' \
-              % (val, '"'+e.name+'"', ext, efd)
+        out = '  { %3s, %-24s, %-23s, dissect_%s_%s },\n' \
+              % (vval, '&'+ectx.eth_hf[ef]['fullname'], ext, ectx.eth_type[t]['proto'], t)
       else:
         out = ''
       return out   
@@ -2791,7 +4262,7 @@ class ChoiceType (Type):
     fname = ectx.eth_type[tname]['ref'][0]
     tagval = False
     if (ectx.Ber()):
-      lst = self.elt_list
+      lst = self.elt_list[:]
       if hasattr(self, 'ext_list'):
         lst.extend(self.ext_list)
       if (len(lst) > 0):
@@ -2802,7 +4273,13 @@ class ChoiceType (Type):
       for e in (lst):
         if (e.GetTag(ectx)[0] != t):
           tagval = False
-    table = "static const %(ER)s_choice_t %(TABLE)s[] = {\n"
+    if (ectx.Ber()):
+        if (ectx.NewBer()):
+            table = "static const %(ER)s_choice_t %(TABLE)s[] = {\n"
+        else:
+            table = "static const %(ER)s_old_choice_t %(TABLE)s[] = {\n"
+    else:
+        table = "static const %(ER)s_choice_t %(TABLE)s[] = {\n"
     cnt = 0
     if hasattr(self, 'ext_list'):
       ext = 'ASN1_EXTENSION_ROOT'
@@ -2820,15 +4297,24 @@ class ChoiceType (Type):
         table += out_item(val, e, 'ASN1_NOT_EXTENSION_ROOT', ectx)
         cnt += 1
     if (ectx.Ber()):
-      table += "  { 0, 0, 0, 0, NULL }\n};\n"
+      if (ectx.NewBer()):
+        table += "  { 0, NULL, 0, 0, 0, NULL }\n};\n"
+      else:
+        table += "  { 0, 0, 0, 0, NULL }\n};\n"
     else:
       table += "  { 0, NULL, 0, NULL }\n};\n"
     return table
 
   def eth_type_default_body(self, ectx, tname):
     if (ectx.Ber()):
-      body = ectx.eth_fn_call('dissect_%(ER)s_choice', ret='offset',
-                              par=(('%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
+        if (ectx.NewBer()):
+            body = ectx.eth_fn_call('dissect_%(ER)s_choice', ret='offset',
+                              par=(('%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
+                                   ('%(TABLE)s', '%(HF_INDEX)s', '%(ETT_INDEX)s'),
+                                   ('%(VAL_PTR)s',),))
+        else:
+            body = ectx.eth_fn_call('dissect_%(ER)s_old_choice', ret='offset',
+                              par=(('%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
                                    ('%(TABLE)s', '%(HF_INDEX)s', '%(ETT_INDEX)s'),
                                    ('%(VAL_PTR)s',),))
     elif (ectx.Per()):
@@ -2840,6 +4326,14 @@ class ChoiceType (Type):
       body = '#error Can not decode %s' % (tname)
     return body
    
+#--- ChoiceValue ----------------------------------------------------
+class ChoiceValue (Value):
+  def to_str(self, ectx):
+    return self.val.to_str(ectx)
+
+  def fld_obj_eq(self, other):
+    return isinstance(other, ChoiceValue) and (self.choice == other.choice) and (str(self.val.val) == str(other.val.val))
+
 #--- EnumeratedType -----------------------------------------------------------
 class EnumeratedType (Type):
   def to_python (self, ctx):
@@ -2913,6 +4407,17 @@ class EnumeratedType (Type):
     out += ectx.eth_vals(tname, vals)
     return out
 
+  def reg_enum_vals(self, tname, ectx):
+    vals = self.get_vals_etc(ectx)[0]
+    for (val, id) in vals:
+      ectx.eth_reg_value(id, self, val, ethname=ectx.eth_enum_item(tname, id))
+
+  def eth_type_enum(self, tname, ectx):
+    out = '\n'
+    vals = self.get_vals_etc(ectx)[0]
+    out += ectx.eth_enum(tname, vals)
+    return out
+
   def eth_type_default_pars(self, ectx, tname):
     pars = Type.eth_type_default_pars(self, ectx, tname)
     (root_num, ext_num, map_table) = self.get_vals_etc(ectx)[1:]
@@ -2924,7 +4429,7 @@ class EnumeratedType (Type):
     pars['EXT'] = ext
     pars['EXT_NUM'] = str(ext_num)
     if (map_table):
-      pars['TABLE'] = '%(TNAME)s_value_map'
+      pars['TABLE'] = '%(PROTOP)s%(TNAME)s_value_map'
     else:
       pars['TABLE'] = 'NULL'
     return pars
@@ -2941,7 +4446,7 @@ class EnumeratedType (Type):
   def eth_type_default_body(self, ectx, tname):
     if (ectx.Ber()):
       body = ectx.eth_fn_call('dissect_%(ER)s_integer', ret='offset',
-                              par=(('%(IMPLICIT_TAG)s', '%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'),
+                              par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'),
                                    ('%(VAL_PTR)s',),))
     elif (ectx.Per()):
       body = ectx.eth_fn_call('dissect_%(ER)s_enumerated', ret='offset',
@@ -2951,6 +4456,66 @@ class EnumeratedType (Type):
       body = '#error Can not decode %s' % (tname)
     return body
 
+#--- EmbeddedPDVType -----------------------------------------------------------
+class EmbeddedPDVType (Type):
+  def eth_tname(self):
+    return 'EMBEDDED_PDV'
+
+  def eth_ftype(self, ectx):
+    return ('FT_NONE', 'BASE_NONE')
+
+  def GetTTag(self, ectx):
+    return ('BER_CLASS_UNI', 'BER_UNI_TAG_EMBEDDED_PDV')
+
+  def eth_type_default_pars(self, ectx, tname):
+    pars = Type.eth_type_default_pars(self, ectx, tname)
+    if ectx.default_embedded_pdv_cb:
+      pars['TYPE_REF_FN'] = ectx.default_embedded_pdv_cb
+    else:
+      pars['TYPE_REF_FN'] = 'NULL'
+    return pars
+
+  def eth_type_default_body(self, ectx, tname):
+    if (ectx.Ber()):  
+      body = ectx.eth_fn_call('dissect_%(ER)s_EmbeddedPDV_Type', ret='offset',
+                              par=(('%(IMPLICIT_TAG)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(HF_INDEX)s', '%(TYPE_REF_FN)s',),))
+    elif (ectx.Per()):
+      body = ectx.eth_fn_call('dissect_%(ER)s_embedded_pdv', ret='offset',
+                              par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s', '%(TYPE_REF_FN)s',),))
+    else:
+      body = '#error Can not decode %s' % (tname)
+    return body
+
+#--- ExternalType -----------------------------------------------------------
+class ExternalType (Type):
+  def eth_tname(self):
+    return 'EXTERNAL'
+
+  def eth_ftype(self, ectx):
+    return ('FT_NONE', 'BASE_NONE')
+
+  def GetTTag(self, ectx):
+    return ('BER_CLASS_UNI', 'BER_UNI_TAG_EXTERNAL')
+
+  def eth_type_default_pars(self, ectx, tname):
+    pars = Type.eth_type_default_pars(self, ectx, tname)
+    if ectx.default_external_type_cb:
+      pars['TYPE_REF_FN'] = ectx.default_external_type_cb
+    else:
+      pars['TYPE_REF_FN'] = 'NULL'
+    return pars
+
+  def eth_type_default_body(self, ectx, tname):
+    if (ectx.Ber()):  
+      body = ectx.eth_fn_call('dissect_%(ER)s_external_type', ret='offset',
+                              par=(('%(IMPLICIT_TAG)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(HF_INDEX)s', '%(TYPE_REF_FN)s',),))
+    elif (ectx.Per()):
+      body = ectx.eth_fn_call('dissect_%(ER)s_external_type', ret='offset',
+                              par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s', '%(TYPE_REF_FN)s',),))
+    else:
+      body = '#error Can not decode %s' % (tname)
+    return body
+
 #--- OpenType -----------------------------------------------------------
 class OpenType (Type):
   def to_python (self, ctx):
@@ -2983,6 +4548,7 @@ class OpenType (Type):
 
   def eth_type_default_pars(self, ectx, tname):
     pars = Type.eth_type_default_pars(self, ectx, tname)
+    pars['FN_VARIANT'] = ectx.default_opentype_variant
     t = self.single_type()
     if t:
       t = ectx.type[t]['ethname']
@@ -2995,12 +4561,41 @@ class OpenType (Type):
 
   def eth_type_default_body(self, ectx, tname):
     if (ectx.Per()):
-      body = ectx.eth_fn_call('dissect_%(ER)s_open_type', ret='offset',
+      body = ectx.eth_fn_call('dissect_%(ER)s_open_type%(FN_VARIANT)s', ret='offset',
                               par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s', '%(TYPE_REF_FN)s',),))
     else:
       body = '#error Can not decode %s' % (tname)
     return body
 
+#--- InstanceOfType -----------------------------------------------------------
+class InstanceOfType (Type):
+  def eth_tname(self):
+    return 'INSTANCE_OF'
+
+  def eth_ftype(self, ectx):
+    return ('FT_NONE', 'BASE_NONE')
+
+  def GetTTag(self, ectx):
+    return ('BER_CLASS_UNI', 'BER_UNI_TAG_EXTERNAL')
+
+  def eth_type_default_pars(self, ectx, tname):
+    pars = Type.eth_type_default_pars(self, ectx, tname)
+    if ectx.default_external_type_cb:
+      pars['TYPE_REF_FN'] = ectx.default_external_type_cb
+    else:
+      pars['TYPE_REF_FN'] = 'NULL'
+    return pars
+
+  def eth_type_default_body(self, ectx, tname):
+    if (ectx.Ber()):  
+      body = ectx.eth_fn_call('dissect_%(ER)s_external_type', ret='offset',
+                              par=(('%(IMPLICIT_TAG)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(HF_INDEX)s', '%(TYPE_REF_FN)s',),))
+    elif (ectx.Per()):
+      body = '#error Can not decode %s' % (tname)
+    else:
+      body = '#error Can not decode %s' % (tname)
+    return body
+
 #--- AnyType -----------------------------------------------------------
 class AnyType (Type):
   def to_python (self, ctx):
@@ -3034,7 +4629,7 @@ class NullType (Type):
   def eth_type_default_body(self, ectx, tname):
     if (ectx.Ber()):
       body = ectx.eth_fn_call('dissect_%(ER)s_null', ret='offset',
-                              par=(('%(IMPLICIT_TAG)s', '%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'),))
+                              par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'),))
     elif (ectx.Per()):
       body = ectx.eth_fn_call('dissect_%(ER)s_null', ret='offset',
                               par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),))
@@ -3042,6 +4637,11 @@ class NullType (Type):
       body = '#error Can not decode %s' % (tname)
     return body
 
+#--- NullValue ----------------------------------------------------
+class NullValue (Value):
+  def to_str(self, ectx):
+    return 'NULL'
+
 #--- RealType -----------------------------------------------------------------
 class RealType (Type):
   def to_python (self, ctx):
@@ -3050,16 +4650,30 @@ class RealType (Type):
   def eth_tname(self):
     return 'REAL'
 
-  def eth_type_default_body(self, ectx, tname):
-    body = '#error Can not decode %s' % (tname)
-    return body
+  def GetTTag(self, ectx):
+    return ('BER_CLASS_UNI', 'BER_UNI_TAG_REAL')
 
-#--- BooleanType --------------------------------------------------------------
-class BooleanType (Type):
-  def to_python (self, ctx):
-    return 'asn1.BOOLEAN'
+  def eth_ftype(self, ectx):
+    return ('FT_DOUBLE', 'BASE_NONE')
 
-  def eth_tname(self):
+  def eth_type_default_body(self, ectx, tname):
+    if (ectx.Ber()):
+      body = ectx.eth_fn_call('dissect_%(ER)s_real', ret='offset',
+                              par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'),
+                                   ('%(VAL_PTR)s',),))
+    elif (ectx.Per()):
+      body = ectx.eth_fn_call('dissect_%(ER)s_real', ret='offset',
+                              par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s', '%(VAL_PTR)s',),))
+    else:
+      body = '#error Can not decode %s' % (tname)
+    return body
+
+#--- BooleanType --------------------------------------------------------------
+class BooleanType (Type):
+  def to_python (self, ctx):
+    return 'asn1.BOOLEAN'
+
+  def eth_tname(self):
     return 'BOOLEAN'
 
   def GetTTag(self, ectx):
@@ -3071,7 +4685,7 @@ class BooleanType (Type):
   def eth_type_default_body(self, ectx, tname):
     if (ectx.Ber()):
       body = ectx.eth_fn_call('dissect_%(ER)s_boolean', ret='offset',
-                              par=(('%(IMPLICIT_TAG)s', '%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'),))
+                              par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'),))
     elif (ectx.Per()):
       body = ectx.eth_fn_call('dissect_%(ER)s_boolean', ret='offset',
                               par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s', '%(VAL_PTR)s',),))
@@ -3087,7 +4701,7 @@ class OctetStringType (Type):
   def eth_tname(self):
     if not self.HasConstraint():
       return 'OCTET_STRING'
-    elif self.constr.IsSize():
+    elif self.constr.type == 'Size':
       return 'OCTET_STRING' + '_' + self.constr.eth_constrname()
     else:
       return '#' + self.type + '_' + str(id(self))
@@ -3098,20 +4712,50 @@ class OctetStringType (Type):
   def GetTTag(self, ectx):
     return ('BER_CLASS_UNI', 'BER_UNI_TAG_OCTETSTRING')
 
+  def eth_need_pdu(self, ectx):
+    pdu = None
+    if self.HasContentsConstraint():
+      t = self.constr.GetContents(ectx)
+      if t and (ectx.default_containing_variant in ('_pdu', '_pdu_new')):
+        pdu = { 'type' : t,
+                'new' : ectx.default_containing_variant == '_pdu_new' }
+    return pdu
+
   def eth_type_default_pars(self, ectx, tname):
     pars = Type.eth_type_default_pars(self, ectx, tname)
-    (pars['MIN_VAL'], pars['MAX_VAL'], pars['EXT']) = self.eth_get_size_constr()
+    (pars['MIN_VAL'], pars['MAX_VAL'], pars['EXT']) = self.eth_get_size_constr(ectx)
+    if self.HasContentsConstraint():
+      pars['FN_VARIANT'] = ectx.default_containing_variant
+      t = self.constr.GetContents(ectx)
+      if t:
+        if pars['FN_VARIANT'] in ('_pdu', '_pdu_new'):
+          t = ectx.field[t]['ethname']
+          pars['TYPE_REF_PROTO'] = ''
+          pars['TYPE_REF_TNAME'] = t
+          pars['TYPE_REF_FN'] = 'dissect_%(TYPE_REF_TNAME)s'
+        else:
+          t = ectx.type[t]['ethname']
+          pars['TYPE_REF_PROTO'] = ectx.eth_type[t]['proto']
+          pars['TYPE_REF_TNAME'] = t
+          pars['TYPE_REF_FN'] = 'dissect_%(TYPE_REF_PROTO)s_%(TYPE_REF_TNAME)s'
+      else:
+        pars['TYPE_REF_FN'] = 'NULL'
     return pars
 
   def eth_type_default_body(self, ectx, tname):
     if (ectx.Ber()):
       body = ectx.eth_fn_call('dissect_%(ER)s_octet_string', ret='offset',
-                              par=(('%(IMPLICIT_TAG)s', '%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'),
+                              par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'),
                                    ('%(VAL_PTR)s',),))
     elif (ectx.Per()):
-      body = ectx.eth_fn_call('dissect_%(ER)s_octet_string', ret='offset',
-                              par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),
-                                   ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(VAL_PTR)s',),))
+      if self.HasContentsConstraint():
+        body = ectx.eth_fn_call('dissect_%(ER)s_octet_string_containing%(FN_VARIANT)s', ret='offset',
+                                par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),
+                                     ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(TYPE_REF_FN)s',),))
+      else:
+        body = ectx.eth_fn_call('dissect_%(ER)s_octet_string', ret='offset',
+                                par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),
+                                     ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(VAL_PTR)s',),))
     else:
       body = '#error Can not decode %s' % (tname)
     return body
@@ -3121,7 +4765,7 @@ class CharacterStringType (Type):
   def eth_tname(self):
     if not self.HasConstraint():
       return self.eth_tsname()
-    elif self.constr.IsSize():
+    elif self.constr.type == 'Size':
       return self.eth_tsname() + '_' + self.constr.eth_constrname()
     else:
       return '#' + self.type + '_' + str(id(self))
@@ -3136,33 +4780,18 @@ class RestrictedCharacterStringType (CharacterStringType):
   def GetTTag(self, ectx):
     return ('BER_CLASS_UNI', 'BER_UNI_TAG_' + self.eth_tsname())
 
-  def HasPermAlph(self):
-    return (self.HasConstraint() and 
-            (self.constr.IsPermAlph() or 
-             (self.constr.type == 'Intersection' and (self.constr.subtype[0].IsPermAlph() or self.constr.subtype[1].IsPermAlph()))
-            )
-           )
-
   def eth_type_default_pars(self, ectx, tname):
     pars = Type.eth_type_default_pars(self, ectx, tname)
-    (pars['MIN_VAL'], pars['MAX_VAL'], pars['EXT']) = self.eth_get_size_constr()
+    (pars['MIN_VAL'], pars['MAX_VAL'], pars['EXT']) = self.eth_get_size_constr(ectx)
     (pars['STRING_TYPE'], pars['STRING_TAG']) = (self.eth_tsname(), self.GetTTag(ectx)[1])
-    (pars['ALPHABET'], pars['ALPHABET_LEN']) = ('NULL', '0')
-    if self.HasPermAlph():
-      if self.constr.IsPermAlph():
-        pars['ALPHABET'] = self.constr.subtype.subtype
-      elif self.constr.subtype[0].IsPermAlph():
-        pars['ALPHABET'] = self.constr.subtype[0].subtype.subtype
-      elif self.constr.subtype[1].IsPermAlph():
-        pars['ALPHABET'] = self.constr.subtype[1].subtype.subtype
-      pars['ALPHABET_LEN'] = 'strlen(%(ALPHABET)s)'
+    (pars['ALPHABET'], pars['ALPHABET_LEN']) = self.eth_get_alphabet_constr(ectx)
     return pars
 
   def eth_type_default_body(self, ectx, tname):
     if (ectx.Ber()):
       body = ectx.eth_fn_call('dissect_%(ER)s_restricted_string', ret='offset',
                               par=(('%(IMPLICIT_TAG)s', '%(STRING_TAG)s'),
-                                   ('%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'),
+                                   ('%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'),
                                    ('%(VAL_PTR)s',),))
     elif (ectx.Per() and self.HasPermAlph()):
       body = ectx.eth_fn_call('dissect_%(ER)s_restricted_character_string', ret='offset',
@@ -3259,7 +4888,7 @@ class GeneralizedTime (RestrictedCharacterStringType):
   def eth_type_default_body(self, ectx, tname):
     if (ectx.Ber()):
       body = ectx.eth_fn_call('dissect_%(ER)s_%(STRING_TYPE)s', ret='offset',
-                              par=(('%(IMPLICIT_TAG)s', '%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'),))
+                              par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'),))
       return body
     else:
       return RestrictedCharacterStringType.eth_type_default_body(self, ectx, tname)
@@ -3272,6 +4901,15 @@ class ObjectDescriptor (RestrictedCharacterStringType):
   def eth_tsname(self):
     return 'ObjectDescriptor'
 
+  def eth_type_default_body(self, ectx, tname):
+    if (ectx.Ber()):
+      body = RestrictedCharacterStringType.eth_type_default_body(self, ectx, tname)
+    elif (ectx.Per()):
+      body = ectx.eth_fn_call('dissect_%(ER)s_object_descriptor', ret='offset',
+                              par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s', '%(VAL_PTR)s',),))
+    else:
+      body = '#error Can not decode %s' % (tname)
+    return body
 
 #--- ObjectIdentifierType -----------------------------------------------------
 class ObjectIdentifierType (Type):
@@ -3287,10 +4925,15 @@ class ObjectIdentifierType (Type):
   def GetTTag(self, ectx):
     return ('BER_CLASS_UNI', 'BER_UNI_TAG_OID')
 
+  def eth_type_default_pars(self, ectx, tname):
+    pars = Type.eth_type_default_pars(self, ectx, tname)
+    pars['FN_VARIANT'] = ectx.default_oid_variant
+    return pars
+
   def eth_type_default_body(self, ectx, tname):
     if (ectx.Ber()):
       body = ectx.eth_fn_call('dissect_%(ER)s_object_identifier%(FN_VARIANT)s', ret='offset',
-                              par=(('%(IMPLICIT_TAG)s', '%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s', '%(VAL_PTR)s',),))
+                              par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s', '%(VAL_PTR)s',),))
     elif (ectx.Per()):
       body = ectx.eth_fn_call('dissect_%(ER)s_object_identifier%(FN_VARIANT)s', ret='offset',
                               par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s', '%(VAL_PTR)s',),))
@@ -3303,7 +4946,7 @@ class ObjectIdentifierValue (Value):
   def get_num(self, path, val):
     return str(oid_names.get(path + '/' + val, val))
 
-  def to_str(self):
+  def to_str(self, ectx):
     out = ''
     path = ''
     first = True
@@ -3315,11 +4958,13 @@ class ObjectIdentifierValue (Value):
         vstr = v
       else:
         vstr = self.get_num(path, v)
+      if not first and not vstr.isdigit():
+        vstr = ectx.value_get_val(vstr)
       if first:
         if vstr.isdigit():
           out += '"' + vstr
         else:
-          out += vstr + '"'
+          out += ectx.value_get_eth(vstr) + '"'
       else:
        out += sep + vstr
       path += sep + vstr
@@ -3341,7 +4986,7 @@ class ObjectIdentifierValue (Value):
     else:
       return vstr
 
-class NamedNumber (Node):
+class NamedNumber(Node):
     def to_python (self, ctx):
         return "('%s',%s)" % (self.ident, self.val)
 
@@ -3356,6 +5001,12 @@ class IntegerType (Type):
         return "asn1.INTEGER_class ([%s])" % (",".join (
             map (lambda x: x.to_python (ctx), self.named_list)))
 
+  def add_named_value(self, ident, val):
+    e = NamedNumber(ident = ident, val = val)
+    if not self.named_list: 
+      self.named_list = []
+    self.named_list.append(e)
+
   def eth_tname(self):
     if self.named_list:
       return Type.eth_tname(self)
@@ -3369,6 +5020,7 @@ class IntegerType (Type):
   def GetTTag(self, ectx):
     return ('BER_CLASS_UNI', 'BER_UNI_TAG_INTEGER')
 
+
   def eth_ftype(self, ectx):
     if self.HasConstraint():
       if not self.constr.IsNegativ():
@@ -3387,30 +5039,46 @@ class IntegerType (Type):
     else:
       return False
 
-  def eth_type_vals(self, tname, ectx):
-    if not self.eth_has_vals(): return ''
-    out = '\n'
+  def get_vals(self, ectx):
     vals = []
     for e in (self.named_list):
       vals.append((int(e.val), e.ident))
+    return vals
+
+  def eth_type_vals(self, tname, ectx):
+    if not self.eth_has_vals(): return ''
+    out = '\n'
+    vals = self.get_vals(ectx)
     out += ectx.eth_vals(tname, vals)
     return out
 
+  def reg_enum_vals(self, tname, ectx):
+    vals = self.get_vals(ectx)
+    for (val, id) in vals:
+      ectx.eth_reg_value(id, self, val, ethname=ectx.eth_enum_item(tname, id))
+
+  def eth_type_enum(self, tname, ectx):
+    if not self.eth_has_enum(tname, ectx): return ''
+    out = '\n'
+    vals = self.get_vals(ectx)
+    out += ectx.eth_enum(tname, vals)
+    return out
+
   def eth_type_default_pars(self, ectx, tname):
     pars = Type.eth_type_default_pars(self, ectx, tname)
-    if self.HasConstraint() and self.constr.IsValue():
-      (pars['MIN_VAL'], pars['MAX_VAL'], pars['EXT']) = self.eth_get_value_constr()
+    if self.HasValueConstraint():
+      (pars['MIN_VAL'], pars['MAX_VAL'], pars['EXT']) = self.eth_get_value_constr(ectx)
     return pars
 
   def eth_type_default_body(self, ectx, tname):
     if (ectx.Ber()):
       body = ectx.eth_fn_call('dissect_%(ER)s_integer', ret='offset',
-                              par=(('%(IMPLICIT_TAG)s', '%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'),
+                              par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s', '%(HF_INDEX)s'),
                                    ('%(VAL_PTR)s',),))
-    elif (ectx.Per() and not self.HasConstraint()):
+    elif (ectx.Per() and not self.HasValueConstraint()):
       body = ectx.eth_fn_call('dissect_%(ER)s_integer', ret='offset',
                               par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s', '%(VAL_PTR)s'),))
-    elif (ectx.Per() and ((self.constr.type == 'SingleValue') or (self.constr.type == 'ValueRange'))):
+    elif (ectx.Per() and self.HasValueConstraint()):
       body = ectx.eth_fn_call('dissect_%(ER)s_constrained_integer', ret='offset',
                               par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),
                                    ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(VAL_PTR)s', '%(EXT)s'),))
@@ -3443,6 +5111,15 @@ class BitStringType (Type):
   def eth_need_tree(self):
     return self.named_list
 
+  def eth_need_pdu(self, ectx):
+    pdu = None
+    if self.HasContentsConstraint():
+      t = self.constr.GetContents(ectx)
+      if t and (ectx.default_containing_variant in ('_pdu', '_pdu_new')):
+        pdu = { 'type' : t,
+                'new' : ectx.default_containing_variant == '_pdu_new' }
+    return pdu
+
   def eth_named_bits(self):
     bits = []
     if (self.named_list):
@@ -3452,12 +5129,28 @@ class BitStringType (Type):
 
   def eth_type_default_pars(self, ectx, tname):
     pars = Type.eth_type_default_pars(self, ectx, tname)
-    (pars['MIN_VAL'], pars['MAX_VAL'], pars['EXT']) = self.eth_get_size_constr()
+    (pars['MIN_VAL'], pars['MAX_VAL'], pars['EXT']) = self.eth_get_size_constr(ectx)
     if not pars.has_key('ETT_INDEX'):
       pars['ETT_INDEX'] = '-1'
     pars['TABLE'] = 'NULL'
     if self.eth_named_bits():
-      pars['TABLE'] = '%(TNAME)s_bits'
+      pars['TABLE'] = '%(PROTOP)s%(TNAME)s_bits'
+    if self.HasContentsConstraint():
+      pars['FN_VARIANT'] = ectx.default_containing_variant
+      t = self.constr.GetContents(ectx)
+      if t:
+        if pars['FN_VARIANT'] in ('_pdu', '_pdu_new'):
+          t = ectx.field[t]['ethname']
+          pars['TYPE_REF_PROTO'] = ''
+          pars['TYPE_REF_TNAME'] = t
+          pars['TYPE_REF_FN'] = 'dissect_%(TYPE_REF_TNAME)s'
+        else:
+          t = ectx.type[t]['ethname']
+          pars['TYPE_REF_PROTO'] = ectx.eth_type[t]['proto']
+          pars['TYPE_REF_TNAME'] = t
+          pars['TYPE_REF_FN'] = 'dissect_%(TYPE_REF_PROTO)s_%(TYPE_REF_TNAME)s'
+      else:
+        pars['TYPE_REF_FN'] = 'NULL'
     return pars
 
   def eth_type_default_table(self, ectx, tname):
@@ -3471,26 +5164,106 @@ class BitStringType (Type):
   def eth_type_default_body(self, ectx, tname):
     if (ectx.Ber()):
       body = ectx.eth_fn_call('dissect_%(ER)s_bitstring', ret='offset',
-                              par=(('%(IMPLICIT_TAG)s', '%(PINFO)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
+                              par=(('%(IMPLICIT_TAG)s', '%(ACTX)s', '%(TREE)s', '%(TVB)s', '%(OFFSET)s'),
                                    ('%(TABLE)s', '%(HF_INDEX)s', '%(ETT_INDEX)s',),
                                    ('%(VAL_PTR)s',),))
     elif (ectx.Per()):
-      body = ectx.eth_fn_call('dissect_%(ER)s_bit_string', ret='offset',
-                              par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),
-                                   ('%(MIN_VAL)s', '%(MAX_VAL)s','%(EXT)s','%(VAL_PTR)s'),))
+      if self.HasContentsConstraint():
+        body = ectx.eth_fn_call('dissect_%(ER)s_bit_string_containing%(FN_VARIANT)s', ret='offset',
+                                par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),
+                                     ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(EXT)s', '%(TYPE_REF_FN)s'),))
+      else:
+        body = ectx.eth_fn_call('dissect_%(ER)s_bit_string', ret='offset',
+                                par=(('%(TVB)s', '%(OFFSET)s', '%(ACTX)s', '%(TREE)s', '%(HF_INDEX)s'),
+                                     ('%(MIN_VAL)s', '%(MAX_VAL)s', '%(EXT)s', '%(VAL_PTR)s'),))
     else:
       body = '#error Can not decode %s' % (tname)
     return body
 
+#--- BStringValue ------------------------------------------------------------
+bstring_tab = {
+  '0000' : '0',
+  '0001' : '1',
+  '0010' : '2',
+  '0011' : '3',
+  '0100' : '4',
+  '0101' : '5',
+  '0110' : '6',
+  '0111' : '7',
+  '1000' : '8',
+  '1001' : '9',
+  '1010' : 'A',
+  '1011' : 'B',
+  '1100' : 'C',
+  '1101' : 'D',
+  '1110' : 'E',
+  '1111' : 'F',
+}
+class BStringValue (Value):
+  def to_str(self, ectx):
+    v = self.val[1:-2]
+    if len(v) % 8:
+      v += '0' * (8 - len(v) % 8)
+    vv = '0x'
+    for i in (range(0, len(v), 4)):
+      vv += bstring_tab[v[i:i+4]]
+    return vv
+
+#--- HStringValue ------------------------------------------------------------
+class HStringValue (Value):
+  def to_str(self, ectx):
+    vv = '0x'
+    vv += self.val[1:-2]
+    return vv
+
+#--- FieldSpec ----------------------------------------------------------------
+class FieldSpec (Node):
+  def __init__(self,*args, **kw) :
+    self.name = None
+    Node.__init__ (self,*args, **kw)
+
+  def SetName(self, name):
+    self.name = name
+
+  def get_repr(self):
+    return ['#UNSUPPORTED_' + self.type]
+
+  def fld_repr(self):
+    repr = [self.name]
+    repr.extend(self.get_repr())
+    return repr
+
+class TypeFieldSpec (FieldSpec):
+  def get_repr(self):
+    return []
+
+class FixedTypeValueFieldSpec (FieldSpec):
+  def get_repr(self):
+    if isinstance(self.typ, Type_Ref):
+      repr = ['TypeReference', self.typ.val]
+    else:
+      repr = [self.typ.type]
+    return repr
+
+class FixedTypeValueSetFieldSpec (FieldSpec):
+  pass
+
+class ObjectFieldSpec (FieldSpec):
+  def get_repr(self):
+    return ['ClassReference', self.cls]
+
+class ObjectSetFieldSpec (FieldSpec):
+  def get_repr(self):
+    return ['ClassReference', self.cls]
 
 #==============================================================================
     
 def p_module_list_1 (t):
-    'module_list : module_list module_def'
+    'module_list : module_list ModuleDefinition'
     t[0] = t[1] + [t[2]]
 
 def p_module_list_2 (t):
-    'module_list : module_def'
+    'module_list : ModuleDefinition'
     t[0] = [t[1]]
 
 
@@ -3501,76 +5274,78 @@ def p_module_list_2 (t):
 
 # 11.2 Type references
 def p_type_ref (t):
-    'type_ref : UCASE_IDENT'
-    t[0] = Type_Ref(val=t[1])
+  'type_ref : UCASE_IDENT'
+  t[0] = Type_Ref(val=t[1])
+
+# 11.3 Identifiers
+def p_identifier (t):
+  'identifier : LCASE_IDENT'
+  t[0] = t[1]
 
 # 11.4 Value references
 def p_valuereference (t):
-    'valuereference : LCASE_IDENT'
-    t[0] = t[1]
+  'valuereference : LCASE_IDENT'
+  t[0] = Value_Ref(val=t[1])
+
+# 11.5 Module references
+def p_modulereference (t):
+  'modulereference : UCASE_IDENT'
+  t[0] = t[1]
 
 
 # 12 Module definition --------------------------------------------------------
 
 # 12.1
-def p_module_def (t):
-    'module_def : module_ident DEFINITIONS TagDefault ASSIGNMENT BEGIN module_body END'
-    t[0] = Module (ident = t[1], tag_def = t[3], body = t[6])
+def p_ModuleDefinition (t):
+  'ModuleDefinition : ModuleIdentifier DEFINITIONS TagDefault ASSIGNMENT BEGIN ModuleBody END'
+  t[0] = Module (ident = t[1], tag_def = t[3], body = t[6])
 
 def p_TagDefault_1 (t):
-    '''TagDefault : EXPLICIT TAGS
-    | IMPLICIT TAGS
-    | AUTOMATIC TAGS'''
-    t[0] = Default_Tags (dfl_tag = t[1])
+  '''TagDefault : EXPLICIT TAGS
+  | IMPLICIT TAGS
+  | AUTOMATIC TAGS'''
+  t[0] = Default_Tags (dfl_tag = t[1])
 
 def p_TagDefault_2 (t):
-    'TagDefault : '
-    # 12.2 The "TagDefault" is taken as EXPLICIT TAGS if it is "empty".
-    t[0] = Default_Tags (dfl_tag = 'EXPLICIT') 
+  'TagDefault : '
+  # 12.2 The "TagDefault" is taken as EXPLICIT TAGS if it is "empty".
+  t[0] = Default_Tags (dfl_tag = 'EXPLICIT') 
 
-def p_module_ident (t):
-    'module_ident : type_ref assigned_ident' # name, oid
-    # XXX coerce type_ref to module_ref
-    t [0] = Node('module_ident', val = t[1].val, ident = t[2])
+def p_ModuleIdentifier_1 (t):
+  'ModuleIdentifier : modulereference DefinitiveIdentifier' # name, oid
+  t [0] = Node('module_ident', val = t[1], ident = t[2])
 
+def p_ModuleIdentifier_2 (t):
+  'ModuleIdentifier : modulereference' # name, oid
+  t [0] = Node('module_ident', val = t[1], ident = None)
 
-# XXX originally we had both type_ref and module_ref, but that caused
-# a reduce/reduce conflict (because both were UCASE_IDENT).  Presumably
-# this didn't cause a problem in the original ESNACC grammar because it
-# was LALR(1) and PLY is (as of 1.1) only SLR.
+def p_DefinitiveIdentifier (t):
+  'DefinitiveIdentifier : ObjectIdentifierValue'
+  t[0] = t[1]
 
 #def p_module_ref (t):
 #    'module_ref : UCASE_IDENT'
 #    t[0] = t[1]
 
-def p_assigned_ident_1 (t):
-    'assigned_ident : ObjectIdentifierValue'
-    t[0] = t[1]
+def p_ModuleBody_1 (t):
+  'ModuleBody : Exports Imports AssignmentList'
+  t[0] = Module_Body (exports = t[1], imports = t[2], assign_list = t[3])
 
-def p_assigned_ident_2 (t):
-    'assigned_ident : LCASE_IDENT'
-    t[0] = t[1]
+def p_ModuleBody_2 (t):
+  'ModuleBody : '
+  t[0] = Node ('module_body', exports = [], imports = [], assign_list = [])
 
-def p_assigned_ident_3 (t):
-    'assigned_ident : '
-    pass
-
-def p_module_body_1 (t):
-    'module_body : exports Imports AssignmentList'
-    t[0] = Module_Body (exports = t[1], imports = t[2], assign_list = t[3])
-
-def p_module_body_2 (t):
-    'module_body : '
-    t[0] = Node ('module_body', exports = [], imports = [],
-                 assign_list = [])
-
-def p_exports_1 (t):
-    'exports : EXPORTS syms_exported SEMICOLON'
+def p_Exports_1 (t):
+    'Exports : EXPORTS syms_exported SEMICOLON'
     t[0] = t[2]
 
-def p_exports_2 (t):
-    'exports : '
-    t[0] = []
+def p_Exports_2 (t):
+    'Exports : EXPORTS ALL SEMICOLON'
+    t[0] = [ 'ALL' ]
+
+def p_Exports_3 (t):
+    'Exports : '
+    t[0] = [ 'ALL' ]
 
 def p_syms_exported_1 (t):
     'syms_exported : exp_sym_list'
@@ -3589,91 +5364,138 @@ def p_exp_sym_list_2 (t):
     t[0] = t[1] + [t[3]]
     
 
-def p_Imports_1(t):
-    'Imports : IMPORTS SymbolsImported SEMICOLON'
-    t[0] = t[2]
+def p_Imports_1 (t):
+  'Imports : importsbegin IMPORTS SymbolsImported SEMICOLON'
+  t[0] = t[3]
+  global lcase_ident_assigned
+  lcase_ident_assigned = {}
+
+def p_importsbegin (t):
+  'importsbegin : '
+  global lcase_ident_assigned
+  global g_conform
+  lcase_ident_assigned = {}
+  lcase_ident_assigned.update(g_conform.use_item('ASSIGNED_ID', 'OBJECT_IDENTIFIER'))
 
 def p_Imports_2 (t):
-    'Imports : '
-    t[0] = []
+  'Imports : '
+  t[0] = []
 
 def p_SymbolsImported_1(t):
-    'SymbolsImported : '
-    t[0] = []
+  'SymbolsImported : '
+  t[0] = []
 
 def p_SymbolsImported_2 (t):
-    'SymbolsImported : SymbolsFromModuleList'
-    t[0] = t[1]
+  'SymbolsImported : SymbolsFromModuleList'
+  t[0] = t[1]
 
 def p_SymbolsFromModuleList_1 (t):
-    'SymbolsFromModuleList : SymbolsFromModuleList SymbolsFromModule'
-    t[0] = t[1] + [t[2]]
+   'SymbolsFromModuleList : SymbolsFromModuleList SymbolsFromModule'
+   t[0] = t[1] + [t[2]]
 
 def p_SymbolsFromModuleList_2 (t):
-    'SymbolsFromModuleList : SymbolsFromModule'
-    t[0] = [t[1]]
+   'SymbolsFromModuleList : SymbolsFromModule'
+   t[0] = [t[1]]
 
 def p_SymbolsFromModule (t):
-    'SymbolsFromModule : SymbolList FROM module_ident'
-    t[0] = Node ('SymbolList', symbol_list = t[1], module = t[3])
+  'SymbolsFromModule : SymbolList FROM GlobalModuleReference'
+  t[0] = Node ('SymbolList', symbol_list = t[1], module = t[3])
+  for s in (t[0].symbol_list): 
+    if (isinstance(s, Value_Ref)): lcase_ident_assigned[s.val] = t[3]
+  if t[0].module.val == 'Remote-Operations-Information-Objects':
+    for i in range(len(t[0].symbol_list)):
+      s = t[0].symbol_list[i]
+      if isinstance(s, Type_Ref) or isinstance(s, Class_Ref):
+        x880_import(s.val)
+        if isinstance(s, Type_Ref) and is_class_ident(s.val):
+          t[0].symbol_list[i] = Class_Ref (val = s.val)
+
+def p_GlobalModuleReference (t):
+  'GlobalModuleReference : modulereference AssignedIdentifier'
+  t [0] = Node('module_ident', val = t[1], ident = t[2])
+
+def p_AssignedIdentifier_1 (t):
+  'AssignedIdentifier : ObjectIdentifierValue'
+  t[0] = t[1]
+
+def p_AssignedIdentifier_2 (t):
+  'AssignedIdentifier : LCASE_IDENT_ASSIGNED'
+  t[0] = t[1]
+
+def p_AssignedIdentifier_3 (t):
+  'AssignedIdentifier : '
+  pass
 
 def p_SymbolList_1 (t):
-    'SymbolList : Symbol'
-    t[0] = [t[1]]
+  'SymbolList : Symbol'
+  t[0] = [t[1]]
 
 def p_SymbolList_2 (t):
-    'SymbolList : SymbolList COMMA Symbol'
-    t[0] = t[1] + [t[3]]
+  'SymbolList : SymbolList COMMA Symbol'
+  t[0] = t[1] + [t[3]]
 
 def p_Symbol (t):
-    '''Symbol : type_ref
-              | ParameterizedReference
-              | identifier''' # XXX omit DefinedMacroName
-    t[0] = t[1]
+  '''Symbol : Reference
+            | ParameterizedReference'''
+  t[0] = t[1]
 
-def p_Reference (t):
-    '''Reference : type_ref
-                 | valuereference'''
-    t[0] = t[1]
+def p_Reference_1 (t):
+  '''Reference : type_ref
+               | valuereference
+               | objectclassreference '''
+  t[0] = t[1]
+
+def p_Reference_2 (t):
+  '''Reference : LCASE_IDENT_ASSIGNED'''
+  t[0] = Value_Ref (val=t[1])
 
 def p_AssignmentList_1 (t):
-    'AssignmentList : AssignmentList Assignment'
-    t[0] = t[1] + [t[2]]
+  'AssignmentList : AssignmentList Assignment'
+  t[0] = t[1] + [t[2]]
 
 def p_AssignmentList_2 (t):
-    'AssignmentList : Assignment SEMICOLON'
-    t[0] = [t[1]]
+  'AssignmentList : Assignment SEMICOLON'
+  t[0] = [t[1]]
 
 def p_AssignmentList_3 (t):
-    'AssignmentList : Assignment'
-    t[0] = [t[1]]
+  'AssignmentList : Assignment'
+  t[0] = [t[1]]
 
 def p_Assignment (t):
-    '''Assignment : TypeAssignment
-                  | ValueAssignment
-                  | pyquote
-                  | ParameterizedTypeAssignment'''
-    t[0] = t[1]
-
-def p_pyquote (t):
-    '''pyquote : PYQUOTE'''
-    t[0] = PyQuote (val = t[1])
+  '''Assignment : TypeAssignment
+                | ValueAssignment
+                | ValueSetTypeAssignment
+                | ObjectClassAssignment
+                | ObjectAssignment
+                | ObjectSetAssignment
+                | ParameterizedAssignment
+                | pyquote '''
+  t[0] = t[1]
 
 
 # 13 Referencing type and value definitions -----------------------------------
 
 # 13.1
 def p_DefinedType (t): 
-  '''DefinedType : ext_type_ref
-  | type_ref
-  | ParameterizedType'''
+  '''DefinedType : ExternalTypeReference
+                 | type_ref
+                 | ParameterizedType'''
   t[0] = t[1]
 
 def p_DefinedValue(t):
-  '''DefinedValue : ext_val_ref
-                  | identifier'''
+  '''DefinedValue : ExternalValueReference
+                  | valuereference'''
   t[0] = t[1]
 
+# 13.6
+def p_ExternalTypeReference (t):
+  'ExternalTypeReference : modulereference DOT type_ref'
+  t[0] = Node ('ExternalTypeReference', module = t[1], typ = t[3])
+
+def p_ExternalValueReference (t):
+  'ExternalValueReference : modulereference DOT identifier'
+  t[0] = Node ('ExternalValueReference', module = t[1], ident = t[3])
+
 
 # 15 Assigning types and values -----------------------------------------------
 
@@ -3685,8 +5507,29 @@ def p_TypeAssignment (t):
 
 # 15.2
 def p_ValueAssignment (t):
-  'ValueAssignment : identifier Type ASSIGNMENT Value'
-  t[0] = value_assign (ident = t[1], typ = t[2], val = t[4])
+  'ValueAssignment : LCASE_IDENT ValueType ASSIGNMENT Value'
+  t[0] = ValueAssignment(ident = t[1], typ = t[2], val = t[4])
+
+# only "simple" types are supported to simplify grammer
+def p_ValueType (t):
+  '''ValueType : type_ref
+               | BooleanType
+               | IntegerType
+               | ObjectIdentifierType
+               | OctetStringType
+               | RealType '''
+
+  t[0] = t[1]
+
+# 15.6
+def p_ValueSetTypeAssignment (t):
+  'ValueSetTypeAssignment : UCASE_IDENT ValueType ASSIGNMENT ValueSet'
+  t[0] = Node('ValueSetTypeAssignment', name=t[1], typ=t[2], val=t[4])
+
+# 15.7
+def p_ValueSet (t):
+  'ValueSet : lbraceignore rbraceignore'
+  t[0] = None
 
 
 # 16 Definition of types and values -------------------------------------------
@@ -3705,7 +5548,10 @@ def p_BuiltinType (t):
                  | BooleanType
                  | CharacterStringType
                  | ChoiceType
+                 | EmbeddedPDVType
                  | EnumeratedType
+                 | ExternalType
+                 | InstanceOfType
                  | IntegerType
                  | NullType
                  | ObjectClassFieldType
@@ -3716,21 +5562,16 @@ def p_BuiltinType (t):
                  | SequenceOfType
                  | SetType
                  | SetOfType
-                 | selection_type
                  | TaggedType'''
   t[0] = t[1]
 
 # 16.3
 def p_ReferencedType (t):
   '''ReferencedType : DefinedType
-                    | UsefulType'''
+                    | UsefulType
+                    | SelectionType'''
   t[0] = t[1]
 
-def p_ext_type_ref (t):
-    'ext_type_ref : type_ref DOT type_ref'
-    # XXX coerce 1st type_ref to module_ref
-    t[0] = Node ('ext_type_ref', module = t[1], typ = t[3])
-
 # 16.5
 def p_NamedType (t):
   'NamedType : identifier Type'
@@ -3740,15 +5581,17 @@ def p_NamedType (t):
 # 16.7
 def p_Value (t):
   '''Value : BuiltinValue
-           | ReferencedValue'''
+           | ReferencedValue
+           | ObjectClassFieldValue'''
   t[0] = t[1]
 
 # 16.9
 def p_BuiltinValue (t):
   '''BuiltinValue : BooleanValue
+                  | ChoiceValue
+                  | IntegerValue
                   | ObjectIdentifierValue
-                  | special_real_val
-                  | SignedNumber
+                  | RealValue
                   | SequenceValue
                   | hex_string
                   | binary_string
@@ -3757,7 +5600,8 @@ def p_BuiltinValue (t):
 
 # 16.11
 def p_ReferencedValue (t):
-  '''ReferencedValue : DefinedValue'''
+  '''ReferencedValue : DefinedValue
+                     | ValueFromObject'''
   t[0] = t[1]
 
 # 16.13
@@ -3789,7 +5633,7 @@ def p_IntegerType_1 (t):
 
 def p_IntegerType_2 (t):
   'IntegerType : INTEGER LBRACE NamedNumberList RBRACE'
-  t[0] = IntegerType (named_list = t[3])
+  t[0] = IntegerType(named_list = t[3])
 
 def p_NamedNumberList_1 (t):
   'NamedNumberList : NamedNumber'
@@ -3802,7 +5646,7 @@ def p_NamedNumberList_2 (t):
 def p_NamedNumber (t):
   '''NamedNumber : identifier LPAREN SignedNumber RPAREN
                  | identifier LPAREN DefinedValue RPAREN'''
-  t[0] = NamedNumber (ident = t[1], val = t[3])
+  t[0] = NamedNumber(ident = t[1], val = t[3])
 
 def p_SignedNumber_1 (t):
   'SignedNumber : NUMBER'
@@ -3812,6 +5656,10 @@ def p_SignedNumber_2 (t):
   'SignedNumber : MINUS NUMBER'
   t[0] = '-' + t[2]
 
+# 18.9
+def p_IntegerValue (t):
+  'IntegerValue : SignedNumber'
+  t[0] = t [1]
 
 # 19 Notation for the enumerated type -----------------------------------------
 
@@ -3854,8 +5702,20 @@ def p_Identifier (t):
 
 # 20.1
 def p_RealType (t):
-    'RealType : REAL'
-    t[0] = RealType ()
+  'RealType : REAL'
+  t[0] = RealType ()
+
+# 20.6
+def p_RealValue (t):
+  '''RealValue : REAL_NUMBER
+               | SpecialRealValue'''
+  t[0] = t [1]
+
+def p_SpecialRealValue (t):
+  '''SpecialRealValue : PLUS_INFINITY
+                      | MINUS_INFINITY'''
+  t[0] = t[1]
+
 
 # 21 Notation for the bitstring type ------------------------------------------
 
@@ -3894,100 +5754,137 @@ def p_OctetStringType (t):
 
 # 23.1
 def p_NullType (t):
-    'NullType : NULL'
-    t[0] = NullType ()
+  'NullType : NULL'
+  t[0] = NullType ()
 
 # 23.3
-#def p_NullValue (t):
-#    'NullValue : NULL'
-#    t[0] = t[1]
+def p_NullValue (t):
+  'NullValue : NULL'
+  t[0] = NullValue ()
 
 
 # 24 Notation for sequence types ----------------------------------------------
 
 # 24.1
 def p_SequenceType_1 (t):
-    'SequenceType : SEQUENCE LBRACE RBRACE'
-    t[0] = SequenceType (elt_list = [])
+  'SequenceType : SEQUENCE LBRACE RBRACE'
+  t[0] = SequenceType (elt_list = [])
 
 def p_SequenceType_2 (t):
-    'SequenceType : SEQUENCE LBRACE ComponentTypeLists RBRACE'
-    if t[3].has_key('ext_list'):
-        t[0] = SequenceType (elt_list = t[3]['elt_list'], ext_list = t[3]['ext_list'])
-    else:
-        t[0] = SequenceType (elt_list = t[3]['elt_list'])
+  'SequenceType : SEQUENCE LBRACE ComponentTypeLists RBRACE'
+  t[0] = SequenceType (elt_list = t[3]['elt_list'])
+  if t[3].has_key('ext_list'):
+    t[0].ext_list = t[3]['ext_list']
+  if t[3].has_key('elt_list2'):
+    t[0].ext_list = t[3]['elt_list2']
 
 def p_ExtensionAndException_1 (t):
-    'ExtensionAndException : ELLIPSIS'
-    t[0] = []
+  'ExtensionAndException : ELLIPSIS'
+  t[0] = []
 
 def p_OptionalExtensionMarker_1 (t):
-    'OptionalExtensionMarker : COMMA ELLIPSIS'
-    t[0] = True
+  'OptionalExtensionMarker : COMMA ELLIPSIS'
+  t[0] = True
 
 def p_OptionalExtensionMarker_2 (t):
-    'OptionalExtensionMarker : '
-    t[0] = False
+  'OptionalExtensionMarker : '
+  t[0] = False
 
 def p_ComponentTypeLists_1 (t):
-    'ComponentTypeLists : element_type_list'
-    t[0] = {'elt_list' : t[1]}
+  'ComponentTypeLists : ComponentTypeList'
+  t[0] = {'elt_list' : t[1]}
 
 def p_ComponentTypeLists_2 (t):
-    'ComponentTypeLists : element_type_list COMMA ExtensionAndException extension_additions OptionalExtensionMarker'
-    t[0] = {'elt_list' : t[1], 'ext_list' : t[4]}
+    'ComponentTypeLists : ComponentTypeList COMMA ExtensionAndException OptionalExtensionMarker'
+    t[0] = {'elt_list' : t[1], 'ext_list' : []}
 
 def p_ComponentTypeLists_3 (t):
-    'ComponentTypeLists : ExtensionAndException extension_additions OptionalExtensionMarker'
+    'ComponentTypeLists : ComponentTypeList COMMA ExtensionAndException ExtensionAdditionList OptionalExtensionMarker'
+    t[0] = {'elt_list' : t[1], 'ext_list' : t[4]}
+
+def p_ComponentTypeLists_4 (t):
+    'ComponentTypeLists : ComponentTypeList COMMA ExtensionAndException ExtensionEndMarker COMMA ComponentTypeList'
+    t[0] = {'elt_list' : t[1], 'ext_list' : [], 'elt_list2' : t[6]}
+
+def p_ComponentTypeLists_5 (t):
+    'ComponentTypeLists : ComponentTypeList COMMA ExtensionAndException ExtensionAdditionList ExtensionEndMarker COMMA ComponentTypeList'
+    t[0] = {'elt_list' : t[1], 'ext_list' : t[4], 'elt_list2' : t[7]}
+
+def p_ComponentTypeLists_6 (t):
+    'ComponentTypeLists : ExtensionAndException OptionalExtensionMarker'
+    t[0] = {'elt_list' : [], 'ext_list' : []}
+
+def p_ComponentTypeLists_7 (t):
+    'ComponentTypeLists : ExtensionAndException ExtensionAdditionList OptionalExtensionMarker'
     t[0] = {'elt_list' : [], 'ext_list' : t[2]}
 
-def p_extension_additions_1 (t):
-    'extension_additions : extension_addition_list'
-    t[0] = t[1]
+#def p_RootComponentTypeList (t):
+#    'RootComponentTypeList : ComponentTypeList'
+#    t[0] = t[1]
 
-def p_extension_additions_2 (t):
-    'extension_additions : '
-    t[0] = []
+def p_ExtensionEndMarker (t):
+  'ExtensionEndMarker : COMMA ELLIPSIS'
+  pass
 
-def p_extension_addition_list_1 (t):
-    'extension_addition_list : COMMA extension_addition'
-    t[0] = [t[2]]
+#def p_extension_additions_1 (t):
+#    'extension_additions : extension_addition_list'
+#    t[0] = t[1]
 
-def p_extension_addition_list_2 (t):
-    'extension_addition_list : extension_addition_list COMMA extension_addition'
-    t[0] = t[1] + [t[3]]
+#def p_extension_additions_2 (t):
+#    'extension_additions : '
+#    t[0] = []
+
+def p_ExtensionAdditionList_1 (t):
+  'ExtensionAdditionList : COMMA extension_addition'
+  t[0] = [t[2]]
+
+def p_ExtensionAdditionList_2 (t):
+  'ExtensionAdditionList : ExtensionAdditionList COMMA extension_addition'
+  t[0] = t[1] + [t[3]]
 
 def p_extension_addition_1 (t):
-    'extension_addition : element_type'
+    'extension_addition : ComponentType'
     t[0] = t[1]
 
-def p_element_type_list_1 (t):
-    'element_type_list : element_type'
-    t[0] = [t[1]]
+def p_ComponentTypeList_1 (t):
+  'ComponentTypeList : ComponentType'
+  t[0] = [t[1]]
 
-def p_element_type_list_2 (t):
-    'element_type_list : element_type_list COMMA element_type'
-    t[0] = t[1] + [t[3]]
+def p_ComponentTypeList_2 (t):
+  'ComponentTypeList : ComponentTypeList COMMA ComponentType'
+  t[0] = t[1] + [t[3]]
 
-def p_element_type_1 (t):
-    'element_type : NamedType'
-    t[0] = Node ('elt_type', val = t[1], optional = 0)
+def p_ComponentType_1 (t):
+  'ComponentType : NamedType'
+  t[0] = Node ('elt_type', val = t[1], optional = 0)
 
-def p_element_type_2 (t):
-    'element_type : NamedType OPTIONAL'
-    t[0] = Node ('elt_type', val = t[1], optional = 1)
+def p_ComponentType_2 (t):
+  'ComponentType : NamedType OPTIONAL'
+  t[0] = Node ('elt_type', val = t[1], optional = 1)
 
-def p_element_type_3 (t):
-    'element_type : NamedType DEFAULT Value'
-    t[0] = Node ('elt_type', val = t[1], optional = 1, default = t[3])
-#          /*
-#           * this rules uses NamedValue instead of Value
-#           * for the stupid choice value syntax (fieldname value)
-#           * it should be like a set/seq value (ie with
-#           * enclosing { }
-#           */
+def p_ComponentType_3 (t):
+  'ComponentType : NamedType DEFAULT DefaultValue'
+  t[0] = Node ('elt_type', val = t[1], optional = 1, default = t[3])
 
-# XXX get to COMPONENTS later
+def p_ComponentType_4 (t):
+  'ComponentType : COMPONENTS OF Type'
+  t[0] = Node ('components_of', typ = t[3])
+
+def p_DefaultValue_1 (t):
+  '''DefaultValue : ReferencedValue 
+                  | BooleanValue
+                  | ChoiceValue
+                  | IntegerValue
+                  | RealValue
+                  | hex_string
+                  | binary_string
+                  | char_string
+                  | ObjectClassFieldValue'''
+  t[0] = t[1]
+
+def p_DefaultValue_2 (t):
+  'DefaultValue : lbraceignore rbraceignore'
+  t[0] = ''
 
 # 24.17
 def p_SequenceValue_1 (t):
@@ -4021,16 +5918,15 @@ def p_SequenceOfType (t):
 
 # 26.1
 def p_SetType_1 (t):
-    'SetType : SET LBRACE RBRACE'
-    if t[3].has_key('ext_list'):
-        t[0] = SetType (elt_list = [])
+  'SetType : SET LBRACE RBRACE'
+  t[0] = SetType (elt_list = [])
 
 def p_SetType_2 (t):
-    'SetType : SET LBRACE ComponentTypeLists RBRACE'
-    if t[3].has_key('ext_list'):
-        t[0] = SetType (elt_list = t[3]['elt_list'], ext_list = t[3]['ext_list'])
-    else:
-        t[0] = SetType (elt_list = t[3]['elt_list'])
+  'SetType : SET LBRACE ComponentTypeLists RBRACE'
+  if t[3].has_key('ext_list'):
+    t[0] = SetType (elt_list = t[3]['elt_list'], ext_list = t[3]['ext_list'])
+  else:
+    t[0] = SetType (elt_list = t[3]['elt_list'])
 
 
 # 27 Notation for set-of types ------------------------------------------------
@@ -4087,9 +5983,21 @@ def p_alternative_type_list_2 (t):
     'alternative_type_list : alternative_type_list COMMA NamedType'
     t[0] = t[1] + [t[3]]
 
-def p_selection_type (t): # XXX what is this?
-    'selection_type : identifier LT Type'
-    return Node ('seltype', ident = t[1], typ = t[3])
+# 28.10
+def p_ChoiceValue_1 (t):
+  '''ChoiceValue : identifier COLON Value
+                 | identifier COLON NullValue '''
+  val = t[3]
+  if not isinstance(val, Value):
+    val = Value(val=val)
+  t[0] = ChoiceValue (choice = t[1], val = val)
+
+# 29 Notation for selection types
+
+# 29.1
+def p_SelectionType (t): #
+  'SelectionType : identifier LT Type'
+  t[0] = SelectionType (typ = t[3], sel = t[1])
 
 # 30 Notation for tagged types ------------------------------------------------
 
@@ -4134,10 +6042,6 @@ def p_AnyType (t):
     'AnyType : ANY'
     t[0] = AnyType ()
 
-#def p_any_type_2 (t):
-#    'any_type : ANY DEFINED BY identifier'
-#    t[0] = Literal (val='asn1.ANY_constr(def_by="%s")' % t[4]) # XXX
-
 
 # 31 Notation for the object identifier type ----------------------------------
 
@@ -4152,22 +6056,46 @@ def p_ObjectIdentifierValue (t):
     t[0] = ObjectIdentifierValue (comp_list=t[2])
 
 def p_oid_comp_list_1 (t):
-    'oid_comp_list : oid_comp_list oid_component'
+    'oid_comp_list : oid_comp_list ObjIdComponents'
     t[0] = t[1] + [t[2]]
 
 def p_oid_comp_list_2 (t):
-    'oid_comp_list : oid_component'
+    'oid_comp_list : ObjIdComponents'
     t[0] = [t[1]]
 
-def p_oid_component (t):
-    '''oid_component : number_form
-    | name_form
-    | name_and_number_form'''
-    t[0] = t[1]
+def p_ObjIdComponents (t):
+  '''ObjIdComponents : NameForm
+                     | NumberForm
+                     | NameAndNumberForm'''
+  t[0] = t[1]
+
+def p_NameForm (t):
+  '''NameForm : LCASE_IDENT
+              | LCASE_IDENT_ASSIGNED'''
+  t [0] = t[1]
+
+def p_NumberForm (t):
+  '''NumberForm : NUMBER'''
+#                | DefinedValue'''
+  t [0] = t[1]
+
+def p_NameAndNumberForm (t):
+  '''NameAndNumberForm : LCASE_IDENT_ASSIGNED LPAREN NumberForm RPAREN
+                       | LCASE_IDENT LPAREN NumberForm RPAREN'''
+  t[0] = Node('name_and_number', ident = t[1], number = t[3])
+  
+# 33 Notation for the embedded-pdv type -------------------------------------------
+# 33.1
+def p_EmbeddedPDVType (t):
+  'EmbeddedPDVType : EMBEDDED PDV'
+  t[0] = EmbeddedPDVType()
+
+# 34 Notation for the external type -------------------------------------------
 
-def p_number_form (t):
-    'number_form : NUMBER'
-    t [0] = t[1]
+# 34.1
+def p_ExternalType (t):
+  'ExternalType : EXTERNAL'
+  t[0] = ExternalType()
 
 # 36 Notation for character string types --------------------------------------
 
@@ -4298,32 +6226,75 @@ def p_ConstraintSpec (t):
 
 # 46.1
 def p_ElementSetSpecs_1 (t):
-    'ElementSetSpecs : RootElementSetSpec'
-    t[0] = t[1]
+  'ElementSetSpecs : RootElementSetSpec'
+  t[0] = t[1]
 
 def p_ElementSetSpecs_2 (t):
-    'ElementSetSpecs : RootElementSetSpec COMMA ELLIPSIS'
-    t[0] = t[1]
-    t[0].ext = True
+  'ElementSetSpecs : RootElementSetSpec COMMA ELLIPSIS'
+  t[0] = t[1]
+  t[0].ext = True
 
 def p_ElementSetSpecs_3 (t):
-    'ElementSetSpecs : RootElementSetSpec COMMA ELLIPSIS COMMA ElementSetSpecs'
-    t[0] = t[1]
-    t[0].ext = True
+  'ElementSetSpecs : RootElementSetSpec COMMA ELLIPSIS COMMA AdditionalElementSetSpec'
+  t[0] = t[1]
+  t[0].ext = True
 
-# skip compound constraints, only simple ones are supported
+def p_RootElementSetSpec (t):
+  'RootElementSetSpec : ElementSetSpec'
+  t[0] = t[1]
 
-def p_RootElementSetSpec_1 (t):
-    'RootElementSetSpec : SubtypeElements'
-    t[0] = t[1]
+def p_AdditionalElementSetSpec (t):
+  'AdditionalElementSetSpec : ElementSetSpec'
+  t[0] = t[1]
+
+def p_ElementSetSpec (t):
+  'ElementSetSpec : Unions'
+  t[0] = t[1]
+
+def p_Unions_1 (t):
+  'Unions : Intersections'
+  t[0] = t[1]
 
-def p_RootElementSetSpec_2 (t):
-    'RootElementSetSpec : SubtypeElements IntersectionMark SubtypeElements'
-    t[0] = Constraint(type = 'Intersection', subtype = [t[1], t[3]])
+def p_Unions_2 (t):
+  'Unions : UElems UnionMark Intersections'
+  t[0] = Constraint(type = 'Union', subtype = [t[1], t[3]])
+
+def p_UElems (t):
+  'UElems : Unions'
+  t[0] = t[1]
+
+def p_Intersections_1 (t):
+  'Intersections : IntersectionElements'
+  t[0] = t[1]
+
+def p_Intersections_2 (t):
+  'Intersections : IElems IntersectionMark IntersectionElements'
+  t[0] = Constraint(type = 'Intersection', subtype = [t[1], t[3]])
+
+def p_IElems (t):
+  'IElems : Intersections'
+  t[0] = t[1]
+
+def p_IntersectionElements (t):
+  'IntersectionElements : Elements'
+  t[0] = t[1]
+
+def p_UnionMark (t):
+  '''UnionMark : BAR
+               | UNION'''
 
 def p_IntersectionMark (t):
-    '''IntersectionMark : CIRCUMFLEX
-                        | INTERSECTION'''
+  '''IntersectionMark : CIRCUMFLEX
+                      | INTERSECTION'''
+
+# 46.5
+def p_Elements_1 (t):
+  'Elements : SubtypeElements'
+  t[0] = t[1]
+
+def p_Elements_2 (t):
+  'Elements : LPAREN ElementSetSpec RPAREN'
+  t[0] = t[2]
 
 # 47 Subtype elements ---------------------------------------------------------
 
@@ -4348,45 +6319,46 @@ def p_SingleValue (t):
 # 47.3 Contained subtype
 # 47.3.1
 def p_ContainedSubtype (t):
-    'ContainedSubtype : Includes Type'
-    t[0] = Constraint(type = 'ContainedSubtype', subtype = t[2]) 
+  'ContainedSubtype : Includes Type'
+  t[0] = Constraint(type = 'ContainedSubtype', subtype = t[2]) 
 
 def p_Includes (t):
-    '''Includes : INCLUDES 
-                | '''
+  '''Includes : INCLUDES 
+              | '''
 
 # 47.4 Value range
 # 47.4.1
 def p_ValueRange (t):
-    'ValueRange : lower_end_point RANGE upper_end_point'
-    t[0] = Constraint(type = 'ValueRange', subtype = [t[1], t[3]])
+  'ValueRange : LowerEndpoint RANGE UpperEndpoint'
+  t[0] = Constraint(type = 'ValueRange', subtype = [t[1], t[3]])
 
 # 47.4.3
-def p_lower_end_point_1 (t):
-    'lower_end_point : lower_end_value '
-    t[0] = t[1]
+def p_LowerEndpoint_1 (t):
+  'LowerEndpoint : LowerEndValue'
+  t[0] = t[1]
 
-def p_lower_end_point_2 (t):
-    'lower_end_point : lower_end_value LT' # XXX LT first?
-    t[0] = t[1] # but not inclusive range
+def p_LowerEndpoint_2 (t):
+  'LowerEndpoint : LowerEndValue LT'
+  t[0] = t[1] # but not inclusive range
     
-def p_upper_end_point_1 (t):
-    'upper_end_point : upper_end_value'
-    t[0] = t[1]
+def p_UpperEndpoint_1 (t):
+  'UpperEndpoint : UpperEndValue'
+  t[0] = t[1]
 
-def p_upper_end_point_2 (t):
-    'upper_end_point : LT upper_end_value'
-    t[0] = t[1] # but not inclusive range
+def p_UpperEndpoint_2 (t):
+  'UpperEndpoint : LT UpperEndValue'
+  t[0] = t[1] # but not inclusive range
 
-def p_lower_end_value (t):
-    '''lower_end_value : Value
-                       | MIN'''
-    t[0] = t[1] # XXX
+# 47.4.4
+def p_LowerEndValue (t):
+  '''LowerEndValue : Value
+                   | MIN'''
+  t[0] = t[1] # XXX
 
-def p_upper_end_value (t):
-    '''upper_end_value : Value
-                       | MAX'''
-    t[0] = t[1]
+def p_UpperEndValue (t):
+  '''UpperEndValue : Value
+                    | MAX'''
+  t[0] = t[1]
 
 # 47.5 Size constraint
 # 47.5.1
@@ -4479,9 +6451,19 @@ def p_PatternConstraint (t):
 # 49 The exception identifier
 
 # 49.4
-def p_ExceptionSpec (t):
-    'ExceptionSpec : '
-    pass
+def p_ExceptionSpec_1 (t):
+  'ExceptionSpec : EXCLAMATION ExceptionIdentification'
+  pass
+
+def p_ExceptionSpec_2 (t):
+  'ExceptionSpec : '
+  pass
+
+def p_ExceptionIdentification (t):
+  '''ExceptionIdentification : SignedNumber
+                             | DefinedValue
+                             | Type COLON Value '''
+  pass
 
 #  /*-----------------------------------------------------------------------*/
 #  /* Value Notation Productions */
@@ -4489,49 +6471,13 @@ def p_ExceptionSpec (t):
 
 
 
-
-def p_ext_val_ref (t):
-    'ext_val_ref : type_ref DOT identifier'
-    # XXX coerce type_ref to module_ref
-    return Node ('ext_val_ref', module = t[1], ident = t[3])
-
-def p_special_real_val (t):
-    '''special_real_val : PLUS_INFINITY
-    | MINUS_INFINITY'''
-    t[0] = t[1]
-
-
-# Note that Z39.50 v3 spec has upper-case here for, e.g., SUTRS.
-# I've hacked the grammar to be liberal about what it accepts.
-# XXX should have -strict command-line flag to only accept lowercase
-# here, since that's what X.208 says.
-def p_name_form (t):
-    '''name_form : type_ref
-    | identifier'''
-    t[0] = t[1]
-
-def p_name_and_number_form_1 (t):
-    '''name_and_number_form : identifier LPAREN number_form RPAREN
-    | type_ref LPAREN number_form RPAREN'''
-    t[0] = Node ('name_and_number', ident = t[1], number = t[3])
-
-def p_name_and_number_form_2 (t):
-    'name_and_number_form : identifier LPAREN DefinedValue RPAREN'
-    t[0] = Node ('name_and_number', ident = t[1], val = t[3])
-
-# see X.208 if you are dubious about lcase only for identifier 
-def p_identifier (t):
-    'identifier : LCASE_IDENT'
-    t[0] = t[1]
-
-
 def p_binary_string (t):
-    'binary_string : BSTRING'
-    t[0] = t[1]
+  'binary_string : BSTRING'
+  t[0] = BStringValue(val = t[1])
 
 def p_hex_string (t):
-    'hex_string : HSTRING'
-    t[0] = t[1]
+  'hex_string : HSTRING'
+  t[0] = HStringValue(val = t[1])
 
 def p_char_string (t):
     'char_string : QSTRING'
@@ -4546,56 +6492,508 @@ def p_number (t):
 
 # 7 ASN.1 lexical items -------------------------------------------------------
 
-# 7.4 Type field references
+# 7.1 Information object class references
 
-def p_typefieldreference (t):
-  'typefieldreference : AMPERSAND UCASE_IDENT'
-  t[0] = t[2]
+def p_objectclassreference (t):
+  'objectclassreference : CLASS_IDENT'
+  t[0] = Class_Ref(val=t[1])
 
-# 7.5 Value field references
+# 7.2 Information object references
 
-def p_valuefieldreference (t):
-  'valuefieldreference : AMPERSAND LCASE_IDENT'
-  t[0] = t[2]
+def p_objectreference (t):
+  'objectreference : LCASE_IDENT'
+  t[0] = t[1]
+
+# 7.3 Information object set references
+
+#def p_objectsetreference (t):
+#  'objectsetreference : UCASE_IDENT'
+#  t[0] = t[1]
+
+# 7.4 Type field references
+# ucasefieldreference
+# 7.5 Value field references
+# lcasefieldreference
+# 7.6 Value set field references
+# ucasefieldreference
+# 7.7 Object field references
+# lcasefieldreference
+# 7.8 Object set field references
+# ucasefieldreference
+
+def p_ucasefieldreference (t):
+  'ucasefieldreference : AMPERSAND UCASE_IDENT'
+  t[0] = '&' + t[2]
+
+def p_lcasefieldreference (t):
+  'lcasefieldreference : AMPERSAND LCASE_IDENT'
+  t[0] = '&' + t[2]
 
 # 8 Referencing definitions
 
 # 8.1
 def p_DefinedObjectClass (t):
-  'DefinedObjectClass : UsefulObjectClassReference'
+  '''DefinedObjectClass : objectclassreference
+                        | UsefulObjectClassReference'''
+  t[0] = t[1]
+  global obj_class
+  obj_class = t[0].val
+
+def p_DefinedObject (t):
+  '''DefinedObject : objectreference'''
   t[0] = t[1]
 
 # 8.4
 def p_UsefulObjectClassReference (t):
   '''UsefulObjectClassReference : TYPE_IDENTIFIER 
                                 | ABSTRACT_SYNTAX'''
-  t[0] = t[1]
+  t[0] = Class_Ref(val=t[1])
 
 # 9 Information object class definition and assignment
 
-# 9.14
-def p_FieldName (t):
-  '''FieldName : typefieldreference
-               | valuefieldreference'''
+# 9.1
+def p_ObjectClassAssignment (t):
+  '''ObjectClassAssignment : CLASS_IDENT ASSIGNMENT ObjectClass
+                           | UCASE_IDENT ASSIGNMENT ObjectClass'''
+  t[0] = t[3]
+  t[0].SetName(t[1])
+  if isinstance(t[0], ObjectClassDefn):
+    t[0].reg_types()
+
+# 9.2
+def p_ObjectClass (t):
+  '''ObjectClass : DefinedObjectClass
+                 | ObjectClassDefn'''
+  t[0] = t[1]
+
+# 9.3
+def p_ObjectClassDefn (t):
+  '''ObjectClassDefn : CLASS LBRACE FieldSpecs RBRACE
+                     | CLASS LBRACE FieldSpecs RBRACE WithSyntaxSpec'''
+  t[0] = ObjectClassDefn(fields = t[3])
+
+def p_FieldSpecs_1 (t):
+  'FieldSpecs : FieldSpec'
+  t[0] = [t[1]]
+
+def p_FieldSpecs_2 (t):
+  'FieldSpecs : FieldSpecs COMMA FieldSpec'
+  t[0] = t[1] + [t[3]]
+
+def p_WithSyntaxSpec (t):
+  'WithSyntaxSpec : WITH SYNTAX lbraceignore rbraceignore'
+  t[0] = None
+
+# 9.4
+def p_FieldSpec (t):
+  '''FieldSpec : TypeFieldSpec
+               | FixedTypeValueFieldSpec
+               | FixedTypeValueSetFieldSpec
+               | ObjectFieldSpec
+               | ObjectSetFieldSpec '''
+  t[0] = t[1]
+
+# 9.5
+def p_TypeFieldSpec (t):
+  '''TypeFieldSpec : ucasefieldreference
+                   | ucasefieldreference TypeOptionalitySpec '''
+  t[0] = TypeFieldSpec()
+  t[0].SetName(t[1])
+
+def p_TypeOptionalitySpec_1 (t):
+  'TypeOptionalitySpec ::= OPTIONAL'
+  pass
+
+def p_TypeOptionalitySpec_2 (t):
+  'TypeOptionalitySpec ::= DEFAULT Type'
+  pass
+
+# 9.6
+def p_FixedTypeValueFieldSpec (t):
+  '''FixedTypeValueFieldSpec : lcasefieldreference Type
+                             | lcasefieldreference Type UNIQUE
+                             | lcasefieldreference Type ValueOptionalitySpec
+                             | lcasefieldreference Type UNIQUE ValueOptionalitySpec '''
+  t[0] = FixedTypeValueFieldSpec(typ = t[2])
+  t[0].SetName(t[1])
+
+def p_ValueOptionalitySpec_1 (t):
+  'ValueOptionalitySpec ::= OPTIONAL'
+  pass
+
+def p_ValueOptionalitySpec_2 (t):
+  'ValueOptionalitySpec ::= DEFAULT Value'
+  pass
+
+# 9.9
+def p_FixedTypeValueSetFieldSpec (t):
+  '''FixedTypeValueSetFieldSpec : ucasefieldreference Type
+                                | ucasefieldreference Type ValueSetOptionalitySpec '''
+  t[0] = FixedTypeValueSetFieldSpec()
+  t[0].SetName(t[1])
+
+def p_ValueSetOptionalitySpec_1 (t):
+  'ValueSetOptionalitySpec ::= OPTIONAL'
+  pass
+
+def p_ValueSetOptionalitySpec_2 (t):
+  'ValueSetOptionalitySpec ::= DEFAULT ValueSet'
+  pass
+
+# 9.11
+def p_ObjectFieldSpec (t):
+  '''ObjectFieldSpec : lcasefieldreference DefinedObjectClass
+                     | lcasefieldreference DefinedObjectClass ObjectOptionalitySpec '''
+  t[0] = ObjectFieldSpec(cls=t[2])
+  t[0].SetName(t[1])
+  global obj_class
+  obj_class = None
+
+def p_ObjectOptionalitySpec_1 (t):
+  'ObjectOptionalitySpec ::= OPTIONAL'
+  pass
+
+def p_ObjectOptionalitySpec_2 (t):
+  'ObjectOptionalitySpec ::= DEFAULT Object'
+  pass
+
+# 9.12
+def p_ObjectSetFieldSpec (t):
+  '''ObjectSetFieldSpec : ucasefieldreference DefinedObjectClass
+                        | ucasefieldreference DefinedObjectClass ObjectSetOptionalitySpec '''
+  t[0] = ObjectSetFieldSpec(cls=t[2])
+  t[0].SetName(t[1])
+
+def p_ObjectSetOptionalitySpec_1 (t):
+  'ObjectSetOptionalitySpec ::= OPTIONAL'
+  pass
+
+def p_ObjectSetOptionalitySpec_2 (t):
+  'ObjectSetOptionalitySpec ::= DEFAULT ObjectSet'
+  pass
+
+# 9.13
+def p_PrimitiveFieldName (t):
+  '''PrimitiveFieldName : ucasefieldreference
+                        | lcasefieldreference '''
+  t[0] = t[1]
+
+# 9.13
+def p_FieldName_1 (t):
+  'FieldName : PrimitiveFieldName'
+  t[0] = t[1]
+
+def p_FieldName_2 (t):
+  'FieldName : FieldName DOT PrimitiveFieldName'
+  t[0] = t[1] + '.' + t[3]
+
+# 11 Information object definition and assignment
+
+# 11.1
+def p_ObjectAssignment (t):
+  'ObjectAssignment : objectreference DefinedObjectClass ASSIGNMENT Object'
+  t[0] = ObjectAssignment (ident = t[1], cls=t[2].val, val=t[4])
+  global obj_class
+  obj_class = None
+
+# 11.3
+def p_Object (t):
+  '''Object : DefinedObject
+            | ObjectDefn
+            | ParameterizedObject'''
+  t[0] = t[1]
+
+# 11.4
+def p_ObjectDefn (t):
+  'ObjectDefn : lbraceobject bodyobject rbraceobject'
+  t[0] = t[2]
+
+#  {...} block of object definition
+def p_lbraceobject(t):
+  'lbraceobject : braceobjectbegin LBRACE'
+  t[0] = t[1]
+
+def p_braceobjectbegin(t):
+  'braceobjectbegin : '
+  global lexer
+  global obj_class
+  if set_class_syntax(obj_class):
+    state = 'INITIAL'
+  else:
+    lexer.level = 1
+    state = 'braceignore'
+  lexer.push_state(state)
+
+def p_rbraceobject(t):
+  'rbraceobject : braceobjectend RBRACE'
+  t[0] = t[2]
+
+def p_braceobjectend(t):
+  'braceobjectend : '
+  global lexer
+  lexer.pop_state()
+  set_class_syntax(None)
+
+def p_bodyobject_1 (t):
+  'bodyobject : '
+  t[0] = { }
+
+def p_bodyobject_2 (t):
+  'bodyobject : cls_syntax_list'
+  t[0] = t[1]
+
+def p_cls_syntax_list_1 (t):
+  'cls_syntax_list : cls_syntax_list cls_syntax'
+  t[0] = t[1]
+  t[0].update(t[2])
+
+def p_cls_syntax_list_2 (t):
+  'cls_syntax_list : cls_syntax'
   t[0] = t[1]
 
+# X.681
+def p_cls_syntax_1 (t):
+  'cls_syntax : Type IDENTIFIED BY Value'
+  t[0] = { get_class_fieled(' ') : t[1], get_class_fieled(' '.join((t[2], t[3]))) : t[4] }
+
+def p_cls_syntax_2 (t):
+  'cls_syntax : HAS PROPERTY Value'
+  t[0] = { get_class_fieled(' '.join(t[1:-1])) : t[-1:][0] }
+
+# X.880
+def p_cls_syntax_3 (t):
+  '''cls_syntax : ERRORS ObjectSet
+                 | LINKED ObjectSet
+                 | RETURN RESULT BooleanValue 
+                 | SYNCHRONOUS BooleanValue
+                 | INVOKE PRIORITY Value 
+                 | RESULT_PRIORITY Value 
+                 | PRIORITY Value 
+                 | ALWAYS RESPONDS BooleanValue
+                 | IDEMPOTENT BooleanValue '''
+  t[0] = { get_class_fieled(' '.join(t[1:-1])) : t[-1:][0] }
+
+def p_cls_syntax_4 (t):
+  '''cls_syntax : ARGUMENT Type
+                 | RESULT Type
+                 | PARAMETER Type
+                 | CODE Value '''
+  t[0] = { get_class_fieled(t[1]) : t[2] }
+
+def p_cls_syntax_5 (t):
+  '''cls_syntax : ARGUMENT Type OPTIONAL BooleanValue
+                 | RESULT Type OPTIONAL BooleanValue
+                 | PARAMETER Type OPTIONAL BooleanValue '''
+  t[0] = { get_class_fieled(t[1]) : t[2], get_class_fieled(' '.join((t[1], t[3]))) : t[4] }
+
+# 12 Information object set definition and assignment
+
+# 12.1
+def p_ObjectSetAssignment (t):
+  'ObjectSetAssignment : UCASE_IDENT CLASS_IDENT ASSIGNMENT ObjectSet'
+  t[0] = Node('ObjectSetAssignment', name=t[1], cls=t[2], val=t[4])
+
+# 12.3
+def p_ObjectSet (t):
+  'ObjectSet : lbraceignore rbraceignore'
+  t[0] = None
+
 # 14 Notation for the object class field type ---------------------------------
 
 # 14.1
 def p_ObjectClassFieldType (t):
-  'ObjectClassFieldType : DefinedObjectClass DOT FieldName'''
+  'ObjectClassFieldType : DefinedObjectClass DOT FieldName'
   t[0] = get_type_from_class(t[1], t[3])
 
-object_class_types = {
-  'TYPE-IDENTIFIER/id'   : lambda : ObjectIdentifierType(),
-  'TYPE-IDENTIFIER/Type' : lambda : OpenType(),
-  'ABSTRACT-SYNTAX/id'       : lambda : ObjectIdentifierType(),
-  'ABSTRACT-SYNTAX/Type'     : lambda : OpenType(),
-  'ABSTRACT-SYNTAX/property' : lambda : BitStringType(),
+# 14.6
+def p_ObjectClassFieldValue (t):
+  '''ObjectClassFieldValue : OpenTypeFieldVal'''
+  t[0] = t[1]
+
+def p_OpenTypeFieldVal (t):
+  '''OpenTypeFieldVal : Type COLON Value
+                      | NullType COLON NullValue'''
+  t[0] = t[3]
+
+
+# 15 Information from objects -------------------------------------------------
+
+# 15.1
+
+def p_ValueFromObject (t):
+  'ValueFromObject : LCASE_IDENT DOT FieldName'
+  t[0] = t[1] + '.' + t[3]
+
+
+# Annex C - The instance-of type ----------------------------------------------
+
+# C.2
+def p_InstanceOfType (t):
+  'InstanceOfType : INSTANCE OF DefinedObjectClass'
+  t[0] = InstanceOfType()
+
+
+# ---  tables ---
+
+useful_object_class_types = {
+  # Annex A
+  'TYPE-IDENTIFIER.&id'   : lambda : ObjectIdentifierType(),
+  'TYPE-IDENTIFIER.&Type' : lambda : OpenType(),
+  # Annex B
+  'ABSTRACT-SYNTAX.&id'       : lambda : ObjectIdentifierType(),
+  'ABSTRACT-SYNTAX.&Type'     : lambda : OpenType(),
+  'ABSTRACT-SYNTAX.&property' : lambda : BitStringType(),
+}
+
+object_class_types = { }
+
+object_class_typerefs = { }
+
+object_class_classrefs = { }
+
+class_types_creator = {
+  'BooleanType'          : lambda : BooleanType(),
+  'IntegerType'          : lambda : IntegerType(),
+  'ObjectIdentifierType' : lambda : ObjectIdentifierType(),
+  'OpenType'             : lambda : OpenType(),
+}
+
+class_names = { }
+
+x681_syntaxes = {
+  'TYPE-IDENTIFIER' : {
+    ' '             : '&Type',
+    'IDENTIFIED'    : 'IDENTIFIED',
+    #'BY'            : 'BY',         
+    'IDENTIFIED BY' : '&id',         
+  },
+  'ABSTRACT-SYNTAX' : {
+    ' '             : '&Type',
+    'IDENTIFIED'    : 'IDENTIFIED',
+    #'BY'            : 'BY',         
+    'IDENTIFIED BY' : '&id',         
+    'HAS'           : 'HAS',
+    'PROPERTY'      : 'PROPERTY',         
+    'HAS PROPERTY'  : '&property',         
+  },
 }
 
+class_syntaxes_enabled = { 
+  'TYPE-IDENTIFIER' : True,
+  'ABSTRACT-SYNTAX' : True,
+}
+
+class_syntaxes = {
+  'TYPE-IDENTIFIER' : x681_syntaxes['TYPE-IDENTIFIER'],
+  'ABSTRACT-SYNTAX' : x681_syntaxes['ABSTRACT-SYNTAX'],
+}
+
+class_current_syntax = None
+
+def get_syntax_tokens(syntaxes):
+  tokens = { }
+  for s in (syntaxes):
+    for k in (syntaxes[s].keys()):
+      if k.find(' ') < 0:
+        tokens[k] = k
+        tokens[k] = tokens[k].replace('-', '_')
+  return tokens.values()
+
+tokens = tokens + get_syntax_tokens(x681_syntaxes)
+
+def set_class_syntax(syntax):
+  global class_syntaxes_enabled
+  global class_current_syntax
+  #print "set_class_syntax", syntax, class_current_syntax
+  if class_syntaxes_enabled.get(syntax, False):
+    class_current_syntax = syntax
+    return True
+  else:
+    class_current_syntax = None
+    return False
+
+def is_class_syntax(name):
+  global class_syntaxes
+  global class_current_syntax
+  #print "is_class_syntax", name, class_current_syntax
+  if not class_current_syntax:
+    return False
+  return class_syntaxes[class_current_syntax].has_key(name)
+
+def get_class_fieled(name):
+  if not class_current_syntax:
+    return None
+  return class_syntaxes[class_current_syntax][name]
+
+def is_class_ident(name):
+  return class_names.has_key(name)
+
+def add_class_ident(name):
+  class_names[name] = name
+
 def get_type_from_class(cls, fld):
-  return object_class_types.get(cls + '/' + fld, lambda : AnyType())()
+  flds = fld.split('.')
+  if (isinstance(cls, Class_Ref)):
+    key = cls.val + '.' + flds[0]
+  else:
+    key = cls + '.' + flds[0]
+
+  if object_class_classrefs.has_key(key):
+    return get_type_from_class(object_class_classrefs[key], '.'.join(flds[1:]))
+
+  if object_class_typerefs.has_key(key):
+    return Type_Ref(val=object_class_typerefs[key])
+
+  creator = lambda : AnyType()
+  creator = useful_object_class_types.get(key, creator)
+  creator = object_class_types.get(key, creator)
+  return creator()
+
+def set_type_to_class(cls, fld, pars):
+  key = cls + '.' + fld
+  typename = 'OpenType'
+  if (len(pars) > 0):
+    typename = pars[0]
+  else:
+    pars.append(typename)
+  typeref = None
+  if (len(pars) > 1):
+    if (isinstance(pars[1], Class_Ref)):
+      pars[1] = pars[1].val
+    typeref = pars[1]
+
+  msg = None
+  if object_class_types.has_key(key): 
+    msg = object_class_types[key]().type
+  if object_class_typerefs.has_key(key):
+    msg = "TypeReference " + object_class_typerefs[key]
+  if object_class_classrefs.has_key(key):
+    msg = "ClassReference " + object_class_classrefs[key]
+
+  if msg == ' '.join(pars): 
+    msg = None
+
+  if msg:
+    msg0 = "Can not define CLASS field %s as '%s'\n" % (key, ' '.join(pars))
+    msg1 = "Already defined as '%s'" % (msg)
+    raise msg0 + msg1
+
+  if (typename == 'ClassReference'):
+    if not typeref: return False
+    object_class_classrefs[key] = typeref
+    return True
+
+  if (typename == 'TypeReference'):
+    if not typeref: return False
+    object_class_typerefs[key] = typeref
+    return True
+
+  creator = class_types_creator.get(typename)
+  if creator:
+    object_class_types[key] = creator
+    return True
+  else:
+    return False
 
 #--- ITU-T Recommendation X.682 -----------------------------------------------
 
@@ -4603,9 +7001,9 @@ def get_type_from_class(cls, fld):
 
 # 8.1
 def p_GeneralConstraint (t):
-  '''GeneralConstraint : UserDefinedConstraint'''
-#                         | TableConstraint
-#                         | ContentsConstraint''
+  '''GeneralConstraint : UserDefinedConstraint
+                       | TableConstraint
+                       | ContentsConstraint'''
   t[0] = t[1]
 
 # 9 User-defined constraints --------------------------------------------------
@@ -4629,79 +7027,289 @@ def p_UserDefinedConstraintParameterList_3 (t):
 
 # 9.3
 def p_UserDefinedConstraintParameter (t):
-  'UserDefinedConstraintParameter : type_ref'
+  'UserDefinedConstraintParameter : Type'
+  t[0] = t[1]
+
+# 10 Table constraints, including component relation constraints --------------
+
+# 10.3
+def p_TableConstraint (t):
+  '''TableConstraint : SimpleTableConstraint
+                     | ComponentRelationConstraint'''
+  t[0] = Constraint(type = 'Table', subtype = t[1]) 
+
+def p_SimpleTableConstraint (t):
+  'SimpleTableConstraint : LBRACE UCASE_IDENT RBRACE'
+  t[0] = t[2]
+
+# 10.7
+def p_ComponentRelationConstraint (t):
+  'ComponentRelationConstraint : LBRACE UCASE_IDENT RBRACE LBRACE AtNotations RBRACE'
+  t[0] = t[2] + str(t[5])
+
+def p_AtNotations_1 (t):
+  'AtNotations : AtNotation'
+  t[0] = [t[1]]
+
+def p_AtNotations_2 (t):
+  'AtNotations : AtNotations COMMA  AtNotation'
+  t[0] = t[1] + [t[3]]
+
+def p_AtNotation_1 (t):
+  'AtNotation : AT ComponentIdList'
+  t[0] = '@' + t[2]
+
+def p_AtNotation_2 (t):
+  'AtNotation : AT DOT Level ComponentIdList'
+  t[0] = '@.' + t[3] + t[4]
+
+def p_Level_1 (t):
+  'Level : DOT Level'
+  t[0] = '.' + t[2]
+
+def p_Level_2 (t):
+  'Level : '
+  t[0] = ''
+
+def p_ComponentIdList_1 (t):
+  'ComponentIdList : LCASE_IDENT'
   t[0] = t[1]
 
+def p_ComponentIdList_2 (t):
+  'ComponentIdList : ComponentIdList DOT LCASE_IDENT'
+  t[0] = t[1] + '.' + t[3]
+
+# 11 Contents constraints -----------------------------------------------------
+
+# 11.1
+def p_ContentsConstraint (t):
+  'ContentsConstraint : CONTAINING type_ref'
+  t[0] = Constraint(type = 'Contents', subtype = t[2]) 
+
 
 #--- ITU-T Recommendation X.683 -----------------------------------------------
 
 # 8 Parameterized assignments -------------------------------------------------
 
 # 8.1
+def p_ParameterizedAssignment (t):
+  '''ParameterizedAssignment : ParameterizedTypeAssignment
+                             | ParameterizedObjectAssignment
+                             | ParameterizedObjectSetAssignment'''
+  t[0] = t[1]
 
 # 8.2
 def p_ParameterizedTypeAssignment (t):
   'ParameterizedTypeAssignment : UCASE_IDENT ParameterList ASSIGNMENT Type'
   t[0] = t[4]
-  t[0].SetName(t[1] + 'xxx')
+  t[0].SetName(t[1])  # t[0].SetName(t[1] + 'xxx')
+
+def p_ParameterizedObjectAssignment (t):
+  'ParameterizedObjectAssignment : objectreference ParameterList DefinedObjectClass ASSIGNMENT Object'
+  t[0] = ObjectAssignment (ident = t[1], cls=t[3].val, val=t[5])
+  global obj_class
+  obj_class = None
+
+def p_ParameterizedObjectSetAssignment (t):
+  'ParameterizedObjectSetAssignment : UCASE_IDENT ParameterList DefinedObjectClass ASSIGNMENT ObjectSet'
+  t[0] = Node('ObjectSetAssignment', name=t[1], cls=t[3].val, val=t[5])
 
 # 8.3
 def p_ParameterList (t):
-    'ParameterList : LBRACE Parameters RBRACE'
-    t[0] = t[2]
+  'ParameterList : lbraceignore rbraceignore'
 
-def p_Parameters_1 (t):
-  'Parameters : Parameter'
-  t[0] = [t[1]]
+#def p_ParameterList (t):
+#  'ParameterList : LBRACE Parameters RBRACE'
+#  t[0] = t[2]
 
-def p_Parameters_2 (t):
-  'Parameters : Parameters COMMA Parameter'
-  t[0] = t[1] + [t[3]]
+#def p_Parameters_1 (t):
+#  'Parameters : Parameter'
+#  t[0] = [t[1]]
 
-def p_Parameter_1 (t):
-  'Parameter : Type COLON Reference'
-  t[0] = [t[1], t[3]]
+#def p_Parameters_2 (t):
+#  'Parameters : Parameters COMMA Parameter'
+#  t[0] = t[1] + [t[3]]
 
-def p_Parameter_2 (t):
-  'Parameter : Reference'
-  t[0] = t[1]
+#def p_Parameter_1 (t):
+#  'Parameter : Type COLON Reference'
+#  t[0] = [t[1], t[3]]
+
+#def p_Parameter_2 (t):
+#  'Parameter : Reference'
+#  t[0] = t[1]
 
 
 # 9 Referencing parameterized definitions -------------------------------------
 
 # 9.1
 def p_ParameterizedReference (t):
-  'ParameterizedReference : type_ref LBRACE RBRACE'
+  'ParameterizedReference : Reference LBRACE RBRACE'
   t[0] = t[1]
-  t[0].val += 'xxx'
+  #t[0].val += 'xxx'
 
 # 9.2
 def p_ParameterizedType (t):
   'ParameterizedType : type_ref ActualParameterList'
   t[0] = t[1]
-  t[0].val += 'xxx'
+  #t[0].val += 'xxx'
+
+
+def p_ParameterizedObject (t):
+  'ParameterizedObject : DefinedObject ActualParameterList'
+  t[0] = t[1]
+  #t[0].val += 'xxx'
 
 # 9.5
 def p_ActualParameterList (t):
-    'ActualParameterList : LBRACE ActualParameters RBRACE'
-    t[0] = t[2]
+  'ActualParameterList : lbraceignore rbraceignore'
 
-def p_ActualParameters_1 (t):
-  'ActualParameters : ActualParameter'
-  t[0] = [t[1]]
+#def p_ActualParameterList (t):
+#  'ActualParameterList : LBRACE ActualParameters RBRACE'
+#  t[0] = t[2]
 
-def p_ActualParameters_2 (t):
-  'ActualParameters : ActualParameters COMMA ActualParameter'
-  t[0] = t[1] + [t[3]]
+#def p_ActualParameters_1 (t):
+#  'ActualParameters : ActualParameter'
+#  t[0] = [t[1]]
+
+#def p_ActualParameters_2 (t):
+#  'ActualParameters : ActualParameters COMMA ActualParameter'
+#  t[0] = t[1] + [t[3]]
+
+#def p_ActualParameter (t):
+#  '''ActualParameter : Type
+#                     | Value'''
+#  t[0] = t[1]
+
+
+#--- ITU-T Recommendation X.880 -----------------------------------------------
+
+x880_classes = {
+  'OPERATION' : {
+    '&ArgumentType'         : [],      
+    '&argumentTypeOptional' : [ 'BooleanType' ],
+    '&returnResult'         : [ 'BooleanType' ],
+    '&ResultType'           : [],            
+    '&resultTypeOptional'   : [ 'BooleanType' ],
+    '&Errors'               : [ 'ClassReference', 'ERROR' ],
+    '&Linked'               : [ 'ClassReference', 'OPERATION' ],
+    '&synchronous'          : [ 'BooleanType' ],
+    '&idempotent'           : [ 'BooleanType' ],
+    '&alwaysReturns'        : [ 'BooleanType' ],
+#    '&InvokePriority'         #UNSUPPORTED_FixedTypeValueSetFieldSpec
+#    '&ResultPriority'         #UNSUPPORTED_FixedTypeValueSetFieldSpec
+    '&operationCode'        : [ 'TypeReference', 'Code' ],
+  },
+  'ERROR' : {
+    '&ParameterType'         : [],                
+    '&parameterTypeOptional' : [ 'BooleanType' ],
+#    '&ErrorPriority'          #UNSUPPORTED_FixedTypeValueSetFieldSpec
+    '&errorCode'             : [ 'TypeReference', 'Code' ],
+  },
+  'OPERATION-PACKAGE' : {
+  },
+  'CONNECTION-PACKAGE' : {
+  },
+  'CONTRACT' : {
+  },
+  'ROS-OBJECT-CLASS' : {
+  },
+}
+
+x880_syntaxes = {
+  'OPERATION' : {
+    'ARGUMENT'       : '&ArgumentType',
+    'ARGUMENT OPTIONAL' : '&argumentTypeOptional',
+    'RESULT'         : '&ResultType',         
+    'RESULT OPTIONAL' : '&resultTypeOptional',         
+    'RETURN'         : 'RETURN',
+    'RETURN RESULT'  : '&returnResult',
+    'ERRORS'         : '&Errors',         
+    'LINKED'         : '&Linked',         
+    'SYNCHRONOUS'    : '&synchronous',    
+    'IDEMPOTENT'     : '&idempotent',     
+    'ALWAYS'         : 'ALWAYS',         
+    'RESPONDS'       : 'RESPONDS',
+    'ALWAYS RESPONDS' : '&alwaysReturns',       
+    'INVOKE'         : 'INVOKE',         
+    'PRIORITY'       : 'PRIORITY',
+    'INVOKE PRIORITY' : '&InvokePriority',
+    'RESULT-PRIORITY': '&ResultPriority',
+    'CODE'           : '&operationCode',           
+  },
+  'ERROR' : {
+    'PARAMETER'      : '&ParameterType',       
+    'PARAMETER OPTIONAL' : '&parameterTypeOptional',       
+    'PRIORITY'       : '&ErrorPriority',       
+    'CODE'           : '&errorCode',           
+  },
+#  'OPERATION-PACKAGE' : {
+#  },
+#  'CONNECTION-PACKAGE' : {
+#  },
+#  'CONTRACT' : {
+#  },
+#  'ROS-OBJECT-CLASS' : {
+#  },
+}
+
+def x880_import(name):
+  if x880_syntaxes.has_key(name):
+    class_syntaxes_enabled[name] = True
+    class_syntaxes[name] = x880_syntaxes[name]
+  if x880_classes.has_key(name):
+    add_class_ident(name)
+    for f in (x880_classes[name].keys()):
+      set_type_to_class(name, f, x880_classes[name][f])
+
+tokens = tokens + get_syntax_tokens(x880_syntaxes)
+
+#  {...} OID value
+#def p_lbrace_oid(t):
+#  'lbrace_oid : brace_oid_begin LBRACE'
+#  t[0] = t[1]
+
+#def p_brace_oid_begin(t):
+#  'brace_oid_begin : '
+#  global in_oid
+#  in_oid = True
+
+#def p_rbrace_oid(t):
+#  'rbrace_oid : brace_oid_end RBRACE'
+#  t[0] = t[2]
+
+#def p_brace_oid_end(t):
+#  'brace_oid_end : '
+#  global in_oid
+#  in_oid = False
 
-def p_ActualParameter (t):
-  '''ActualParameter : Type
-                     | Value'''
+#  {...} block to be ignored
+def p_lbraceignore(t):
+  'lbraceignore : braceignorebegin LBRACE'
   t[0] = t[1]
 
+def p_braceignorebegin(t):
+  'braceignorebegin : '
+  global lexer
+  lexer.level = 1
+  lexer.push_state('braceignore')
+
+def p_rbraceignore(t):
+  'rbraceignore : braceignoreend RBRACE'
+  t[0] = t[2]
+
+def p_braceignoreend(t):
+  'braceignoreend : '
+  global lexer
+  lexer.pop_state()
 
 def p_error(t):
-    raise ParseError(str(t))
+  global input_file
+  raise ParseError(t, input_file)
+
+def p_pyquote (t):
+    '''pyquote : PYQUOTE'''
+    t[0] = PyQuote (val = t[1])
+
 
 def testlex (s):
     lexer.input (s)
@@ -4743,16 +7351,20 @@ asn2wrs [-h|?] [-d dbg] [-b] [-p proto] [-c conform_file] [-e] input_file(s) ...
   -u            : unaligned (default is aligned)
   -p proto      : protocol name (implies -S)
                   default is module-name from input_file (renamed by #.MODULE if present)
+  -F            : create 'field functions'
+  -T            : tagged type support (experimental)
   -o name       : output files name core (default is <proto>)
   -O dir        : output directory
   -c conform_file : conformation file
+  -I path       : path for conformance file includes
   -e            : create conformation file for exported types
   -S            : single output for multiple modules
   -s template   : single file output (template is input file without .c/.h extension)
   -k            : keep intermediate files though single file output is used
+  -L            : suppress #line directive from .cnf file
   input_file(s) : input ASN.1 file(s)
 
-  -d dbg     : debug output, dbg = [l][y][p][s][a][t][c][o]
+  -d dbg     : debug output, dbg = [l][y][p][s][a][t][c][m][o]
                l - lex 
                y - yacc
                p - parsing
@@ -4760,81 +7372,110 @@ asn2wrs [-h|?] [-d dbg] [-b] [-p proto] [-c conform_file] [-e] input_file(s) ...
                a - list of assignments
                t - tables
                c - conformance values
+               m - list of compiled modules with dependency
                o - list of output files
 """
 
 def eth_main():
+  global input_file
+  global g_conform
+  global lexer
   print "ASN.1 to Wireshark dissector compiler";
   try:
-    opts, args = getopt.getopt(sys.argv[1:], "h?d:buXp:o:O:c:eSs:k");
+    opts, args = getopt.getopt(sys.argv[1:], "h?d:buXp:FTo:O:c:I:eSs:kL");
   except getopt.GetoptError:
     eth_usage(); sys.exit(2)
   if len(args) < 1:
     eth_usage(); sys.exit(2)
 
   conform = EthCnf()
+  conf_to_read = None
   output = EthOut()
   ectx = EthCtx(conform, output)
   ectx.encoding = 'per'
   ectx.proto_opt = None
+  ectx.fld_opt = {}
+  ectx.tag_opt = False
   ectx.outnm_opt = None
   ectx.aligned = True
   ectx.dbgopt = ''
   ectx.new = True
   ectx.expcnf = False
   ectx.merge_modules = False
+  ectx.group_by_prot = False
+  ectx.conform.last_group = 0
+  ectx.conform.suppress_line = False;
   ectx.output.outnm = None
   ectx.output.single_file = None
   for o, a in opts:
     if o in ("-h", "-?"):
       eth_usage(); sys.exit(2)
-    if o in ("-b",):
-      ectx.encoding = 'ber'
-    if o in ("-p",):
-      ectx.proto_opt = a
-      ectx.merge_modules = True
     if o in ("-c",):
-      ectx.conform.read(a)
-    if o in ("-u",):
-      ectx.aligned = False
-    if o in ("-d",):
-      ectx.dbgopt = a
-    if o in ("-e",):
-      ectx.expcnf = True
-    if o in ("-S",):
-      ectx.merge_modules = True
-    if o in ("-o",):
-      ectx.outnm_opt = a
-    if o in ("-O",):
-      ectx.output.outdir = a
-    if o in ("-s",):
-      ectx.output.single_file = a
-    if o in ("-k",):
-      ectx.output.keep = True
-    if o in ("-X",):
-        warnings.warn("Command line option -X is obsolete and can be removed")
+      conf_to_read = a
+    if o in ("-I",):
+      ectx.conform.include_path.append(a)
+    #if o in ("-X",):
+    #    warnings.warn("Command line option -X is obsolete and can be removed")
+
+  if conf_to_read:
+    ectx.conform.read(conf_to_read)
+
+  for o, a in opts:
+    if o in ("-h", "-?", "-c", "-I"):
+      pass  # already processed
+    else:
+      par = []
+      if a: par.append(a)
+      ectx.conform.set_opt(o, par, "commandline", 0)
 
   (ld, yd, pd) = (0, 0, 0); 
   if ectx.dbg('l'): ld = 1
   if ectx.dbg('y'): yd = 1
   if ectx.dbg('p'): pd = 2
   lexer = lex.lex(debug=ld)
-  yacc.yacc(method='SLR', debug=yd)
+  yacc.yacc(method='LALR', debug=yd)
+  g_conform = ectx.conform
   ast = []
   for fn in args:
+    input_file = fn
+    lexer.lineno = 1
     f = open (fn, "r")
     ast.extend(yacc.parse(f.read(), lexer=lexer, debug=pd))
     f.close ()
   ectx.eth_clean()
-  for module in ast:
-    eth_do_module(module, ectx)
-    if (not ectx.merge_modules):  # output for each module
-      ectx.eth_prepare()
-      ectx.eth_do_output()
-      ectx.eth_clean()
   if (ectx.merge_modules):  # common output for all module
+    ectx.eth_clean()
+    for module in ast:
+      eth_do_module(module, ectx)
     ectx.eth_prepare()
     ectx.eth_do_output()
+  elif (ectx.groups()):  # group by protocols/group
+    groups = []
+    pr2gr = {}
+    if (ectx.group_by_prot):  # group by protocols
+      for module in ast:
+        prot = module.get_proto(ectx)
+        if not pr2gr.has_key(prot):
+          pr2gr[prot] = len(groups)
+          groups.append([])
+        groups[pr2gr[prot]].append(module)
+    else:  # group by groups
+      pass
+    for gm in (groups):
+      ectx.eth_clean()
+      for module in gm:
+        eth_do_module(module, ectx)
+      ectx.eth_prepare()
+      ectx.eth_do_output()
+  else:   # output for each module
+    for module in ast:
+      ectx.eth_clean()
+      eth_do_module(module, ectx)
+      ectx.eth_prepare()
+      ectx.eth_do_output()
+
+  if ectx.dbg('m'):
+    ectx.dbg_modules()
 
   if ectx.dbg('c'):
     ectx.conform.dbg_print()