%%

/*
 * Yacc rules.
 *
 */


/*
 * One mibFile may contain multiple MIB modules.
 * It's also possible that there's no module in a file.
 */
mibFile:		modules
    			
	|		/* empty */
    			
	;

modules:		module
			
	|		modules module
			
	;

/*
 * The general structure of a module is described at REF:RFC1902,3. .
 * An example is given at REF:RFC1902,5.7. .
 */
module:			moduleName
			
			DEFINITIONS COLON_COLON_EQUAL BEGIN_
			exportsClause
			linkagePart
			declarationPart
			END
			
	;

/*
 * REF:RFC1902,3.2.
 */
linkagePart:		linkageClause
			
	|		/* empty */
			
	;

linkageClause:		IMPORTS importPart ';'
			
        ;

exportsClause:		/* empty */
			
	|		EXPORTS
			
			/* the scanner skips until... */
			';'
			
	;

importPart:		imports
			
	|		/* empty */
			
			/* TODO: ``IMPORTS ;'' allowed? refer ASN.1! */
	;

imports:		import
			
	|		imports import
			
	;

import:			importIdentifiers FROM moduleName
			/* TODO: multiple clauses with same moduleName
			 * allowed? I guess so. refer ASN.1! */
			
	;

importIdentifiers:	importIdentifier
			
	|		importIdentifiers ',' importIdentifier
			/* TODO: might this list list be empty? */
			
	;

/*
 * Note that some named types must not be imported, REF:RFC1902,590 .
 */
importIdentifier:	LOWERCASE_IDENTIFIER
			
	|		UPPERCASE_IDENTIFIER
			
	|		importedKeyword
			/* TODO: what exactly is allowed here?
			 * What should be checked? */
			
	;

/*
 * These keywords are no real keywords. They have to be imported
 * from the SMI, TC, CONF MIBs.
 */
/*
 * TODO: Think! Shall we really leave these words as keywords or should
 * we prefer the symbol table appropriately??
 */
importedKeyword:	ACCESS
        |		AGENT_CAPABILITIES
	|		AUGMENTS
	|		BITS
	|		CONTACT_INFO
	|		CREATION_REQUIRES
	|		COUNTER32
	|		COUNTER64
	|		DEFVAL
	|		DESCRIPTION
	|		DISPLAY_HINT
	|		GROUP
	|		GAUGE32
	|		IMPLIED
	|		INDEX
	|		INTEGER32
	|		IPADDRESS
	|		LAST_UPDATED
	|		MANDATORY_GROUPS
	|		MAX_ACCESS
	|		MIN_ACCESS
	|		MODULE
	|		MODULE_COMPLIANCE
	|		MODULE_IDENTITY
	|		NOTIFICATIONS
	|		NOTIFICATION_GROUP
	|		NOTIFICATION_TYPE
	|		OBJECT_GROUP
	|		OBJECT_IDENTITY
	|		OBJECT_TYPE
	|		OBJECTS
	|		ORGANIZATION
	|		OPAQUE
	|		PRODUCT_RELEASE
	|		REFERENCE
	|		REVISION
	|		STATUS
	|		SUPPORTS
	|		SYNTAX
	|		TEXTUAL_CONVENTION
	|		TIMETICKS
	|		TRAP_TYPE
	|		UNITS
	|		UNSIGNED32
	|		VARIATION
	|		WRITE_SYNTAX
			/* TODO: which keywords should really be
			 * allowed in import clauses? */
	;

moduleName:		UPPERCASE_IDENTIFIER
			
	;

/*
 * The paragraph at REF:RFC1902,490 lists roughly what's allowed
 * in the body of an information module.
 */
declarationPart:	declarations
			
	|		/* empty */
			
			/* TODO: might this list really be emtpy? */
	;

declarations:		declaration
			
	|		declarations declaration
			
	;

declaration:		typeDeclaration
			
	|		valueDeclaration
			
	|		objectIdentityClause
			
	|		objectTypeClause
			
	|		trapTypeClause
			
	|		notificationTypeClause
			
	|		moduleIdentityClause
			
			/* TODO: check it's first and once */
	|		moduleComplianceClause
			
	|		objectGroupClause
			
	|		notificationGroupClause
			
	|		macroClause
			
	|		error '}'
			
	;

