Initial revision

diff --git a/libasn1parser/asn1p_y.y b/libasn1parser/asn1p_y.y
new file mode 100644
index 0000000..822a8ef
--- /dev/null
+++ b/libasn1parser/asn1p_y.y
@@ -0,0 +1,1982 @@
+%{
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "asn1parser.h"
+
+#define YYPARSE_PARAM	param
+#define YYERROR_VERBOSE
+
+int yylex(void);
+int yyerror(const char *msg);
+void asn1p_lexer_hack_push_opaque_state(void);
+void asn1p_lexer_hack_enable_with_syntax(void);
+#define	yylineno	asn1p_lineno
+extern int asn1p_lineno;
+
+
+static asn1p_value_t *
+	_convert_bitstring2binary(char *str, int base);
+
+#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);	\
+			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)
+
+%}
+
+
+/*
+ * 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 */
+	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 */
+	enum asn1p_expr_marker_e a_marker;	/* OPTIONAL/DEFAULT */
+	enum asn1p_constr_pres_e a_pres;	/* PRESENT/ABSENT/OPTIONAL */
+	asn1_integer_t		 a_int;
+	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	<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
+%token	<a_int>		TOK_number
+%token	<a_int>		TOK_number_negative
+%token	<tv_str>	TOK_typereference
+%token	<tv_str>	TOK_objectclassreference	/* "CLASS1" */
+%token	<tv_str>	TOK_typefieldreference		/* "&Pork" */
+%token	<tv_str>	TOK_valuefieldreference		/* "&id" */
+
+/*
+ * 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_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_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
+
+%left			'|' TOK_UNION
+%left			'^' TOK_INTERSECTION
+%left			TOK_EXCEPT
+
+/* Misc tags */
+%token			TOK_TwoDots		/* .. */
+%token			TOK_ThreeDots		/* ... */
+%token	<a_tag>		TOK_tag			/* [0] */
+
+
+/*
+ * Types defined herein.
+ */
+%type	<a_grammar>		ModuleList
+%type	<a_module>		ModuleSpecification
+%type	<a_module>		ModuleSpecificationBody
+%type	<a_module>		ModuleSpecificationElement
+%type	<a_module>		optModuleSpecificationBody	/* Optional */
+%type	<a_module_flags>	optModuleSpecificationFlags
+%type	<a_module_flags>	ModuleSpecificationFlags	/* Set of FL */
+%type	<a_module_flags>	ModuleSpecificationFlag		/* Single FL */
+%type	<a_module>		ImportsDefinition
+%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>		DataTypeMember
+%type	<a_expr>		ExtensionAndException
+%type	<a_expr>		TypeDeclaration
+%type	<a_ref>			ComplexTypeReference
+%type	<a_ref>			ComplexTypeReferenceAmpList
+%type	<a_refcomp>		ComplexTypeReferenceElement
+%type	<a_refcomp>		ClassFieldIdentifier
+%type	<a_refcomp>		ClassFieldName
+%type	<a_expr>		ClassFieldList
+%type	<a_expr>		ClassField
+%type	<a_expr>		ClassDeclaration
+%type	<a_expr>		ConstrainedTypeDeclaration
+%type	<a_expr>		DataTypeReference	/* Type1 ::= Type2 */
+%type	<a_expr>		DefinedTypeRef
+%type	<a_expr>		ValueSetDefinition  /* Val INTEGER ::= {1|2} */
+%type	<a_expr>		ValueDefinition		/* val INTEGER ::= 1*/
+%type	<a_value>		optValueSetBody
+%type	<a_value>		InlineOrDefinedValue
+%type	<a_value>		DefinedValue
+%type	<a_value>		SignedNumber
+%type	<a_expr>		ConstructedType
+%type	<a_expr>		ConstructedDataTypeDefinition
+//%type	<a_expr>		optUniverationDefinition
+%type	<a_expr>		UniverationDefinition
+%type	<a_expr>		UniverationList
+%type	<a_expr>		UniverationElement
+%type	<tv_str>		TypeRefName
+%type	<tv_str>		ObjectClassReference
+%type	<tv_nametag>		TaggedIdentifier
+%type	<tv_str>		Identifier
+%type	<a_parg>		ParameterArgumentName
+%type	<a_plist>		ParameterArgumentList
+%type	<a_expr>		ActualParameter
+%type	<a_expr>		ActualParameterList
+%type	<a_oid>			ObjectIdentifier	/* OID */
+%type	<a_oid>			optObjectIdentifier	/* Optional OID */
+%type	<a_oid>			ObjectIdentifierBody
+%type	<a_oid_arc>		ObjectIdentifierElement
+%type	<a_expr>		BasicType
+%type	<a_type>		BasicTypeId
+%type	<a_type>		BasicTypeId_UniverationCompatible
+%type	<a_type>		BasicString
+%type	<tv_opaque>		Opaque
+//%type	<tv_opaque>		StringValue
+%type	<a_tag>			Tag		/* [UNIVERSAL 0] IMPLICIT */
+%type	<a_tag>			optTag		/* [UNIVERSAL 0] IMPLICIT */
+%type	<a_constr>		optConstraints
+%type	<a_constr>		Constraints
+%type	<a_constr>		SingleConstraint	/* (SIZE(2)) */
+%type	<a_constr>		ConstraintElementSet	/* 1..2,...,3 */
+%type	<a_constr>		ConstraintSubtypeElement /* 1..2 */
+%type	<a_constr>		ConstraintElementIntersection
+%type	<a_constr>		ConstraintElementException
+%type	<a_constr>		ConstraintElementUnion
+%type	<a_constr>		ConstraintElement
+%type	<a_constr>		SimpleTableConstraint
+%type	<a_constr>		TableConstraint
+%type	<a_constr>		WithComponents
+%type	<a_constr>		WithComponentsList
+%type	<a_constr>		WithComponentsElement
+%type	<a_constr>		ComponentRelationConstraint
+%type	<a_constr>		AtNotationList
+%type	<a_ref>			AtNotationElement
+%type	<a_value>		ConstraintValue
+%type	<a_ctype>		ConstraintSpec
+%type	<a_ctype>		ConstraintRangeSpec
+%type	<a_wsynt>		optWithSyntax
+%type	<a_wsynt>		WithSyntax
+%type	<a_wsynt>		WithSyntaxFormat
+%type	<a_wchunk>		WithSyntaxFormatToken
+%type	<a_marker>		optMarker Marker
+%type	<a_int>			optUnique
+%type	<a_pres>		optPresenceConstraint PresenceConstraint
+%type	<tv_str>		ComponentIdList
+
+
+%%
+
+
+ParsedGrammar:
+	ModuleList {
+		*(void **)param = $1;
+	}
+	;
+
+ModuleList:
+	ModuleSpecification {
+		$$ = asn1p_new();
+		checkmem($$);
+		TQ_ADD(&($$->modules), $1, mod_next);
+	}
+	| ModuleList ModuleSpecification {
+		$$ = $1;
+		TQ_ADD(&($$->modules), $2, mod_next);
+	}
+	;
+
+/*
+ * ASN module definition.
+ * === EXAMPLE ===
+ * MySyntax DEFINITIONS AUTOMATIC TAGS ::=
+ * BEGIN
+ * ...
+ * END 
+ * === EOF ===
+ */
+
+ModuleSpecification:
+	TypeRefName optObjectIdentifier TOK_DEFINITIONS
+		optModuleSpecificationFlags
+		TOK_PPEQ TOK_BEGIN
+		optModuleSpecificationBody
+		TOK_END {
+
+		if($7) {
+			$$ = $7;
+		} else {
+			/* There's a chance that a module is just plain empty */
+			$$ = asn1p_module_new();
+		}
+		checkmem($$);
+
+		$$->Identifier = $1;
+		$$->module_oid = $2;
+		$$->module_flags = $4;
+	}
+	;
+
+/*
+ * 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.
+ */
+optModuleSpecificationFlags:
+	{ $$ = MSF_NOFLAGS; }
+	| ModuleSpecificationFlags {
+		$$ = $1;
+	}
+	;
+
+/*
+ * Module flags.
+ */
+ModuleSpecificationFlags:
+	ModuleSpecificationFlag {
+		$$ = $1;
+	}
+	| ModuleSpecificationFlags ModuleSpecificationFlag {
+		$$ = $1 | $2;
+	}
+	;
+
+/*
+ * Single module flag.
+ */
+ModuleSpecificationFlag:
+	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;
+	}
+	;
+
+/*
+ * Optional module body.
+ */
+optModuleSpecificationBody:
+	{ $$ = 0; }
+	| ModuleSpecificationBody {
+		assert($1);
+		$$ = $1;
+	}
+	;
+
+/*
+ * ASN.1 Module body.
+ */
+ModuleSpecificationBody:
+	ModuleSpecificationElement {
+		$$ = $1;
+	}
+	| ModuleSpecificationBody ModuleSpecificationElement {
+		$$ = $1;
+
+#ifdef	MY_IMPORT
+#error	MY_IMPORT DEFINED ELSEWHERE!
+#endif
+#define	MY_IMPORT(foo,field)	do {				\
+		if(TQ_FIRST(&($2->foo))) {			\
+			TQ_ADD(&($$->foo),			\
+				TQ_REMOVE(&($2->foo), field),	\
+				field);				\
+			assert(TQ_FIRST(&($2->foo)) == 0);	\
+		} } while(0)
+
+		MY_IMPORT(imports, xp_next);
+		MY_IMPORT(exports, xp_next);
+		MY_IMPORT(members, next);
+#undef	MY_IMPORT
+
+	}
+	;
+
+/*
+ * One of the elements of ASN.1 module specification.
+ */
+ModuleSpecificationElement:
+	ImportsDefinition {
+		$$ = $1;
+	}
+	| ExportsDefinition {
+		$$ = asn1p_module_new();
+		checkmem($$);
+		if($1) {
+			TQ_ADD(&($$->exports), $1, xp_next);
+		} else {
+			/* "EXPORTS ALL;" ? */
+		}
+	}
+	| DataTypeReference {
+		$$ = asn1p_module_new();
+		checkmem($$);
+		assert($1->expr_type != A1TC_INVALID);
+		assert($1->meta_type != AMT_INVALID);
+		TQ_ADD(&($$->members), $1, next);
+	}
+	| ValueDefinition {
+		$$ = asn1p_module_new();
+		checkmem($$);
+		assert($1->expr_type != A1TC_INVALID);
+		assert($1->meta_type != AMT_INVALID);
+		TQ_ADD(&($$->members), $1, next);
+	}
+	/*
+	 * Value set definition
+	 * === EXAMPLE ===
+	 * EvenNumbers INTEGER ::= { 2 | 4 | 6 | 8 }
+	 * === EOF ===
+	 */
+	| ValueSetDefinition {
+		$$ = asn1p_module_new();
+		checkmem($$);
+		assert($1->expr_type != A1TC_INVALID);
+		assert($1->meta_type != AMT_INVALID);
+		TQ_ADD(&($$->members), $1, next);
+	}
+
+	/*
+	 * Erroneous attemps
+	 */
+	| BasicString {
+		return yyerror(
+			"Attempt to redefine a standard basic type, "
+			"use -ftypesXY to switch back "
+			"to older version of ASN.1 standard");
+	}
+	;
+
+/*
+ * === EXAMPLE ===
+ * IMPORTS Type1, value FROM Module { iso standard(0) } ;
+ * === EOF ===
+ */
+ImportsDefinition:
+	TOK_IMPORTS ImportsBundleSet ';' {
+		$$ = $2;
+	}
+	/*
+	 * Some error cases.
+	 */
+	| TOK_IMPORTS TOK_FROM /* ... */ {
+		return yyerror("Empty IMPORTS list");
+	}
+	;
+
+ImportsBundleSet:
+	ImportsBundle {
+		$$ = asn1p_module_new();
+		checkmem($$);
+		TQ_ADD(&($$->imports), $1, xp_next);
+	}
+	| ImportsBundleSet ImportsBundle {
+		$$ = $1;
+		TQ_ADD(&($$->imports), $2, xp_next);
+	}
+	;
+
+ImportsBundle:
+	ImportsList TOK_FROM TypeRefName optObjectIdentifier {
+		$$ = $1;
+		$$->from = $3;
+		$$->from_oid = $4;
+		checkmem($$);
+	}
+	;
+
+ImportsList:
+	ImportsElement {
+		$$ = asn1p_xports_new();
+		checkmem($$);
+		TQ_ADD(&($$->members), $1, next);
+	}
+	| ImportsList ',' ImportsElement {
+		$$ = $1;
+		TQ_ADD(&($$->members), $3, next);
+	}
+	;
+
+ImportsElement:
+	TypeRefName {
+		$$ = asn1p_expr_new(yylineno);
+		checkmem($$);
+		$$->Identifier = $1;
+		$$->expr_type = A1TC_REFERENCE;
+	}
+	| Identifier {
+		$$ = asn1p_expr_new(yylineno);
+		checkmem($$);
+		$$->Identifier = $1;
+		$$->expr_type = A1TC_REFERENCE;
+	}
+	;
+
+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(&($$->members), $1, next);
+	}
+	| ExportsBody ',' ExportsElement {
+		$$ = $1;
+		TQ_ADD(&($$->members), $3, next);
+	}
+	;
+
+ExportsElement:
+	TypeRefName {
+		$$ = asn1p_expr_new(yylineno);
+		checkmem($$);
+		$$->Identifier = $1;
+		$$->expr_type = A1TC_EXPORTVAR;
+	}
+	| Identifier {
+		$$ = asn1p_expr_new(yylineno);
+		checkmem($$);
+		$$->Identifier = $1;
+		$$->expr_type = A1TC_EXPORTVAR;
+	}
+	;
+
+
+ValueSetDefinition:
+	TypeRefName DefinedTypeRef TOK_PPEQ '{' optValueSetBody '}' {
+		$$ = $2;
+		assert($$->Identifier == 0);
+		$$->Identifier = $1;
+		$$->meta_type = AMT_VALUESET;
+		// take care of optValueSetBody 
+	}
+	;
+
+DefinedTypeRef:
+	ComplexTypeReference {
+		$$ = asn1p_expr_new(yylineno);
+		checkmem($$);
+		$$->reference = $1;
+		$$->expr_type = A1TC_REFERENCE;
+		$$->meta_type = AMT_TYPEREF;
+	}
+	| BasicTypeId {
+		$$ = asn1p_expr_new(yylineno);
+		checkmem($$);
+		$$->expr_type = $1;
+		$$->meta_type = AMT_TYPE;
+	}
+	;
+
+optValueSetBody:
+	{ }
+	| ConstraintElementSet {
+	}
+	;
+
+
+/*
+ * Data Type Reference.
+ * === EXAMPLE ===
+ * Type3 ::= CHOICE { a Type1,  b Type 2 }
+ * === EOF ===
+ */
+
+DataTypeReference:
+	/*
+	 * Optionally tagged type definition.
+	 */
+	TypeRefName TOK_PPEQ optTag TOK_TYPE_IDENTIFIER {
+		$$ = asn1p_expr_new(yylineno);
+		checkmem($$);
+		$$->Identifier = $1;
+		$$->tag = $3;
+		$$->expr_type = A1TC_TYPEID;
+		$$->meta_type = AMT_TYPE;
+	}
+	| TypeRefName TOK_PPEQ optTag ConstrainedTypeDeclaration {
+		$$ = $4;
+		$$->Identifier = $1;
+		$$->tag = $3;
+		assert($$->expr_type);
+		assert($$->meta_type);
+	}
+	| TypeRefName TOK_PPEQ ClassDeclaration {
+		$$ = $3;
+		$$->Identifier = $1;
+		assert($$->expr_type == A1TC_CLASSDEF);
+		assert($$->meta_type == AMT_OBJECT);
+	}
+	/*
+	 * Parametrized <Type> declaration:
+	 * === EXAMPLE ===
+	 *   SIGNED { ToBeSigned } ::= SEQUENCE {
+	 *      toBeSigned  ToBeSigned,
+	 *      algorithm   AlgorithmIdentifier,
+	 *      signature   BIT STRING
+	 *   }
+	 * === EOF ===
+	 */
+	| TypeRefName '{' ParameterArgumentList '}'
+		TOK_PPEQ ConstrainedTypeDeclaration {
+		$$ = $6;
+		assert($$->Identifier == 0);
+		$$->Identifier = $1;
+		$$->params = $3;
+		$$->meta_type = AMT_PARAMTYPE;
+	}
+	;
+
+ParameterArgumentList:
+	ParameterArgumentName {
+		int ret;
+		$$ = asn1p_paramlist_new(yylineno);
+		checkmem($$);
+		ret = asn1p_paramlist_add_param($$, $1.governor, $1.argument);
+		checkmem(ret == 0);
+		if($1.governor) asn1p_ref_free($1.governor);
+		if($1.argument) free($1.argument);
+	}
+	| ParameterArgumentList ',' ParameterArgumentName {
+		int ret;
+		$$ = $1;
+		ret = asn1p_paramlist_add_param($$, $3.governor, $3.argument);
+		checkmem(ret == 0);
+		if($3.governor) asn1p_ref_free($3.governor);
+		if($3.argument) free($3.argument);
+	}
+	;
+	
+ParameterArgumentName:
+	TypeRefName {
+		$$.governor = NULL;
+		$$.argument = $1;
+	}
+	| TypeRefName ':' Identifier {
+		int ret;
+		$$.governor = asn1p_ref_new(yylineno);
+		ret = asn1p_ref_add_component($$.governor, $1, 0);
+		checkmem(ret == 0);
+		$$.argument = $3;
+	}
+	| BasicTypeId ':' Identifier {
+		int ret;
+		$$.governor = asn1p_ref_new(yylineno);
+		ret = asn1p_ref_add_component($$.governor,
+			ASN_EXPR_TYPE2STR($1), 1);
+		checkmem(ret == 0);
+		$$.argument = $3;
+	}
+	;
+
+ActualParameterList:
+	ActualParameter {
+		$$ = asn1p_expr_new(yylineno);
+		checkmem($$);
+		TQ_ADD(&($$->members), $1, next);
+	}
+	| ActualParameterList ',' ActualParameter {
+		$$ = $1;
+		TQ_ADD(&($$->members), $3, next);
+	}
+	;
+
+ActualParameter:
+	TypeDeclaration {
+		$$ = $1;
+	}
+	| Identifier {
+		$$ = asn1p_expr_new(yylineno);
+		checkmem($$);
+		$$->Identifier = $1;
+		$$->expr_type = A1TC_REFERENCE;
+		$$->meta_type = AMT_VALUE;
+	}
+	;
+
+/*
+ * A collection of constructed data type members.
+ */
+ConstructedDataTypeDefinition:
+	DataTypeMember {
+		$$ = asn1p_expr_new(yylineno);
+		checkmem($$);
+		TQ_ADD(&($$->members), $1, next);
+	}
+	| ConstructedDataTypeDefinition ',' DataTypeMember {
+		$$ = $1;
+		TQ_ADD(&($$->members), $3, next);
+	}
+	;
+
+ClassDeclaration:
+	TOK_CLASS '{' ClassFieldList '}' optWithSyntax {
+		$$ = $3;
+		checkmem($$);
+		$$->with_syntax = $5;
+		assert($$->expr_type == A1TC_CLASSDEF);
+		assert($$->meta_type == AMT_OBJECT);
+	}
+	;
+
+optUnique:
+	{ $$ = 0; }
+	| TOK_UNIQUE { $$ = 1; }
+	;
+
+ClassFieldList:
+	ClassField {
+		$$ = asn1p_expr_new(yylineno);
+		checkmem($$);
+		$$->expr_type = A1TC_CLASSDEF;
+		$$->meta_type = AMT_OBJECT;
+		TQ_ADD(&($$->members), $1, next);
+	}
+	| ClassFieldList ',' ClassField {
+		$$ = $1;
+		TQ_ADD(&($$->members), $3, next);
+	}
+	;
+
+ClassField:
+	ClassFieldIdentifier optMarker {
+		$$ = asn1p_expr_new(yylineno);
+		checkmem($$);
+		$$->Identifier = $1.name;
+		$$->expr_type = A1TC_CLASSFIELD;
+		$$->meta_type = AMT_OBJECTFIELD;
+		$$->marker = $2;
+	}
+	| ClassFieldIdentifier ConstrainedTypeDeclaration optUnique {
+		$$ = $2;
+		$$->Identifier = $1.name;
+		$$->unique = $3;
+	}
+	| ClassFieldIdentifier ClassFieldIdentifier optMarker optUnique {
+		int ret;
+		$$ = asn1p_expr_new(yylineno);
+		checkmem($$);
+		$$->Identifier = $1.name;
+		$$->reference = asn1p_ref_new(yylineno);
+		checkmem($$->reference);
+		ret = asn1p_ref_add_component($$->reference,
+				$2.name, $2.lex_type);
+		checkmem(ret == 0);
+		$$->expr_type = A1TC_CLASSFIELD;
+		$$->meta_type = AMT_OBJECTFIELD;
+		$$->marker = $3;
+		$$->unique = $4;
+	}
+	;
+
+optWithSyntax:
+	{ $$ = 0; }
+	| WithSyntax {
+		$$ = $1;
+	}
+	;
+
+WithSyntax:
+	TOK_WITH TOK_SYNTAX '{'
+		{ asn1p_lexer_hack_enable_with_syntax(); }
+		WithSyntaxFormat
+		'}' {
+		$$ = $5;
+	}
+	;
+
+WithSyntaxFormat:
+	WithSyntaxFormatToken {
+		$$ = asn1p_wsyntx_new();
+		TQ_ADD(&($$->chunks), $1, next);
+	}
+	| WithSyntaxFormat WithSyntaxFormatToken {
+		$$ = $1;
+		TQ_ADD(&($$->chunks), $2, next);
+	}
+	;
+
+WithSyntaxFormatToken:
+	TOK_opaque {
+		$$ = asn1p_wsyntx_chunk_frombuf($1.buf, $1.len, 0);
+	}
+	| ClassFieldIdentifier {
+		asn1p_ref_t *ref;
+		int ret;
+		ref = asn1p_ref_new(yylineno);
+		checkmem(ref);
+		ret = asn1p_ref_add_component(ref, $1.name, $1.lex_type);
+		checkmem(ret == 0);
+		$$ = asn1p_wsyntx_chunk_fromref(ref, 0);
+	}
+	;
+
+/*
+ * A data type member goes like this
+ * ===
+ * memb1 [0] Type1 { a(1), b(2) } (2)
+ * ===
+ * Therefore, we propose a split.
+ * ^^^^^^^^^ ^^^^^^^^^^
+ * ^TaggedIdentifier  ^TypeDeclaration
+ * 				^ConstrainedTypeDeclaration
+ */
+
+/*
+ * A member of a constructed data type ("a" or "b" in above example).
+ */
+DataTypeMember:
+	TaggedIdentifier ConstrainedTypeDeclaration {
+		$$ = $2;
+		assert($$->Identifier == 0);
+		$$->Identifier = $1.name;
+		$$->tag = $1.tag;
+	}
+	| ExtensionAndException {
+		$$ = $1;
+	}
+	;
+
+ConstrainedTypeDeclaration:
+	TypeDeclaration optConstraints optMarker {
+		$$ = $1;
+		$$->constraints = $2;
+		$$->marker = $3;
+	}
+	;
+
+ExtensionAndException:
+	TOK_ThreeDots {
+		$$ = asn1p_expr_new(asn1p_lineno);
+		checkmem($$);
+		$$->Identifier = strdup("...");
+		checkmem($$->Identifier);
+		$$->expr_type = A1TC_EXTENSIBLE;
+		$$->meta_type = AMT_TYPE;
+	}
+	| TOK_ThreeDots '!' DefinedValue {
+		$$ = asn1p_expr_new(asn1p_lineno);
+		checkmem($$);
+		$$->Identifier = strdup("...");
+		checkmem($$->Identifier);
+		$$->value = $3;
+		$$->expr_type = A1TC_EXTENSIBLE;
+		$$->meta_type = AMT_TYPE;
+	}
+	| TOK_ThreeDots '!' SignedNumber {
+		$$ = asn1p_expr_new(asn1p_lineno);
+		checkmem($$);
+		$$->Identifier = strdup("...");
+		$$->value = $3;
+		checkmem($$->Identifier);
+		$$->expr_type = A1TC_EXTENSIBLE;
+		$$->meta_type = AMT_TYPE;
+	}
+	;
+
+TypeDeclaration:
+	BasicType {
+		$$ = $1;
+	}
+	| BasicString {
+		$$ = asn1p_expr_new(yylineno);
+		checkmem($$);
+		$$->expr_type = $1;
+		$$->meta_type = AMT_TYPE;
+	}
+	| ConstructedType {
+		$$ = $1;
+		checkmem($$);
+		assert($$->meta_type);
+	}
+	/*
+	 * A parametrized assignment.
+	 */
+	| TypeRefName '{' ActualParameterList '}' {
+		int ret;
+		$$ = $3;
+		assert($$->expr_type == 0);
+		assert($$->meta_type == 0);
+		assert($$->reference == 0);
+		$$->reference = asn1p_ref_new(yylineno);
+		checkmem($$->reference);
+		ret = asn1p_ref_add_component($$->reference, $1, RLT_UNKNOWN);
+		checkmem(ret == 0);
+		free($1);
+		$$->expr_type = A1TC_PARAMETRIZED;
+		$$->meta_type = AMT_TYPE;
+	}
+	/*
+	 * A DefinedType reference.
+	 * "CLASS1.&id.&id2"
+	 * or
+	 * "Module.Type"
+	 * or
+	 * "Module.identifier"
+	 * or
+	 * "Type"
+	 */
+	| ComplexTypeReference {
+		$$ = asn1p_expr_new(yylineno);
+		checkmem($$);
+		$$->reference = $1;
+		$$->expr_type = A1TC_REFERENCE;
+		$$->meta_type = AMT_TYPEREF;
+	}
+	| TOK_INSTANCE TOK_OF ComplexTypeReference {
+		$$ = asn1p_expr_new(yylineno);
+		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);
+		checkmem($$);
+		ret = asn1p_ref_add_component($$, $1, RLT_UNKNOWN);
+		checkmem(ret == 0);
+		free($1);
+	}
+	| TOK_typereference '.' TypeRefName {
+		int ret;
+		$$ = asn1p_ref_new(yylineno);
+		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);
+	}
+	| TOK_typereference '.' Identifier {
+		int ret;
+		$$ = asn1p_ref_new(yylineno);
+		checkmem($$);
+		ret = asn1p_ref_add_component($$, $1, RLT_UNKNOWN);
+		checkmem(ret == 0);
+		ret = asn1p_ref_add_component($$, $3, RLT_lowercase);
+		checkmem(ret == 0);
+		free($1);
+	}
+	| ObjectClassReference {
+		int ret;
+		$$ = asn1p_ref_new(yylineno);
+		checkmem($$);
+		ret = asn1p_ref_add_component($$, $1, RLT_CAPITALS);
+		free($1);
+		checkmem(ret == 0);
+	}
+	| ObjectClassReference '.' 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);
+		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:	ClassFieldName;
+ClassFieldIdentifier:		ClassFieldName;
+
+ClassFieldName:
+	/* "&Type1" */
+	TOK_typefieldreference {
+		$$.lex_type = RLT_AmpUppercase;
+		$$.name = $1;
+	}
+	/* "&id" */
+	| TOK_valuefieldreference {
+		$$.lex_type = RLT_Amplowercase;
+		$$.name = $1;
+	}
+	;
+
+
+/*
+ * === EXAMPLE ===
+ * value INTEGER ::= 1
+ * === EOF ===
+ */
+ValueDefinition:
+	Identifier DefinedTypeRef TOK_PPEQ InlineOrDefinedValue {
+		$$ = $2;
+		assert($$->Identifier == NULL);
+		$$->Identifier = $1;
+		$$->meta_type = AMT_VALUE;
+		$$->value = $4;
+	}
+	;
+
+InlineOrDefinedValue:
+	'{' { asn1p_lexer_hack_push_opaque_state(); }
+		Opaque /* '}' */ {
+		$$ = asn1p_value_frombuf($3.buf, $3.len, 0);
+		checkmem($$);
+		$$->type = ATV_UNPARSED;
+	}
+	| TOK_bstring {
+		$$ = _convert_bitstring2binary($1, 'B');
+		checkmem($$);
+	}
+	| TOK_hstring {
+		$$ = _convert_bitstring2binary($1, 'H');
+		checkmem($$);
+	}
+	| TOK_cstring {
+		$$ = asn1p_value_frombuf($1.buf, $1.len, 0);
+		checkmem($$);
+	}
+	| SignedNumber {
+		$$ = $1;
+	}
+	| DefinedValue {
+		$$ = $1;
+	}
+	;
+
+DefinedValue:
+	Identifier {
+		asn1p_ref_t *ref;
+		int ret;
+		ref = asn1p_ref_new(yylineno);
+		checkmem(ref);
+		ret = asn1p_ref_add_component(ref, $1, RLT_lowercase);
+		checkmem(ret == 0);
+		$$ = asn1p_value_fromref(ref, 0);
+		checkmem($$);
+		free($1);
+	}
+	| TypeRefName '.' Identifier {
+		asn1p_ref_t *ref;
+		int ret;
+		ref = asn1p_ref_new(yylineno);
+		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);
+	}
+	;
+
+Opaque:
+	TOK_opaque {
+		$$.len = $1.len + 2;
+		$$.buf = malloc($$.len + 1);
+		checkmem($$.buf);
+		$$.buf[0] = '{';
+		$$.buf[1] = ' ';
+		memcpy($$.buf + 2, $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;
+	}
+	;
+
+BasicTypeId:
+	TOK_BOOLEAN { $$ = ASN_BASIC_BOOLEAN; }
+	| TOK_NULL { $$ = ASN_BASIC_NULL; }
+	| TOK_REAL { $$ = ASN_BASIC_REAL; }
+	| BasicTypeId_UniverationCompatible { $$ = $1; }
+	| 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; }
+	;
+
+/*
+ * 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; }
+	;
+
+BasicType:
+	BasicTypeId {
+		$$ = asn1p_expr_new(asn1p_lineno);
+		checkmem($$);
+		$$->expr_type = $1;
+		$$->meta_type = AMT_TYPE;
+	}
+	| BasicTypeId_UniverationCompatible UniverationDefinition {
+		if($2) {
+			$$ = $2;
+		} else {
+			$$ = asn1p_expr_new(asn1p_lineno);
+			checkmem($$);
+		}
+		$$->expr_type = $1;
+		$$->meta_type = AMT_TYPE;
+	}
+	;
+
+BasicString:
+	TOK_BMPString { $$ = ASN_STRING_BMPString; }
+	| TOK_GeneralString {
+		$$ = ASN_STRING_GeneralString;
+		return yyerror("GeneralString is not supported");
+	}
+	| TOK_GraphicString {
+		$$ = ASN_STRING_GraphicString;
+		return yyerror("GraphicString is not supported");
+	}
+	| 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;
+		return yyerror("T61String not implemented yet");
+	}
+	| TOK_TeletexString { $$ = ASN_STRING_TeletexString; }
+	| TOK_UniversalString { $$ = ASN_STRING_UniversalString; }
+	| TOK_UTF8String { $$ = ASN_STRING_UTF8String; }
+	| TOK_VideotexString {
+		$$ = ASN_STRING_VideotexString;
+		return yyerror("VideotexString is no longer supported");
+	}
+	| TOK_VisibleString { $$ = ASN_STRING_VisibleString; }
+	| TOK_ObjectDescriptor { $$ = ASN_STRING_ObjectDescriptor; }
+	;
+
+ConstructedType:
+	TOK_CHOICE '{' ConstructedDataTypeDefinition '}'	{
+		$$ = $3;
+		assert($$->expr_type == A1TC_INVALID);
+		$$->expr_type = ASN_CONSTR_CHOICE;
+		$$->meta_type = AMT_TYPE;
+	}
+	| TOK_SEQUENCE '{' ConstructedDataTypeDefinition '}'	{
+		$$ = $3;
+		assert($$->expr_type == A1TC_INVALID);
+		$$->expr_type = ASN_CONSTR_SEQUENCE;
+		$$->meta_type = AMT_TYPE;
+	}
+	| TOK_SET '{' ConstructedDataTypeDefinition '}'		{
+		$$ = $3;
+		assert($$->expr_type == A1TC_INVALID);
+		$$->expr_type = ASN_CONSTR_SET;
+		$$->meta_type = AMT_TYPE;
+	}
+	| TOK_SEQUENCE optConstraints TOK_OF TypeDeclaration {
+		$$ = asn1p_expr_new(asn1p_lineno);
+		checkmem($$);
+		$$->constraints = $2;
+		$$->expr_type = ASN_CONSTR_SEQUENCE_OF;
+		$$->meta_type = AMT_TYPE;
+		TQ_ADD(&($$->members), $4, next);
+	}
+	| TOK_SET optConstraints TOK_OF TypeDeclaration {
+		$$ = asn1p_expr_new(asn1p_lineno);
+		checkmem($$);
+		$$->constraints = $2;
+		$$->expr_type = ASN_CONSTR_SET_OF;
+		$$->meta_type = AMT_TYPE;
+		TQ_ADD(&($$->members), $4, next);
+	}
+	| TOK_ANY 						{
+		$$ = asn1p_expr_new(asn1p_lineno);
+		checkmem($$);
+		$$->expr_type = ASN_CONSTR_ANY;
+		$$->meta_type = AMT_TYPE;
+	}
+	| TOK_ANY TOK_DEFINED TOK_BY Identifier			{
+		int ret;
+		$$ = asn1p_expr_new(asn1p_lineno);
+		checkmem($$);
+		$$->reference = asn1p_ref_new(yylineno);
+		ret = asn1p_ref_add_component($$->reference,
+			$4, RLT_lowercase);
+		checkmem(ret == 0);
+		$$->expr_type = ASN_CONSTR_ANY;
+		$$->meta_type = AMT_TYPE;
+	}
+	;
+
+/*
+ * Data type constraints.
+ */
+optConstraints:
+	{ $$ = 0; }
+	| Constraints { $$ = $1; }
+	;
+
+Union:		'|' | TOK_UNION;
+Intersection:	'^' | TOK_INTERSECTION;
+Except:		      TOK_EXCEPT;
+
+Constraints:
+	TOK_SIZE '('  ConstraintElementSet ')' {
+		/*
+		 * This is a special case, for compatibility purposes.
+		 * It goes without parenthesis.
+		 */
+		int ret;
+		$$ = asn1p_constraint_new(yylineno);
+		checkmem($$);
+		$$->type = ACT_CT_SIZE;
+		ret = asn1p_constraint_insert($$, $3);
+		checkmem(ret == 0);
+	}
+	| SingleConstraint {
+		CONSTRAINT_INSERT($$, ACT_CA_SET, $1, 0);
+	}
+	| Constraints SingleConstraint {
+		CONSTRAINT_INSERT($$, ACT_CA_SET, $1, $2);
+	}
+	;
+
+SingleConstraint:
+	'(' ConstraintElementSet ')' {
+		$$ = $2;
+	}
+	;
+
+ConstraintElementSet:
+	ConstraintElement {
+		$$ = $1;
+	}
+	| ConstraintElement ',' TOK_ThreeDots {
+		asn1p_constraint_t *ct;
+		ct = asn1p_constraint_new(yylineno);
+		checkmem(ct);
+		ct->type = ACT_EL_EXT;
+		CONSTRAINT_INSERT($$, ACT_CA_CSV, $1, ct);
+	}
+	| ConstraintElement ',' TOK_ThreeDots ',' ConstraintElement {
+		asn1p_constraint_t *ct;
+		ct = asn1p_constraint_new(yylineno);
+		checkmem(ct);
+		ct->type = ACT_EL_EXT;
+		CONSTRAINT_INSERT($$, ACT_CA_CSV, $1, ct);
+		CONSTRAINT_INSERT($$, ACT_CA_CSV, $1, $5);
+	}
+	| TOK_ThreeDots {
+		$$ = asn1p_constraint_new(yylineno);
+		checkmem($$);
+		$$->type = ACT_EL_EXT;
+	}
+	| TOK_ThreeDots ',' ConstraintElement {
+		asn1p_constraint_t *ct;
+		ct = asn1p_constraint_new(yylineno);
+		checkmem(ct);
+		ct->type = ACT_EL_EXT;
+		CONSTRAINT_INSERT($$, ACT_CA_CSV, ct, $3);
+	}
+	;
+
+ConstraintElement: ConstraintElementUnion { $$ = $1; } ;
+
+ConstraintElementUnion:
+	ConstraintElementIntersection { $$ = $1; }
+	| ConstraintElementUnion Union ConstraintElementIntersection {
+		CONSTRAINT_INSERT($$, ACT_CA_UNI, $1, $3);
+	}
+	;
+
+ConstraintElementIntersection:
+	ConstraintElementException { $$ = $1; }
+	| ConstraintElementIntersection Intersection
+		ConstraintElementException {
+		CONSTRAINT_INSERT($$, ACT_CA_INT, $1, $3);
+	}
+	;
+
+ConstraintElementException:
+	ConstraintSubtypeElement { $$ = $1; }
+	| ConstraintElementException Except ConstraintSubtypeElement {
+		CONSTRAINT_INSERT($$, ACT_CA_EXC, $1, $3);
+	}
+	;
+
+ConstraintSubtypeElement:
+	ConstraintValue {
+		$$ = asn1p_constraint_new(yylineno);
+		checkmem($$);
+		$$->type = ACT_EL_VALUE;
+		$$->value = $1;
+	}
+	| ConstraintValue ConstraintRangeSpec ConstraintValue {
+		$$ = asn1p_constraint_new(yylineno);
+		checkmem($$);
+		$$->type = $2;
+		$$->range_start = $1;
+		$$->range_stop = $3;
+	}
+	| ConstraintSpec '(' ConstraintElementSet ')' {
+		int ret;
+		$$ = asn1p_constraint_new(yylineno);
+		checkmem($$);
+		$$->type = $1;
+		ret = asn1p_constraint_insert($$, $3);
+		checkmem(ret == 0);
+	}
+	| TableConstraint {
+		$$ = $1;
+	}
+	| WithComponents {
+		$$ = $1;
+	}
+	;
+
+ConstraintRangeSpec:
+	TOK_TwoDots		{ $$ = ACT_EL_RANGE; }
+	| TOK_TwoDots '<'	{ $$ = ACT_EL_RLRANGE; }
+	| '<' TOK_TwoDots	{ $$ = ACT_EL_LLRANGE; }
+	| '<' TOK_TwoDots '<'	{ $$ = ACT_EL_ULRANGE; }
+	;
+
+ConstraintSpec:
+	TOK_SIZE {
+		$$ = ACT_CT_SIZE;
+	}
+	| TOK_FROM {
+		$$ = ACT_CT_FROM;
+	}
+	;
+
+ConstraintValue:
+	SignedNumber {
+		$$ = $1;
+	}
+	| Identifier {
+		asn1p_ref_t *ref;
+		int ret;
+		ref = asn1p_ref_new(yylineno);
+		checkmem(ref);
+		ret = asn1p_ref_add_component(ref, $1, RLT_lowercase);
+		checkmem(ret == 0);
+		$$ = asn1p_value_fromref(ref, 0);
+		checkmem($$);
+		free($1);
+	}
+	| TOK_cstring {
+		$$ = asn1p_value_frombuf($1.buf, $1.len, 0);
+		checkmem($$);
+	}
+	| TOK_MIN {
+		$$ = asn1p_value_fromint(123);
+		checkmem($$);
+		$$->type = ATV_MIN;
+	}
+	| TOK_MAX {
+		$$ = asn1p_value_fromint(321);
+		checkmem($$);
+		$$->type = ATV_MAX;
+	}
+	| TOK_FALSE {
+		$$ = asn1p_value_fromint(0);
+		checkmem($$);
+		$$->type = ATV_FALSE;
+	}
+	| TOK_TRUE {
+		$$ = asn1p_value_fromint(1);
+		checkmem($$);
+		$$->type = ATV_TRUE;
+	}
+	;
+
+WithComponents:
+	TOK_WITH TOK_COMPONENTS '{' WithComponentsList '}' {
+		CONSTRAINT_INSERT($$, ACT_CT_WCOMPS, $4, 0);
+	}
+	;
+
+WithComponentsList:
+	WithComponentsElement {
+		$$ = $1;
+	}
+	| WithComponentsList ',' WithComponentsElement {
+		CONSTRAINT_INSERT($$, ACT_CT_WCOMPS, $1, $3);
+	}
+	;
+
+WithComponentsElement:
+	TOK_ThreeDots {
+		$$ = asn1p_constraint_new(yylineno);
+		checkmem($$);
+		$$->type = ACT_EL_EXT;
+	}
+	| Identifier optConstraints optPresenceConstraint {
+		$$ = asn1p_constraint_new(yylineno);
+		checkmem($$);
+		$$->type = ACT_EL_VALUE;
+		$$->value = asn1p_value_frombuf($1, strlen($1), 0);
+		$$->presence = $3;
+	}
+	;
+
+/*
+ * presence constraint for WithComponents
+ */
+optPresenceConstraint:
+	{ $$ = ACPRES_DEFAULT; }
+	| PresenceConstraint { $$ = $1; }
+	;
+
+PresenceConstraint:
+	TOK_PRESENT {
+		$$ = ACPRES_PRESENT;
+	}
+	| TOK_ABSENT {
+		$$ = ACPRES_ABSENT;
+	}
+	| TOK_OPTIONAL {
+		$$ = ACPRES_OPTIONAL;
+	}
+	;
+
+TableConstraint:
+	SimpleTableConstraint {
+		$$ = $1;
+	}
+	| ComponentRelationConstraint {
+		$$ = $1;
+	}
+	;
+
+/*
+ * "{ExtensionSet}"
+ */
+SimpleTableConstraint:
+	'{' TypeRefName '}' {
+		asn1p_ref_t *ref = asn1p_ref_new(yylineno);
+		asn1p_constraint_t *ct;
+		int ret;
+		ret = asn1p_ref_add_component(ref, $2, 0);
+		checkmem(ret == 0);
+		ct = asn1p_constraint_new(yylineno);
+		checkmem($$);
+		ct->type = ACT_EL_VALUE;
+		ct->value = asn1p_value_fromref(ref, 0);
+		CONSTRAINT_INSERT($$, ACT_CA_CRC, ct, 0);
+	}
+	;
+
+ComponentRelationConstraint:
+	SimpleTableConstraint '{' AtNotationList '}' {
+		CONSTRAINT_INSERT($$, ACT_CA_CRC, $1, $3);
+	}
+	;
+
+AtNotationList:
+	AtNotationElement {
+		$$ = asn1p_constraint_new(yylineno);
+		checkmem($$);
+		$$->type = ACT_EL_VALUE;
+		$$->value = asn1p_value_fromref($1, 0);
+	}
+	| AtNotationList ',' AtNotationElement {
+		asn1p_constraint_t *ct;
+		ct = asn1p_constraint_new(yylineno);
+		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);
+		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);
+		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';
+	}
+	;
+
+
+
+/*
+ * MARKERS
+ */
+
+optMarker:
+	{ $$ = EM_NOMARK; }
+	| Marker { $$ = $1; }
+	;
+
+Marker:
+	TOK_OPTIONAL {
+		$$ = EM_OPTIONAL;
+	}
+	| TOK_DEFAULT DefaultValue {
+		$$ = EM_DEFAULT;
+		/* FIXME: store DefaultValue somewhere */
+	}
+	;
+
+DefaultValue:
+	ConstraintValue {
+	}
+	| BasicTypeId {
+	}
+	| '{' { asn1p_lexer_hack_push_opaque_state(); } Opaque /* '}' */ {
+	}
+	;
+
+/*
+ * Universal enumeration definition to use in INTEGER and ENUMERATED.
+ * === EXAMPLE ===
+ * Gender ::= ENUMERATED { unknown(0), male(1), female(2) }
+ * Temperature ::= INTEGER { absolute-zero(-273), freezing(0), boiling(100) }
+ * === EOF ===
+ */
+/*
+optUniverationDefinition:
+	{ $$ = 0; }
+	| UniverationDefinition {
+		$$ = $1;
+	}
+	;
+*/
+
+UniverationDefinition:
+	'{' '}' {
+		$$ = asn1p_expr_new(asn1p_lineno);
+		checkmem($$);
+	}
+	| '{' UniverationList '}' {
+		$$ = $2;
+	}
+	;
+
+UniverationList:
+	UniverationElement {
+		$$ = asn1p_expr_new(asn1p_lineno);
+		checkmem($$);
+		TQ_ADD(&($$->members), $1, next);
+	}
+	| UniverationList ',' UniverationElement {
+		$$ = $1;
+		TQ_ADD(&($$->members), $3, next);
+	}
+	;
+
+UniverationElement:
+	Identifier {
+		$$ = asn1p_expr_new(asn1p_lineno);
+		checkmem($$);
+		$$->expr_type = A1TC_UNIVERVAL;
+		$$->meta_type = AMT_VALUE;
+		$$->Identifier = $1;
+	}
+	| Identifier '(' SignedNumber ')' {
+		$$ = asn1p_expr_new(asn1p_lineno);
+		checkmem($$);
+		$$->expr_type = A1TC_UNIVERVAL;
+		$$->meta_type = AMT_VALUE;
+		$$->Identifier = $1;
+		$$->value = $3;
+	}
+	| Identifier '(' DefinedValue ')' {
+		$$ = asn1p_expr_new(asn1p_lineno);
+		checkmem($$);
+		$$->expr_type = A1TC_UNIVERVAL;
+		$$->meta_type = AMT_VALUE;
+		$$->Identifier = $1;
+		$$->value = $3;
+	}
+	| SignedNumber {
+		$$ = asn1p_expr_new(asn1p_lineno);
+		checkmem($$);
+		$$->expr_type = A1TC_UNIVERVAL;
+		$$->meta_type = AMT_VALUE;
+		$$->value = $1;
+	}
+	| TOK_ThreeDots {
+		$$ = asn1p_expr_new(asn1p_lineno);
+		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($$);
+	}
+	;
+
+/*
+ * 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:
+	TOK_tag {
+		$$ = $1;
+		$$.tag_mode = TM_DEFAULT;
+	}
+	| TOK_tag TOK_IMPLICIT {
+		$$ = $1;
+		$$.tag_mode = TM_IMPLICIT;
+	}
+	| TOK_tag TOK_EXPLICIT {
+		$$ = $1;
+		$$.tag_mode = TM_EXPLICIT;
+	}
+	;
+
+TypeRefName:
+	TOK_typereference {
+		checkmem($1);
+		$$ = $1;
+	}
+	| TOK_objectclassreference {
+		checkmem($1);
+		$$ = $1;
+	}
+	;
+
+ObjectClassReference:
+	TOK_objectclassreference {
+		checkmem($1);
+		$$ = $1;
+	}
+	;
+
+Identifier:
+	TOK_identifier {
+		checkmem($1);
+		$$ = $1;
+	}
+	;
+
+TaggedIdentifier:
+	Identifier {
+		memset(&$$, 0, sizeof($$));
+		$$.name = $1;
+	}
+	| Identifier Tag {
+		$$.name = $1;
+		$$.tag = $2;
+	}
+	;
+
+
+%%
+
+
+/*
+ * 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;
+}
+
+extern char *asn1p_text;
+
+int
+yyerror(const char *msg) {
+	fprintf(stderr,
+		"ASN.1 grammar parse error "
+		"near line %d (token \"%s\"): %s\n",
+		asn1p_lineno, asn1p_text, msg);
+	return -1;
+}
+
+