 16179383fb
			
		
	
	16179383fb
	
	
	
		
			
			Record when a CHOICE field is promoted from IMPLICIT to EXPLICIT and convey this in the ASN.1 compiler's JSON output, so that other tools (e.g. which have a representation isomorphic to the original ASN.1) may use it.
		
			
				
	
	
		
			2037 lines
		
	
	
		
			55 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			2037 lines
		
	
	
		
			55 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan
 | |
|  * (Royal Institute of Technology, Stockholm, Sweden).
 | |
|  * All rights reserved.
 | |
|  *
 | |
|  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
 | |
|  *
 | |
|  * Redistribution and use in source and binary forms, with or without
 | |
|  * modification, are permitted provided that the following conditions
 | |
|  * are met:
 | |
|  *
 | |
|  * 1. Redistributions of source code must retain the above copyright
 | |
|  *    notice, this list of conditions and the following disclaimer.
 | |
|  *
 | |
|  * 2. Redistributions in binary form must reproduce the above copyright
 | |
|  *    notice, this list of conditions and the following disclaimer in the
 | |
|  *    documentation and/or other materials provided with the distribution.
 | |
|  *
 | |
|  * 3. Neither the name of the Institute nor the names of its contributors
 | |
|  *    may be used to endorse or promote products derived from this software
 | |
|  *    without specific prior written permission.
 | |
|  *
 | |
|  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 | |
|  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | |
|  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | |
|  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 | |
|  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | |
|  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | |
|  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | |
|  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | |
|  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | |
|  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | |
|  * SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| /* $Id$ */
 | |
| 
 | |
| %{
 | |
| 
 | |
| #include <config.h>
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <stdint.h>
 | |
| #include <string.h>
 | |
| #include "symbol.h"
 | |
| #include "lex.h"
 | |
| #include "gen_locl.h"
 | |
| #include "der.h"
 | |
| 
 | |
| static Type *new_type (Typetype t);
 | |
| /*static IOSClass *new_class(struct fieldhead *);*/
 | |
| /*static IOSObject *new_object(struct objfieldhead *);*/
 | |
| /*IOSObjectSet *new_object_set(struct objectshead *);*/
 | |
| static struct objectshead *add_object_set_spec(struct objectshead *, IOSObject *);
 | |
| static ObjectField *new_field_setting(char *, Type *, struct value *);
 | |
| static struct objfieldhead *add_field_setting(struct objfieldhead *, ObjectField *);
 | |
| static struct fieldhead *add_field_spec(struct fieldhead *, Field *);
 | |
| static Field *new_type_field(char *, int, Type *);
 | |
| static Field *new_fixed_type_value_field(char *, Type *, int, int, struct value *);
 | |
| static Type *parametrize_type(Type *, IOSClass *);
 | |
| static Type *type_from_class_field(IOSClass *, const char *);
 | |
| static void validate_object_set(IOSObjectSet *);
 | |
| /*static Type *type_from_object(const char *, const char *);*/
 | |
| static struct constraint_spec *new_constraint_spec(enum ctype);
 | |
| static Type *new_tag(int tagclass, int tagvalue, int tagenv, Type *oldtype);
 | |
| void yyerror (const char *);
 | |
| #define yyerror yyerror
 | |
| static struct objid *new_objid(const char *label, int value);
 | |
| static void add_oid_to_tail(struct objid *, struct objid *);
 | |
| static void fix_labels(Symbol *s);
 | |
| 
 | |
| struct string_list {
 | |
|     char *string;
 | |
|     struct string_list *next;
 | |
| };
 | |
| 
 | |
| static int default_tag_env = TE_EXPLICIT;
 | |
| static unsigned long idcounter;
 | |
| 
 | |
| /* Declarations for Bison */
 | |
| #define YYMALLOC malloc
 | |
| #define YYFREE   free
 | |
| 
 | |
| %}
 | |
| 
 | |
| %union {
 | |
|     int64_t constant;
 | |
|     struct value *value;
 | |
|     struct range *range;
 | |
|     char *name;
 | |
|     Type *type;
 | |
|     IOSClass *class;
 | |
|     IOSObjectSet *objectset;
 | |
|     IOSObject *object;
 | |
|     Field *field;
 | |
|     ObjectField *objfield;
 | |
|     Member *member;
 | |
|     IOSClass *formalparam;
 | |
|     struct objid *objid;
 | |
|     char *defval;
 | |
|     struct string_list *sl;
 | |
|     struct tagtype tag;
 | |
|     struct memhead *members;
 | |
|     struct fieldhead *fields;
 | |
|     struct objectshead *objects;
 | |
|     struct objfieldhead *objfields;
 | |
|     struct constraint_spec *constraint_spec;
 | |
| }
 | |
| 
 | |
| %token kw_ABSENT
 | |
| %token kw_ABSTRACT_SYNTAX
 | |
| %token kw_ALL
 | |
| %token kw_APPLICATION
 | |
| %token kw_AUTOMATIC
 | |
| %token kw_BEGIN
 | |
| %token kw_BIT
 | |
| %token kw_BMPString
 | |
| %token kw_BOOLEAN
 | |
| %token kw_BY
 | |
| %token kw_CHARACTER
 | |
| %token kw_CHOICE
 | |
| %token kw_CLASS
 | |
| %token kw_COMPONENT
 | |
| %token kw_COMPONENTS
 | |
| %token kw_CONSTRAINED
 | |
| %token kw_CONTAINING
 | |
| %token kw_DEFAULT
 | |
| %token kw_DEFINITIONS
 | |
| %token kw_EMBEDDED
 | |
| %token kw_ENCODED
 | |
| %token kw_END
 | |
| %token kw_ENUMERATED
 | |
| %token kw_EXCEPT
 | |
| %token kw_EXPLICIT
 | |
| %token kw_EXPORTS
 | |
| %token kw_EXTENSIBILITY
 | |
| %token kw_EXTERNAL
 | |
| %token kw_FALSE
 | |
| %token kw_FROM
 | |
| %token kw_GeneralString
 | |
| %token kw_GeneralizedTime
 | |
| %token kw_GraphicString
 | |
| %token kw_IA5String
 | |
| %token kw_IDENTIFIER
 | |
| %token kw_IMPLICIT
 | |
| %token kw_IMPLIED
 | |
| %token kw_IMPORTS
 | |
| %token kw_INCLUDES
 | |
| %token kw_INSTANCE
 | |
| %token kw_INTEGER
 | |
| %token kw_INTERSECTION
 | |
| %token kw_ISO646String
 | |
| %token kw_MAX
 | |
| %token kw_MIN
 | |
| %token kw_MINUS_INFINITY
 | |
| %token kw_NULL
 | |
| %token kw_NumericString
 | |
| %token kw_OBJECT
 | |
| %token kw_OCTET
 | |
| %token kw_OF
 | |
| %token kw_OPTIONAL
 | |
| %token kw_ObjectDescriptor
 | |
| %token kw_PATTERN
 | |
| %token kw_PDV
 | |
| %token kw_PLUS_INFINITY
 | |
| %token kw_PRESENT
 | |
| %token kw_PRIVATE
 | |
| %token kw_PrintableString
 | |
| %token kw_REAL
 | |
| %token kw_RELATIVE_OID
 | |
| %token kw_SEQUENCE
 | |
| %token kw_SET
 | |
| %token kw_SIZE
 | |
| %token kw_STRING
 | |
| %token kw_SYNTAX
 | |
| %token kw_T61String
 | |
| %token kw_TAGS
 | |
| %token kw_TRUE
 | |
| %token kw_TYPE_IDENTIFIER
 | |
| %token kw_TeletexString
 | |
| %token kw_UNION
 | |
| %token kw_UNIQUE
 | |
| %token kw_UNIVERSAL
 | |
| %token kw_UTCTime
 | |
| %token kw_UTF8String
 | |
| %token kw_UniversalString
 | |
| %token kw_VideotexString
 | |
| %token kw_VisibleString
 | |
| %token kw_WITH
 | |
| 
 | |
| %token RANGE
 | |
| %token EEQUAL
 | |
| %token ELLIPSIS
 | |
| 
 | |
| %token <name> TYPE_IDENTIFIER  referencename
 | |
| %token <name> CLASS_IDENTIFIER
 | |
| %token <name> VALUE_IDENTIFIER
 | |
| %token <name> STRING
 | |
| 
 | |
| %token <constant> NUMBER
 | |
| %type <constant> SignedNumber
 | |
| %type <constant> Class tagenv
 | |
| %type <constant> DummyReference
 | |
| 
 | |
| %type <name> Identifier
 | |
| 
 | |
| /*
 | |
|  * The NULL keyword being both a value and a type causes a reduce/reduce
 | |
|  * conflict in the FieldSetting production since its alternatives are
 | |
|  *
 | |
|  *	'&' Identifier Type
 | |
|  *
 | |
|  * and
 | |
|  *
 | |
|  *	'&' Identifier Value
 | |
|  *
 | |
|  * and NULL is both a type and a value.
 | |
|  *
 | |
|  * For now we work around this by having a ValueExNull production that excludes
 | |
|  * the NULL value.  To really get past this will require unifying the type and
 | |
|  * value types (e.g., via type punning).
 | |
|  */
 | |
| %type <value> Value ValueExNull
 | |
| %type <value> BuiltinValue BuiltinValueExNull
 | |
| %type <value> IntegerValue
 | |
| %type <value> BooleanValue
 | |
| %type <value> ObjectIdentifierValue
 | |
| %type <value> CharacterStringValue
 | |
| %type <value> NullValue
 | |
| %type <value> DefinedValue
 | |
| %type <value> ReferencedValue
 | |
| %type <value> Valuereference
 | |
| 
 | |
| %type <class> DefinedObjectClass ParamGovernor
 | |
| %type <class> ObjectClassDefn
 | |
| %type <class> Parameter
 | |
| 
 | |
| %type <type> Type
 | |
| %type <type> BuiltinType
 | |
| %type <type> BitStringType
 | |
| %type <type> BooleanType
 | |
| %type <type> ChoiceType
 | |
| %type <type> ConstrainedType
 | |
| %type <type> UnconstrainedType
 | |
| %type <type> EnumeratedType
 | |
| %type <type> IntegerType
 | |
| %type <type> NullType
 | |
| %type <type> OctetStringType
 | |
| %type <type> SequenceType
 | |
| %type <type> SequenceOfType
 | |
| %type <type> SetType
 | |
| %type <type> SetOfType
 | |
| %type <type> TaggedType
 | |
| %type <type> ReferencedType
 | |
| %type <type> DefinedType
 | |
| %type <type> UsefulType
 | |
| %type <type> ObjectIdentifierType
 | |
| %type <type> CharacterStringType
 | |
| %type <type> RestrictedCharactedStringType
 | |
| %type <type> ObjectClassFieldType
 | |
| %type <type> ParameterizedType
 | |
| /*%type <type> TypeFromObject*/
 | |
| 
 | |
| %type <objectset> ObjectSet DefinedObjectSet
 | |
| %type <objectset> ActualParameter
 | |
| %type <object> Object DefinedObject ObjectDefn
 | |