/*
 * Macro clauses. Its contents are not really parsed, but skipped by
 * the scanner until 'END' is read. This is just to make the SMI
 * documents readable.
 */
macroClause:		macroName
			MACRO
			
			/* the scanner skips until... */
			END
			
	;

macroName:		MODULE_IDENTITY      
	|		OBJECT_TYPE	    
	|		TRAP_TYPE	    
	|		NOTIFICATION_TYPE   
	|		OBJECT_IDENTITY	    
	|		TEXTUAL_CONVENTION  
	|		OBJECT_GROUP	    
	|		NOTIFICATION_GROUP  
	|		MODULE_COMPLIANCE   
	|		AGENT_CAPABILITIES  
	;

choiceClause:		CHOICE
			
			/* the scanner skips until... */
			'}'
			
	;

/*
 * The only ASN.1 value declarations are for OIDs, REF:RFC1902,491 .
 */
valueDeclaration:	LOWERCASE_IDENTIFIER
			
			OBJECT IDENTIFIER
			COLON_COLON_EQUAL '{' objectIdentifier '}'
			
	;

/*
 * This is for simple ASN.1 style type assignments and textual conventions.
 */
typeDeclaration:	typeName
			
			COLON_COLON_EQUAL typeDeclarationRHS
			
	;

typeName:		UPPERCASE_IDENTIFIER
			
	|		typeSMI
			
	;

typeSMI:		INTEGER32   
	|		IPADDRESS   
	|		COUNTER32   
	|		GAUGE32     
	|		UNSIGNED32  
	|		TIMETICKS   
	|		OPAQUE      
	|		COUNTER64   
	;

typeDeclarationRHS:	Syntax
			
	|		TEXTUAL_CONVENTION
			DisplayPart
			STATUS Status
			DESCRIPTION Text
			ReferPart
			SYNTAX Syntax
			
	|		choiceClause
			
	;

/* REF:RFC1902,7.1.12. */
conceptualTable:	SEQUENCE OF row
			
	;

row:			UPPERCASE_IDENTIFIER
			/*
			 * In this case, we do NOT allow `Module.Type'.
			 * The identifier must be defined in the local
			 * module.
			 */
			
		        /* TODO: this must be an entryType */
	;

/* REF:RFC1902,7.1.12. */
entryType:		SEQUENCE '{' sequenceItems '}'
			
;

sequenceItems:		sequenceItem
			
	|		sequenceItems ',' sequenceItem
			/* TODO: might this list be emtpy? */
			
	;

/*
 * In a SEQUENCE { ... } there are no sub-types, enumerations or
 * named bits. REF: draft, p.29
 * NOTE: REF:RFC1902,7.1.12. was less clear, it said:
 * `normally omitting the sub-typing information'
 */
sequenceItem:		LOWERCASE_IDENTIFIER sequenceSyntax
			
	;

Syntax:			ObjectSyntax
			
	|		BITS '{' NamedBits '}'
			/* TODO: standalone `BITS' ok? seen in RMON2-MIB */
			/* -> no, it's only allowed in a SEQUENCE {...} */
			
	;

sequenceSyntax:		/* ObjectSyntax */
			sequenceObjectSyntax
			
	|		BITS
			
	|		UPPERCASE_IDENTIFIER anySubType
			
	;

NamedBits:		NamedBit
			
	|		NamedBits ',' NamedBit
			
	;

NamedBit:		identifier
			
			'(' number ')'
			
	;

identifier:		LOWERCASE_IDENTIFIER
			/* TODO */
			
	;

objectIdentityClause:	LOWERCASE_IDENTIFIER
			
			OBJECT_IDENTITY
			STATUS Status
			DESCRIPTION Text
			ReferPart
			COLON_COLON_EQUAL
			'{' objectIdentifier '}'
			
	;

