Initial version of asn1c
[com/asn1c.git] / libasn1parser / asn1p_y.y
diff --git a/libasn1parser/asn1p_y.y b/libasn1parser/asn1p_y.y
new file mode 100644 (file)
index 0000000..16c55de
--- /dev/null
@@ -0,0 +1,2637 @@
+%{
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "asn1parser.h"
+
+#define YYPARSE_PARAM  param
+#define YYPARSE_PARAM_TYPE     void **
+#define YYERROR_VERBOSE
+#define YYDEBUG 1
+#define YYFPRINTF   prefixed_fprintf
+
+/*
+ * Prefix parser debug with "PARSER: " for easier human eye scanning.
+ */
+static int
+__attribute__((format(printf, 2, 3)))
+prefixed_fprintf(FILE *f, const char *fmt, ...) {
+    static int line_ended = 1;
+    va_list ap;
+    va_start(ap, fmt);
+    if(line_ended) {
+        fprintf(f, "PARSER: ");
+        line_ended = 0;
+    }
+    size_t len = strlen(fmt);
+    if(len && fmt[len-1] == '\n') {
+        line_ended = 1;
+    }
+    int ret = vfprintf(f, fmt, ap);
+    va_end(ap);
+    return ret;
+}
+
+int yylex(void);
+static int yyerror(const char *msg);
+
+#ifdef YYBYACC
+int yyparse(void **param);     /* byacc does not produce a prototype */
+#endif
+void asn1p_lexer_hack_push_opaque_state(void);
+void asn1p_lexer_hack_enable_with_syntax(void);
+void asn1p_lexer_hack_push_encoding_control(void);
+#define        yylineno        asn1p_lineno
+extern int asn1p_lineno;
+const char *asn1p_parse_debug_filename;
+#define ASN_FILENAME asn1p_parse_debug_filename
+
+/*
+ * Process directives as <ASN1C:RepresentAsPointer>
+ */
+extern int asn1p_as_pointer;
+
+/*
+ * This temporary variable is used to solve the shortcomings of 1-lookahead
+ * parser.
+ */
+static struct AssignedIdentifier *saved_aid;
+
+static asn1p_value_t *_convert_bitstring2binary(char *str, int base);
+static void _fixup_anonymous_identifier(asn1p_expr_t *expr);
+
+static asn1p_module_t *currentModule;
+#define        NEW_EXPR()      (asn1p_expr_new(yylineno, currentModule))
+
+#define        checkmem(ptr)   do {                                            \
+               if(!(ptr))                                              \
+               return yyerror("Memory failure");                       \
+       } while(0)
+
+#define        CONSTRAINT_INSERT(root, constr_type, arg1, arg2) do {           \
+               if(arg1->type != constr_type) {                         \
+                       int __ret;                                      \
+                       root = asn1p_constraint_new(yylineno, currentModule);   \
+                       checkmem(root);                                 \
+                       root->type = constr_type;                       \
+                       __ret = asn1p_constraint_insert(root,           \
+                               arg1);                                  \
+                       checkmem(__ret == 0);                           \
+               } else {                                                \
+                       root = arg1;                                    \
+               }                                                       \
+               if(arg2) {                                              \
+                       int __ret                                       \
+                       = asn1p_constraint_insert(root, arg2);          \
+                       checkmem(__ret == 0);                           \
+               }                                                       \
+       } while(0)
+
+#ifdef AL_IMPORT
+#error AL_IMPORT DEFINED ELSEWHERE!
+#endif
+#define AL_IMPORT(to, where, from, field)                                      \
+    do {                                                                       \
+        if(!(from)) break;                                                     \
+        while(TQ_FIRST(&((from)->where))) {                                    \
+            TQ_ADD(&((to)->where), TQ_REMOVE(&((from)->where), field), field); \
+        }                                                                      \
+        assert(TQ_FIRST(&((from)->where)) == 0);                               \
+    } while(0)
+
+%}
+
+
+/*
+ * Token value definition.
+ * a_*:   ASN-specific types.
+ * tv_*:  Locally meaningful types.
+ */
+%union {
+       asn1p_t                 *a_grammar;
+       asn1p_module_flags_e     a_module_flags;
+       asn1p_module_t          *a_module;
+       asn1p_expr_type_e        a_type;        /* ASN.1 Type */
+       asn1p_expr_t            *a_expr;        /* Constructed collection */
+       asn1p_constraint_t      *a_constr;      /* Constraint */
+       enum asn1p_constraint_type_e    a_ctype;/* Constraint type */
+       asn1p_xports_t          *a_xports;      /* IMports/EXports */
+       struct AssignedIdentifier a_aid;        /* Assigned Identifier */
+       asn1p_oid_t             *a_oid;         /* Object Identifier */
+       asn1p_oid_arc_t          a_oid_arc;     /* Single OID's arc */
+       struct asn1p_type_tag_s  a_tag;         /* A tag */
+       asn1p_ref_t             *a_ref;         /* Reference to custom type */
+       asn1p_wsyntx_t          *a_wsynt;       /* WITH SYNTAX contents */
+       asn1p_wsyntx_chunk_t    *a_wchunk;      /* WITH SYNTAX chunk */
+       struct asn1p_ref_component_s a_refcomp; /* Component of a reference */
+       asn1p_value_t           *a_value;       /* Number, DefinedValue, etc */
+       struct asn1p_param_s     a_parg;        /* A parameter argument */
+       asn1p_paramlist_t       *a_plist;       /* A pargs list */
+       struct asn1p_expr_marker_s a_marker;    /* OPTIONAL/DEFAULT */
+       enum asn1p_constr_pres_e a_pres;        /* PRESENT/ABSENT/OPTIONAL */
+       asn1c_integer_t          a_int;
+       double                   a_dbl;
+       char    *tv_str;
+       struct {
+               char *buf;
+               int len;
+       }       tv_opaque;
+       struct {
+               char *name;
+               struct asn1p_type_tag_s tag;
+       } tv_nametag;
+};
+
+/*
+ * Token types returned by scanner.
+ */
+%token                 TOK_PPEQ        /* "::=", Pseudo Pascal EQuality */
+%token                 TOK_VBracketLeft TOK_VBracketRight      /* "[[", "]]" */
+%token <tv_opaque>     TOK_whitespace  /* A span of whitespace */
+%token <tv_opaque>     TOK_opaque      /* opaque data (driven from .y) */
+%token <tv_str>        TOK_bstring
+%token <tv_opaque>     TOK_cstring
+%token <tv_str>        TOK_hstring
+%token <tv_str>        TOK_identifier "identifier"
+%token <a_int>         TOK_number "number"
+%token <a_int>         TOK_number_negative "negative number"
+%token <a_dbl>         TOK_realnumber
+%token <a_int>         TOK_tuple
+%token <a_int>         TOK_quadruple
+%token <tv_str>        TOK_typereference
+%token <tv_str>        TOK_capitalreference            /* "CLASS1" */
+%token <tv_str>        TOK_typefieldreference          /* "&Pork" */
+%token <tv_str>        TOK_valuefieldreference         /* "&id" */
+%token <tv_str>        TOK_Literal                     /* "BY" */
+
+/*
+ * Tokens available with asn1p_lexer_hack_push_extended_values().
+ */
+%token              TOK_ExtValue_BIT_STRING
+
+/*
+ * Token types representing ASN.1 standard keywords.
+ */
+%token                 TOK_ABSENT
+%token                 TOK_ABSTRACT_SYNTAX
+%token                 TOK_ALL
+%token                 TOK_ANY
+%token                 TOK_APPLICATION
+%token                 TOK_AUTOMATIC
+%token                 TOK_BEGIN
+%token                 TOK_BIT
+%token                 TOK_BMPString
+%token                 TOK_BOOLEAN
+%token                 TOK_BY
+%token                 TOK_CHARACTER
+%token                 TOK_CHOICE
+%token                 TOK_CLASS
+%token                 TOK_COMPONENT
+%token                 TOK_COMPONENTS
+%token                 TOK_CONSTRAINED
+%token                 TOK_CONTAINING
+%token                 TOK_DEFAULT
+%token                 TOK_DEFINITIONS
+%token                 TOK_DEFINED
+%token                 TOK_EMBEDDED
+%token                 TOK_ENCODED
+%token                 TOK_ENCODING_CONTROL
+%token                 TOK_END
+%token                 TOK_ENUMERATED
+%token                 TOK_EXPLICIT
+%token                 TOK_EXPORTS
+%token                 TOK_EXTENSIBILITY
+%token                 TOK_EXTERNAL
+%token                 TOK_FALSE
+%token                 TOK_FROM
+%token                 TOK_GeneralizedTime
+%token                 TOK_GeneralString
+%token                 TOK_GraphicString
+%token                 TOK_IA5String
+%token                 TOK_IDENTIFIER
+%token                 TOK_IMPLICIT
+%token                 TOK_IMPLIED
+%token                 TOK_IMPORTS
+%token                 TOK_INCLUDES
+%token                 TOK_INSTANCE
+%token                 TOK_INSTRUCTIONS
+%token                 TOK_INTEGER
+%token                 TOK_ISO646String
+%token                 TOK_MAX
+%token                 TOK_MIN
+%token                 TOK_MINUS_INFINITY
+%token                 TOK_NULL
+%token                 TOK_NumericString
+%token                 TOK_OBJECT
+%token                 TOK_ObjectDescriptor
+%token                 TOK_OCTET
+%token                 TOK_OF
+%token                 TOK_OPTIONAL
+%token                 TOK_PATTERN
+%token                 TOK_PDV
+%token                 TOK_PLUS_INFINITY
+%token                 TOK_PRESENT
+%token                 TOK_PrintableString
+%token                 TOK_PRIVATE
+%token                 TOK_REAL
+%token                 TOK_RELATIVE_OID
+%token                 TOK_SEQUENCE
+%token                 TOK_SET
+%token                 TOK_SIZE
+%token                 TOK_STRING
+%token                 TOK_SYNTAX
+%token                 TOK_T61String
+%token                 TOK_TAGS
+%token                 TOK_TeletexString
+%token                 TOK_TRUE
+%token                 TOK_TYPE_IDENTIFIER
+%token                 TOK_UNIQUE
+%token                 TOK_UNIVERSAL
+%token                 TOK_UniversalString
+%token                 TOK_UTCTime
+%token                 TOK_UTF8String
+%token                 TOK_VideotexString
+%token                 TOK_VisibleString
+%token                 TOK_WITH
+%token                 UTF8_BOM    "UTF-8 byte order mark"
+
+%nonassoc              TOK_EXCEPT
+%left                  '^' TOK_INTERSECTION
+%left                  '|' TOK_UNION
+
+/* Misc tags */
+%token                 TOK_TwoDots             ".."
+%token                 TOK_ThreeDots   "..."
+
+
+/*
+ * Types defined herein.
+ */
+%type  <a_grammar>             ModuleList
+%type  <a_module>              ModuleDefinition
+%type  <a_module>              ModuleBody
+%type  <a_module>              AssignmentList
+%type  <a_module>              Assignment
+%type  <a_module>              optModuleBody   /* Optional */
+%type  <a_module_flags>        optModuleDefinitionFlags
+%type  <a_module_flags>        ModuleDefinitionFlags   /* Set of FL */
+%type  <a_module_flags>        ModuleDefinitionFlag            /* Single FL */
+%type  <a_module>              optImports
+%type  <a_module>              optExports
+%type  <a_module>              ImportsDefinition
+%type  <a_module>              optImportsBundleSet
+%type  <a_module>              ImportsBundleSet
+%type  <a_xports>              ImportsBundle
+%type  <a_xports>              ImportsList
+%type  <a_xports>              ExportsDefinition
+%type  <a_xports>              ExportsBody
+%type  <a_expr>                ImportsElement
+%type  <a_expr>                ExportsElement
+%type  <a_expr>                ExtensionAndException
+%type  <a_expr>                Type
+%type  <a_expr>                TaggedType
+%type  <a_expr>                MaybeIndirectTaggedType
+%type  <a_expr>                UntaggedType
+%type  <a_expr>                DefinedUntaggedType
+%type  <a_expr>                ConcreteTypeDeclaration "concrete TypeDeclaration"
+%type  <a_expr>                TypeDeclaration
+%type  <a_expr>                MaybeIndirectTypeDeclaration
+%type  <a_ref>                 ComplexTypeReference
+%type  <a_ref>                 ComplexTypeReferenceAmpList
+%type  <a_refcomp>             ComplexTypeReferenceElement
+%type  <a_refcomp>             PrimitiveFieldReference
+%type  <a_expr>                FieldSpec
+%type  <a_ref>                 FieldName
+%type  <a_ref>                 DefinedObjectClass
+%type  <a_expr>                ClassField
+%type  <a_expr>                ObjectClass
+%type  <a_expr>                DataTypeReference       /* Type1 ::= Type2 */
+%type  <a_expr>                DefinedType
+%type  <a_constr>              ValueSet                /* {a|b|c}*/
+%type  <a_expr>                ValueSetTypeAssignment  /* Val INTEGER ::= {1|2} */
+%type  <a_expr>                ValueAssignment         /* val INTEGER ::= 1*/
+%type  <a_value>               Value
+%type  <a_value>               SimpleValue
+%type  <a_value>               DefinedValue
+%type  <a_value>               SignedNumber
+%type  <a_value>               RealValue
+%type  <a_value>               BitStringValue
+%type  <a_expr>                optComponentTypeLists
+%type  <a_expr>                ComponentTypeLists
+%type  <a_expr>                ComponentType
+%type  <a_expr>                AlternativeTypeLists
+%type  <a_expr>                AlternativeType
+%type  <a_expr>                UniverationList
+%type  <a_expr>                Enumerations
+%type  <a_expr>                NamedBitList
+%type  <a_expr>                NamedBit
+%type  <a_expr>                NamedNumberList
+%type  <a_expr>                NamedNumber
+%type  <a_expr>                IdentifierList
+%type  <a_expr>                IdentifierElement
+%type  <a_expr>                UniverationElement
+%type  <tv_str>                TypeRefName
+%type  <tv_str>                Identifier
+%type  <a_ref>             IdentifierAsReference
+%type  <a_value>               IdentifierAsValue
+%type  <tv_str>                optIdentifier
+%type  <a_parg>                ParameterArgumentName
+%type  <a_plist>               ParameterArgumentList
+%type  <a_expr>                ActualParameter
+%type  <a_expr>                ActualParameterList
+%type  <a_aid>                 AssignedIdentifier      /* OID/DefinedValue */
+%type  <a_oid>                 ObjectIdentifier        /* OID */
+%type  <a_oid>                 optObjectIdentifier     /* Optional OID */
+%type  <a_oid>                 ObjectIdentifierBody
+%type  <a_oid_arc>             ObjectIdentifierElement
+%type  <a_expr>                BuiltinType
+%type  <a_type>                BasicTypeId
+%type  <a_type>                BasicTypeId_UniverationCompatible
+%type  <a_type>                BasicString
+%type  <tv_opaque>             Opaque
+%type  <tv_opaque>             OpaqueFirstToken
+%type  <a_tag>                 Tag             /* [UNIVERSAL 0] IMPLICIT */
+%type  <a_tag>                 TagClass TagTypeValue TagPlicit
+%type  <a_tag>                 optTag          /* [UNIVERSAL 0] IMPLICIT */
+%type  <a_constr>              optConstraint
+%type  <a_constr>              optManyConstraints  /* Only for Type */
+%type  <a_constr>              ManyConstraints
+%type  <a_constr>              optSizeOrConstraint
+%type  <a_constr>              Constraint
+%type  <a_constr>              PermittedAlphabet
+%type  <a_constr>              SizeConstraint
+%type  <a_constr>              SingleTypeConstraint
+%type  <a_constr>              MultipleTypeConstraints
+%type  <a_constr>              NamedConstraint
+%type  <a_constr>              FullSpecification
+%type  <a_constr>              PartialSpecification
+%type  <a_constr>              TypeConstraints
+%type  <a_constr>              ConstraintSpec
+%type  <a_constr>              SubtypeConstraint
+%type  <a_constr>              GeneralConstraint
+%type  <a_constr>              ElementSetSpecs         /* 1..2,...,3 */
+%type  <a_constr>              ElementSetSpec          /* 1..2 */
+%type  <a_constr>              Unions
+%type  <a_constr>              Intersections
+%type  <a_constr>              IntersectionElements
+%type  <a_constr>              Elements
+%type  <a_constr>              SubtypeElements /* 1..2 */
+%type  <a_constr>              SimpleTableConstraint
+%type  <a_constr>              UserDefinedConstraint
+%type  <a_constr>              TableConstraint
+%type  <a_constr>              ContentsConstraint
+%type  <a_constr>              PatternConstraint
+%type  <a_constr>              InnerTypeConstraints
+%type  <a_constr>              ValueRange
+%type  <a_constr>              ComponentRelationConstraint
+%type  <a_constr>              AtNotationList
+%type  <a_ref>                 AtNotationElement
+%type  <a_value>               SingleValue
+%type  <a_value>               LowerEndValue
+%type  <a_value>               UpperEndValue
+%type  <a_value>               ContainedSubtype
+%type  <a_ctype>               ConstraintRangeSpec
+%type  <a_value>               RestrictedCharacterStringValue
+%type  <a_wsynt>               optWithSyntax
+%type  <a_wsynt>               WithSyntax
+%type  <a_wsynt>               WithSyntaxList
+%type  <a_wchunk>              WithSyntaxToken
+%type  <a_marker>              optMarker Marker
+%type  <a_int>                 optUNIQUE
+%type  <a_pres>                optPresenceConstraint PresenceConstraint
+%type  <tv_str>                ComponentIdList
+%type  <a_int>                 NSTD_IndirectMarker
+
+%%
+
+
+ParsedGrammar:
+       UTF8_BOM ModuleList {
+               *(void **)param = $2;
+       }
+       | ModuleList {
+               *(void **)param = $1;
+       }
+       ;
+
+ModuleList:
+       ModuleDefinition {
+               $$ = asn1p_new();
+               checkmem($$);
+               TQ_ADD(&($$->modules), $1, mod_next);
+       }
+       | ModuleList ModuleDefinition {
+               $$ = $1;
+               TQ_ADD(&($$->modules), $2, mod_next);
+       }
+       ;
+
+/*
+ * ASN module definition.
+ * === EXAMPLE ===
+ * MySyntax DEFINITIONS AUTOMATIC TAGS ::=
+ * BEGIN
+ * ...
+ * END 
+ * === EOF ===
+ */
+
+ModuleDefinition:
+       TypeRefName { currentModule = asn1p_module_new(); }
+       optObjectIdentifier TOK_DEFINITIONS
+               optModuleDefinitionFlags
+               TOK_PPEQ TOK_BEGIN
+               optModuleBody
+               TOK_END {
+
+               $$ = currentModule;
+
+               if($8) {
+                       asn1p_module_t tmp = *($$);
+                       *($$) = *($8);
+                       *($8) = tmp;
+                       asn1p_module_free($8);
+               } else {
+                       /* There's a chance that a module is just plain empty */
+               }
+
+               $$->ModuleName = $1;
+               $$->module_oid = $3;
+               $$->module_flags = $5;
+       }
+       ;
+
+/*
+ * Object Identifier Definition
+ * { iso member-body(2) 3 }
+ */
+optObjectIdentifier:
+       { $$ = 0; }
+       | ObjectIdentifier { $$ = $1; }
+       ;
+       
+ObjectIdentifier:
+       '{' ObjectIdentifierBody '}' {
+               $$ = $2;
+       }
+       | '{' '}' {
+               $$ = 0;
+       }
+       ;
+
+ObjectIdentifierBody:
+       ObjectIdentifierElement {
+               $$ = asn1p_oid_new();
+               asn1p_oid_add_arc($$, &$1);
+               if($1.name)
+                       free($1.name);
+       }
+       | ObjectIdentifierBody ObjectIdentifierElement {
+               $$ = $1;
+               asn1p_oid_add_arc($$, &$2);
+               if($2.name)
+                       free($2.name);
+       }
+       ;
+
+ObjectIdentifierElement:
+       Identifier {                                    /* iso */
+               $$.name = $1;
+               $$.number = -1;
+       }
+       | Identifier '(' TOK_number ')' {               /* iso(1) */
+               $$.name = $1;
+               $$.number = $3;
+       }
+       | TOK_number {                                  /* 1 */
+               $$.name = 0;
+               $$.number = $1;
+       }
+       ;
+       
+/*
+ * Optional module flags.
+ */
+optModuleDefinitionFlags:
+       { $$ = MSF_NOFLAGS; }
+       | ModuleDefinitionFlags {
+               $$ = $1;
+       }
+       ;
+
+/*
+ * Module flags.
+ */
+ModuleDefinitionFlags:
+       ModuleDefinitionFlag {
+               $$ = $1;
+       }
+       | ModuleDefinitionFlags ModuleDefinitionFlag {
+               $$ = $1 | $2;
+       }
+       ;
+
+/*
+ * Single module flag.
+ */
+ModuleDefinitionFlag:
+       TOK_EXPLICIT TOK_TAGS {
+               $$ = MSF_EXPLICIT_TAGS;
+       }
+       | TOK_IMPLICIT TOK_TAGS {
+               $$ = MSF_IMPLICIT_TAGS;
+       }
+       | TOK_AUTOMATIC TOK_TAGS {
+               $$ = MSF_AUTOMATIC_TAGS;
+       }
+       | TOK_EXTENSIBILITY TOK_IMPLIED {
+               $$ = MSF_EXTENSIBILITY_IMPLIED;
+       }
+       /* EncodingReferenceDefault */
+       | TOK_capitalreference TOK_INSTRUCTIONS {
+               /* X.680Amd1 specifies TAG and XER */
+               if(strcmp($1, "TAG") == 0) {
+                       $$ = MSF_TAG_INSTRUCTIONS;
+               } else if(strcmp($1, "XER") == 0) {
+                       $$ = MSF_XER_INSTRUCTIONS;
+               } else {
+                       fprintf(stderr,
+                               "WARNING: %s INSTRUCTIONS at %s:%d: "
+                               "Unrecognized encoding reference\n",
+                               $1, ASN_FILENAME, yylineno);
+                       $$ = MSF_unk_INSTRUCTIONS;
+               }
+               free($1);
+       }
+       ;
+
+/*
+ * Optional module body.
+ */
+optModuleBody:
+       { $$ = 0; }
+       | ModuleBody {
+               $$ = $1;
+       }
+       ;
+
+/*
+ * ASN.1 Module body.
+ */
+ModuleBody:
+       optExports optImports AssignmentList {
+               $$ = asn1p_module_new();
+               AL_IMPORT($$, exports, $1, xp_next);
+               AL_IMPORT($$, imports, $2, xp_next);
+               asn1p_module_move_members($$, $3);
+
+               asn1p_module_free($1);
+               asn1p_module_free($2);
+               asn1p_module_free($3);
+       }
+       ;
+
+AssignmentList:
+       Assignment {
+               $$ = $1;
+       }
+       | AssignmentList Assignment {
+               if($1) {
+                       $$ = $1;
+               } else {
+                       $$ = $2;
+                       break;
+               }
+        asn1p_module_move_members($$, $2);
+               asn1p_module_free($2);
+       }
+       ;
+
+
+/*
+ * One of the elements of ASN.1 module specification.
+ */
+Assignment:
+       DataTypeReference {
+               $$ = asn1p_module_new();
+               checkmem($$);
+               assert($1->expr_type != A1TC_INVALID);
+               assert($1->meta_type != AMT_INVALID);
+               asn1p_module_member_add($$, $1);
+       }
+       | ValueAssignment {
+               $$ = asn1p_module_new();
+               checkmem($$);
+               assert($1->expr_type != A1TC_INVALID);
+               assert($1->meta_type != AMT_INVALID);
+               asn1p_module_member_add($$, $1);
+       }
+       /*
+        * Value set definition
+        * === EXAMPLE ===
+        * EvenNumbers INTEGER ::= { 2 | 4 | 6 | 8 }
+        * === EOF ===
+        * Also ObjectClassSet.
+        */
+       | ValueSetTypeAssignment {
+               $$ = asn1p_module_new();
+               checkmem($$);
+               assert($1->expr_type != A1TC_INVALID);
+               assert($1->meta_type != AMT_INVALID);
+               asn1p_module_member_add($$, $1);
+       }
+       | TOK_ENCODING_CONTROL TOK_capitalreference 
+               { asn1p_lexer_hack_push_encoding_control(); }
+                       {
+               fprintf(stderr,
+                       "WARNING: ENCODING-CONTROL %s "
+                       "specification at %s:%d ignored\n",
+                       $2, ASN_FILENAME, yylineno);
+               free($2);
+               $$ = 0;
+       }
+
+       /*
+        * Erroneous attemps
+        */
+       | BasicString {
+               return yyerror(
+                       "Attempt to redefine a standard basic string type, "
+                       "please comment out or remove this type redefinition.");
+       }
+       ;
+
+/*
+ * === EXAMPLE ===
+ * IMPORTS Type1, value FROM Module { iso standard(0) } ;
+ * === EOF ===
+ */
+optImports:
+       { $$ = 0; }
+       | ImportsDefinition;
+
+ImportsDefinition:
+       TOK_IMPORTS optImportsBundleSet ';' {
+               if(!saved_aid && 0)
+                       return yyerror("Unterminated IMPORTS FROM, "
+                                       "expected semicolon ';'");
+               saved_aid = 0;
+               $$ = $2;
+       }
+       /*
+        * Some error cases.
+        */
+       | TOK_IMPORTS TOK_FROM /* ... */ {
+               return yyerror("Empty IMPORTS list");
+       }
+       ;
+
+optImportsBundleSet:
+       { $$ = asn1p_module_new(); }
+       | ImportsBundleSet;
+
+ImportsBundleSet:
+       ImportsBundle {
+               $$ = asn1p_module_new();
+               checkmem($$);
+               TQ_ADD(&($$->imports), $1, xp_next);
+       }
+       | ImportsBundleSet ImportsBundle {
+               $$ = $1;
+               TQ_ADD(&($$->imports), $2, xp_next);
+       }
+       ;
+
+AssignedIdentifier:
+       { memset(&$$, 0, sizeof($$)); }
+       | ObjectIdentifier { $$.oid = $1; };
+       /* | DefinedValue { $$.value = $1; }; // Handled through saved_aid */
+
+ImportsBundle:
+       ImportsList TOK_FROM TypeRefName AssignedIdentifier {
+               $$ = $1;
+               $$->fromModuleName = $3;
+               $$->identifier = $4;
+               /* This stupid thing is used for look-back hack. */
+               saved_aid = $$->identifier.oid ? 0 : &($$->identifier);
+               checkmem($$);
+       }
+       ;
+
+ImportsList:
+       ImportsElement {
+               $$ = asn1p_xports_new();
+               checkmem($$);
+               TQ_ADD(&($$->xp_members), $1, next);
+       }
+       | ImportsList ',' ImportsElement {
+               $$ = $1;
+               TQ_ADD(&($$->xp_members), $3, next);
+       }
+       ;
+
+ImportsElement:
+       TypeRefName {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->Identifier = $1;
+               $$->expr_type = A1TC_REFERENCE;
+       }
+       | TypeRefName '{' '}' {         /* Completely equivalent to above */
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->Identifier = $1;
+               $$->expr_type = A1TC_REFERENCE;
+       }
+       | Identifier {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->Identifier = $1;
+               $$->expr_type = A1TC_REFERENCE;
+       }
+       ;
+
+
+optExports:
+       { $$ = 0; }
+       | ExportsDefinition {
+               $$ = asn1p_module_new();
+               checkmem($$);
+               if($1) {
+                       TQ_ADD(&($$->exports), $1, xp_next);
+               } else {
+                       /* "EXPORTS ALL;" */
+               }
+       }
+       ;
+
+ExportsDefinition:
+       TOK_EXPORTS ExportsBody ';' {
+               $$ = $2;
+       }
+       | TOK_EXPORTS TOK_ALL ';' {
+               $$ = 0;
+       }
+       | TOK_EXPORTS ';' {
+               /* Empty EXPORTS clause effectively prohibits export. */
+               $$ = asn1p_xports_new();
+               checkmem($$);
+       }
+       ;
+
+ExportsBody:
+       ExportsElement {
+               $$ = asn1p_xports_new();
+               assert($$);
+               TQ_ADD(&($$->xp_members), $1, next);
+       }
+       | ExportsBody ',' ExportsElement {
+               $$ = $1;
+               TQ_ADD(&($$->xp_members), $3, next);
+       }
+       ;
+
+ExportsElement:
+       TypeRefName {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->Identifier = $1;
+               $$->expr_type = A1TC_EXPORTVAR;
+       }
+       | TypeRefName '{' '}' {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->Identifier = $1;
+               $$->expr_type = A1TC_EXPORTVAR;
+       }
+       | Identifier {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->Identifier = $1;
+               $$->expr_type = A1TC_EXPORTVAR;
+       }
+       ;
+
+
+ValueSet: '{' ElementSetSpecs '}' { $$ = $2; };
+
+ValueSetTypeAssignment:
+       TypeRefName Type TOK_PPEQ ValueSet {
+               $$ = $2;
+               assert($$->Identifier == 0);
+               $$->Identifier = $1;
+               $$->meta_type = AMT_VALUESET;
+               $$->constraints = $4;
+       }
+       ;
+
+DefinedType:
+       /*
+        * A DefinedType reference.
+        * "CLASS1.&id.&id2"
+        * or
+        * "Module.Type"
+        * or
+        * "Module.identifier"
+        * or
+        * "Type"
+        */
+       ComplexTypeReference {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->reference = $1;
+               $$->expr_type = A1TC_REFERENCE;
+               $$->meta_type = AMT_TYPEREF;
+       }
+       /*
+        * A parameterized assignment.
+        */
+       | ComplexTypeReference '{' ActualParameterList '}' {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->reference = $1;
+               $$->rhs_pspecs = $3;
+               $$->expr_type = A1TC_REFERENCE;
+               $$->meta_type = AMT_TYPEREF;
+       }
+       ;
+
+/*
+ * Data Type Reference.
+ * === EXAMPLE ===
+ * Type3 ::= CHOICE { a Type1,  b Type 2 }
+ * === EOF ===
+ */
+DataTypeReference:
+       /*
+        * Optionally tagged type definition.
+        */
+       TypeRefName TOK_PPEQ Type {
+               $$ = $3;
+               $$->Identifier = $1;
+               assert($$->expr_type);
+               assert($$->meta_type);
+       }
+       | TypeRefName TOK_PPEQ ObjectClass {
+               $$ = $3;
+               $$->Identifier = $1;
+               assert($$->expr_type == A1TC_CLASSDEF);
+               assert($$->meta_type == AMT_OBJECTCLASS);
+       }
+       /*
+        * Parameterized <Type> declaration:
+        * === EXAMPLE ===
+        *   SIGNED { ToBeSigned } ::= SEQUENCE {
+        *      toBeSigned  ToBeSigned,
+        *      algorithm   AlgorithmIdentifier,
+        *      signature   BIT STRING
+        *   }
+        * === EOF ===
+        */
+       | TypeRefName '{' ParameterArgumentList '}' TOK_PPEQ Type {
+               $$ = $6;
+               $$->Identifier = $1;
+               $$->lhs_params = $3;
+       }
+       /* Parameterized CLASS declaration */
+       | TypeRefName '{' ParameterArgumentList '}' TOK_PPEQ ObjectClass {
+               $$ = $6;
+               $$->Identifier = $1;
+               $$->lhs_params = $3;
+       }
+       ;
+
+ParameterArgumentList:
+       ParameterArgumentName {
+               int ret;
+               $$ = asn1p_paramlist_new(yylineno);
+               checkmem($$);
+               ret = asn1p_paramlist_add_param($$, $1.governor, $1.argument);
+               checkmem(ret == 0);
+               asn1p_ref_free($1.governor);
+               free($1.argument);
+       }
+       | ParameterArgumentList ',' ParameterArgumentName {
+               int ret;
+               $$ = $1;
+               ret = asn1p_paramlist_add_param($$, $3.governor, $3.argument);
+               checkmem(ret == 0);
+               asn1p_ref_free($3.governor);
+               free($3.argument);
+       }
+       ;
+       
+ParameterArgumentName:
+       TypeRefName {
+               $$.governor = NULL;
+               $$.argument = $1;
+       }
+       | TypeRefName ':' Identifier {
+               int ret;
+               $$.governor = asn1p_ref_new(yylineno, currentModule);
+               ret = asn1p_ref_add_component($$.governor, $1, 0);
+               checkmem(ret == 0);
+               $$.argument = $3;
+               free($1);
+       }
+       | TypeRefName ':' TypeRefName {
+               int ret;
+               $$.governor = asn1p_ref_new(yylineno, currentModule);
+               ret = asn1p_ref_add_component($$.governor, $1, 0);
+               checkmem(ret == 0);
+               $$.argument = $3;
+               free($1);
+       }
+       | BasicTypeId ':' Identifier {
+               int ret;
+               $$.governor = asn1p_ref_new(yylineno, currentModule);
+               ret = asn1p_ref_add_component($$.governor,
+                       ASN_EXPR_TYPE2STR($1), 1);
+               checkmem(ret == 0);
+               $$.argument = $3;
+       }
+       | BasicTypeId ':' TypeRefName {
+               int ret;
+               $$.governor = asn1p_ref_new(yylineno, currentModule);
+               ret = asn1p_ref_add_component($$.governor,
+                       ASN_EXPR_TYPE2STR($1), 1);
+               checkmem(ret == 0);
+               $$.argument = $3;
+       }
+       ;
+
+ActualParameterList:
+       ActualParameter {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               asn1p_expr_add($$, $1);
+       }
+       | ActualParameterList ',' ActualParameter {
+               $$ = $1;
+               asn1p_expr_add($$, $3);
+       }
+       ;
+
+ActualParameter:
+       UntaggedType    /* act. Type */
+       | SimpleValue {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->Identifier = strdup("?");
+               $$->expr_type = A1TC_REFERENCE;
+               $$->meta_type = AMT_VALUE;
+               $$->value = $1;
+       }
+       | DefinedValue {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->Identifier = strdup("?");
+               $$->expr_type = A1TC_REFERENCE;
+               $$->meta_type = AMT_VALUE;
+               $$->value = $1;
+       }
+       | ValueSet {
+               $$ = NEW_EXPR();
+               $$->expr_type = A1TC_VALUESET;
+               $$->meta_type = AMT_VALUESET;
+               $$->constraints = $1;
+       }
+       ;
+
+/*
+       | '{' ActualParameter '}' {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               asn1p_expr_add($$, $2);
+               $$->expr_type = A1TC_PARAMETRIZED;
+               $$->meta_type = AMT_TYPE;
+       }
+       ;
+*/
+
+/*
+ * A collection of constructed data type members.
+ */
+optComponentTypeLists:
+       { $$ = NEW_EXPR(); }
+       | ComponentTypeLists { $$ = $1; };
+
+ComponentTypeLists:
+       ComponentType {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               asn1p_expr_add($$, $1);
+       }
+       | ComponentTypeLists ',' ComponentType {
+               $$ = $1;
+               asn1p_expr_add($$, $3);
+       }
+       | ComponentTypeLists ',' TOK_VBracketLeft ComponentTypeLists TOK_VBracketRight {
+               $$ = $1;
+               $4->meta_type = AMT_TYPE;
+               $4->expr_type = ASN_CONSTR_SEQUENCE;
+               $4->marker.flags |= EM_OPTIONAL;
+               asn1p_expr_add($$, $4);
+       }
+       ;
+
+ComponentType:
+       Identifier MaybeIndirectTaggedType optMarker {
+               $$ = $2;
+               assert($$->Identifier == 0);
+               $$->Identifier = $1;
+               $3.flags |= $$->marker.flags;
+               $$->marker = $3;
+       }
+       | MaybeIndirectTaggedType optMarker {
+               $$ = $1;
+               $2.flags |= $$->marker.flags;
+               $$->marker = $2;
+               _fixup_anonymous_identifier($$);
+       }
+       | TOK_COMPONENTS TOK_OF MaybeIndirectTaggedType {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->meta_type = $3->meta_type;
+               $$->expr_type = A1TC_COMPONENTS_OF;
+               asn1p_expr_add($$, $3);
+       }
+       | ExtensionAndException {
+               $$ = $1;
+       }
+       ;
+
+AlternativeTypeLists:
+       AlternativeType {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               asn1p_expr_add($$, $1);
+       }
+       | AlternativeTypeLists ',' AlternativeType {
+               $$ = $1;
+               asn1p_expr_add($$, $3);
+       }
+       ;
+
+AlternativeType:
+       Identifier MaybeIndirectTaggedType {
+               $$ = $2;
+               assert($$->Identifier == 0);
+               $$->Identifier = $1;
+       }
+       | ExtensionAndException {
+               $$ = $1;
+       }
+       | MaybeIndirectTaggedType {
+               $$ = $1;
+               _fixup_anonymous_identifier($$);
+       }
+       ;
+
+ObjectClass:
+       TOK_CLASS '{' FieldSpec '}' optWithSyntax {
+               $$ = $3;
+               checkmem($$);
+               $$->with_syntax = $5;
+               assert($$->expr_type == A1TC_CLASSDEF);
+               assert($$->meta_type == AMT_OBJECTCLASS);
+       }
+       ;
+
+optUNIQUE:
+       { $$ = 0; }
+       | TOK_UNIQUE { $$ = 1; }
+       ;
+
+FieldSpec:
+       ClassField {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->expr_type = A1TC_CLASSDEF;
+               $$->meta_type = AMT_OBJECTCLASS;
+               asn1p_expr_add($$, $1);
+       }
+       | FieldSpec ',' ClassField {
+               $$ = $1;
+               asn1p_expr_add($$, $3);
+       }
+       ;
+
+       /* X.681 */
+ClassField:
+
+       /* TypeFieldSpec ::= typefieldreference TypeOptionalitySpec? */
+       TOK_typefieldreference optMarker {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->Identifier = $1;
+               $$->meta_type = AMT_OBJECTFIELD;
+               $$->expr_type = A1TC_CLASSFIELD_TFS;    /* TypeFieldSpec */
+               $$->marker = $2;
+       }
+
+       /* FixedTypeValueFieldSpec ::= valuefieldreference Type UNIQUE ? ValueOptionalitySpec ? */
+       | TOK_valuefieldreference Type optUNIQUE optMarker {
+               $$ = NEW_EXPR();
+               $$->Identifier = $1;
+               $$->meta_type = AMT_OBJECTFIELD;
+               $$->expr_type = A1TC_CLASSFIELD_FTVFS;  /* FixedTypeValueFieldSpec */
+               $$->unique = $3;
+               $$->marker = $4;
+               asn1p_expr_add($$, $2);
+       }
+
+       /* VariableTypeValueFieldSpec ::= valuefieldreference FieldName ValueOptionalitySpec ? */
+       | TOK_valuefieldreference FieldName optMarker {
+               $$ = NEW_EXPR();
+               $$->Identifier = $1;
+               $$->meta_type = AMT_OBJECTFIELD;
+               $$->expr_type = A1TC_CLASSFIELD_VTVFS;
+               $$->reference = $2;
+               $$->marker = $3;
+       }
+
+       /*  ObjectFieldSpec ::= objectfieldreference DefinedObjectClass ObjectOptionalitySpec ? */
+       | TOK_valuefieldreference DefinedObjectClass optMarker {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->Identifier = $1;
+               $$->reference = $2;
+               $$->meta_type = AMT_OBJECTFIELD;
+               $$->expr_type = A1TC_CLASSFIELD_OFS;
+               $$->marker = $3;
+       }
+
+       /* VariableTypeValueSetFieldSpec ::= valuesetfieldreference FieldName ValueOptionalitySpec ? */
+       | TOK_typefieldreference FieldName optMarker {
+               $$ = NEW_EXPR();
+               $$->Identifier = $1;
+               $$->meta_type = AMT_OBJECTFIELD;
+               $$->expr_type = A1TC_CLASSFIELD_VTVSFS;
+               $$->reference = $2;
+               $$->marker = $3;
+       }
+
+       /* FixedTypeValueSetFieldSpec ::= valuesetfieldreference Type ValueSetOptionalitySpec ? */
+       | TOK_typefieldreference Type optMarker {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->Identifier = $1;
+               $$->meta_type = AMT_OBJECTFIELD;
+               $$->expr_type = A1TC_CLASSFIELD_FTVSFS;
+               asn1p_expr_add($$, $2);
+               $$->marker = $3;
+       }
+
+       /*  ObjectSetFieldSpec ::= objectsetfieldreference DefinedObjectClass ObjectOptionalitySpec ? */
+       | TOK_typefieldreference DefinedObjectClass optMarker {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->Identifier = $1;
+               $$->reference = $2;
+               $$->meta_type = AMT_OBJECTFIELD;
+               $$->expr_type = A1TC_CLASSFIELD_OSFS;
+               $$->marker = $3;
+       }
+       ;
+
+optWithSyntax:
+       { $$ = 0; }
+       | WithSyntax {
+               $$ = $1;
+       }
+       ;
+
+WithSyntax:
+       TOK_WITH TOK_SYNTAX '{'
+               { asn1p_lexer_hack_enable_with_syntax(); }
+               WithSyntaxList
+               '}' {
+               $$ = $5;
+       }
+       ;
+
+WithSyntaxList:
+       WithSyntaxToken {
+               $$ = asn1p_wsyntx_new();
+               TQ_ADD(&($$->chunks), $1, next);
+       }
+       | WithSyntaxList WithSyntaxToken {
+               $$ = $1;
+               TQ_ADD(&($$->chunks), $2, next);
+       }
+       ;
+
+WithSyntaxToken:
+       TOK_whitespace {
+               $$ = asn1p_wsyntx_chunk_fromstring($1.buf, 0);
+               $$->type = WC_WHITESPACE;
+       }
+       | TOK_Literal {
+               $$ = asn1p_wsyntx_chunk_fromstring($1, 0);
+       }
+       | PrimitiveFieldReference {
+               $$ = asn1p_wsyntx_chunk_fromstring($1.name, 0);
+               $$->type = WC_FIELD;
+       }
+       | '[' WithSyntaxList ']' {
+               $$ = asn1p_wsyntx_chunk_fromsyntax($2);
+       }
+       ;
+
+ExtensionAndException:
+       TOK_ThreeDots {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->Identifier = strdup("...");
+               checkmem($$->Identifier);
+               $$->expr_type = A1TC_EXTENSIBLE;
+               $$->meta_type = AMT_TYPE;
+       }
+       | TOK_ThreeDots '!' DefinedValue {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->Identifier = strdup("...");
+               checkmem($$->Identifier);
+               $$->value = $3;
+               $$->expr_type = A1TC_EXTENSIBLE;
+               $$->meta_type = AMT_TYPE;
+       }
+       | TOK_ThreeDots '!' SignedNumber {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->Identifier = strdup("...");
+               $$->value = $3;
+               checkmem($$->Identifier);
+               $$->expr_type = A1TC_EXTENSIBLE;
+               $$->meta_type = AMT_TYPE;
+       }
+       ;
+
+Type: TaggedType;
+
+TaggedType:
+    optTag UntaggedType {
+        $$ = $2;
+        $$->tag = $1;
+    }
+    ;
+
+DefinedUntaggedType:
+       DefinedType optManyConstraints {
+               $$ = $1;
+               /*
+                * Outer constraint for SEQUENCE OF and SET OF applies
+                * to the inner type.
+                */
+               if($$->expr_type == ASN_CONSTR_SEQUENCE_OF
+               || $$->expr_type == ASN_CONSTR_SET_OF) {
+                       assert(!TQ_FIRST(&($$->members))->constraints);
+                       TQ_FIRST(&($$->members))->constraints = $2;
+               } else {
+                       if($$->constraints) {
+                               assert(!$2);
+                               /* Check this : optManyConstraints is not used ?! */
+                               asn1p_constraint_free($2);
+                       } else {
+                               $$->constraints = $2;
+                       }
+               }
+       }
+       ;
+
+UntaggedType:
+       TypeDeclaration optManyConstraints {
+               $$ = $1;
+               /*
+                * Outer constraint for SEQUENCE OF and SET OF applies
+                * to the inner type.
+                */
+               if($$->expr_type == ASN_CONSTR_SEQUENCE_OF
+               || $$->expr_type == ASN_CONSTR_SET_OF) {
+                       assert(!TQ_FIRST(&($$->members))->constraints);
+                       TQ_FIRST(&($$->members))->constraints = $2;
+               } else {
+                       if($$->constraints) {
+                               assert(!$2);
+                               /* Check this : optManyConstraints is not used ?! */
+                               asn1p_constraint_free($2);
+                       } else {
+                               $$->constraints = $2;
+                       }
+               }
+       }
+       ;
+
+MaybeIndirectTaggedType:
+    optTag MaybeIndirectTypeDeclaration optManyConstraints {
+               $$ = $2;
+               $$->tag = $1;
+               /*
+                * Outer constraint for SEQUENCE OF and SET OF applies
+                * to the inner type.
+                */
+               if($$->expr_type == ASN_CONSTR_SEQUENCE_OF
+               || $$->expr_type == ASN_CONSTR_SET_OF) {
+                       assert(!TQ_FIRST(&($$->members))->constraints);
+                       TQ_FIRST(&($$->members))->constraints = $3;
+               } else {
+                       if($$->constraints) {
+                               assert(!$2);
+                               /* Check this : optManyConstraints is not used ?! */
+                               asn1p_constraint_free($3);
+                       } else {
+                               $$->constraints = $3;
+                       }
+               }
+       }
+    ;
+
+NSTD_IndirectMarker:
+       {
+               $$ = asn1p_as_pointer ? EM_INDIRECT : 0;
+               asn1p_as_pointer = 0;
+       }
+       ;
+
+MaybeIndirectTypeDeclaration:
+    NSTD_IndirectMarker TypeDeclaration {
+        $$ = $2;
+               $$->marker.flags |= $1;
+
+               if(($$->marker.flags & EM_INDIRECT)
+               && ($$->marker.flags & EM_OPTIONAL) != EM_OPTIONAL) {
+                       fprintf(stderr,
+                               "INFO: Directive <ASN1C:RepresentAsPointer> "
+                               "applied to %s at %s:%d\n",
+                               ASN_EXPR_TYPE2STR($$->expr_type)
+                                       ?  ASN_EXPR_TYPE2STR($$->expr_type)
+                                       : "member",
+                               ASN_FILENAME, $$->_lineno
+                       );
+               }
+    }
+    ;
+
+TypeDeclaration:
+    ConcreteTypeDeclaration
+    | DefinedType;
+
+ConcreteTypeDeclaration:
+       BuiltinType
+       | TOK_CHOICE '{' AlternativeTypeLists '}' {
+               $$ = $3;
+               assert($$->expr_type == A1TC_INVALID);
+               $$->expr_type = ASN_CONSTR_CHOICE;
+               $$->meta_type = AMT_TYPE;
+       }
+       | TOK_SEQUENCE '{' optComponentTypeLists '}' {
+               $$ = $3;
+               assert($$->expr_type == A1TC_INVALID);
+               $$->expr_type = ASN_CONSTR_SEQUENCE;
+               $$->meta_type = AMT_TYPE;
+       }
+       | TOK_SET '{' optComponentTypeLists '}' {
+               $$ = $3;
+               assert($$->expr_type == A1TC_INVALID);
+               $$->expr_type = ASN_CONSTR_SET;
+               $$->meta_type = AMT_TYPE;
+       }
+       | TOK_SEQUENCE optSizeOrConstraint TOK_OF optIdentifier optTag MaybeIndirectTypeDeclaration {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->constraints = $2;
+               $$->expr_type = ASN_CONSTR_SEQUENCE_OF;
+               $$->meta_type = AMT_TYPE;
+               $6->Identifier = $4;
+               $6->tag = $5;
+               asn1p_expr_add($$, $6);
+       }
+       | TOK_SET optSizeOrConstraint TOK_OF optIdentifier optTag MaybeIndirectTypeDeclaration {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->constraints = $2;
+               $$->expr_type = ASN_CONSTR_SET_OF;
+               $$->meta_type = AMT_TYPE;
+               $6->Identifier = $4;
+               $6->tag = $5;
+               asn1p_expr_add($$, $6);
+       }
+       | TOK_ANY                                       {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->expr_type = ASN_TYPE_ANY;
+               $$->meta_type = AMT_TYPE;
+       }
+       | TOK_ANY TOK_DEFINED TOK_BY Identifier         {
+               int ret;
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->reference = asn1p_ref_new(yylineno, currentModule);
+               ret = asn1p_ref_add_component($$->reference,
+                       $4, RLT_lowercase);
+               checkmem(ret == 0);
+               $$->expr_type = ASN_TYPE_ANY;
+               $$->meta_type = AMT_TYPE;
+               free($4);
+       }
+       | TOK_INSTANCE TOK_OF ComplexTypeReference {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->reference = $3;
+               $$->expr_type = A1TC_INSTANCE;
+               $$->meta_type = AMT_TYPE;
+       }
+       ;
+
+/*
+ * A type name consisting of several components.
+ * === EXAMPLE ===
+ * === EOF ===
+ */
+ComplexTypeReference:
+       TOK_typereference {
+               int ret;
+               $$ = asn1p_ref_new(yylineno, currentModule);
+               checkmem($$);
+               ret = asn1p_ref_add_component($$, $1, RLT_UNKNOWN);
+               checkmem(ret == 0);
+               free($1);
+       }
+       | TOK_capitalreference {
+               int ret;
+               $$ = asn1p_ref_new(yylineno, currentModule);
+               checkmem($$);
+               ret = asn1p_ref_add_component($$, $1, RLT_CAPITALS);
+               free($1);
+               checkmem(ret == 0);
+       }
+       | TOK_typereference '.' TypeRefName {
+               int ret;
+               $$ = asn1p_ref_new(yylineno, currentModule);
+               checkmem($$);
+               ret = asn1p_ref_add_component($$, $1, RLT_UNKNOWN);
+               checkmem(ret == 0);
+               ret = asn1p_ref_add_component($$, $3, RLT_UNKNOWN);
+               checkmem(ret == 0);
+               free($1);
+               free($3);
+       }
+       | TOK_capitalreference '.' TypeRefName {
+               int ret;
+               $$ = asn1p_ref_new(yylineno, currentModule);
+               checkmem($$);
+               ret = asn1p_ref_add_component($$, $1, RLT_UNKNOWN);
+               checkmem(ret == 0);
+               ret = asn1p_ref_add_component($$, $3, RLT_UNKNOWN);
+               checkmem(ret == 0);
+               free($1);
+               free($3);
+       }
+       | TOK_capitalreference '.' ComplexTypeReferenceAmpList {
+               int ret;
+               $$ = $3;
+               ret = asn1p_ref_add_component($$, $1, RLT_CAPITALS);
+               free($1);
+               checkmem(ret == 0);
+               /*
+                * Move the last element infront.
+                */
+               {
+                       struct asn1p_ref_component_s tmp_comp;
+                       tmp_comp = $$->components[$$->comp_count-1];
+                       memmove(&$$->components[1],
+                               &$$->components[0],
+                               sizeof($$->components[0])
+                               * ($$->comp_count - 1));
+                       $$->components[0] = tmp_comp;
+               }
+       }
+       ;
+
+ComplexTypeReferenceAmpList:
+       ComplexTypeReferenceElement {
+               int ret;
+               $$ = asn1p_ref_new(yylineno, currentModule);
+               checkmem($$);
+               ret = asn1p_ref_add_component($$, $1.name, $1.lex_type);
+               free($1.name);
+               checkmem(ret == 0);
+       }
+       | ComplexTypeReferenceAmpList '.' ComplexTypeReferenceElement {
+               int ret;
+               $$ = $1;
+               ret = asn1p_ref_add_component($$, $3.name, $3.lex_type);
+               free($3.name);
+               checkmem(ret == 0);
+       }
+       ;
+
+ComplexTypeReferenceElement:   PrimitiveFieldReference;
+
+PrimitiveFieldReference:
+       /* "&Type1" */
+       TOK_typefieldreference {
+               $$.lex_type = RLT_AmpUppercase;
+               $$.name = $1;
+       }
+       /* "&id" */
+       | TOK_valuefieldreference {
+               $$.lex_type = RLT_Amplowercase;
+               $$.name = $1;
+       }
+       ;
+
+
+FieldName:
+       /* "&Type1" */
+       TOK_typefieldreference {
+               $$ = asn1p_ref_new(yylineno, currentModule);
+               asn1p_ref_add_component($$, $1, RLT_AmpUppercase);
+               free($1);
+       }
+       | FieldName '.' TOK_typefieldreference {
+               $$ = $$;
+               asn1p_ref_add_component($$, $3, RLT_AmpUppercase);
+               free($3);
+       }
+       | FieldName '.' TOK_valuefieldreference {
+               $$ = $$;
+               asn1p_ref_add_component($$, $3, RLT_Amplowercase);
+               free($3);
+       }
+       ;
+
+DefinedObjectClass:
+       TOK_capitalreference {
+               $$ = asn1p_ref_new(yylineno, currentModule);
+               asn1p_ref_add_component($$, $1, RLT_CAPITALS);
+               free($1);
+       }
+/*
+       | TypeRefName '.' TOK_capitalreference {
+               $$ = asn1p_ref_new(yylineno, currentModule);
+               asn1p_ref_add_component($$, $1, RLT_AmpUppercase);
+               asn1p_ref_add_component($$, $3, RLT_CAPITALS);
+               free($1);
+               free($3);
+       }
+*/
+       ;
+
+
+/*
+ * === EXAMPLE ===
+ * value INTEGER ::= 1
+ * === EOF ===
+ */
+ValueAssignment:
+       Identifier Type TOK_PPEQ Value {
+               $$ = $2;
+               assert($$->Identifier == NULL);
+               $$->Identifier = $1;
+               $$->meta_type = AMT_VALUE;
+               $$->value = $4;
+       }
+       ;
+
+Value:
+       SimpleValue
+       | DefinedValue
+       | '{' { asn1p_lexer_hack_push_opaque_state(); } Opaque {
+               $$ = asn1p_value_frombuf($3.buf, $3.len, 0);
+               checkmem($$);
+               $$->type = ATV_UNPARSED;
+       }
+    ;
+
+SimpleValue:
+       TOK_NULL {
+               $$ = asn1p_value_fromint(0);
+               checkmem($$);
+               $$->type = ATV_NULL;
+       }
+       | TOK_FALSE {
+               $$ = asn1p_value_fromint(0);
+               checkmem($$);
+               $$->type = ATV_FALSE;
+       }
+       | TOK_TRUE {
+               $$ = asn1p_value_fromint(1);
+               checkmem($$);
+               $$->type = ATV_TRUE;
+       }
+       | SignedNumber
+       | RealValue
+       | RestrictedCharacterStringValue
+       | BitStringValue
+       ;
+
+DefinedValue:
+       IdentifierAsValue
+       | TypeRefName '.' Identifier {
+               asn1p_ref_t *ref;
+               int ret;
+               ref = asn1p_ref_new(yylineno, currentModule);
+               checkmem(ref);
+               ret = asn1p_ref_add_component(ref, $1, RLT_UNKNOWN);
+               checkmem(ret == 0);
+               ret = asn1p_ref_add_component(ref, $3, RLT_lowercase);
+               checkmem(ret == 0);
+               $$ = asn1p_value_fromref(ref, 0);
+               checkmem($$);
+               free($1);
+               free($3);
+       }
+       ;
+
+
+RestrictedCharacterStringValue:
+       TOK_cstring {
+               $$ = asn1p_value_frombuf($1.buf, $1.len, 0);
+               checkmem($$);
+       }
+       | TOK_tuple {
+               $$ = asn1p_value_fromint($1);
+               checkmem($$);
+               $$->type = ATV_TUPLE;
+       }
+       | TOK_quadruple {
+               $$ = asn1p_value_fromint($1);
+               checkmem($$);
+               $$->type = ATV_QUADRUPLE;
+       }
+       ;
+
+Opaque:
+    OpaqueFirstToken {
+               $$.len = $1.len + 1;
+               $$.buf = malloc(1 + $$.len + 1);
+               checkmem($$.buf);
+               $$.buf[0] = '{';
+               memcpy($$.buf + 1, $1.buf, $1.len);
+               $$.buf[$$.len] = '\0';
+               free($1.buf);
+    }
+       | Opaque TOK_opaque {
+               int newsize = $1.len + $2.len;
+               char *p = malloc(newsize + 1);
+               checkmem(p);
+               memcpy(p         , $1.buf, $1.len);
+               memcpy(p + $1.len, $2.buf, $2.len);
+               p[newsize] = '\0';
+               free($1.buf);
+               free($2.buf);
+               $$.buf = p;
+               $$.len = newsize;
+       }
+       ;
+
+OpaqueFirstToken:
+    TOK_opaque
+    | Identifier {
+        $$.len = strlen($1);
+        $$.buf = $1;
+    };
+
+BasicTypeId:
+       TOK_BOOLEAN { $$ = ASN_BASIC_BOOLEAN; }
+       | TOK_NULL { $$ = ASN_BASIC_NULL; }
+       | TOK_REAL { $$ = ASN_BASIC_REAL; }
+       | TOK_OCTET TOK_STRING { $$ = ASN_BASIC_OCTET_STRING; }
+       | TOK_OBJECT TOK_IDENTIFIER { $$ = ASN_BASIC_OBJECT_IDENTIFIER; }
+       | TOK_RELATIVE_OID { $$ = ASN_BASIC_RELATIVE_OID; }
+       | TOK_EXTERNAL { $$ = ASN_BASIC_EXTERNAL; }
+       | TOK_EMBEDDED TOK_PDV { $$ = ASN_BASIC_EMBEDDED_PDV; }
+       | TOK_CHARACTER TOK_STRING { $$ = ASN_BASIC_CHARACTER_STRING; }
+       | TOK_UTCTime { $$ = ASN_BASIC_UTCTime; }
+       | TOK_GeneralizedTime { $$ = ASN_BASIC_GeneralizedTime; }
+       | BasicString
+       | BasicTypeId_UniverationCompatible
+       ;
+
+/*
+ * A type identifier which may be used with "{ a(1), b(2) }" clause.
+ */
+BasicTypeId_UniverationCompatible:
+       TOK_INTEGER { $$ = ASN_BASIC_INTEGER; }
+       | TOK_ENUMERATED { $$ = ASN_BASIC_ENUMERATED; }
+       | TOK_BIT TOK_STRING { $$ = ASN_BASIC_BIT_STRING; }
+       ;
+
+BuiltinType:
+       BasicTypeId {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->expr_type = $1;
+               $$->meta_type = AMT_TYPE;
+       }
+    | TOK_INTEGER '{' NamedNumberList '}' {
+        $$ = $3;
+        $$->expr_type = ASN_BASIC_INTEGER;
+        $$->meta_type = AMT_TYPE;
+    }
+    | TOK_ENUMERATED '{' Enumerations '}' {
+        $$ = $3;
+        $$->expr_type = ASN_BASIC_ENUMERATED;
+        $$->meta_type = AMT_TYPE;
+    }
+    | TOK_BIT TOK_STRING '{' NamedBitList '}' {
+        $$ = $4;
+        $$->expr_type = ASN_BASIC_BIT_STRING;
+        $$->meta_type = AMT_TYPE;
+    }
+    | TOK_ExtValue_BIT_STRING '{' IdentifierList '}' {
+        $$ = $3;
+        $$->expr_type = ASN_BASIC_BIT_STRING;
+        $$->meta_type = AMT_TYPE;
+    }
+    | TOK_ExtValue_BIT_STRING '{' '}' {
+               $$ = NEW_EXPR();
+               checkmem($$);
+        $$->expr_type = ASN_BASIC_BIT_STRING;
+        $$->meta_type = AMT_TYPE;
+    }
+       ;
+
+BasicString:
+       TOK_BMPString { $$ = ASN_STRING_BMPString; }
+       | TOK_GeneralString {
+               $$ = ASN_STRING_GeneralString;
+               fprintf(stderr, "WARNING: GeneralString is not fully supported\n");
+       }
+       | TOK_GraphicString {
+               $$ = ASN_STRING_GraphicString;
+               fprintf(stderr, "WARNING: GraphicString is not fully supported\n");
+       }
+       | TOK_IA5String { $$ = ASN_STRING_IA5String; }
+       | TOK_ISO646String { $$ = ASN_STRING_ISO646String; }
+       | TOK_NumericString { $$ = ASN_STRING_NumericString; }
+       | TOK_PrintableString { $$ = ASN_STRING_PrintableString; }
+       | TOK_T61String {
+               $$ = ASN_STRING_T61String;
+               fprintf(stderr, "WARNING: T61String is not fully supported\n");
+       }
+       | TOK_TeletexString { $$ = ASN_STRING_TeletexString; }
+       | TOK_UniversalString { $$ = ASN_STRING_UniversalString; }
+       | TOK_UTF8String { $$ = ASN_STRING_UTF8String; }
+       | TOK_VideotexString {
+               $$ = ASN_STRING_VideotexString;
+               fprintf(stderr, "WARNING: VideotexString is not fully supported\n");
+       }
+       | TOK_VisibleString { $$ = ASN_STRING_VisibleString; }
+       | TOK_ObjectDescriptor { $$ = ASN_STRING_ObjectDescriptor; }
+       ;
+
+
+/*
+ * Data type constraints.
+ */
+UnionMark:             '|' | TOK_UNION;
+IntersectionMark:      '^' | TOK_INTERSECTION;
+
+/* empty | Constraint */
+optConstraint:
+       { $$ = 0; }
+       | Constraint;
+
+/* empty | Constraint... */
+optManyConstraints:
+       { $$ = 0; }
+       | ManyConstraints;
+
+/* empty | Constraint | SIZE(...) */
+optSizeOrConstraint:
+       { $$ = 0; }
+       | Constraint
+       | SizeConstraint
+       ;
+
+Constraint:
+    '(' ConstraintSpec ')' {
+               CONSTRAINT_INSERT($$, ACT_CA_SET, $2, 0);
+    }
+    ;
+
+ManyConstraints:
+    Constraint
+       | ManyConstraints Constraint {
+        if($2->type == ACT_CA_SET && $2->el_count == 1) {
+            CONSTRAINT_INSERT($$, ACT_CA_SET, $1, $2->elements[0]);
+        } else {
+            CONSTRAINT_INSERT($$, ACT_CA_SET, $1, $2);
+        }
+       }
+       ;
+
+ConstraintSpec: SubtypeConstraint | GeneralConstraint;
+
+SubtypeConstraint: ElementSetSpecs;
+
+ElementSetSpecs:
+       TOK_ThreeDots  {
+               $$ = asn1p_constraint_new(yylineno, currentModule);
+               $$->type = ACT_EL_EXT;
+       }
+   | ElementSetSpec
+   | ElementSetSpec ',' TOK_ThreeDots {
+       asn1p_constraint_t *ct;
+       ct = asn1p_constraint_new(yylineno, currentModule);
+       ct->type = ACT_EL_EXT;
+       CONSTRAINT_INSERT($$, ACT_CA_CSV, $1, ct);
+   }
+   | ElementSetSpec ',' TOK_ThreeDots ',' ElementSetSpec {
+       asn1p_constraint_t *ct;
+       ct = asn1p_constraint_new(yylineno, currentModule);
+       ct->type = ACT_EL_EXT;
+       CONSTRAINT_INSERT($$, ACT_CA_CSV, $1, ct);
+       ct = $$;
+       CONSTRAINT_INSERT($$, ACT_CA_CSV, ct, $5);
+   }
+;
+
+ElementSetSpec:
+       Unions
+       | TOK_ALL TOK_EXCEPT Elements {
+               CONSTRAINT_INSERT($$, ACT_CA_AEX, $3, 0);
+       }
+       ;
+
+Unions:
+       Intersections
+       | Unions UnionMark Intersections {
+               CONSTRAINT_INSERT($$, ACT_CA_UNI, $1, $3);
+       }
+       ;
+
+Intersections:
+       IntersectionElements
+       |  Intersections IntersectionMark IntersectionElements {
+               CONSTRAINT_INSERT($$, ACT_CA_INT, $1, $3);
+       }
+       ;
+
+
+IntersectionElements:
+       Elements
+       | Elements TOK_EXCEPT Elements {
+               CONSTRAINT_INSERT($$, ACT_CA_EXC, $1, $3);
+       }
+       ;
+
+Elements:
+    SubtypeElements
+    | '(' ElementSetSpec ')' {
+        int ret;
+        $$ = asn1p_constraint_new(yylineno, currentModule);
+        checkmem($$);
+        $$->type = ACT_CA_SET;
+        ret = asn1p_constraint_insert($$, $2);
+        checkmem(ret == 0);
+    }
+    ;
+
+SubtypeElements:
+       SingleValue {
+               $$ = asn1p_constraint_new(yylineno, currentModule);
+               checkmem($$);
+               $$->type = ACT_EL_VALUE;
+               $$->value = $1;
+       }
+       | ContainedSubtype {
+               $$ = asn1p_constraint_new(yylineno, currentModule);
+               checkmem($$);
+               $$->type = ACT_EL_TYPE;
+               $$->containedSubtype = $1;
+       }
+    | PermittedAlphabet /* FROM ... */
+    | SizeConstraint    /* SIZE ... */
+    /* | TypeConstraint is via ContainedSubtype */
+       | InnerTypeConstraints  /* WITH COMPONENT[S] ... */
+       | PatternConstraint     /* PATTERN ... */
+       | ValueRange
+       ;
+
+
+PermittedAlphabet:
+       TOK_FROM Constraint {
+               CONSTRAINT_INSERT($$, ACT_CT_FROM, $2, 0);
+       };
+
+SizeConstraint:
+       TOK_SIZE Constraint {
+               CONSTRAINT_INSERT($$, ACT_CT_SIZE, $2, 0);
+       };
+
+PatternConstraint:
+       TOK_PATTERN TOK_cstring {
+               $$ = asn1p_constraint_new(yylineno, currentModule);
+               $$->type = ACT_CT_PATTERN;
+               $$->value = asn1p_value_frombuf($2.buf, $2.len, 0);
+       }
+       | TOK_PATTERN Identifier {
+               asn1p_ref_t *ref;
+               $$ = asn1p_constraint_new(yylineno, currentModule);
+               $$->type = ACT_CT_PATTERN;
+               ref = asn1p_ref_new(yylineno, currentModule);
+               asn1p_ref_add_component(ref, $2, RLT_lowercase);
+               $$->value = asn1p_value_fromref(ref, 0);
+               free($2);
+       }
+       ;
+
+ValueRange:
+    LowerEndValue ConstraintRangeSpec UpperEndValue {
+               $$ = asn1p_constraint_new(yylineno, currentModule);
+               checkmem($$);
+               $$->type = $2;
+               $$->range_start = $1;
+               $$->range_stop = $3;
+    };
+
+LowerEndValue:
+    SingleValue
+    | TOK_MIN {
+               $$ = asn1p_value_fromint(-123);
+               $$->type = ATV_MIN;
+    };
+
+UpperEndValue:
+    SingleValue
+    | TOK_MAX {
+               $$ = asn1p_value_fromint(321);
+               $$->type = ATV_MAX;
+    };
+
+SingleValue: Value;
+
+BitStringValue:
+       TOK_bstring {
+               $$ = _convert_bitstring2binary($1, 'B');
+               checkmem($$);
+               free($1);
+       }
+       | TOK_hstring {
+               $$ = _convert_bitstring2binary($1, 'H');
+               checkmem($$);
+               free($1);
+       }
+       ;
+
+ContainedSubtype:
+    TOK_INCLUDES Type {
+               $$ = asn1p_value_fromtype($2);
+               checkmem($$);
+               asn1p_expr_free($2);
+    }
+    /* Can't put Type here because of conflicts. Simplified subset */
+    | DefinedUntaggedType {
+               $$ = asn1p_value_fromtype($1);
+               checkmem($$);
+               asn1p_expr_free($1);
+    }
+       ;
+
+/*
+ * X.680 08/2015
+ * #51.8.5
+ */
+InnerTypeConstraints:
+       TOK_WITH TOK_COMPONENT SingleTypeConstraint {
+               CONSTRAINT_INSERT($$, ACT_CT_WCOMP, $3, 0);
+       }
+       | TOK_WITH TOK_COMPONENTS MultipleTypeConstraints {
+        assert($3->type == ACT_CA_CSV);
+        $3->type = ACT_CT_WCOMPS;
+        $$ = $3;
+       }
+       ;
+SingleTypeConstraint: Constraint;
+MultipleTypeConstraints: FullSpecification | PartialSpecification;
+FullSpecification: '{' TypeConstraints '}' { $$ = $2; };
+PartialSpecification:
+    '{' TOK_ThreeDots ',' TypeConstraints '}' {
+        assert($4->type == ACT_CA_CSV);
+               $$ = asn1p_constraint_new(yylineno, currentModule);
+        $$->type = ACT_CA_CSV;
+               asn1p_constraint_t *ct = asn1p_constraint_new(yylineno, currentModule);
+               checkmem($$);
+               ct->type = ACT_EL_EXT;
+        asn1p_constraint_insert($$, ct);
+        for(unsigned i = 0; i < $4->el_count; i++) {
+            asn1p_constraint_insert($$, $4->elements[i]);
+        }
+    };
+TypeConstraints:
+    NamedConstraint {
+        $$ = asn1p_constraint_new(yylineno, currentModule);
+        $$->type = ACT_CA_CSV;
+        asn1p_constraint_insert($$, $1);
+    }
+    | TypeConstraints ',' NamedConstraint {
+        $$ = $1;
+        asn1p_constraint_insert($$, $3);
+       }
+       ;
+NamedConstraint:
+       IdentifierAsValue optConstraint optPresenceConstraint {
+        $$ = asn1p_constraint_new(yylineno, currentModule);
+        checkmem($$);
+        $$->type = ACT_EL_VALUE;
+        $$->value = $1;
+        if($2) asn1p_constraint_insert($$, $2);
+        $$->presence = $3;
+    }
+    ;
+
+/*
+ * presence constraint for NamedConstraint
+ */
+optPresenceConstraint:
+       { $$ = ACPRES_DEFAULT; }
+       | PresenceConstraint { $$ = $1; }
+       ;
+
+PresenceConstraint:
+       TOK_PRESENT {
+               $$ = ACPRES_PRESENT;
+       }
+       | TOK_ABSENT {
+               $$ = ACPRES_ABSENT;
+       }
+       | TOK_OPTIONAL {
+               $$ = ACPRES_OPTIONAL;
+       }
+       ;
+
+
+/* X.682 */
+GeneralConstraint:
+       UserDefinedConstraint
+       | TableConstraint
+       | ContentsConstraint
+       ;
+
+UserDefinedConstraint:
+       TOK_CONSTRAINED TOK_BY '{'
+               { asn1p_lexer_hack_push_opaque_state(); } Opaque /* '}' */ {
+               $$ = asn1p_constraint_new(yylineno, currentModule);
+               checkmem($$);
+               $$->type = ACT_CT_CTDBY;
+               $$->value = asn1p_value_frombuf($5.buf, $5.len, 0);
+               checkmem($$->value);
+               $$->value->type = ATV_UNPARSED;
+       }
+       ;
+
+ContentsConstraint:
+       TOK_CONTAINING Type {
+               $$ = asn1p_constraint_new(yylineno, currentModule);
+               $$->type = ACT_CT_CTNG;
+               $$->value = asn1p_value_fromtype($2);
+               asn1p_expr_free($2);
+       }
+       ;
+
+ConstraintRangeSpec:
+       TOK_TwoDots             { $$ = ACT_EL_RANGE; }
+       | TOK_TwoDots '<'       { $$ = ACT_EL_RLRANGE; }
+       | '<' TOK_TwoDots       { $$ = ACT_EL_LLRANGE; }
+       | '<' TOK_TwoDots '<'   { $$ = ACT_EL_ULRANGE; }
+       ;
+TableConstraint:
+       SimpleTableConstraint {
+               $$ = $1;
+       }
+       | ComponentRelationConstraint {
+               $$ = $1;
+       }
+       ;
+
+/*
+ * "{ExtensionSet}"
+ */
+SimpleTableConstraint:
+       '{' TypeRefName '}' {
+               asn1p_ref_t *ref = asn1p_ref_new(yylineno, currentModule);
+               asn1p_constraint_t *ct;
+               int ret;
+               ret = asn1p_ref_add_component(ref, $2, 0);
+               checkmem(ret == 0);
+               ct = asn1p_constraint_new(yylineno, currentModule);
+               checkmem($$);
+               ct->type = ACT_EL_VALUE;
+               ct->value = asn1p_value_fromref(ref, 0);
+               CONSTRAINT_INSERT($$, ACT_CA_CRC, ct, 0);
+               free($2);
+       }
+       ;
+
+ComponentRelationConstraint:
+       SimpleTableConstraint '{' AtNotationList '}' {
+               CONSTRAINT_INSERT($$, ACT_CA_CRC, $1, $3);
+       }
+       ;
+
+AtNotationList:
+       AtNotationElement {
+               $$ = asn1p_constraint_new(yylineno, currentModule);
+               checkmem($$);
+               $$->type = ACT_EL_VALUE;
+               $$->value = asn1p_value_fromref($1, 0);
+       }
+       | AtNotationList ',' AtNotationElement {
+               asn1p_constraint_t *ct;
+               ct = asn1p_constraint_new(yylineno, currentModule);
+               checkmem(ct);
+               ct->type = ACT_EL_VALUE;
+               ct->value = asn1p_value_fromref($3, 0);
+               CONSTRAINT_INSERT($$, ACT_CA_CSV, $1, ct);
+       }
+       ;
+
+/*
+ * @blah
+ */
+AtNotationElement:
+       '@' ComponentIdList {
+               char *p = malloc(strlen($2) + 2);
+               int ret;
+               *p = '@';
+               strcpy(p + 1, $2);
+               $$ = asn1p_ref_new(yylineno, currentModule);
+               ret = asn1p_ref_add_component($$, p, 0);
+               checkmem(ret == 0);
+               free(p);
+               free($2);
+       }
+       | '@' '.' ComponentIdList {
+               char *p = malloc(strlen($3) + 3);
+               int ret;
+               p[0] = '@';
+               p[1] = '.';
+               strcpy(p + 2, $3);
+               $$ = asn1p_ref_new(yylineno, currentModule);
+               ret = asn1p_ref_add_component($$, p, 0);
+               checkmem(ret == 0);
+               free(p);
+               free($3);
+       }
+       ;
+
+/* identifier "." ... */
+ComponentIdList:
+       Identifier {
+               $$ = $1;
+       }
+       | ComponentIdList '.' Identifier {
+               int l1 = strlen($1);
+               int l3 = strlen($3);
+               $$ = malloc(l1 + 1 + l3 + 1);
+               memcpy($$, $1, l1);
+               $$[l1] = '.';
+               memcpy($$ + l1 + 1, $3, l3);
+               $$[l1 + 1 + l3] = '\0';
+               free($1);
+               free($3);
+       }
+       ;
+
+
+
+/*
+ * MARKERS
+ */
+
+optMarker:
+       {
+               $$.flags = EM_NOMARK;
+               $$.default_value = 0;
+       }
+       | Marker { $$ = $1; }
+       ;
+
+Marker:
+       TOK_OPTIONAL {
+               $$.flags = EM_OPTIONAL | EM_INDIRECT;
+               $$.default_value = 0;
+       }
+       | TOK_DEFAULT Value {
+               $$.flags = EM_DEFAULT;
+               $$.default_value = $2;
+       }
+       ;
+
+IdentifierList:
+    IdentifierElement {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               asn1p_expr_add($$, $1);
+    }
+    | IdentifierList ',' IdentifierElement {
+               $$ = $1;
+               asn1p_expr_add($$, $3);
+    };
+
+IdentifierElement:
+    Identifier {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->expr_type = A1TC_UNIVERVAL;
+               $$->meta_type = AMT_VALUE;
+               $$->Identifier = $1;
+    }
+
+NamedNumberList:
+       NamedNumber {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               asn1p_expr_add($$, $1);
+       }
+       | NamedNumberList ',' NamedNumber {
+               $$ = $1;
+               asn1p_expr_add($$, $3);
+       }
+       ;
+
+NamedNumber:
+       Identifier '(' SignedNumber ')' {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->expr_type = A1TC_UNIVERVAL;
+               $$->meta_type = AMT_VALUE;
+               $$->Identifier = $1;
+               $$->value = $3;
+       }
+       | Identifier '(' DefinedValue ')' {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->expr_type = A1TC_UNIVERVAL;
+               $$->meta_type = AMT_VALUE;
+               $$->Identifier = $1;
+               $$->value = $3;
+       };
+
+NamedBitList:
+       NamedBit {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               asn1p_expr_add($$, $1);
+       }
+       | NamedBitList ',' NamedBit {
+               $$ = $1;
+               asn1p_expr_add($$, $3);
+       }
+       ;
+
+NamedBit:
+       Identifier '(' TOK_number ')' {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->expr_type = A1TC_UNIVERVAL;
+               $$->meta_type = AMT_VALUE;
+               $$->Identifier = $1;
+               $$->value = asn1p_value_fromint($3);
+       }
+       | Identifier '(' DefinedValue ')' {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->expr_type = A1TC_UNIVERVAL;
+               $$->meta_type = AMT_VALUE;
+               $$->Identifier = $1;
+               $$->value = $3;
+       };
+
+Enumerations:
+    UniverationList {
+               $$ = $1;
+        asn1p_expr_t *first_memb = TQ_FIRST(&($$->members));
+        if(first_memb) {
+            if(first_memb->expr_type == A1TC_EXTENSIBLE) {
+                return yyerror(
+                    "The ENUMERATION cannot start with extension (...).");
+            }
+        } else {
+            return yyerror(
+                "The ENUMERATION list cannot be empty.");
+        }
+    }
+
+UniverationList:
+       UniverationElement {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               asn1p_expr_add($$, $1);
+       }
+       | UniverationList ',' UniverationElement {
+               $$ = $1;
+               asn1p_expr_add($$, $3);
+       }
+       ;
+
+UniverationElement:
+       Identifier {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->expr_type = A1TC_UNIVERVAL;
+               $$->meta_type = AMT_VALUE;
+               $$->Identifier = $1;
+       }
+       | Identifier '(' SignedNumber ')' {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->expr_type = A1TC_UNIVERVAL;
+               $$->meta_type = AMT_VALUE;
+               $$->Identifier = $1;
+               $$->value = $3;
+       }
+       | Identifier '(' DefinedValue ')' {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->expr_type = A1TC_UNIVERVAL;
+               $$->meta_type = AMT_VALUE;
+               $$->Identifier = $1;
+               $$->value = $3;
+       }
+       | SignedNumber {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->expr_type = A1TC_UNIVERVAL;
+               $$->meta_type = AMT_VALUE;
+               $$->value = $1;
+       }
+       | TOK_ThreeDots {
+               $$ = NEW_EXPR();
+               checkmem($$);
+               $$->Identifier = strdup("...");
+               checkmem($$->Identifier);
+               $$->expr_type = A1TC_EXTENSIBLE;
+               $$->meta_type = AMT_VALUE;
+       }
+       ;
+
+SignedNumber:
+       TOK_number {
+               $$ = asn1p_value_fromint($1);
+               checkmem($$);
+       }
+       | TOK_number_negative {
+               $$ = asn1p_value_fromint($1);
+               checkmem($$);
+       }
+       ;
+
+RealValue:
+       TOK_realnumber {
+               $$ = asn1p_value_fromdouble($1);
+               checkmem($$);
+       }
+       ;
+
+/*
+ * SEQUENCE definition.
+ * === EXAMPLE ===
+ * Struct1 ::= SEQUENCE {
+ *     memb1 Struct2,
+ *     memb2 SEQUENCE OF {
+ *             memb2-1 Struct 3
+ *     }
+ * }
+ * === EOF ===
+ */
+
+
+
+/*
+ * SET definition.
+ * === EXAMPLE ===
+ * Person ::= SET {
+ *     name [0] PrintableString (SIZE(1..20)),
+ *     country [1] PrintableString (SIZE(1..20)) DEFAULT default-country,
+ * }
+ * === EOF ===
+ */
+
+optTag:
+       { memset(&$$, 0, sizeof($$)); }
+       | Tag { $$ = $1; }
+       ;
+
+Tag:
+       TagTypeValue TagPlicit {
+               $$ = $1;
+               $$.tag_mode = $2.tag_mode;
+       }
+       ;
+
+TagTypeValue:
+       '[' TagClass TOK_number ']' {
+               $$ = $2;
+               $$.tag_value = $3;
+       };
+
+TagClass:
+       { $$.tag_class = TC_CONTEXT_SPECIFIC; }
+       | TOK_UNIVERSAL { $$.tag_class = TC_UNIVERSAL; }
+       | TOK_APPLICATION { $$.tag_class = TC_APPLICATION; }
+       | TOK_PRIVATE { $$.tag_class = TC_PRIVATE; }
+       ;
+
+TagPlicit:
+       { $$.tag_mode = TM_DEFAULT; }
+       | TOK_IMPLICIT { $$.tag_mode = TM_IMPLICIT; }
+       | TOK_EXPLICIT { $$.tag_mode = TM_EXPLICIT; }
+       ;
+
+TypeRefName:
+       TOK_typereference {
+               checkmem($1);
+               $$ = $1;
+       }
+       | TOK_capitalreference {
+               checkmem($1);
+               $$ = $1;
+       }
+       ;
+
+
+optIdentifier:
+       { $$ = 0; }
+       | Identifier {
+               $$ = $1;
+       }
+       ;
+
+Identifier:
+       TOK_identifier {
+               checkmem($1);
+               $$ = $1;
+       }
+       ;
+
+IdentifierAsReference:
+    Identifier {
+               $$ = asn1p_ref_new(yylineno, currentModule);
+               asn1p_ref_add_component($$, $1, RLT_lowercase);
+               free($1);
+    };
+
+IdentifierAsValue:
+    IdentifierAsReference {
+               $$ = asn1p_value_fromref($1, 0);
+    };
+
+%%
+
+
+/*
+ * Convert Xstring ('0101'B or '5'H) to the binary vector.
+ */
+static asn1p_value_t *
+_convert_bitstring2binary(char *str, int base) {
+       asn1p_value_t *val;
+       int slen;
+       int memlen;
+       int baselen;
+       int bits;
+       uint8_t *binary_vector;
+       uint8_t *bv_ptr;
+       uint8_t cur_val;
+
+       assert(str);
+       assert(str[0] == '\'');
+
+       switch(base) {
+       case 'B':
+               baselen = 1;
+               break;
+       case 'H':
+               baselen = 4;
+               break;
+       default:
+               assert(base == 'B' || base == 'H');
+               errno = EINVAL;
+               return NULL;
+       }
+
+       slen = strlen(str);
+       assert(str[slen - 1] == base);
+       assert(str[slen - 2] == '\'');
+
+       memlen = slen / (8 / baselen);  /* Conservative estimate */
+
+       bv_ptr = binary_vector = malloc(memlen + 1);
+       if(bv_ptr == NULL)
+               /* ENOMEM */
+               return NULL;
+
+       cur_val = 0;
+       bits = 0;
+       while(*(++str) != '\'') {
+               switch(baselen) {
+               case 1:
+                       switch(*str) {
+                       case '1':
+                               cur_val |= 1 << (7 - (bits % 8));
+                       case '0':
+                               break;
+                       default:
+                               assert(!"_y UNREACH1");
+                       case ' ': case '\r': case '\n':
+                               continue;
+                       }
+                       break;
+               case 4:
+                       switch(*str) {
+                       case '0': case '1': case '2': case '3': case '4':
+                       case '5': case '6': case '7': case '8': case '9':
+                               cur_val |= (*str - '0') << (4 - (bits % 8));
+                               break;
+                       case 'A': case 'B': case 'C':
+                       case 'D': case 'E': case 'F':
+                               cur_val |= ((*str - 'A') + 10)
+                                       << (4 - (bits % 8));
+                               break;
+                       default:
+                               assert(!"_y UNREACH2");
+                       case ' ': case '\r': case '\n':
+                               continue;
+                       }
+                       break;
+               }
+
+               bits += baselen;
+               if((bits % 8) == 0) {
+                       *bv_ptr++ = cur_val;
+                       cur_val = 0;
+               }
+       }
+
+       *bv_ptr = cur_val;
+       assert((bv_ptr - binary_vector) <= memlen);
+
+       val = asn1p_value_frombits(binary_vector, bits, 0);
+       if(val == NULL) {
+               free(binary_vector);
+       }
+
+       return val;
+}
+
+/*
+ * For unnamed types (used in old X.208 compliant modules)
+ * generate some sort of interim names, to not to force human being to fix
+ * the specification's compliance to modern ASN.1 standards.
+ */
+static void
+_fixup_anonymous_identifier(asn1p_expr_t *expr) {
+       char *p;
+       assert(expr->Identifier == 0);
+
+       /*
+        * Try to figure out the type name
+        * without going too much into details
+        */
+       expr->Identifier = ASN_EXPR_TYPE2STR(expr->expr_type);
+       if(expr->reference && expr->reference->comp_count > 0)
+               expr->Identifier = expr->reference->components[0].name;
+
+       fprintf(stderr,
+               "WARNING: Line %d: expected lower-case member identifier, "
+               "found an unnamed %s.\n"
+               "WARNING: Obsolete X.208 syntax detected, "
+               "please give the member a name.\n",
+               yylineno, expr->Identifier ? expr->Identifier : "type");
+
+       if(!expr->Identifier)
+               expr->Identifier = "unnamed";
+       expr->Identifier = strdup(expr->Identifier);
+       assert(expr->Identifier);
+       /* Make a lowercase identifier from the type name */
+       for(p = expr->Identifier; *p; p++) {
+               switch(*p) {
+               case 'A' ... 'Z': *p += 32; break;
+               case ' ': *p = '_'; break;
+               case '-': *p = '_'; break;
+               }
+       }
+       fprintf(stderr, "NOTE: Assigning temporary identifier \"%s\". "
+                       "Name clash may occur later.\n",
+               expr->Identifier);
+}
+
+static int
+yyerror(const char *msg) {
+       extern char *asn1p_text;
+       fprintf(stderr,
+               "ASN.1 grammar parse error "
+               "near %s:%d (token \"%s\"): %s\n",
+               ASN_FILENAME, yylineno, asn1p_text, msg);
+       return -1;
+}
+