| %type <objfield> FieldSetting
 | |
| 
 | |
| %type <tag> Tag
 | |
| 
 | |
| %type <field> FieldSpec TypeFieldSpec FixedTypeValueFieldSpec
 | |
| %type <fields> FieldSpecList
 | |
| %type <member> ComponentType
 | |
| %type <member> NamedBit
 | |
| %type <member> NamedNumber
 | |
| %type <member> NamedType
 | |
| %type <members> ComponentTypeList
 | |
| %type <members> Enumerations
 | |
| %type <members> NamedBitList
 | |
| %type <members> NamedNumberList
 | |
| %type <objects> ObjectSetSpec
 | |
| %type <objfields> FieldSettings
 | |
| 
 | |
| %type <objid> objid objid_list objid_element objid_opt
 | |
| %type <range> range size
 | |
| 
 | |
| %type <sl> referencenames
 | |
| 
 | |
| %type <constraint_spec> Constraint
 | |
| %type <constraint_spec> ConstraintSpec
 | |
| %type <constraint_spec> SubtypeConstraint
 | |
| %type <constraint_spec> GeneralConstraint
 | |
| %type <constraint_spec> ContentsConstraint
 | |
| %type <constraint_spec> UserDefinedConstraint
 | |
| %type <constraint_spec> SimpleTableConstraint TableConstraint
 | |
| %type <constraint_spec> ComponentRelationConstraint
 | |
| 
 | |
| 
 | |
| %start ModuleDefinition
 | |
| 
 | |
| %%
 | |
| 
 | |
| /*
 | |
|  * We have sinned by allowing types to have names that start with lower-case,
 | |
|  * and values that have names that start with upper-case.
 | |
|  *
 | |
|  * UPDATE: We sin no more.  However, parts of this block comment are still
 | |
|  * relevant.
 | |
|  *
 | |
|  * That worked when we only supported basic X.680 because the rules for
 | |
|  * TypeAssignment and ValueAssignment are clearly unambiguous in spite of the
 | |
|  * case issue.
 | |
|  *
 | |
|  * We now pay the price because X.681 adds productions where the only thing we
 | |
|  * have to help us distinguish certain rules is the form of an identifier: the
 | |
|  * case of its first letter.
 | |
|  *
 | |
|  * We have cleansed our sin by not allowing wrong-case identifiers any more.
 | |
|  *
 | |
|  * Some historical instances of this sin in-tree:
 | |
|  *
 | |
|  *  - DOMAIN-X500-COMPRESS  (value (enum) but name starts with upper-case)
 | |
|  *  - krb5int32		    (type         but name starts with lower-case)
 | |
|  *  - krb5uint32	    (type         but name starts with lower-case)
 | |
|  *  - hdb_keyset	    (type         but name starts with lower-case)
 | |
|  *  - hdb_entry		    (type         but name starts with lower-case)
 | |
|  *  - hdb_entry_alias       (type         but name starts with lower-case)
 | |
|  *  - HDB_DB_FORMAT INTEGER (value (int)  but name starts with upper-case)
 | |
|  *
 | |
|  * We have fixed all of these and others, in some cases leaving behind aliases
 | |
|  * in header files as needed.
 | |
|  *
 | |
|  * We have one shift/reduce conflict (shift ObjectClassAssignment, reduce
 | |
|  * TypeAssignment) and one reduce/reduce conflict (ObjectAssignment vs
 | |
|  * ValueAssignment) that we avoid by requiring CLASS names to start with an
 | |
|  * underscore.
 | |
|  *
 | |
|  * In the FieldSetting rule, also, we get a reduce/reduce conflict if we use
 | |
|  * `Identifier' instead of `TYPE_IDENTIFIER' for type field settings and
 | |
|  * `VALUE_IDENTIFIER' for value field settings, and then we can't make
 | |
|  * progress.
 | |
|  *
 | |
|  * Looking forward, we may not (will not) be able to distinguish ValueSet and
 | |
|  * ObjectSet field settings from each other either, and we may not (will not)
 | |
|  * be able distinguish Object and Value field settings from each other as well.
 | |
|  * To deal with those we will have to run-time type-tag and type-pun the C
 | |
|  * structures for valueset/objectset and value/object, and have one rule for
 | |
|  * each of those that inspects the type of the item to decide what kind of
 | |
|  * setting it is.
 | |
|  *
 | |
|  * Sadly, the extended syntax for ASN.1 (x.680 + x.681/2/3) appears to have
 | |
|  * ambiguities that cannot be resolved with bison/yacc.
 | |
|  */
 | |
| Identifier	: TYPE_IDENTIFIER { $$ = $1; }
 | |
| 		| VALUE_IDENTIFIER { $$ = $1; };
 | |
| 
 | |
| ModuleDefinition: Identifier objid_opt kw_DEFINITIONS TagDefault ExtensionDefault
 | |
| 			EEQUAL kw_BEGIN ModuleBody kw_END
 | |