objectTypeClause:	LOWERCASE_IDENTIFIER
			
			OBJECT_TYPE
			SYNTAX Syntax
		        UnitsPart
			MaxAccessPart
			STATUS Status
			descriptionClause
			ReferPart
			IndexPart
			DefValPart
			COLON_COLON_EQUAL '{' ObjectName '}'
			
	;

descriptionClause:	/* empty */
			
	|		DESCRIPTION Text
			
	;

trapTypeClause:		LOWERCASE_IDENTIFIER
			
			TRAP_TYPE
			
			ENTERPRISE objectIdentifier
			VarPart
			DescrPart
			ReferPart
			COLON_COLON_EQUAL number
			/* TODO: range of number? */
			
	;

VarPart:		VARIABLES '{' VarTypes '}'
			
	|		/* empty */
			
	;

VarTypes:		VarType
			
	|		VarTypes ',' VarType
			
	;

VarType:		ObjectName
			
	;

DescrPart:		DESCRIPTION Text
			
	|		/* empty */
			
	;

MaxAccessPart:		MAX_ACCESS
			
			Access
			
	|		ACCESS
			
			Access
			/* TODO: limited values in v1 */
			
	;

notificationTypeClause:	LOWERCASE_IDENTIFIER
			
			NOTIFICATION_TYPE
			ObjectsPart
			STATUS Status
			DESCRIPTION Text
			ReferPart
			COLON_COLON_EQUAL
			'{' NotificationName '}'
			
	;

moduleIdentityClause:	LOWERCASE_IDENTIFIER
			
			MODULE_IDENTITY
			
			LAST_UPDATED ExtUTCTime
			
			ORGANIZATION Text
			CONTACT_INFO Text
			DESCRIPTION Text
			RevisionPart
			COLON_COLON_EQUAL
			'{' objectIdentifier '}'
			
        ;

ObjectSyntax:		SimpleSyntax
			
	|		typeTag SimpleSyntax
			
	|		conceptualTable	     /* TODO: possible? row? entry? */
			
	|		row		     /* the uppercase name of a row  */
			
	|		entryType	     /* SEQUENCE { ... } phrase */
			
	|		ApplicationSyntax
			
        ;

typeTag:		'[' APPLICATION number ']' IMPLICIT
			
	|		'[' UNIVERSAL number ']' IMPLICIT
			
	;

/*
 * In a SEQUENCE { ... } there are no sub-types, enumerations or
 * named bits. REF: draft, p.29
 */
sequenceObjectSyntax:	sequenceSimpleSyntax
			
/*	|		conceptualTable	     /* TODO: possible? row? entry? */
/*	|		row		     /* the uppercase name of a row  */
/*	|		entryType	     /* it's SEQUENCE { ... } phrase */
	|		sequenceApplicationSyntax
			
        ;

/* TODO: specify really according to ObjectSyntax!!! */
valueofObjectSyntax:	valueofSimpleSyntax
			
			/* conceptualTables and rows do not have DEFVALs
			 */
			/* valueofApplicationSyntax would not introduce any
			 * further syntax of ObjectSyntax values.
			 */
	;

SimpleSyntax:		INTEGER			/* (-2147483648..2147483647) */
			
	|		INTEGER integerSubType
			
	|		INTEGER enumSpec
			
	|		INTEGER32		/* (-2147483648..2147483647) */
			
        |		INTEGER32 integerSubType
			
	|		UPPERCASE_IDENTIFIER enumSpec
			
	|		moduleName '.' UPPERCASE_IDENTIFIER enumSpec
			/* TODO: UPPERCASE_IDENTIFIER must be an INTEGER */
			
	|		UPPERCASE_IDENTIFIER integerSubType
			
	|		moduleName '.' UPPERCASE_IDENTIFIER integerSubType
			/* TODO: UPPERCASE_IDENTIFIER must be an INT/Int32. */
			
	|		OCTET STRING		/* (SIZE (0..65535))	     */
			
	|		OCTET STRING octetStringSubType
			
	|		UPPERCASE_IDENTIFIER octetStringSubType
			
	|		moduleName '.' UPPERCASE_IDENTIFIER octetStringSubType
			/* TODO: UPPERCASE_IDENTIFIER must be an OCTET STR. */
			
	|		OBJECT IDENTIFIER
			
        ;

valueofSimpleSyntax:	number			/* 0..2147483647 */
			/* NOTE: Counter64 must not have a DEFVAL */
			
	|		'-' number		/* -2147483648..0 */
			
	|		BIN_STRING		/* number or OCTET STRING */
			
	|		HEX_STRING		/* number or OCTET STRING */
			
	|		LOWERCASE_IDENTIFIER	/* enumeration or named oid */
			
	|		QUOTED_STRING		/* an OCTET STRING */
			
			/* NOTE: If the value is an OBJECT IDENTIFIER, then
			 *       it must be expressed as a single ASN.1
			 *	 identifier, and not as a collection of
			 *	 of sub-identifiers.
			 *	 REF: draft,p.34
			 *	 Anyway, we try to accept it. But it's only
			 *	 possible for numbered sub-identifiers, since
			 *	 other identifiers would make something like
			 *	 { gaga } indistiguishable from a BitsValue.
			 */
	|		'{' objectIdentifier_defval '}'
			/*
			 * This is only for some MIBs with invalid numerical
			 * OID notation for DEFVALs. We DO NOT parse them
			 * correctly. We just don't want to produce a
			 * parser error.
			 */
			
	;

/*
 * In a SEQUENCE { ... } there are no sub-types, enumerations or
 * named bits. REF: draft, p.29
 */
sequenceSimpleSyntax:	INTEGER	anySubType	/* (-2147483648..2147483647) */
			
        |		INTEGER32 anySubType	/* (-2147483648..2147483647) */
			
	|		OCTET STRING anySubType
			
	|		OBJECT IDENTIFIER
			
	;

ApplicationSyntax:	IPADDRESS
			
	|		COUNTER32		/* (0..4294967295)	     */
			
	|		GAUGE32			/* (0..4294967295)	     */
			
	|		GAUGE32 integerSubType
			
	|		UNSIGNED32		/* (0..4294967295)	     */
			
	|		UNSIGNED32 integerSubType
			
	|		TIMETICKS		/* (0..4294967295)	     */
			
	|		OPAQUE			/* IMPLICIT OCTET STRING     */
			
	|		COUNTER64	        /* (0..18446744073709551615) */
			
	;

/*
 * In a SEQUENCE { ... } there are no sub-types, enumerations or
 * named bits. REF: draft, p.29
 */
sequenceApplicationSyntax: IPADDRESS
			
	|		COUNTER32		/* (0..4294967295)	     */
			
	|		GAUGE32	anySubType	/* (0..4294967295)	     */
			
	|		UNSIGNED32 anySubType /* (0..4294967295)	     */
			
	|		TIMETICKS		/* (0..4294967295)	     */
			
	|		OPAQUE			/* IMPLICIT OCTET STRING     */
			
	|		COUNTER64	        /* (0..18446744073709551615) */
			
	;

anySubType:		integerSubType
			
	|	        octetStringSubType
			
	|		enumSpec
			
	|		/* empty */
			
        ;		      


/* REF: draft,p.46 */
integerSubType:		'(' ranges ')'		/* at least one range        */
			/*
			 * the specification mentions an alternative of an
			 * empty RHS here. this would lead to reduce/reduce
			 * conflicts. instead, we differentiate the parent
			 * rule(s) (SimpleSyntax).
			 */
			
	;

octetStringSubType:	'(' SIZE '(' ranges ')' ')'
			/*
			 * the specification mentions an alternative of an
			 * empty RHS here. this would lead to reduce/reduce
			 * conflicts. instead, we differentiate the parent
			 * rule(s) (SimpleSyntax).
			 */
			
	;

ranges:			range
			
	|		ranges '|' range
			
	;

range:			value
			
	|		value DOT_DOT value
			
	;

value:			'-' number
			
	|		number
			
	|		HEX_STRING
			
	|		BIN_STRING
			
	;

enumSpec:		'{' enumItems '}'
			
	;

enumItems:		enumItem
			
	|		enumItems ',' enumItem
			
	;