| 		{
 | |
|                     struct objid **o = objid2list($2);
 | |
|                     size_t i;
 | |
| 
 | |
|                     fprintf(jsonfile,
 | |
|                             "{\"module\":\"%s\",\"tagging\":\"%s\",\"objid\":[", $1,
 | |
|                             default_tag_env == TE_EXPLICIT ? "explicit" : "implicit");
 | |
| 
 | |
|                     for (i = 0; o && o[i]; i++) {
 | |
|                         fprintf(jsonfile, "%s{\"value\":%d", i ? "," : "", o[i]->value);
 | |
|                         if (o[i]->label)
 | |
|                             fprintf(jsonfile, ",\"label\":\"%s\"", o[i]->label);
 | |
|                         fprintf(jsonfile, "}");
 | |
|                     }
 | |
|                     fprintf(jsonfile, "]}\n");
 | |
|                     free(o);
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| TagDefault	: kw_EXPLICIT kw_TAGS
 | |
| 			{ default_tag_env = TE_EXPLICIT; }
 | |
| 		| kw_IMPLICIT kw_TAGS
 | |
| 			{ default_tag_env = TE_IMPLICIT; }
 | |
| 		| kw_AUTOMATIC kw_TAGS
 | |
| 		      { lex_error_message("automatic tagging is not supported"); }
 | |
| 		| /* empty */
 | |
| 		;
 | |
| 
 | |
| ExtensionDefault: kw_EXTENSIBILITY kw_IMPLIED
 | |
| 		      { lex_error_message("no extensibility options supported"); }
 | |
| 		| /* empty */
 | |
| 		;
 | |
| 
 | |
| ModuleBody	: Exports Imports AssignmentList
 | |
| 		| /* empty */
 | |
| 		;
 | |
| 
 | |
| Imports		: kw_IMPORTS SymbolsImported ';'
 | |
| 		| /* empty */
 | |
| 		;
 | |
| 
 | |
| SymbolsImported	: SymbolsFromModuleList
 | |
| 		| /* empty */
 | |
| 		;
 | |
| 
 | |
| SymbolsFromModuleList: SymbolsFromModule
 | |
| 		| SymbolsFromModuleList SymbolsFromModule
 | |
| 		;
 | |
| 
 | |
| SymbolsFromModule: referencenames kw_FROM Identifier objid_opt
 | |
| 		{
 | |
| 		    /*
 | |
|                      * FIXME We really could use knowing what kind of thing the
 | |
|                      * identifier identifies -- a type, a value, what?
 | |
| 		     *
 | |
| 		     * Our sin of allowing type names to start with lower-case
 | |
| 		     * and values with upper-case means we can't tell.  So we
 | |
| 		     * assume it's types only, but that means we can't import
 | |
| 		     * OID values, but we really want to!
 | |
|                      *
 | |
|                      * One thing we could do is not force `s->stype = Stype'
 | |
|                      * here, instead set it to a new `Sunknown' value so that
 | |
|                      * the first place that refers to this symbol with enough
 | |
|                      * context to imply a symbol type can set it.
 | |
| 		     */
 | |
| 		    struct string_list *sl;
 | |
| 		    for(sl = $1; sl != NULL; sl = sl->next) {
 | |
| 			Symbol *s = addsym(sl->string);
 | |
| 			s->stype = Stype;
 | |
| 			gen_template_import(s);
 | |
| 		    }
 | |
| 		    add_import($3);
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| Exports		: kw_EXPORTS referencenames ';'
 | |
| 		{
 | |
| 		    struct string_list *sl;
 | |
| 		    for(sl = $2; sl != NULL; sl = sl->next)
 | |
| 			add_export(sl->string);
 | |
| 		}
 | |
| 		| kw_EXPORTS kw_ALL
 | |
| 		| /* empty */
 | |
| 		;
 | |
| 
 | |
| AssignmentList	: Assignment
 | |
| 		| Assignment AssignmentList
 | |
| 		;
 | |
| 
 | |
| Assignment	: TypeAssignment
 | |
| 		| ValueAssignment
 | |
| 		| ParameterizedTypeAssignment
 | |
| 		| ObjectClassAssignment
 | |
| 		| ObjectAssignment
 | |
| 		| ObjectSetAssignment
 | |
| 	     /* | ParameterizedAssignment // from X.683 */
 | |
| 		;
 | |
| 
 | |
| referencenames	: Identifier ',' referencenames
 | |
| 		{
 | |
| 		    $$ = emalloc(sizeof(*$$));
 | |
| 		    $$->string = $1;
 | |
| 		    $$->next = $3;
 | |
| 		}
 | |
| 		| Identifier
 | |
| 		{
 | |
| 		    $$ = emalloc(sizeof(*$$));
 | |
| 		    $$->string = $1;
 | |
| 		    $$->next = NULL;
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| DefinedObjectClass
 | |
| 		: CLASS_IDENTIFIER
 | |
| 		{
 | |
| 		    Symbol *s = addsym($1);
 | |
| 		    if(s->stype != Sclass)
 | |
| 		      lex_error_message ("%s is not a class\n", $1);
 | |
| 		    $$ = s->iosclass;
 | |
| 		};
 | |
| 
 | |
| ObjectClassAssignment
 | |
| 		: CLASS_IDENTIFIER EEQUAL ObjectClassDefn
 | |
| 		{
 | |
| 		    Symbol *s = addsym($1);
 | |
| 		    s->stype = Sclass;
 | |
| 		    s->iosclass = $3;
 | |
| 		    s->iosclass->symbol = s;
 | |
| 		    fix_labels(s);
 | |
| 		}
 | |
| 		| CLASS_IDENTIFIER EEQUAL DefinedObjectClass
 | |
| 		{
 | |
| 		    Symbol *s = addsym($1);
 | |
| 		    s->stype = Sclass;
 | |
| 		    s->iosclass = $3;
 | |
| 		}
 | |
| 	     /* | ParameterizedObjectClass */
 | |
| 		;
 | |
| 
 | |
| ObjectClassDefn : kw_CLASS '{' FieldSpecList '}'
 | |
| 		{
 | |
| 		    $$ = ecalloc(1, sizeof(*$$));
 | |
| 		    $$->fields = $3;
 | |
| 		    $$->id = idcounter++;
 | |
| 		};
 | |
| 
 | |
| ObjectAssignment: VALUE_IDENTIFIER DefinedObjectClass EEQUAL Object
 | |
| 		{
 | |
| 		    Symbol *s = addsym($1);
 | |
| 		    s->stype = Sobj;
 | |
| 		    s->object = $4;
 | |
| 		    s->object->iosclass = $2;
 | |
| 		    if (!s->object->symbol)
 | |
| 			s->object->symbol = s;
 | |
| 		    fix_labels(s);
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| ObjectSetAssignment
 | |
| 		: TYPE_IDENTIFIER DefinedObjectClass EEQUAL ObjectSet
 | |
| 		{
 | |
| 		    Symbol *s = addsym($1);
 | |
| 		    s->stype = Sobjset;
 | |
| 		    s->iosclass = $2;
 | |
| 		    s->objectset = $4;
 | |
|                     s->objectset->symbol = s->objectset->symbol ? s->objectset->symbol : s;
 | |
| 		    s->objectset->iosclass = $2;
 | |
|                     validate_object_set($4);
 | |
|                     generate_template_objectset_forwards(s);
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| ObjectSet       : '{' ObjectSetSpec '}'
 | |
| 		{
 | |
| 		    $$ = ecalloc(1, sizeof(*$$));
 | |
| 		    $$->objects = $2;
 | |
| 		    $$->id = idcounter++;
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| ObjectSetSpec   : DefinedObject
 | |
| 		{ $$ = add_object_set_spec(NULL, $1); }
 | |
| 		| ObjectSetSpec '|' DefinedObject
 | |
| 		{ $$ = add_object_set_spec($1, $3); }
 | |
| 		;
 | |
| 
 | |
| Object		: DefinedObject
 | |
| 		| ObjectDefn
 | |
| 	     /* | ObjectFromObject      */
 | |
| 	     /* | ParameterizedObject   */
 | |
| 		;
 | |
| 
 | |
| DefinedObject	: VALUE_IDENTIFIER
 | |
| 		{
 | |
| 		  Symbol *s = addsym($1);
 | |
| 		  if(s->stype != Sobj)
 | |
| 		    lex_error_message ("%s is not an object\n", $1);
 | |
| 		  $$ = s->object;
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| DefinedObjectSet: TYPE_IDENTIFIER
 | |
| 		{
 | |
| 		  Symbol *s = addsym($1);
 | |
| 		  if(s->stype != Sobjset && s->stype != SUndefined)
 | |
| 		    lex_error_message ("%s is not an object set\n", $1);
 | |
| 		  $$ = s->objectset;
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| 
 | |
| ObjectDefn	: '{' FieldSettings '}' /* DefaultSyntax */
 | |
| 		{
 | |
| 		    $$ = ecalloc(1, sizeof(*$$));
 | |
| 		    $$->objfields = $2;
 | |
| 		    $$->id = idcounter++;
 | |
| 		}
 | |
| 	     /* | DefinedSyntax */
 | |
| 		;
 | |
| 
 | |
| FieldSettings	: FieldSetting
 | |
| 		{
 | |
| 		$$ = add_field_setting(NULL, $1);
 | |
| 		}
 | |
| 		| FieldSettings ',' FieldSetting
 | |
| 		{
 | |
| 		$$ = add_field_setting($1, $3);
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| /* See note on `Identifier' */
 | |
| FieldSetting	: '&' Identifier Type
 | |
| 		{ $$ = new_field_setting($2, $3, NULL); }
 | |
| 		| '&' Identifier ValueExNull
 | |
| 		{ $$ = new_field_setting($2, NULL, $3); }
 | |
| 	     /* | '&' TYPE_IDENTIFIER ValueSet   */
 | |
| 	     /* | '&' VALUE_IDENTIFIER Object     */
 | |
| 	     /* | '&' TYPE_IDENTIFIER ObjectSet  */
 | |
| 		;
 | |
| 
 | |
| /* Fields of a class */
 | |
| FieldSpecList	: FieldSpec
 | |
| 		{ $$ = add_field_spec(NULL, $1); }
 | |
| 		| FieldSpecList ',' FieldSpec
 | |
| 		{ $$ = add_field_spec($1, $3); };
 | |
| 
 | |
| /*
 | |
|  * Fields of a CLASS
 | |
|  *
 | |
|  * There are seven kinds of class/object fields:
 | |
|  *
 | |
|  *  - type fields,
 | |
|  *  - fixed-type value fields,
 | |
|  *  - fixed-type value set fields,
 | |
|  *  - variable-type value fields
 | |
|  *  - variable-type value set fields
 | |
|  *  - object fields
 | |
|  *  - object set fields
 | |
|  *
 | |
|  * We care only to support the bare minimum to treat open types as a CHOICE of
 | |
|  * sorts and automatically encode/decode values in open types.  That's: type
 | |
|  * fields and fixed-type value fields.
 | |
|  */
 | |
| FieldSpec	: TypeFieldSpec
 | |
| 		| FixedTypeValueFieldSpec
 | |
| 	     /* | VariableTypeValueFieldSpec    */
 | |
| 	     /* | VariableTypeValueSetFieldSpec */
 | |
| 	     /* | FixedTypeValueSetFieldSpec    */
 | |
| 	     /* | ObjectFieldSpec               */
 | |
| 	     /* | ObjectSetFieldSpec            */
 | |
| 		;
 | |
| TypeFieldSpec	: '&' Identifier
 | |
| 		{ $$ = new_type_field($2, 0, NULL); }
 | |
| 		| '&' Identifier kw_OPTIONAL
 | |
| 		{ $$ = new_type_field($2, 1, NULL); }
 | |
| 		| '&' Identifier kw_DEFAULT Type
 | |
| 		{ $$ = new_type_field($2, 1, $4); }
 | |
| 		;
 | |
| 
 | |
| FixedTypeValueFieldSpec
 | |
| 		: '&' Identifier Type
 | |
| 		{ $$ = new_fixed_type_value_field($2, $3, 0, 0, NULL); }
 | |
| 		| '&' Identifier Type kw_UNIQUE
 | |
| 		{ $$ = new_fixed_type_value_field($2, $3, 1, 0, NULL); }
 | |
| 		| '&' Identifier Type kw_UNIQUE kw_OPTIONAL
 | |
| 		{ $$ = new_fixed_type_value_field($2, $3, 1, 1, NULL); }
 | |
| 		| '&' Identifier Type kw_UNIQUE kw_DEFAULT Value
 | |
| 		{ $$ = new_fixed_type_value_field($2, $3, 1, 0, $6); }
 | |
| 		| '&' Identifier Type kw_OPTIONAL
 | |
| 		{ $$ = new_fixed_type_value_field($2, $3, 0, 1, NULL); }
 | |
| 		| '&' Identifier Type kw_DEFAULT Value
 | |
| 		{ $$ = new_fixed_type_value_field($2, $3, 0, 0, $5); };
 | |
| 
 | |
| /*
 | |
|  * Now we need a bit of X.683, just enough to parse PKIX.
 | |
|  *
 | |
|  * E.g., we need to parse this sort of type definition, which isn't quite the
 | |
|  * final type definition because the ExtensionSet will be provided later.
 | |
|  *
 | |
|  *-- <- ObjectClassDefn ->
 | |
|  *   EXTENSION ::= CLASS {
 | |
|  *       &id  OBJECT IDENTIFIER UNIQUE,
 | |
|  *    -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | |
|  *    -- FixedTypeValueFieldSpec
 | |
|  *
 | |
|  *       &ExtnType,
 | |
|  *    -- ^^^^^^^^^
 | |
|  *    -- TypeFieldSpec
 | |
|  *
 | |
|  *       &Critical    BOOLEAN DEFAULT {TRUE | FALSE }
 | |
|  *    -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | |
|  *    -- FixedTypeValueFieldSpec
 | |
|  *   } WITH SYNTAX {
 | |
|  *       SYNTAX &ExtnType IDENTIFIED BY &id
 | |
|  *       [CRITICALITY &Critical]
 | |
|  *   }
 | |
|  *
 | |
|  *-- <--------- ParameterizedTypeAssignment -------->
 | |
|  *   -- NOTE: The name of this type has to be Extension, really.
 | |
|  *   --       But the name of the Extension type with the actual
 | |
|  *   --       parameter provided also has to be Extension.
 | |
|  *   --       We could disallow that and require that the various
 | |
|  *   --       Extension types all have different names, then we'd
 | |
|  *   --       let the one with the actual parameter in PKIX be the
 | |
|  *   --       one named Extension.  Or we could find a way to let
 | |
|  *   --       them all share one symbol name, or at least two:
 | |
|  *   --       the one with the formal parameter, and just one with
 | |
|  *   --       an actual parameter.
 | |
|  *   --
 | |
|  *   --       Also, IMPORTing types that have formal parameters is
 | |
|  *   --       almost certainly going to require parsing the IMPORTed
 | |
|  *   --       module.  Until we do that, users will be able to work
 | |
|  *   --       around that by just copying CLASSes and pameterized
 | |
|  *   --       type definitions around.  But when we do start parsing
 | |
|  *   --       IMPORTed modules we might need to do something about
 | |
|  *   --       many types possibly having the same names, though we
 | |
|  *   --       might do nothing and simply say "don't do that!".
 | |
|  *   Extension{EXTENSION:ExtensionSet} ::= SEQUENCE {
 | |
|  *                    -- ^^^^^^^^^^^^
 | |
|  *                    -- is a DummyReference, which is a Reference, basically
 | |
|  *                    -- it is an object set variable which will have an object
 | |
|  *                    -- set value supplied where constrained types are defined
 | |
|  *                    -- from this one, possibly anonymous types where
 | |
|  *                    -- SEQUENCE/SET members of this type are defined.
 | |
|  *          -- ^^^^^^^^^
 | |
|  *          -- is a ParamGovernor, really, just Governor, either a Type or
 | |
|  *          -- DefinedObjectClass (we only need DefinedObjectClass)
 | |
|  *          -- ^^^^^^^^^^^^^^^^^^^^^^
 | |
|  *          -- is a Parameter
 | |
|  *         -- ^^^^^^^^^^^^^^^^^^^^^^^^
 | |
|  *         -- is a ParameterList (we need only support one param though)
 | |
|  *      extnID      EXTENSION.&id({ExtensionSet}),
 | |
|  *                            -- ^^^^^^^^^^^^^^^^
 | |
|  *                            -- simple table constraint limiting id to OIDs
 | |
|  *                            -- from ExtensionSet
 | |
|  *               -- ^^^^^^^^^^^^^
 | |
|  *               -- a reference to the id field of the EXTENSION CLASS
 | |
|  *      critical    BOOLEAN DEFAULT FALSE,
 | |
|  *      extnValue   OCTET STRING (CONTAINING
 | |
|  *                   -- ObjectClassFieldType
 | |
|  *                   -- vvvvvvvvvvvvvvvvvvv
 | |
|  *                      EXTENSION.&ExtnType({ExtensionSet}{@extnID}))
 | |
|  *                                                     -- ^^^^^^^^^
 | |
|  *                                                     -- AtNotation
 | |
|  *                                       -- ^^^^^^^^^^^^^^
 | |
|  *                                       -- DefinedObjectSet
 | |
|  *                                       -- ^^^^^^^^^^^^^^^^^^^^^^^^
 | |
|  *                                       -- ComponentRelationConstraint
 | |
|  *                                       -- says that extnValue will contain
 | |
|  *                                       -- a value of a type identified by
 | |
|  *                                       -- the OID in extnID in the object
 | |
|  *                                       -- set ExtensionSet (which is a set
 | |
|  *                                       -- of {OID, type} objects)
 | |
|  *                                      -- ^^^^^^^^^^^^^^^^^^^^^^^^^^
 | |
|  *                                      -- ConstraintSpec
 | |
|  *                   -- ^^^^^^^^^^^^^^^^^^^
 | |
|  *                   -- another type ref
 | |
|  *   }
 | |
|  *
 | |
|  * Then later we'll see (ParameterizedType, a part of DefinedType):
 | |
|  *
 | |
|  *   TBSCertificate  ::=  SEQUENCE  {
 | |
|  *      ...
 | |
|  *                        -- Here is where the object set is linked into the
 | |
|  *                        -- whole thing, making *magic* possible.  This is
 | |
|  *                        -- where the real Extensions type is defined.  Sadly
 | |
|  *                        -- this might mean we can't have a C type named
 | |
|  *                        -- Extensions.  Hmmm.  We might need an ASN.1
 | |
|  *                        -- extension that lets use do this:
 | |
|  *                        --
 | |
|  *                        --    Extension ::= Extension{{CertExtensions}}
 | |
|  *                        --
 | |
|  *                        -- or
 | |
|  *                        --
 | |
|  *                        --    Extension ::= ParameterizedExtension{{CertExtensions}}
 | |
|  *                        --
 | |
|  *                        -- and then rename the Extension type above to this.
 | |
|  *                        -- Then we can define Extensions as a SEQUENCE OF
 | |
|  *                        -- that.
 | |
|  *                        --
 | |
|  *                        -- <-   ParameterizedType    ->
 | |
|  *      extensions      [3]  Extensions{{CertExtensions}} OPTIONAL
 | |
|  *                                    -- ^^^^^^^^^^^^^^
 | |
|  *                                    -- ObjectSetSpec
 | |
|  *                                   -- ^^^^^^^^^^^^^^^^
 | |
|  *                                   -- ObjectSet
 | |
|  *                                  -- ^^^^^^^^^^^^^^^^^^
 | |
|  *                                  -- ActualParameterList
 | |
|  *                        -- ^^^^^^^^^^
 | |
|  *                        -- Type
 | |
|  *   }
 | |
|  *
 | |
|  * Then:
 | |
|  *
 | |
|  *   -- Object set, limits what Extensions can be in TBSCertificate.
 | |
|  *-- <-   ObjectSetAssignment    ->
 | |
|  *   CertExtensions EXTENSION ::= {
 | |
|  *               -- ^^^^^^^^^
 | |
|  *               -- DefinedObjectClass
 | |
|  *-- ^^^^^^^^^^^^^^
 | |
|  *-- objectsetreference, for us, IDENTIFIER
 | |
|  *      ext-AuthorityKeyIdentifier | ext-SubjectKeyIdentifier | ...
 | |
|  *   }
 | |
|  *
 | |
|  * and:
 | |
|  *
 | |
|  *   -- ObjectAssignment (with defined syntax, which we're not going to support):
 | |
|  *   --
 | |
|  *   -- Defines one particular object in the CertExtensions object set.
 | |
|  *   -- We don't need th SYNTAX bits though -- ETOOMUCHWORK.
 | |
|  *   -- This says that the OID id-ce-authorityKeyIdentifier means the extnValue
 | |
|  *   -- is a DER-encoded AuthorityKeyIdentifier.
 | |
|  *   ext-AuthorityKeyIdentifier EXTENSION ::= { SYNTAX
 | |
|  *       AuthorityKeyIdentifier IDENTIFIED BY
 | |
|  *       id-ce-authorityKeyIdentifier }
 | |
|  *   id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::=  { id-ce 35 }
 | |
|  *
 | |
|  *   -- ObjectAssignment (with default syntax):
 | |
|  *   ext-AuthorityKeyIdentifier EXTENSION ::= {
 | |
|  *       -- fields don't have to be in order since we have the field names
 | |
|  *       &extnId id-ce-authorityKeyIdentifier,
 | |
|  *       &extnValue AuthorityKeyIdentifier
 | |
|  *   }
 | |
|  *
 | |
|  *   -- Plain old type def using only X.680
 | |
|  *   AuthorityKeyIdentifier ::= SEQUENCE {
 | |
|  *       keyIdentifier             [0] KeyIdentifier            OPTIONAL,
 | |
|  *       authorityCertIssuer       [1] GeneralNames             OPTIONAL,
 | |
|  *       authorityCertSerialNumber [2] CertificateSerialNumber  OPTIONAL }
 | |
|  *
 | |
|  * In terms of compilation, we'll want to support only the template backend,
 | |
|  * though we'll generate the same C types for both, the template backend and
 | |
|  * the codegen backend.
 | |
|  *
 | |
|  * The generators should see a type for Extension that includes a) the
 | |
|  * parametrization (relating members in the SEQUENCE to fields in the CLASS),
 | |
|  * and b) the object set CertExtensions for the _same_ class.
 | |
|  *
 | |
|  *  - The C types for ASN.1 parametrized types with object set parameters
 | |
|  *    should be laid out just as before, but with additional fields:
 | |
|  *
 | |
|  *      typedef struct Extension {
 | |
|  *        heim_oid extnID;
 | |
|  *        int *critical;
 | |
|  *        heim_octet_string extnValue;
 | |
|  *        // NEW FIELDS BELOW
 | |
|  *        enum {
 | |
|  *          opentypechoice_unknown_Extension = 0
 | |
|  *          opentypechoice_Extension_id_ce_authorityKeyIdentifier,
 | |
|  *          ...
 | |
|  *        } _element;
 | |
|  *        union {
 | |
|  *          // er, what should this be named?! we have no name information
 | |
|  *          // and naming it after its object value name is probably not a good
 | |
|  *          // idea or not easy.  We do have the OID value and possible name
 | |
|  *          // though, so we should use that:
 | |
|  *          AuthorityKeyIdentifier id_ce_authorityKeyIdentifier;
 | |
|  *          ...
 | |
|  *        } _u;
 | |
|  *      } Extension;
 | |
|  *
 | |
|  * - The template for this should consist of new struct asn1_template entries
 | |
|  *   following the ones for the normal fields of Extension.  The first of these
 | |
|  *   should have an OP that indicates that the following N entries correspond
 | |
|  *   to the object set that specifies this open type, then the following N
 | |
|  *   entries should each point to an object in the object set.  Or maybe the
 | |
|  *   object set should be a separate template -- either way.  We'll also want a
 | |
|  *   flag to indicate whether the object set is sorted (none of the type IDs
 | |
|  *   are IMPORTed) or not (some of the type IDs are IMPORTed) so we can binary
 | |
|  *   search the object set at encode/decode time.
 | |
|  *
 | |
|  *   Hmm, we can assume the object sets are already sorted when there's
 | |
|  *   IMPORTed IDs -- the author can do it.  Yes, they're sets, but lexically
 | |
|  *   they must be in some order.
 | |
|  *
 | |
|  *   I like that, actually, requiring that the module author manually sort the
 | |
|  *   object sets, at least when they refer to type IDs that are IMPORTed.  Or
 | |
|  *   maybe forbid object sets that use IMPORTed type IDs -- the module author
 | |
|  *   can always copy their definitions anyways.
 | |
|  */
 | |
| 
 | |
| TypeAssignment	: Identifier EEQUAL Type
 | |
| 		{
 | |
| 		    Symbol *s = addsym($1);
 | |
| 		    s->stype = Stype;
 | |
| 		    s->type = $3;
 | |
| 		    fix_labels(s);
 | |
| 
 | |
| 		    /*
 | |
| 		     * Hack: make sure that non-anonymous enumeration types get
 | |
| 		     * a symbol tacked on so we can generate a template for
 | |
| 		     * their members for value printing.
 | |
| 		     */
 | |
| 		    if (s->type->type == TTag && $3->symbol == NULL &&
 | |
| 			$3->subtype != NULL && $3->subtype->type == TInteger &&
 | |
| 			$3->subtype->symbol == NULL) {
 | |
| 			$3->subtype->symbol = s;
 | |
| 		    }
 | |
| 		    if (original_order)
 | |
| 			generate_type(s);
 | |
| 		    else
 | |
| 			generate_type_header_forwards(s);
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| ParameterizedTypeAssignment
 | |
| 		/* For now we'll only support one parameter -- enough for PKIX */
 | |
| 		: Identifier '{' Parameter '}' EEQUAL Type
 | |
| 		{
 | |
| 		    char *pname = NULL;
 | |
| 		    Symbol *s;
 | |
| 
 | |
| 		    if (asprintf(&pname, "%s{%s:x}", $1, $3->symbol->name) == -1 ||
 | |
| 			pname == NULL)
 | |
| 			err(1, "Out of memory");
 | |
| 		    s = addsym(pname);
 | |
| 		    free($1);
 | |
| 		    s->stype = Sparamtype;
 | |
| 		    s->type = parametrize_type($6, $3);
 | |
| 		    s->type->symbol = s;
 | |
| 		    fix_labels(s);
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| /*
 | |
|  * We're not going to support governor variables for now.  We don't need to.
 | |
|  *
 | |
|  * Also, we're not going to support more than one formal parameter.
 | |
|  * Correspondingly we'll only support a single actual parameter (the count of
 | |
|  * formal and actual parameters has to match, naturally).
 | |
|  */
 | |
| 
 | |
| Parameter       : ParamGovernor ':' DummyReference
 | |
| 		{ $$ = $1; };
 | |
| 	     /* | DummyReference */
 | |
| 		;
 | |
| 
 | |
| DummyReference  : TYPE_IDENTIFIER { $$ = idcounter++; };
 | |
| 
 | |
| ParamGovernor   : DefinedObjectClass
 | |
| 		{ $$ = $1; }
 | |
| 	     /* | DummyGovernor */
 | |
| 	     /* | Type */
 | |
| 		;
 | |
| 
 | |
| UnconstrainedType : BitStringType
 | |
|                   | BooleanType
 | |
|                   | CharacterStringType
 | |
|                   | ChoiceType
 | |
|                   | EnumeratedType
 | |
|                   | IntegerType
 | |
|                   | NullType
 | |
|                   | ObjectIdentifierType
 | |
|                   | OctetStringType
 | |
|                   | SequenceType
 | |
|                   | SetType
 | |
|                   | ObjectClassFieldType; /* X.681 */
 | |
| 
 | |
| Type		: BuiltinType | ReferencedType | ConstrainedType ;
 | |
| 
 | |
| BuiltinType	: BitStringType
 | |
| 		| BooleanType
 | |
| 		| CharacterStringType
 | |
| 		| ChoiceType
 | |
| 		| EnumeratedType
 | |
| 		| IntegerType
 | |
| 		| NullType
 | |
| 		| ObjectIdentifierType
 | |
| 		| OctetStringType
 | |
| 		| SequenceType
 | |
| 		| SequenceOfType
 | |
| 		| SetType
 | |
| 		| SetOfType
 | |
| 		| TaggedType
 | |
| 		| ObjectClassFieldType  /* X.681 */
 | |
| 	     /* | InstanceOfType        // X.681 */
 | |
| 		;
 | |
| 
 | |
| ObjectClassFieldType
 | |
| 		: DefinedObjectClass '.' '&' Identifier
 | |
| 		{ $$ = type_from_class_field($1, $4); };
 | |
| 
 | |
| BooleanType	: kw_BOOLEAN
 | |
| 		{
 | |
| 			$$ = new_tag(ASN1_C_UNIV, UT_Boolean,
 | |
| 				     TE_EXPLICIT, new_type(TBoolean));
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
|              /*
 | |
|               * The spec says the values in a ValueRange are Values, but a) all
 | |
|               * the various value ranges do not involve OBJECT IDENTIFIER, b)
 | |
|               * we only support integer value ranges at this time (as opposed
 | |
|               * to, e.g., time ranges, and we don't even support time values at
 | |
|               * this time), c) allowing OBJECT IDENTIFIER here causes a
 | |
|               * shift-reduce conflict, so we limit ourselves to integer values
 | |
|               * in ranges.  We could always define IntegerValueRange,
 | |
|               * TimeValueRange, etc. when we add support for more value types.
 | |
|               */
 | |
| range		: IntegerValue RANGE IntegerValue
 | |
| 		{
 | |
| 		    if($1->type != integervalue)
 | |
| 			lex_error_message("Non-integer used in first part of range");
 | |
| 		    if($1->type != integervalue)
 | |
| 			lex_error_message("Non-integer in second part of range");
 | |
| 		    $$ = ecalloc(1, sizeof(*$$));
 | |
| 		    $$->min = $1->u.integervalue;
 | |
| 		    $$->max = $3->u.integervalue;
 | |
| 		}
 | |
| 		| IntegerValue RANGE kw_MAX
 | |
| 		{
 | |
| 		    if($1->type != integervalue)
 | |
| 			lex_error_message("Non-integer in first part of range");
 | |
| 		    $$ = ecalloc(1, sizeof(*$$));
 | |
| 		    $$->min = $1->u.integervalue;
 | |
| 		    $$->max = INT_MAX;
 | |
| 		}
 | |
| 		| kw_MIN RANGE IntegerValue
 | |
| 		{
 | |
| 		    if($3->type != integervalue)
 | |
| 			lex_error_message("Non-integer in second part of range");
 | |
| 		    $$ = ecalloc(1, sizeof(*$$));
 | |
| 		    $$->min = INT_MIN;
 | |
| 		    $$->max = $3->u.integervalue;
 | |
| 		}
 | |
| 		| IntegerValue
 | |
| 		{
 | |
| 		    if($1->type != integervalue)
 | |
| 			lex_error_message("Non-integer used in limit");
 | |
| 		    $$ = ecalloc(1, sizeof(*$$));
 | |
| 		    $$->min = $1->u.integervalue;
 | |
| 		    $$->max = $1->u.integervalue;
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| 
 | |
| IntegerType	: kw_INTEGER
 | |
| 		{
 | |
| 			$$ = new_tag(ASN1_C_UNIV, UT_Integer,
 | |
| 				     TE_EXPLICIT, new_type(TInteger));
 | |
| 		}
 | |
| 		| kw_INTEGER '{' NamedNumberList '}'
 | |
| 		{
 | |
| 		  $$ = new_type(TInteger);
 | |
| 		  $$->members = $3;
 | |
| 		  $$ = new_tag(ASN1_C_UNIV, UT_Integer, TE_EXPLICIT, $$);
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| NamedNumberList	: NamedNumber
 | |
| 		{
 | |
| 			$$ = emalloc(sizeof(*$$));
 | |
| 			HEIM_TAILQ_INIT($$);
 | |
| 			HEIM_TAILQ_INSERT_HEAD($$, $1, members);
 | |
| 		}
 | |
| 		| NamedNumberList ',' NamedNumber
 | |
| 		{
 | |
| 			HEIM_TAILQ_INSERT_TAIL($1, $3, members);
 | |
| 			$$ = $1;
 | |
| 		}
 | |
| 		| NamedNumberList ',' ELLIPSIS
 | |
| 			{ $$ = $1; } /* XXX used for Enumerations */
 | |
| 		;
 | |
| 
 | |
| NamedNumber	: Identifier '(' SignedNumber ')'
 | |
| 		{
 | |
| 			$$ = emalloc(sizeof(*$$));
 | |
| 			$$->name = $1;
 | |
| 			$$->gen_name = estrdup($1);
 | |
| 			output_name ($$->gen_name);
 | |
| 			$$->val = $3;
 | |
| 			$$->optional = 0;
 | |
| 			$$->ellipsis = 0;
 | |
| 			$$->type = NULL;
 | |
| 		}
 | |
| 		| Identifier '(' DefinedValue ')'
 | |
| 		{
 | |
| 			if ($3->type != integervalue)
 | |
| 			    lex_error_message("Named number %s not a numeric value",
 | |
| 					      $3->s->name);
 | |
| 			$$ = emalloc(sizeof(*$$));
 | |
| 			$$->name = $1;
 | |
| 			$$->gen_name = estrdup($1);
 | |
| 			output_name ($$->gen_name);
 | |
| 			$$->val = $3->u.integervalue;
 | |
| 			$$->optional = 0;
 | |
| 			$$->ellipsis = 0;
 | |
| 			$$->type = NULL;
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| EnumeratedType	: kw_ENUMERATED '{' Enumerations '}'
 | |
| 		{
 | |
| 		  $$ = new_type(TInteger);
 | |
| 		  $$->members = $3;
 | |
| 		  $$ = new_tag(ASN1_C_UNIV, UT_Enumerated, TE_EXPLICIT, $$);
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| Enumerations	: NamedNumberList /* XXX */
 | |
| 		;
 | |
| 
 | |
| BitStringType	: kw_BIT kw_STRING
 | |
| 		{
 | |
| 		  $$ = new_type(TBitString);
 | |
| 		  $$->members = emalloc(sizeof(*$$->members));
 | |
| 		  HEIM_TAILQ_INIT($$->members);
 | |
| 		  $$ = new_tag(ASN1_C_UNIV, UT_BitString, TE_EXPLICIT, $$);
 | |
| 		}
 | |
| 		| kw_BIT kw_STRING '{' NamedBitList '}'
 | |
| 		{
 | |
| 		  $$ = new_type(TBitString);
 | |
| 		  $$->members = $4;
 | |
| 		  $$ = new_tag(ASN1_C_UNIV, UT_BitString, TE_EXPLICIT, $$);
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| ObjectIdentifierType: kw_OBJECT kw_IDENTIFIER
 | |
| 		{
 | |
| 			$$ = new_tag(ASN1_C_UNIV, UT_OID,
 | |
| 				     TE_EXPLICIT, new_type(TOID));
 | |
| 		}
 | |
| 		;
 | |
| OctetStringType	: kw_OCTET kw_STRING size
 | |
| 		{
 | |
| 		    Type *t = new_type(TOctetString);
 | |
| 		    t->range = $3;
 | |
| 		    if (t->range) {
 | |
| 			if (t->range->min < 0)
 | |
| 			    lex_error_message("can't use a negative SIZE range "
 | |
| 					      "length for OCTET STRING");
 | |
| 		    }
 | |
| 		    $$ = new_tag(ASN1_C_UNIV, UT_OctetString,
 | |
| 				 TE_EXPLICIT, t);
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| NullType	: kw_NULL
 | |
| 		{
 | |
| 			$$ = new_tag(ASN1_C_UNIV, UT_Null,
 | |
| 				     TE_EXPLICIT, new_type(TNull));
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| size		:
 | |
| 		{ $$ = NULL; }
 | |
| 		| kw_SIZE '(' range ')'
 | |
| 		{ $$ = $3; }
 | |
| 		;
 | |
| 
 | |
| 
 | |
| SequenceType	: kw_SEQUENCE '{' /* ComponentTypeLists */ ComponentTypeList '}'
 | |
| 		{
 | |
| 		  $$ = new_type(TSequence);
 | |
| 		  $$->members = $3;
 | |
| 		  $$ = new_tag(ASN1_C_UNIV, UT_Sequence, default_tag_env, $$);
 | |
| 		}
 | |
| 		| kw_SEQUENCE '{' '}'
 | |
| 		{
 | |
| 		  $$ = new_type(TSequence);
 | |
| 		  $$->members = NULL;
 | |
| 		  $$ = new_tag(ASN1_C_UNIV, UT_Sequence, default_tag_env, $$);
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| SequenceOfType	: kw_SEQUENCE size kw_OF Type
 | |
| 		{
 | |
| 		  $$ = new_type(TSequenceOf);
 | |
| 		  $$->range = $2;
 | |
| 		  if ($$->range) {
 | |
| 		      if ($$->range->min < 0)
 | |
| 			  lex_error_message("can't use a negative SIZE range "
 | |
| 					    "length for SEQUENCE OF");
 | |
| 		    }
 | |
| 
 | |
| 		  $$->subtype = $4;
 | |
| 		  $$ = new_tag(ASN1_C_UNIV, UT_Sequence, default_tag_env, $$);
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| SetType		: kw_SET '{' /* ComponentTypeLists */ ComponentTypeList '}'
 | |
| 		{
 | |
| 		  $$ = new_type(TSet);
 | |
| 		  $$->members = $3;
 | |
| 		  $$ = new_tag(ASN1_C_UNIV, UT_Set, default_tag_env, $$);
 | |
| 		}
 | |
| 		| kw_SET '{' '}'
 | |
| 		{
 | |
| 		  $$ = new_type(TSet);
 | |
| 		  $$->members = NULL;
 | |
| 		  $$ = new_tag(ASN1_C_UNIV, UT_Set, default_tag_env, $$);
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| SetOfType	: kw_SET kw_OF Type
 | |
| 		{
 | |
| 		  $$ = new_type(TSetOf);
 | |
| 		  $$->subtype = $3;
 | |
| 		  $$ = new_tag(ASN1_C_UNIV, UT_Set, default_tag_env, $$);
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| ChoiceType	: kw_CHOICE '{' /* AlternativeTypeLists */ ComponentTypeList '}'
 | |
| 		{
 | |
| 		  $$ = new_type(TChoice);
 | |
| 		  $$->members = $3;
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| ReferencedType	: DefinedType
 | |
| 		| UsefulType
 | |
| 	     /* | TypeFromObject           // X.681 */
 | |
| 	     /* | ValueSetFromObjects      // X.681 */
 | |
| 		;
 | |
| 
 | |
| /*
 | |
| TypeFromObject	: VALUE_IDENTIFIER '.' '&' TYPE_IDENTIFIER
 | |
| 		{ $$ = type_from_object($1, $4); };
 | |
|  */
 | |
| 
 | |
| DefinedType	: TYPE_IDENTIFIER
 | |
| 		{
 | |
| 		  Symbol *s = addsym($1);
 | |
| 		  $$ = new_type(TType);
 | |
| 		  if(s->stype != Stype && s->stype != SUndefined)
 | |
| 		    lex_error_message ("%s is not a type\n", $1);
 | |
| 		  else
 | |
| 		    $$->symbol = s;
 | |
| 		}
 | |
| 		| ParameterizedType
 | |
| 		{ $$ = $1; }
 | |
| 		;
 | |
| 
 | |
| 		/*
 | |
|                  * Should be ActualParameterList, but we'll do just one for now
 | |
|                  * as that's enough for PKIX.
 | |
| 		 */
 | |
| ParameterizedType
 | |
| 		: Identifier '{' ActualParameter '}' /* XXX ActualParameterList */
 | |
| 		{
 | |
| 		  Symbol *s, *ps;
 | |
| 		  char *pname = NULL;
 | |
| 
 | |
| 		  if ($3 == NULL) {
 | |
|                     lex_error_message("Unknown ActualParameter object set parametrizing %s\n", $1);
 | |
|                     exit(1);
 | |
|                   }
 | |
| 
 | |
| 		  /* Lookup the type from a ParameterizedTypeAssignment */
 | |
| 		  if (asprintf(&pname, "%s{%s:x}", $1,
 | |
| 			       $3->iosclass->symbol->name) == -1 ||
 | |
| 		      pname == NULL)
 | |
| 		      err(1, "Out of memory");
 | |
| 		  ps = addsym(pname);
 | |
| 		  if (ps->stype != Sparamtype)
 | |
| 		    lex_error_message ("%s is not a parameterized type\n", $1);
 | |
| 
 | |
| 		  s = addsym($1);
 | |
| 		  $$ = ps->type; /* XXX copy, probably */
 | |
| 		  if (!ps->type)
 | |
| 		    errx(1, "Wrong class (%s) parameter for parameterized "
 | |
| 		         "type %s", $3->iosclass->symbol->name, $1);
 | |
| 		  s->stype = Stype;
 | |
| 		  if(s->stype != Stype && s->stype != SUndefined)
 | |
| 		    lex_error_message ("%s is not a type\n", $1);
 | |
| 		  else
 | |
| 		    $$->symbol = s;
 | |
| 		  $$->actual_parameter = $3;
 | |
| 		  if ($$->type == TTag)
 | |
| 		    $$->subtype->actual_parameter = $3;
 | |
| 		}
 | |
| 
 | |
| /*
 | |
|  * Per X.683 $1 for ActualParameter should be any of: a Type, a Value, a
 | |
|  * ValueSet, a DefinedObjectClass, an Object, or an ObjectSet.  For PKIX we
 | |
|  * need nothing more than an ObjectSet here.
 | |
|  *
 | |
|  * Also, we can't lexically or syntactically tell the difference between all
 | |
|  * these things, though fortunately we can for ObjectSet.
 | |
|  */
 | |
| ActualParameter : DefinedObjectSet
 | |
| 		{ $$ = $1; };
 | |
| 
 | |
| UsefulType	: kw_GeneralizedTime
 | |
| 		{
 | |
| 			$$ = new_tag(ASN1_C_UNIV, UT_GeneralizedTime,
 | |
| 				     TE_EXPLICIT, new_type(TGeneralizedTime));
 | |
| 		}
 | |
| 		| kw_UTCTime
 | |
| 		{
 | |
| 			$$ = new_tag(ASN1_C_UNIV, UT_UTCTime,
 | |
| 				     TE_EXPLICIT, new_type(TUTCTime));
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| ConstrainedType	: UnconstrainedType Constraint
 | |
| 		{
 | |
| 		    $$ = $1;
 | |
|                     if ($2->ctype == CT_RANGE) {
 | |
|                         if ($1->type != TTag || $1->subtype->type != TInteger)
 | |
|                             lex_error_message("RANGE constraints apply only to INTEGER types");
 | |
|                         $$->subtype->range = $2->u.range;
 | |
|                         free($2);
 | |
|                     } else {
 | |
|                         $$->constraint = $2;
 | |
|                     }
 | |
| 		    /* if (Constraint.type == contentConstraint) {
 | |
| 		       assert(Constraint.u.constraint.type == octetstring|bitstring-w/o-NamedBitList); // remember to check type reference too
 | |
| 		       if (Constraint.u.constraint.type) {
 | |
| 		         assert((Constraint.u.constraint.type.length % 8) == 0);
 | |
| 		       }
 | |
| 		      }
 | |
| 		      if (Constraint.u.constraint.encoding) {
 | |
| 		        type == der-oid|ber-oid
 | |
| 		      }
 | |
| 		    */
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| 
 | |
| Constraint	: '(' ConstraintSpec ')'
 | |
| 		{
 | |
| 		    $$ = $2;
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| ConstraintSpec	: SubtypeConstraint | GeneralConstraint
 | |
| 		;
 | |
| 
 | |
| SubtypeConstraint: range
 | |
| 		{
 | |
|                         $$ = new_constraint_spec(CT_RANGE);
 | |
|                         $$->u.range = $1;
 | |
| 		}
 | |
| 
 | |
| GeneralConstraint: ContentsConstraint
 | |
| 		| UserDefinedConstraint
 | |
| 		| TableConstraint
 | |
| 		;
 | |
| 
 | |
| ContentsConstraint: kw_CONTAINING Type
 | |
| 		{
 | |
| 		    $$ = new_constraint_spec(CT_CONTENTS);
 | |
| 		    $$->u.content.type = $2;
 | |
| 		    $$->u.content.encoding = NULL;
 | |
| 		}
 | |
| 		| kw_ENCODED kw_BY Value
 | |
| 		{
 | |
| 		    if ($3->type != objectidentifiervalue)
 | |
| 			lex_error_message("Non-OID used in ENCODED BY constraint");
 | |
| 		    $$ = new_constraint_spec(CT_CONTENTS);
 | |
| 		    $$->u.content.type = NULL;
 | |
| 		    $$->u.content.encoding = $3;
 | |
| 		}
 | |
| 		| kw_CONTAINING Type kw_ENCODED kw_BY Value
 | |
| 		{
 | |
| 		    if ($5->type != objectidentifiervalue)
 | |
| 			lex_error_message("Non-OID used in ENCODED BY constraint");
 | |
| 		    $$ = new_constraint_spec(CT_CONTENTS);
 | |
| 		    $$->u.content.type = $2;
 | |
| 		    $$->u.content.encoding = $5;
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| UserDefinedConstraint: kw_CONSTRAINED kw_BY '{' '}'
 | |
| 		{
 | |
| 		    $$ = new_constraint_spec(CT_USER);
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| TableConstraint : SimpleTableConstraint
 | |
| 		{ $$ = $1; }
 | |
| 		| ComponentRelationConstraint
 | |
| 		{ $$ = $1; };
 | |
| 
 | |
| SimpleTableConstraint
 | |
| 		: '{' TYPE_IDENTIFIER '}'
 | |
| 		{
 | |
| 		    $$ = ecalloc(1, sizeof(*$$));
 | |
| 		    $$->ctype = CT_TABLE_CONSTRAINT;
 | |
| 		    $$->u.content.crel.objectname = $2;
 | |
| 		    $$->u.content.crel.membername = 0;
 | |
| 		};
 | |
| 
 | |
| /*
 | |
|  * In X.682, ComponentRelationConstraint is a fantastically more complicated
 | |
|  * production.  The stuff in the second set of braces is a list of AtNotation,
 | |
|  * and AtNotation is '@' followed by some number of '.'s, followed by a
 | |
|  * ComponentIdList, which is a non-empty set of identifiers separated by '.'s.
 | |
|  * The number of '.'s is a "level" used to identify a SET, SEQUENCE, or CHOICE
 | |
|  * where the path of member identifiers is rooted that ultimately identifies
 | |
|  * the field providing the constraint.
 | |
|  *
 | |
|  * So in
 | |
|  *
 | |
|  *  extnValue   OCTET STRING
 | |
|  *    (CONTAINING
 | |
|  *	EXTENSION.&ExtnType({ExtensionSet}{@extnID}))
 | |
|  *	^^^^^^^^^^^^^^^^^^^
 | |
|  *	ObjectClassFieldType
 | |
|  *	meaning the open type field
 | |
|  *	&ExtnType of EXTENSION
 | |
|  *	                   ^^^^^^^^^^^^^^^^^^^^^^^^^
 | |
|  *	                   GeneralConstraint
 | |
|  *	                    ^^^^^^^^^^^^^^^^^^^^^^^
 | |
|  *	                    ComponentRelationConstraint
 | |
|  *	                    ^^^^^^^^^^^^^^
 | |
|  *	                    DefinedObjectSet
 | |
|  *	                                  ^^^^^^^^
 | |
|  *	                                   '{' AtNotation ','  +  '}'
 | |
|  *
 | |
|  * we have EXTENSION.&ExtnType is the ObjectClassFieldType, and
 | |
|  * ({ExtensionSet}{@extnID}) is the ComponentRelationConstraint on the
 | |
|  * extnValue member, where {ExtensionSet} is the DummyReference from the formal
 | |
|  * parameter of the enclosing parameterized type, and {@extnID} is the
 | |
|  * AtNotation list identifying the field of the class/objects-in-the-object-set
 | |
|  * that will be identifying the type of the extnValue field.
 | |
|  *
 | |
|  * We need just the one AtNotation component.
 | |
|  */
 | |
| ComponentRelationConstraint
 | |
| 		: '{' TYPE_IDENTIFIER '}' '{' '@' Identifier '}'
 | |
| 		{
 | |
| 		    $$ = ecalloc(1, sizeof(*$$));
 | |
| 		    $$->ctype = CT_TABLE_CONSTRAINT;
 | |
| 		    $$->u.content.crel.objectname = $2;
 | |
| 		    $$->u.content.crel.membername = $6;
 | |
| 		};
 | |
| 
 | |
| TaggedType	: Tag tagenv Type
 | |
| 		{
 | |
| 			$$ = new_type(TTag);
 | |
| 			$$->tag = $1;
 | |
| 			$$->tag.tagenv = $2;
 | |
| 			if (template_flag) {
 | |
| 			    $$->subtype = $3;
 | |
| 			} else if ($2 == TE_IMPLICIT) {
 | |
| 			    Type *t = $3;
 | |
| 
 | |
| 			    /*
 | |
| 			     * FIXME We shouldn't do this... The logic for
 | |
| 			     * dealing with IMPLICIT tags belongs elsewhere.
 | |
| 			     */
 | |
| 			    while (t->type == TType) {
 | |
| 				if (t->subtype)
 | |
| 				    t = t->subtype;
 | |
| 				else if (t->symbol && t->symbol->type)
 | |
| 				    t = t->symbol->type;
 | |
| 				else
 | |
| 				    break;
 | |
| 			    }
 | |
| 			    /*
 | |
| 			     * IMPLICIT tags of CHOICE types are EXPLICIT
 | |
| 			     * instead.
 | |
| 			     */
 | |
| 			    if (t->type == TChoice) {
 | |
| 				$$->implicit_choice = 1;
 | |
| 				$$->tag.tagenv = TE_EXPLICIT;
 | |
| 			    }
 | |
| 			    if($3->type == TTag && $2 == TE_IMPLICIT) {
 | |
| 				$$->subtype = $3->subtype;
 | |
| 				free($3);
 | |
| 			    } else {
 | |
| 				$$->subtype = $3;
 | |
| 			    }
 | |
| 			} else {
 | |
| 			    $$->subtype = $3;
 | |
| 			}
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| Tag		: '[' Class NUMBER ']'
 | |
| 		{
 | |
| 			$$.tagclass = $2;
 | |
| 			$$.tagvalue = $3;
 | |
| 			$$.tagenv = default_tag_env;
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| Class		: /* */
 | |
| 		{
 | |
| 			$$ = ASN1_C_CONTEXT;
 | |
| 		}
 | |
| 		| kw_UNIVERSAL
 | |
| 		{
 | |
| 			$$ = ASN1_C_UNIV;
 | |
| 		}
 | |
| 		| kw_APPLICATION
 | |
| 		{
 | |
| 			$$ = ASN1_C_APPL;
 | |
| 		}
 | |
| 		| kw_PRIVATE
 | |
| 		{
 | |
| 			$$ = ASN1_C_PRIVATE;
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| tagenv		: /* */
 | |
| 		{
 | |
| 			$$ = default_tag_env;
 | |
| 		}
 | |
| 		| kw_EXPLICIT
 | |
| 		{
 | |
| 			$$ = default_tag_env;
 | |
| 		}
 | |
| 		| kw_IMPLICIT
 | |
| 		{
 | |
| 			$$ = TE_IMPLICIT;
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| 
 | |
| ValueAssignment	: VALUE_IDENTIFIER Type EEQUAL Value
 | |
| 		{
 | |
| 			Symbol *s;
 | |
| 			s = addsym ($1);
 | |
| 
 | |
| 			s->stype = SValue;
 | |
| 			s->value = $4;
 | |
| 			generate_constant (s);
 | |
| 			/*
 | |
| 			 * Save this value's name so we can know some name for
 | |
| 			 * this value wherever _a_ name may be needed for it.
 | |
| 			 *
 | |
| 			 * This is useful for OIDs used as type IDs in objects
 | |
| 			 * sets of classes with open types.  We'll generate
 | |
| 			 * enum labels from those OIDs' names.
 | |
| 			 */
 | |
|                         s->value->s = s;
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| CharacterStringType: RestrictedCharactedStringType
 | |
| 		;
 | |
| 
 | |
| RestrictedCharactedStringType: kw_GeneralString
 | |
| 		{
 | |
| 			$$ = new_tag(ASN1_C_UNIV, UT_GeneralString,
 | |
| 				     TE_EXPLICIT, new_type(TGeneralString));
 | |
| 		}
 | |
| 		| kw_TeletexString
 | |
| 		{
 | |
| 			$$ = new_tag(ASN1_C_UNIV, UT_TeletexString,
 | |
| 				     TE_EXPLICIT, new_type(TTeletexString));
 | |
| 		}
 | |
| 		| kw_UTF8String
 | |
| 		{
 | |
| 			$$ = new_tag(ASN1_C_UNIV, UT_UTF8String,
 | |
| 				     TE_EXPLICIT, new_type(TUTF8String));
 | |
| 		}
 | |
| 		| kw_PrintableString
 | |
| 		{
 | |
| 			$$ = new_tag(ASN1_C_UNIV, UT_PrintableString,
 | |
| 				     TE_EXPLICIT, new_type(TPrintableString));
 | |
| 		}
 | |
| 		| kw_VisibleString
 | |
| 		{
 | |
| 			$$ = new_tag(ASN1_C_UNIV, UT_VisibleString,
 | |
| 				     TE_EXPLICIT, new_type(TVisibleString));
 | |
| 		}
 | |
| 		| kw_IA5String
 | |
| 		{
 | |
| 			$$ = new_tag(ASN1_C_UNIV, UT_IA5String,
 | |
| 				     TE_EXPLICIT, new_type(TIA5String));
 | |
| 		}
 | |
| 		| kw_BMPString
 | |
| 		{
 | |
| 			$$ = new_tag(ASN1_C_UNIV, UT_BMPString,
 | |
| 				     TE_EXPLICIT, new_type(TBMPString));
 | |
| 		}
 | |
| 		| kw_UniversalString
 | |
| 		{
 | |
| 			$$ = new_tag(ASN1_C_UNIV, UT_UniversalString,
 | |
| 				     TE_EXPLICIT, new_type(TUniversalString));
 | |
| 		}
 | |
| 
 | |
| 		;
 | |
| 
 | |
| ComponentTypeList: ComponentType
 | |
| 		{
 | |
| 			$$ = emalloc(sizeof(*$$));
 | |
| 			HEIM_TAILQ_INIT($$);
 | |
| 			HEIM_TAILQ_INSERT_HEAD($$, $1, members);
 | |
| 		}
 | |
| 		| ComponentTypeList ',' ComponentType
 | |
| 		{
 | |
| 			HEIM_TAILQ_INSERT_TAIL($1, $3, members);
 | |
| 			$$ = $1;
 | |
| 		}
 | |
| 		| ComponentTypeList ',' ELLIPSIS
 | |
| 		{
 | |
| 		        struct member *m = ecalloc(1, sizeof(*m));
 | |
| 			m->name = estrdup("...");
 | |
| 			m->gen_name = estrdup("asn1_ellipsis");
 | |
| 			m->ellipsis = 1;
 | |
| 			HEIM_TAILQ_INSERT_TAIL($1, m, members);
 | |
| 			$$ = $1;
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| NamedType	: Identifier Type
 | |
| 		{
 | |
| 		  $$ = emalloc(sizeof(*$$));
 | |
| 		  $$->name = $1;
 | |
| 		  $$->gen_name = estrdup($1);
 | |
| 		  output_name ($$->gen_name);
 | |
| 		  $$->type = $2;
 | |
| 		  $$->ellipsis = 0;
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| ComponentType	: NamedType
 | |
| 		{
 | |
| 			$$ = $1;
 | |
| 			$$->optional = 0;
 | |
| 			$$->defval = NULL;
 | |
| 		}
 | |
| 		| NamedType kw_OPTIONAL
 | |
| 		{
 | |
| 			$$ = $1;
 | |
| 			$$->optional = 1;
 | |
| 			$$->defval = NULL;
 | |
| 		}
 | |
| 		| NamedType kw_DEFAULT Value
 | |
| 		{
 | |
| 			$$ = $1;
 | |
| 			$$->optional = 0;
 | |
| 			$$->defval = $3;
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| NamedBitList	: NamedBit
 | |
| 		{
 | |
| 			$$ = emalloc(sizeof(*$$));
 | |
| 			HEIM_TAILQ_INIT($$);
 | |
| 			HEIM_TAILQ_INSERT_HEAD($$, $1, members);
 | |
| 		}
 | |
| 		| NamedBitList ',' NamedBit
 | |
| 		{
 | |
| 			HEIM_TAILQ_INSERT_TAIL($1, $3, members);
 | |
| 			$$ = $1;
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| NamedBit	: Identifier '(' NUMBER ')'
 | |
| 		{
 | |
| 		  $$ = emalloc(sizeof(*$$));
 | |
| 		  $$->name = $1;
 | |
| 		  $$->gen_name = estrdup($1);
 | |
| 		  output_name ($$->gen_name);
 | |
| 		  $$->val = $3;
 | |
| 		  $$->optional = 0;
 | |
| 		  $$->ellipsis = 0;
 | |
| 		  $$->type = NULL;
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| objid_opt	: objid
 | |
| 		| /* empty */ { $$ = NULL; }
 | |
| 		;
 | |
| 
 | |
| objid		: '{' objid_list '}'
 | |
| 		{
 | |
| 			$$ = $2;
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| objid_list	:  /* empty */
 | |
| 		{
 | |
| 			$$ = NULL;
 | |
| 		}
 | |
| 		| objid_element objid_list
 | |
| 		{
 | |
| 		        if ($2) {
 | |
| 				$$ = $2;
 | |
| 				add_oid_to_tail($2, $1);
 | |
| 			} else {
 | |
| 				$$ = $1;
 | |
| 			}
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| objid_element	: Identifier '(' NUMBER ')'
 | |
| 		{
 | |
| 			$$ = new_objid($1, $3);
 | |
| 		}
 | |
| 		| Identifier
 | |
| 		{
 | |
| 		    Symbol *s = addsym($1);
 | |
| 		    if(s->stype != SValue ||
 | |
| 		       s->value->type != objectidentifiervalue) {
 | |
| 			lex_error_message("%s is not an object identifier\n",
 | |
| 				      s->name);
 | |
| 			exit(1);
 | |
| 		    }
 | |
| 		    $$ = s->value->u.objectidentifiervalue;
 | |
| 		}
 | |
| 		| NUMBER
 | |
| 		{
 | |
| 		    $$ = new_objid(NULL, $1);
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| Value		: BuiltinValue
 | |
| 		| ReferencedValue
 | |
| 		;
 | |
| 
 | |
| ValueExNull	: BuiltinValueExNull
 | |
| 		| ReferencedValue
 | |
| 		;
 | |
| 
 | |
| BuiltinValue	: BooleanValue
 | |
| 		| CharacterStringValue
 | |
| 		| IntegerValue
 | |
| 		| ObjectIdentifierValue
 | |
| 		| NullValue
 | |
| 		;
 | |
| 
 | |
| BuiltinValueExNull
 | |
| 		: BooleanValue
 | |
| 		| CharacterStringValue
 | |
| 		| IntegerValue
 | |
| 		| ObjectIdentifierValue
 | |
| 		;
 | |
| 
 | |
| ReferencedValue	: DefinedValue
 | |
| 		;
 | |
| 
 | |
| DefinedValue	: Valuereference
 | |
| 		;
 | |
| 
 | |
| Valuereference	: VALUE_IDENTIFIER
 | |
| 		{
 | |
| 			Symbol *s = addsym($1);
 | |
| 			if(s->stype != SValue)
 | |
| 				lex_error_message ("%s is not a value\n",
 | |
| 						s->name);
 | |
| 			else
 | |
| 				$$ = s->value;
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| CharacterStringValue: STRING
 | |
| 		{
 | |
| 			$$ = emalloc(sizeof(*$$));
 | |
| 			$$->type = stringvalue;
 | |
| 			$$->u.stringvalue = $1;
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| BooleanValue	: kw_TRUE
 | |
| 		{
 | |
| 			$$ = emalloc(sizeof(*$$));
 | |
| 			$$->type = booleanvalue;
 | |
| 			$$->u.booleanvalue = 1;
 | |
| 		}
 | |
| 		| kw_FALSE
 | |
| 		{
 | |
| 			$$ = emalloc(sizeof(*$$));
 | |
| 			$$->type = booleanvalue;
 | |
| 			$$->u.booleanvalue = 0;
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| IntegerValue	: SignedNumber
 | |
| 		{
 | |
| 			$$ = emalloc(sizeof(*$$));
 | |
| 			$$->type = integervalue;
 | |
| 			$$->u.integervalue = $1;
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| SignedNumber	: NUMBER
 | |
| 		;
 | |
| 
 | |
| NullValue	: kw_NULL
 | |
| 		{
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| ObjectIdentifierValue: objid
 | |
| 		{
 | |
| 			$$ = emalloc(sizeof(*$$));
 | |
| 			$$->type = objectidentifiervalue;
 | |
| 			$$->u.objectidentifiervalue = $1;
 | |
| 		}
 | |
| 		;
 | |
| 
 | |
| %%
 | |
| 
 | |
| void
 | |
| yyerror (const char *s)
 | |
| {
 | |
|      lex_error_message ("%s\n", s);
 | |
| }
 | |
| 
 | |
| static Type *
 | |
| new_tag(int tagclass, int tagvalue, int tagenv, Type *oldtype)
 | |
| {
 | |
|     Type *t;
 | |
|     if(oldtype->type == TTag && oldtype->tag.tagenv == TE_IMPLICIT) {
 | |
| 	t = oldtype;
 | |
| 	oldtype = oldtype->subtype; /* XXX */
 | |
|     } else
 | |
| 	t = new_type (TTag);
 | |
| 
 | |
|     t->tag.tagclass = tagclass;
 | |
|     t->tag.tagvalue = tagvalue;
 | |
|     t->tag.tagenv = tagenv;
 | |
|     t->subtype = oldtype;
 | |
|     return t;
 | |
| }
 | |
| 
 | |
| static struct objid *
 | |
| new_objid(const char *label, int value)
 | |
| {
 | |
|     struct objid *s;
 | |
|     s = emalloc(sizeof(*s));
 | |
|     s->label = label;
 | |
|     s->value = value;
 | |
|     s->next = NULL;
 | |
|     return s;
 | |
| }
 | |
| 
 | |
| static void
 | |
| add_oid_to_tail(struct objid *head, struct objid *tail)
 | |
| {
 | |
|     struct objid *o;
 | |
|     o = head;
 | |
|     while (o->next)
 | |
| 	o = o->next;
 | |
|     o->next = tail;
 | |
| }
 | |
| 
 | |
| static Type *
 | |
| new_type (Typetype tt)
 | |
| {
 | |
|     Type *t = ecalloc(1, sizeof(*t));
 | |
|     t->type = tt;
 | |
|     t->id = idcounter++;
 | |
|     return t;
 | |
| }
 | |
| 
 | |
| static struct constraint_spec *
 | |
| new_constraint_spec(enum ctype ct)
 | |
| {
 | |
|     struct constraint_spec *c = ecalloc(1, sizeof(*c));
 | |
|     c->ctype = ct;
 | |
|     return c;
 | |
| }
 | |
| 
 | |
| static void fix_labels2(Type *t, const char *prefix);
 | |
| static void fix_labels1(struct memhead *members, const char *prefix)
 | |
| {
 | |
|     Member *m;
 | |
| 
 | |
|     if(members == NULL)
 | |
| 	return;
 | |
|     HEIM_TAILQ_FOREACH(m, members, members) {
 | |
| 	if (asprintf(&m->label, "%s_%s", prefix, m->gen_name) < 0)
 | |
| 	    errx(1, "malloc");
 | |
| 	if (m->label == NULL)
 | |
| 	    errx(1, "malloc");
 | |
| 	if(m->type != NULL)
 | |
| 	    fix_labels2(m->type, m->label);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void fix_labels2(Type *t, const char *prefix)
 | |
| {
 | |
|     for(; t; t = t->subtype)
 | |
| 	fix_labels1(t->members, prefix);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fix_labels(Symbol *s)
 | |
| {
 | |
|     char *p = NULL;
 | |
|     if (asprintf(&p, "choice_%s", s->gen_name) < 0 || p == NULL)
 | |
| 	errx(1, "malloc");
 | |
|     if (s->type)
 | |
| 	fix_labels2(s->type, p);
 | |
|     free(p);
 | |
| }
 | |
| 
 | |
| static struct objectshead *
 | |
| add_object_set_spec(struct objectshead *lst, IOSObject *o)
 | |
| {
 | |
|     if (lst == NULL) {
 | |
| 	lst = emalloc(sizeof(*lst));
 | |
| 	HEIM_TAILQ_INIT(lst);
 | |
| 	HEIM_TAILQ_INSERT_HEAD(lst, o, objects);
 | |
|     } else {
 | |
| 	HEIM_TAILQ_INSERT_TAIL(lst, o, objects);
 | |
|     }
 | |
|     return lst;
 | |
| }
 | |
| 
 | |
| static struct objfieldhead *
 | |
| add_field_setting(struct objfieldhead *lst, ObjectField *f)
 | |
| {
 | |
|     if (lst == NULL) {
 | |
| 	lst = emalloc(sizeof(*lst));
 | |
| 	HEIM_TAILQ_INIT(lst);
 | |
| 	HEIM_TAILQ_INSERT_HEAD(lst, f, objfields);
 | |
|     } else {
 | |
| 	HEIM_TAILQ_INSERT_TAIL(lst, f, objfields);
 | |
|     }
 | |
|     return lst;
 | |
| }
 | |
| 
 | |
| static struct fieldhead *
 | |
| add_field_spec(struct fieldhead *lst, Field *f)
 | |
| {
 | |
|     if (lst == NULL) {
 | |
| 	lst = emalloc(sizeof(*lst));
 | |
| 	HEIM_TAILQ_INIT(lst);
 | |
| 	HEIM_TAILQ_INSERT_HEAD(lst, f, fields);
 | |
|     } else {
 | |
| 	HEIM_TAILQ_INSERT_TAIL(lst, f, fields);
 | |
|     }
 | |
|     return lst;
 | |
| }
 | |
| 
 | |
| static ObjectField *
 | |
| new_field_setting(char *n, Type *t, struct value *v)
 | |
| {
 | |
|     ObjectField *of;
 | |
| 
 | |
|     of = ecalloc(1, sizeof(*of));
 | |
|     of->value = v;
 | |
|     of->type = t;
 | |
|     of->name = n;
 | |
|     return of;
 | |
| }
 | |
| 
 | |
| static Field *
 | |
| new_type_field(char *n, int optional, Type *t)
 | |
| {
 | |
|     Field *f;
 | |
| 
 | |
|     f = ecalloc(1, sizeof(*f));
 | |
|     f->optional = optional;
 | |
|     f->unique = 0;
 | |
|     f->defval = 0;
 | |
|     f->type = t;
 | |
|     f->name = n;
 | |
|     return f;
 | |
| }
 | |
| 
 | |
| static Field *
 | |
| new_fixed_type_value_field(char *n, Type *t, int unique, int optional, struct value *defval)
 | |
| {
 | |
|     Field *f;
 | |
| 
 | |
|     f = ecalloc(1, sizeof(*f));
 | |
|     f->optional = optional;
 | |
|     f->unique = unique;
 | |
|     f->defval = defval;
 | |
|     f->type = t;
 | |
|     f->name = n;
 | |
|     return f;
 | |
| }
 | |
| 
 | |
| static Type *
 | |
| parametrize_type(Type *t, IOSClass *c)
 | |
| {
 | |
|     Type *type;
 | |
| 
 | |
|     type = new_type(TType);
 | |
|     *type = *t; /* XXX Copy, or use subtype; this only works as long as we don't cleanup! */
 | |
|     type->formal_parameter = c;
 | |
|     return type;
 | |
| }
 | |
| 
 | |
| static Type *
 | |
| type_from_class_field(IOSClass *c, const char *n)
 | |
| {
 | |
|     Field *f;
 | |
|     Type *t;
 | |
| 
 | |
|     HEIM_TAILQ_FOREACH(f, c->fields, fields) {
 | |
| 	if (strcmp(f->name, n) == 0) {
 | |
| 	    t = new_type(TType);
 | |
| 	    if (f->type) {
 | |
| 		*t = *f->type;
 | |
| 	    } else {
 | |
| 		Symbol *s = addsym("HEIM_ANY");
 | |
| 		if(s->stype != Stype && s->stype != SUndefined)
 | |
| 		    errx(1, "Do not define HEIM_ANY, only import it\n");
 | |
| 		s->stype = Stype;
 | |
| 		t->symbol = s;
 | |
| 	    }
 | |
| 	    t->typeref.iosclass = c;
 | |
| 	    t->typeref.field = f;
 | |
| 	    return t;
 | |
| 	}
 | |
|     }
 | |
|     return NULL;
 | |
| }
 | |
| 
 | |
| static void
 | |
| validate_object_set(IOSObjectSet *os)
 | |
| {
 | |
|     IOSObject **objects;
 | |
|     ObjectField *of;
 | |
|     IOSObject *o;
 | |
|     Field *cf;
 | |
|     size_t nobjs, i;
 | |
| 
 | |
|     /* Check unique fields */
 | |
|     HEIM_TAILQ_FOREACH(cf, os->iosclass->fields, fields) {
 | |
|         if (!cf->unique)
 | |
|             continue;
 | |
|         if (!cf->type)
 | |
|             errx(1, "Type fields of classes can't be UNIQUE (%s)",
 | |
|                  os->iosclass->symbol->name);
 | |
|         sort_object_set(os, cf, &objects, &nobjs);
 | |
|         for (i = 0; i < nobjs; i++) {
 | |
|             HEIM_TAILQ_FOREACH(of, objects[i]->objfields, objfields) {
 | |
|                 if (strcmp(cf->name, of->name) != 0)
 | |
|                     continue;
 | |
|                 if (!of->value)
 | |
|                     errx(1, "Value not specified for required UNIQUE field %s of object %s",
 | |
|                          cf->name, objects[i]->symbol->name);
 | |
|                 break;
 | |
|             }
 | |
|             if (i == 0)
 | |
|                 continue;
 | |
|             if (object_cmp(&objects[i - 1], &objects[i]) == 0)
 | |
|                 errx(1, "Duplicate values of UNIQUE field %s of objects %s and %s",
 | |
|                      cf->name, objects[i - 1]->symbol->name,
 | |
|                      objects[i]->symbol->name);
 | |
|         }
 | |
|         free(objects);
 | |
|     }
 | |
| 
 | |
|     /* Check required fields */
 | |
|     HEIM_TAILQ_FOREACH(cf, os->iosclass->fields, fields) {
 | |
|         if (cf->optional || cf->defval || !cf->type)
 | |
|             continue;
 | |
|         HEIM_TAILQ_FOREACH(o, os->objects, objects) {
 | |
|             int specified = 0;
 | |
| 
 | |
|             HEIM_TAILQ_FOREACH(of, o->objfields, objfields) {
 | |
|                 if (strcmp(of->name, cf->name) != 0)
 | |
|                     continue;
 | |
|                 if (of->value)
 | |
|                     specified = 1;
 | |
|                 break;
 | |
|             }
 | |
|             if (!specified)
 | |
|                 errx(1, "Value not specified for required non-UNIQUE field %s of object %s",
 | |
|                      cf->name, o->symbol->name);
 | |
|         }
 | |
|     }
 | |
| }
 |