enumItem:		LOWERCASE_IDENTIFIER
			
			'(' enumNumber ')'
			
	;

enumNumber:		number
			
	|		'-' number
			
	;

Status:			LOWERCASE_IDENTIFIER
			
        ;		

Status_Capabilities:	LOWERCASE_IDENTIFIER
			
        ;

DisplayPart:		DISPLAY_HINT Text
			
        |		/* empty */
			
        ;

UnitsPart:		UNITS Text
			
        |		/* empty */
			
        ;

Access:			LOWERCASE_IDENTIFIER
			
        ;

IndexPart:		INDEX
			
			'{' IndexTypes '}'
			
        |		AUGMENTS '{' Entry '}'
			/* TODO: no AUGMENTS clause in v1 */
			/* TODO: how to differ INDEX and AUGMENTS ? */
			
        |		/* empty */
			
	;

IndexTypes:		IndexType
			
        |		IndexTypes ',' IndexType
			/* TODO: might this list be emtpy? */
			
	;

IndexType:		IMPLIED Index
			
	|		Index
			
	;

Index:			ObjectName
			/*
			 * TODO: use the SYNTAX value of the correspondent
			 *       OBJECT-TYPE invocation
			 */
			
        ;

Entry:			ObjectName
			
        ;

DefValPart:		DEFVAL '{' Value '}'
			
	|		/* empty */
			
			/* TODO: different for DefValPart in AgentCaps ? */
	;

Value:			valueofObjectSyntax
			
	|		'{' BitsValue '}'
			
	;

BitsValue:		BitNames
			
	|		/* empty */
			
	;

BitNames:		BitName
			
	|		BitNames ',' BitName
			
	;

BitName:		identifier
			
	;

ObjectName:		objectIdentifier
			
	;

NotificationName:	objectIdentifier
			
	;

ReferPart:		REFERENCE Text
			
	|		/* empty */
			
	;

RevisionPart:		Revisions
			
	|		/* empty */
			
	;

Revisions:		Revision
			
	|		Revisions Revision
			
	;

Revision:		REVISION ExtUTCTime
			DESCRIPTION Text
			
	;

ObjectsPart:		OBJECTS '{' Objects '}'
			
	|		/* empty */
			
	;

Objects:		Object
			
	|		Objects ',' Object
			
	;

Object:			ObjectName
			
	;

NotificationsPart:	NOTIFICATIONS '{' Notifications '}'
			
	;

Notifications:		Notification
			
	|		Notifications ',' Notification
			
	;

Notification:		NotificationName
			
	;

Text:			QUOTED_STRING
			
	;

/*
 * TODO: REF: 
 */
ExtUTCTime:		QUOTED_STRING
			
	;

objectIdentifier:	
			subidentifiers
			
	;

subidentifiers:
			subidentifier
			
	|		subidentifiers
			subidentifier
			
        ;

subidentifier:
			LOWERCASE_IDENTIFIER
			
	|		moduleName '.' LOWERCASE_IDENTIFIER
			
	|		number
			
	|		LOWERCASE_IDENTIFIER '(' number ')'
			
	|		moduleName '.' LOWERCASE_IDENTIFIER '(' number ')'
			
	;

objectIdentifier_defval: subidentifiers_defval
			
        ;		/* TODO: right? */

subidentifiers_defval:	subidentifier_defval
			
	|		subidentifiers_defval subidentifier_defval
			
        ;		/* TODO: right? */

subidentifier_defval:	LOWERCASE_IDENTIFIER '(' number ')'
			
	|		number
			
	;		/* TODO: right? range? */

objectGroupClause:	LOWERCASE_IDENTIFIER
			
			OBJECT_GROUP
			ObjectsPart
			STATUS Status
			DESCRIPTION Text
			ReferPart
			COLON_COLON_EQUAL '{' objectIdentifier '}'
			
	;

notificationGroupClause: LOWERCASE_IDENTIFIER
			
			NOTIFICATION_GROUP
			NotificationsPart
			STATUS Status
			DESCRIPTION Text
			ReferPart
			COLON_COLON_EQUAL '{' objectIdentifier '}'
			
	;

moduleComplianceClause:	LOWERCASE_IDENTIFIER
			
			MODULE_COMPLIANCE
			STATUS Status
			DESCRIPTION Text
			ReferPart
			ComplianceModulePart
			COLON_COLON_EQUAL '{' objectIdentifier '}'
			
	;

ComplianceModulePart:	ComplianceModules
			
	;

ComplianceModules:	ComplianceModule
			
	|		ComplianceModules ComplianceModule
			
	;

ComplianceModule:	MODULE ComplianceModuleName
			
			MandatoryPart
			CompliancePart
			
	;

ComplianceModuleName:	UPPERCASE_IDENTIFIER objectIdentifier
			
	|		UPPERCASE_IDENTIFIER
			
	|		/* empty, only if contained in MIB module */
			/* TODO: RFC 1904 looks a bit different, is this ok? */
			
	;

MandatoryPart:		MANDATORY_GROUPS '{' MandatoryGroups '}'
			
	|		/* empty */
			
	;

MandatoryGroups:	MandatoryGroup
			
	|		MandatoryGroups ',' MandatoryGroup
			
	;

MandatoryGroup:		objectIdentifier
			
	;

CompliancePart:		Compliances
			
	|		/* empty */
			
	;

Compliances:		Compliance
			
	|		Compliances Compliance
			
	;

Compliance:		ComplianceGroup
			
	|		ComplianceObject
			
	;

ComplianceGroup:	GROUP objectIdentifier
			DESCRIPTION Text
			
	;

ComplianceObject:	OBJECT ObjectName
			SyntaxPart
			WriteSyntaxPart
			AccessPart
			DESCRIPTION Text
			
	;

SyntaxPart:		SYNTAX Syntax
			
	|		/* empty */
			
	;

WriteSyntaxPart:	WRITE_SYNTAX WriteSyntax
			
	|		/* empty */
			
	;

WriteSyntax:		Syntax
			
	;

AccessPart:		MIN_ACCESS Access
			
	|		/* empty */
			
	;

agentCapabilitiesClause: LOWERCASE_IDENTIFIER
			
			AGENT_CAPABILITIES
			PRODUCT_RELEASE Text
			STATUS Status_Capabilities
			DESCRIPTION Text
			ReferPart
			ModulePart_Capabilities
			COLON_COLON_EQUAL '{' objectIdentifier '}'
			
	;

ModulePart_Capabilities: Modules_Capabilities
			
	|		/* empty */
			
	;

Modules_Capabilities:	Module_Capabilities
			
	|		Modules_Capabilities Module_Capabilities
			
	;

Module_Capabilities:	SUPPORTS ModuleName_Capabilities
			/* TODO: example in the SimpleBook names the module
			 * while the given syntax provides oids ?! */
			INCLUDES '{' CapabilitiesGroups '}'
			VariationPart
			
	;

CapabilitiesGroups:	CapabilitiesGroup
			
	|		CapabilitiesGroups ',' CapabilitiesGroup
			
	;

CapabilitiesGroup:	objectIdentifier
			
	;

ModuleName_Capabilities: objectIdentifier
			
	|		UPPERCASE_IDENTIFIER
			
	|		/* empty */
			/* empty, only if contained in MIB module */
			/* TODO: ?? */
			
	;

VariationPart:		Variations
			
	|		/* empty */
			
	;

Variations:		Variation
			
	|		Variations Variation
			
	;

Variation:		ObjectVariation
			
	|		NotificationVariation
			
	;

NotificationVariation:	VARIATION ObjectName
			AccessPart
			DESCRIPTION Text
			
	;

ObjectVariation:	VARIATION ObjectName
			SyntaxPart
			WriteSyntaxPart
			AccessPart
			CreationPart
			DefValPart
			DESCRIPTION Text
			
	;

CreationPart:		CREATION_REQUIRES '{' Cells '}'
			
	|		/* empty */
			
	;

Cells:			Cell
			
	|		Cells ',' Cell
			
	;

Cell:			ObjectName
			
	;

number:			NUMBER
			
	;

%%