%{ #include "config.h" #include #include #include #include "config.h" #include "buffer.h" #include "types.h" #include "state.h" #include "ptrarray.h" #define ARRAYOF(TYPE) ((MI_Uint32)TYPE | (MI_Uint32)MI_ARRAY_BIT) extern int yylex(); extern int openIncludeFile(const char* path); %} %union { MI_Boolean boolean; MI_Sint64 integer; MI_Real64 real; MI_Char16 character; char* string; char* identifier; char* dollarIdentifier; MI_Type type; MI_PropertyDecl* property; MI_MethodDecl* methodDecl; MI_ParameterDecl* parameter; MOF_ParameterList parameterList; MOF_FeatureList featureList; MI_QualifierDecl* qualifierDeclaration; MOF_ConstantValue constantValue; MOF_Initializer initializer; MI_Uint32 flags; MI_Qualifier* qualifier; MOF_QualifierList qualifierList; MI_ClassDecl* classDeclaration; MI_InstanceDecl* instanceDeclaration; } %start mofSpecification %token TOK_ERROR %token TOK_BOOLEAN %token TOK_SINT8 %token TOK_UINT8 %token TOK_SINT16 %token TOK_UINT16 %token TOK_SINT32 %token TOK_UINT32 %token TOK_SINT64 %token TOK_UINT64 %token TOK_REAL32 %token TOK_REAL64 %token TOK_DATETIME %token TOK_CHAR16 %token TOK_STRING %token TOK_BOOLEAN_VALUE %token TOK_REF %token TOK_SCOPE %token TOK_CLASS %token TOK_ASSOCIATION %token TOK_INDICATION %token TOK_QUALIFIER %token TOK_PROPERTY %token TOK_REFERENCE %token TOK_METHOD %token TOK_PARAMETER %token TOK_ANY %token TOK_FLAVOR %token TOK_ENABLEOVERRIDE %token TOK_DISABLEOVERRIDE %token TOK_RESTRICTED %token TOK_TOSUBCLASS %token TOK_TRANSLATABLE %token TOK_INSTANCE %token TOK_OF %token TOK_AS %token TOK_PRAGMA %token TOK_SCHEMA %token TOK_INTEGER_VALUE %token TOK_REAL_VALUE %token TOK_STRING_VALUE %token TOK_CHAR_VALUE %token TOK_IDENT %token TOK_ALIAS_IDENTIFIER %token TOK_NULL %type stringValue %type TOK_STRING_VALUE %type identifier %type objectRef %type TOK_INTEGER_VALUE %type TOK_REAL_VALUE %type TOK_CHAR_VALUE %type TOK_BOOLEAN_VALUE %type TOK_IDENT %type TOK_ALIAS_IDENTIFIER %type alias %type constantValue %type dataType %type propertyDeclaration %type parameter %type parameterList %type referenceDeclaration %type methodDeclaration %type classFeatureList %type classBody %type instanceBody %type qualifierDeclaration %type qualifierType %type subscript %type initializer %type arrayInitializer %type arrayInitializerList %type scope %type scopeList %type scopeExpr %type flavor %type flavorList %type flavorExpr %type qualifier %type qualifierList %type qualifierExpr %type qualifierParameter %type classDeclaration %type instanceDeclaration %type valueInitializer %type valueInitializerList %% mofSpecification : mofProduction { } | mofSpecification mofProduction { } | TOK_ERROR { YYABORT; } mofProduction : compilerDirective { } | classDeclaration { /* [TODO: validate the class here] */ $1->flags = MI_FLAG_CLASS; $1->flags |= GetQualFlags($1->qualifiers, $1->numQualifiers); if (FinalizeClass($1) != 0) YYABORT; AddClassDecl($1); if (state.classDeclCallback) (*state.classDeclCallback)($1, state.classDeclCallbackData); } | qualifierDeclaration { AddQualifierDeclaration($1); if (state.qualifierDeclCallback) (*state.qualifierDeclCallback)($1, state.qualifierDeclCallbackData); } | instanceDeclaration { if (FinalizeInstance($1) != 0) YYABORT; AddInstanceDecl($1); if (state.instanceDeclCallback) (*state.instanceDeclCallback)($1, state.instanceDeclCallbackData); } compilerDirective : TOK_PRAGMA TOK_IDENT '(' stringValue ')' { if (strcmp($2, "include") == 0) { if (openIncludeFile($4) != 0) YYABORT; } else if (strcmp($2, "instancelocale") == 0) { if (state.pragmaCallback) (*state.pragmaCallback)($2, $4, state.pragmaCallbackData); } else if (strcmp($2, "locale") == 0) { if (state.pragmaCallback) (*state.pragmaCallback)($2, $4, state.pragmaCallbackData); } else if (strcmp($2, "namespace") == 0) { if (state.pragmaCallback) (*state.pragmaCallback)($2, $4, state.pragmaCallbackData); } else { yywarnf(ID_UNKNOWN_PRAGMA, "warning: unknown pragma: %s=%s", $2, $4); if (state.pragmaCallback) (*state.pragmaCallback)($2, $4, state.pragmaCallbackData); } } classDeclaration : TOK_CLASS identifier classBody { /* Check whether class already exists */ if (FindClassDecl($2)) { yyerrorf(ID_CLASS_ALREADY_DEFINED, "class already defined: \"%s\"", $2); YYABORT; } $$ = CALLOC_T(MI_ClassDecl, 1); $$->flags = MI_FLAG_CLASS; $$->name = $2; $$->properties = $3.propertySet.data; $$->numProperties = $3.propertySet.size; $$->methods = $3.methodList.data; $$->numMethods = $3.methodList.size; } | TOK_CLASS identifier ':' identifier classBody { const MI_ClassDecl* scd; /* Check whether class already exists */ if (FindClassDecl($2)) { yyerrorf(ID_CLASS_ALREADY_DEFINED, "class already defined: \"%s\"", $2); YYABORT; } /* Check whether superclass exists */ scd = FindClassDecl($4); if (!scd) { yyerrorf(ID_UNDEFINED_SUPERCLASS, "super class of \"%s\" is undefined: \"%s\"", $2, $4); YYABORT; } $$ = CALLOC_T(MI_ClassDecl, 1); $$->flags = MI_FLAG_CLASS; $$->name = $2; $$->superClass = $4; $$->superClassDecl = (MI_ClassDecl*)scd; $$->properties = $5.propertySet.data; $$->numProperties = $5.propertySet.size; $$->methods = $5.methodList.data; $$->numMethods = $5.methodList.size; } | qualifierExpr TOK_CLASS identifier classBody { /* Check qualifier scope */ if (CheckScope(MI_FLAG_CLASS, &$1) != 0) YYABORT; /* Check whether class already exists */ if (FindClassDecl($3)) { yyerrorf(ID_CLASS_ALREADY_DEFINED, "class already defined: \"%s\"", $3); YYABORT; } $$ = CALLOC_T(MI_ClassDecl, 1); $$->flags = MI_FLAG_CLASS; $$->name = $3; $$->properties = $4.propertySet.data; $$->numProperties = $4.propertySet.size; $$->methods = $4.methodList.data; $$->numMethods = $4.methodList.size; $$->qualifiers = $1.data; $$->numQualifiers = $1.size; } | qualifierExpr TOK_CLASS identifier ':' identifier classBody { const MI_ClassDecl* scd; /* Check qualifier scope */ if (CheckScope(MI_FLAG_CLASS, &$1) != 0) YYABORT; /* Check whether class already exists */ if (FindClassDecl($3)) { yyerrorf(ID_CLASS_ALREADY_DEFINED, "class already defined: \"%s\"", $3); YYABORT; } /* Check whether superclass exists */ scd = FindClassDecl($5); if (!scd) { yyerrorf(ID_UNDEFINED_SUPERCLASS, "super class of \"%s\" is undefined: \"%s\"", $3, $5); YYABORT; } $$ = CALLOC_T(MI_ClassDecl, 1); $$->flags = MI_FLAG_CLASS; $$->name = $3; $$->superClass = scd->name; $$->superClassDecl = (MI_ClassDecl*)scd; $$->properties = $6.propertySet.data; $$->numProperties = $6.propertySet.size; $$->methods = $6.methodList.data; $$->numMethods = $6.methodList.size; $$->qualifiers = $1.data; $$->numQualifiers = $1.size; } classBody : '{' classFeatureList '}' ';' { $$ = $2; } | '{' '}' ';' { $$.propertySet.data = NULL; $$.propertySet.size = 0; $$.methodList.data = NULL; $$.methodList.size = 0; } classFeatureList : propertyDeclaration { if (CheckPropertyValueConstraints($1) != 0) { YYABORT; } $$.propertySet.data = NULL; $$.propertySet.size = 0; $$.methodList.data = NULL; $$.methodList.size = 0; $1->flags = MI_FLAG_PROPERTY; $1->flags |= GetQualFlags($1->qualifiers, $1->numQualifiers); PtrArray_Append((PtrArray*)&$$.propertySet, $1); } | methodDeclaration { $$.propertySet.data = NULL; $$.propertySet.size = 0; $$.methodList.data = NULL; $$.methodList.size = 0; $1->flags = MI_FLAG_METHOD; $1->flags |= GetQualFlags($1->qualifiers, $1->numQualifiers); PtrArray_Append((PtrArray*)&$$.methodList, $1); } | referenceDeclaration { $$.propertySet.data = NULL; $$.propertySet.size = 0; $$.methodList.data = NULL; $$.methodList.size = 0; $1->flags = MI_FLAG_PROPERTY; $1->flags |= GetQualFlags($1->qualifiers, $1->numQualifiers); PtrArray_Append((PtrArray*)&$$.propertySet, $1); } | classFeatureList propertyDeclaration { if (CheckPropertyValueConstraints($2) != 0) { YYABORT; } if (FindProperty(&$1.propertySet, $2->name)) { yyerrorf(ID_CLASS_FEATURE_ALREADY_DEFINED, "class feature already defined: \"%s\"", $2->name); YYABORT; } $2->flags = MI_FLAG_PROPERTY; $2->flags |= GetQualFlags($2->qualifiers, $2->numQualifiers); PtrArray_Append((PtrArray*)&$$.propertySet, $2); } | classFeatureList methodDeclaration { if (FindMethod(&$1.methodList, $2->name)) { yyerrorf(ID_CLASS_FEATURE_ALREADY_DEFINED, "class feature already defined: \"%s\"", $2->name); YYABORT; } $2->flags = MI_FLAG_METHOD; $2->flags |= GetQualFlags($2->qualifiers, $2->numQualifiers); PtrArray_Append((PtrArray*)&$$.methodList, $2); } | classFeatureList referenceDeclaration { if (FindProperty(&$1.propertySet, $2->name)) { yyerrorf(ID_CLASS_FEATURE_ALREADY_DEFINED, "class feature already defined: \"%s\"", $2->name); YYABORT; } $2->flags = MI_FLAG_PROPERTY; $2->flags |= GetQualFlags($2->qualifiers, $2->numQualifiers); PtrArray_Append((PtrArray*)&$$.propertySet, $2); } qualifierExpr : '[' qualifierList ']' { $$ = $2; } qualifierList : qualifier { $$.data = NULL; $$.size = 0; PtrArray_Append((PtrArray*)&$$, $1); } | qualifierList ',' qualifier { if (FindQualifier(&$1, $3->name)) { yyerrorf(ID_DUPLICATE_QUALIFIER, "duplicate qualifier: \"%s\"", $3->name); YYABORT; } PtrArray_Append((PtrArray*)&$$, $3); } qualifier : identifier { MI_Qualifier* q; const MI_QualifierDecl* qd; qd = FindQualifierDeclaration($1); if (!qd) { yyerrorf(ID_UNDEFINED_QUALIFIER, "undefined qualifier: \"%s\"", $1); YYABORT; } if (qd->type != MI_BOOLEAN) { yyerrorf(ID_MISSING_QUALIFIER_INITIALIZER, "qualifier is missing initializer: \"%s\"", $1); YYABORT; } q = CALLOC_T(MI_Qualifier, 1); q->name = qd->name; /* use casing of qualifier declaration name */ q->type = qd->type; q->flavor = qd->flavor; q->value = NewTrueValue(); $$ = q; } | identifier qualifierParameter { MI_Qualifier* q; const MI_QualifierDecl* qd; void* value; qd = FindQualifierDeclaration($1); if (!qd) { yyerrorf(ID_UNDEFINED_QUALIFIER, "undefined qualifier: \"%s\"", $1); YYABORT; } if (InitializerToValue(&$2, qd->type, &value) != 0) { yyerrorf(ID_INVALID_QUALIFIER_INITIALIZER, "invalid initializer for qualifer: \"%s\"", $1); YYABORT; } q = CALLOC_T(MI_Qualifier, 1); q->name = qd->name; /* use casing of qualifier declaration name */ q->type = qd->type; q->flavor = qd->flavor; q->value = value; $$ = q; } | identifier ':' flavor { MI_Qualifier* q; const MI_QualifierDecl* qd; qd = FindQualifierDeclaration($1); if (!qd) { yyerrorf(ID_UNDEFINED_QUALIFIER, "undefined qualifier: \"%s\"", $1); YYABORT; } if (qd->type != MI_BOOLEAN) { yyerrorf(ID_MISSING_QUALIFIER_INITIALIZER, "qualifier is missing initializer: \"%s\"", $1); YYABORT; } q = CALLOC_T(MI_Qualifier, 1); q->name = qd->name; /* use casing of qualifier declaration name */ q->type = qd->type; q->flavor = PropagateFlavors($3, qd->flavor); q->value = NewTrueValue(); $$ = q; } | identifier qualifierParameter ':' flavor { MI_Qualifier* q; const MI_QualifierDecl* qd; void* value; qd = FindQualifierDeclaration($1); if (!qd) { yyerrorf(ID_UNDEFINED_QUALIFIER, "undefined qualifier: \"%s\"", $1); YYABORT; } if (InitializerToValue(&$2, qd->type, &value) != 0) { yyerrorf(ID_INVALID_QUALIFIER_INITIALIZER, "invalid initializer for qualifer: \"%s\"", $1); YYABORT; } q = CALLOC_T(MI_Qualifier, 1); q->name = qd->name; /* use casing of qualifier declaration name */ q->type = qd->type; q->value = value; q->flavor = PropagateFlavors($4, qd->flavor); $$ = q; } qualifierParameter : '(' constantValue ')' { memset(&$$, 0, sizeof($$)); $$.data = CALLOC_T(MOF_ConstantValue, 1); $$.data[0] = $2; $$.size = 1; } | arrayInitializer { $$ = $1; } flavorList : flavor { $$ = $1; } | flavorList ',' flavor { $$ |= $3; } flavor : TOK_ENABLEOVERRIDE { $$ = MI_FLAG_ENABLEOVERRIDE; } | TOK_DISABLEOVERRIDE { $$ = MI_FLAG_DISABLEOVERRIDE; } | TOK_RESTRICTED { $$ = MI_FLAG_RESTRICTED; } | TOK_TOSUBCLASS { $$ = MI_FLAG_TOSUBCLASS; } | TOK_TRANSLATABLE { $$ = MI_FLAG_TRANSLATABLE; } propertyDeclaration : dataType identifier ';' { $$ = CALLOC_T(MI_PropertyDecl, 1); $$->name = $2; $$->type = $1; } | qualifierExpr dataType identifier ';' { /* Check qualifier scope */ if (CheckScope(MI_FLAG_PROPERTY, &$1) != 0) YYABORT; $$ = CALLOC_T(MI_PropertyDecl, 1); $$->name = $3; $$->type = $2; $$->qualifiers = $1.data; $$->numQualifiers = $1.size; } | dataType identifier subscript ';' { $$ = CALLOC_T(MI_PropertyDecl, 1); $$->name = $2; $$->type = ARRAYOF($1); $$->subscript = (MI_Uint32)$3; } | qualifierExpr dataType identifier subscript ';' { /* Check qualifier scope */ if (CheckScope(MI_FLAG_PROPERTY, &$1) != 0) YYABORT; $$ = CALLOC_T(MI_PropertyDecl, 1); $$->name = $3; $$->type = ARRAYOF($2); $$->qualifiers = $1.data; $$->numQualifiers = $1.size; $$->subscript = (MI_Uint32)$4; } | dataType identifier '=' initializer ';' { void* value; if (InitializerToValue(&$4, $1, &value) != 0) { yyerrorf(ID_INVALID_INITIALIZER, "invalid initializer"); YYABORT; } $$ = CALLOC_T(MI_PropertyDecl, 1); $$->name = $2; $$->type = $1; $$->value = value; } | qualifierExpr dataType identifier '=' initializer ';' { void* value; /* Check qualifier scope */ if (CheckScope(MI_FLAG_PROPERTY, &$1) != 0) YYABORT; if (InitializerToValue(&$5, $2, &value) != 0) { yyerrorf(ID_INVALID_INITIALIZER, "invalid initializer"); YYABORT; } $$ = CALLOC_T(MI_PropertyDecl, 1); $$->name = $3; $$->type = $2; $$->qualifiers = $1.data; $$->numQualifiers = $1.size; $$->value = value; } | dataType identifier subscript '=' initializer ';' { void* value; if (InitializerToValue(&$5, ARRAYOF($1), &value) != 0) { yyerrorf(ID_INVALID_INITIALIZER, "invalid initializer"); YYABORT; } $$ = CALLOC_T(MI_PropertyDecl, 1); $$->name = $2; $$->type = ARRAYOF($1); $$->subscript = (MI_Uint32)$3; $$->value = value; } | qualifierExpr dataType identifier subscript '=' initializer ';' { void* value; /* Check qualifier scope */ if (CheckScope(MI_FLAG_PROPERTY, &$1) != 0) YYABORT; if (InitializerToValue(&$6, ARRAYOF($2), &value) != 0) { yyerrorf(ID_INVALID_INITIALIZER, "invalid initializer"); YYABORT; } $$ = CALLOC_T(MI_PropertyDecl, 1); $$->name = $3; $$->type = ARRAYOF($2); $$->qualifiers = $1.data; $$->numQualifiers = $1.size; $$->subscript = (MI_Uint32)$4; $$->value = value; } referenceDeclaration : objectRef identifier ';' { const MI_ClassDecl* cd; /* Verify that class exists */ cd = FindClassDecl($1); if (!cd) { yyerrorf(ID_UNDEFINED_CLASS, "undefined class: \"%s\"", $1); YYABORT; } $$ = CALLOC_T(MI_PropertyDecl, 1); $$->type = MI_REFERENCE; $$->name = $2; $$->className = cd->name; } | qualifierExpr objectRef identifier ';' { const MI_ClassDecl* cd; /* Verify that class exists */ cd = FindClassDecl($2); if (!cd) { yyerrorf(ID_UNDEFINED_CLASS, "undefined class: \"%s\"", $2); YYABORT; } /* Check qualifier scope */ if (CheckScope(MI_FLAG_REFERENCE, &$1) != 0) YYABORT; $$ = CALLOC_T(MI_PropertyDecl, 1); $$->type = MI_REFERENCE; $$->name = $3; $$->className = cd->name; $$->qualifiers = $1.data; $$->numQualifiers = $1.size; } | objectRef identifier initializer';' { const MI_ClassDecl* cd; /* Verify that class exists */ cd = FindClassDecl($1); if (!cd) { yyerrorf(ID_UNDEFINED_CLASS, "undefined class: \"%s\"", $1); YYABORT; } $$ = CALLOC_T(MI_PropertyDecl, 1); $$->type = MI_REFERENCE; $$->name = $2; $$->className = cd->name; yywarnf(ID_IGNORED_INITIALIZER, "warning: ignored initializer"); /* [TODO: use initializer */ } | qualifierExpr objectRef identifier initializer ';' { const MI_ClassDecl* cd; /* Verify that class exists */ cd = FindClassDecl($2); if (!cd) { yyerrorf(ID_UNDEFINED_CLASS, "undefined class: \"%s\"", $2); YYABORT; } /* Check qualifier scope */ if (CheckScope(MI_FLAG_REFERENCE, &$1) != 0) YYABORT; $$ = CALLOC_T(MI_PropertyDecl, 1); $$->type = MI_REFERENCE; $$->name = $3; $$->className = cd->name; $$->qualifiers = $1.data; $$->numQualifiers = $1.size; yywarnf(ID_IGNORED_INITIALIZER, "warning: ignored initializer"); /* [TODO: use initializer */ } methodDeclaration : dataType identifier '(' parameterList ')' ';' { $$ = CALLOC_T(MI_MethodDecl, 1); $$->name = $2; $$->parameters = $4.data; $$->numParameters = $4.size; $$->returnType = $1; } | qualifierExpr dataType identifier '(' parameterList ')' ';' { /* Check qualifier scope */ if (CheckScope(MI_FLAG_METHOD, &$1) != 0) YYABORT; $$ = CALLOC_T(MI_MethodDecl, 1); $$->name = $3; $$->parameters = $5.data; $$->numParameters = $5.size; $$->qualifiers = $1.data; $$->numQualifiers = $1.size; $$->returnType = $2; } | dataType identifier '(' ')' ';' { MOF_ParameterList parameterList = PTRARRAY_INITIALIZER; $$ = CALLOC_T(MI_MethodDecl, 1); $$->name = $2; $$->parameters = parameterList.data; $$->numParameters = parameterList.size; $$->returnType = $1; } | qualifierExpr dataType identifier '(' ')' ';' { MOF_ParameterList parameterList = PTRARRAY_INITIALIZER; /* Check qualifier scope */ if (CheckScope(MI_FLAG_METHOD, &$1) != 0) YYABORT; $$ = CALLOC_T(MI_MethodDecl, 1); $$->name = $3; $$->parameters = parameterList.data; $$->numParameters = parameterList.size; $$->qualifiers = $1.data; $$->numQualifiers = $1.size; $$->returnType = $2; } dataType : TOK_BOOLEAN { $$ = MI_BOOLEAN; } | TOK_SINT8 { $$ = MI_SINT8; } | TOK_UINT8 { $$ = MI_UINT8; } | TOK_SINT16 { $$ = MI_SINT16; } | TOK_UINT16 { $$ = MI_UINT16; } | TOK_SINT32 { $$ = MI_SINT32; } | TOK_UINT32 { $$ = MI_UINT32; } | TOK_SINT64 { $$ = MI_SINT64; } | TOK_UINT64 { $$ = MI_UINT64; } | TOK_REAL32 { $$ = MI_REAL32; } | TOK_REAL64 { $$ = MI_REAL64; } | TOK_CHAR16 { $$ = MI_CHAR16; } | TOK_DATETIME { $$ = MI_DATETIME; } | TOK_STRING { $$ = MI_STRING; } objectRef : identifier TOK_REF { $$ = $1; } parameterList : parameter { $1->flags = MI_FLAG_PARAMETER; $1->flags |= GetQualFlags($1->qualifiers, $1->numQualifiers); $$.data = NULL; $$.size = 0; PtrArray_Append((PtrArray*)&$$, $1); } | parameterList ',' parameter { if (FindParameter(&$1, $3->name)) { yyerrorf(ID_PARAMETER_ALREADY_DEFINED, "parameter already defined: \"%s\"", $3->name); YYABORT; } $3->flags = MI_FLAG_PARAMETER; $3->flags |= GetQualFlags($3->qualifiers, $3->numQualifiers); PtrArray_Append((PtrArray*)&$$, $3); } parameter : dataType identifier { $$ = CALLOC_T(MI_ParameterDecl, 1); $$->name = $2; $$->type = $1; } | objectRef identifier { const MI_ClassDecl* cd; /* Verify that class exists */ cd = FindClassDecl($1); if (!cd) { yyerrorf(ID_UNDEFINED_CLASS, "undefined class: \"%s\"", $1); YYABORT; } $$ = CALLOC_T(MI_ParameterDecl, 1); $$->name = $2; $$->type = MI_REFERENCE; $$->className = cd->name; } | qualifierExpr dataType identifier { /* Check qualifier scope */ if (CheckScope(MI_FLAG_PARAMETER, &$1) != 0) YYABORT; $$ = CALLOC_T(MI_ParameterDecl, 1); $$->name = $3; $$->type = $2; $$->qualifiers = $1.data; $$->numQualifiers = $1.size; } | qualifierExpr objectRef identifier { const MI_ClassDecl* cd; /* Verify that class exists */ cd = FindClassDecl($2); if (!cd) { yyerrorf(ID_UNDEFINED_CLASS, "undefined class: \"%s\"", $2); YYABORT; } /* Check qualifier scope */ if (CheckScope(MI_FLAG_PARAMETER, &$1) != 0) YYABORT; $$ = CALLOC_T(MI_ParameterDecl, 1); $$->name = $3; $$->type = MI_REFERENCE; $$->className = cd->name; $$->qualifiers = $1.data; $$->numQualifiers = $1.size; } | dataType identifier subscript { $$ = CALLOC_T(MI_ParameterDecl, 1); $$->name = $2; $$->type = ARRAYOF($1); $$->subscript = (MI_Uint32)$3; } | objectRef identifier subscript { const MI_ClassDecl* cd; /* Verify that class exists */ cd = FindClassDecl($1); if (!cd) { yyerrorf(ID_UNDEFINED_CLASS, "undefined class: \"%s\"", $1); YYABORT; } $$ = CALLOC_T(MI_ParameterDecl, 1); $$->name = $2; $$->type = ARRAYOF(MI_REFERENCE); $$->className = cd->name; $$->subscript = (MI_Uint32)$3; } | qualifierExpr dataType identifier subscript { /* Check qualifier scope */ if (CheckScope(MI_FLAG_PARAMETER, &$1) != 0) YYABORT; $$ = CALLOC_T(MI_ParameterDecl, 1); $$->name = $3; $$->type = ARRAYOF($2); $$->subscript = (MI_Uint32)$4; $$->qualifiers = $1.data; $$->numQualifiers = $1.size; } | qualifierExpr objectRef identifier subscript { const MI_ClassDecl* cd; /* Verify that class exists */ cd = FindClassDecl($2); if (!cd) { yyerrorf(ID_UNDEFINED_CLASS, "undefined class: \"%s\"", $2); YYABORT; } /* Check qualifier scope */ if (CheckScope(MI_FLAG_PARAMETER, &$1) != 0) YYABORT; $$ = CALLOC_T(MI_ParameterDecl, 1); $$->name = $3; $$->type = ARRAYOF(MI_REFERENCE); $$->className = cd->name; $$->subscript = (MI_Uint32)$4; $$->qualifiers = $1.data; $$->numQualifiers = $1.size; } subscript : '[' TOK_INTEGER_VALUE ']' { if ($2 <= 0) { yyerrorf(ID_ILLEGAL_ARRAY_SUBSCRIPT, "illegal array subscript: " SINT64_FMT, $2); YYABORT; } $$ = $2; } | '[' ']' { /* 0 signifies a dynamic array */ $$ = 0; } initializer : constantValue { memset(&$$, 0, sizeof($$)); $$.data = CALLOC_T(MOF_ConstantValue, 1); $$.data[0] = $1; $$.size = 1; } | arrayInitializer { $$ = $1; } | TOK_ALIAS_IDENTIFIER { memset(&$$, 0, sizeof($$)); $$.data = CALLOC_T(MOF_ConstantValue, 1); $$.data[0].type = TOK_STRING_VALUE; $$.data[0].value.string = $1; $$.size = 0; } arrayInitializer : '{' arrayInitializerList '}' { $$ = $2; } arrayInitializerList : constantValue { memset(&$$, 0, sizeof($$)); $$.data = CALLOC_T(MOF_ConstantValue, 1); $$.data[0] = $1; $$.size = 1; $$.isArray = 1; } | arrayInitializerList ',' constantValue { $1.data = REALLOC_T(MOF_ConstantValue, $1.data, $1.size + 1); $1.data[$1.size] = $3; $1.size++; $$ = $1; } constantValue : TOK_INTEGER_VALUE { $$.type = TOK_INTEGER_VALUE; $$.value.integer = $1; } | TOK_REAL_VALUE { $$.type = TOK_REAL_VALUE; $$.value.real = $1; } | TOK_CHAR_VALUE { $$.type = TOK_CHAR_VALUE; $$.value.character = $1; } | stringValue { $$.type = TOK_STRING_VALUE; $$.value.string = $1; } | TOK_BOOLEAN_VALUE { $$.type = TOK_BOOLEAN_VALUE; $$.value.boolean = $1; } | TOK_NULL { $$.type = TOK_NULL; } stringValue : TOK_STRING_VALUE { $$ = $1; } | stringValue TOK_STRING_VALUE { size_t size = strlen($1) + strlen($2) + 1; $$ = (char*)MOF_Realloc(&state.heap, $1, size); Strcat($$, size, $2); MOF_Free(&state.heap, $2); } qualifierDeclaration : TOK_QUALIFIER identifier qualifierType scopeExpr ';' { $3->name = $2; $3->scope = $4; $3->flavor = 0; $$ = $3; } | TOK_QUALIFIER identifier qualifierType scopeExpr flavorExpr ';' { $3->name = $2; $3->scope = $4; $3->flavor = $5; $$ = $3; } qualifierType : ':' dataType { $$ = CALLOC_T(MI_QualifierDecl, 1); $$->type = $2; } | ':' dataType '=' initializer { void* value; if (InitializerToValue(&$4, $2, &value) != 0) { yyerrorf(ID_INVALID_INITIALIZER, "invalid initializer"); YYABORT; } $$ = CALLOC_T(MI_QualifierDecl, 1); $$->type = $2; $$->value = value; ReleaseInitializer(&$4); } | ':' dataType subscript { $$ = CALLOC_T(MI_QualifierDecl, 1); $$->type = ARRAYOF($2); $$->subscript = (MI_Uint32)$3; } | ':' dataType subscript '=' initializer { void* value = NULL; if (InitializerToValue(&$5, ARRAYOF($2), &value) != 0) { yyerrorf(ID_INVALID_INITIALIZER, "invalid initializer"); YYABORT; } $$ = CALLOC_T(MI_QualifierDecl, 1); $$->type = ARRAYOF($2); $$->subscript = (MI_Uint32)$3; $$->value = value; ReleaseInitializer(&$5); } scopeExpr : ',' TOK_SCOPE '(' scopeList ')' { $$ = $4; } scopeList : scope { $$ = $1; } | scopeList ',' scope { $$ |= $3; } scope : TOK_CLASS { $$ = MI_FLAG_CLASS; } | TOK_ASSOCIATION { $$ = MI_FLAG_ASSOCIATION; } | TOK_INDICATION { $$ = MI_FLAG_INDICATION; } | TOK_PROPERTY { $$ = MI_FLAG_PROPERTY; } | TOK_REFERENCE { $$ = MI_FLAG_REFERENCE; } | TOK_METHOD { $$ = MI_FLAG_METHOD; } | TOK_PARAMETER { $$ = MI_FLAG_PARAMETER; } | TOK_ANY { $$ = MI_FLAG_ANY; } flavorExpr : ',' TOK_FLAVOR '(' flavorList ')' { /* Reject incompatiable ToSubclass and Restricted flavors */ if ($4 & MI_FLAG_TOSUBCLASS && $4 & MI_FLAG_RESTRICTED) { yyerrorf(ID_INCOMPATIBLE_FLAVORS, "incompatible flavors: %s/%s", "ToSubclass", "Restricted"); YYABORT; } /* Reject incompatiable EnableOverride and DisableOverride flavors */ if ($4 & MI_FLAG_ENABLEOVERRIDE && $4 & MI_FLAG_DISABLEOVERRIDE) { yyerrorf(ID_INCOMPATIBLE_FLAVORS, "incompatible flavors: %s/%s", "EnableOverride", "DisableOverride"); YYABORT; } $$ = $4; } instanceDeclaration : TOK_INSTANCE TOK_OF identifier instanceBody { $$ = CALLOC_T(MI_InstanceDecl, 1); $$->flags = 0; $$->name = $3; $$->properties = $4.propertySet.data; $$->numProperties = $4.propertySet.size; } | qualifierExpr TOK_INDICATION TOK_OF identifier instanceBody { $$ = CALLOC_T(MI_InstanceDecl, 1); $$->flags = 0; $$->name = $4; $$->properties = $5.propertySet.data; $$->numProperties = $5.propertySet.size; $$->qualifiers = $1.data; $$->numQualifiers = $1.size; } | TOK_INSTANCE TOK_OF identifier alias instanceBody { /* [TODO]: handle alias */ $$ = CALLOC_T(MI_InstanceDecl, 1); $$->flags = 0; $$->name = $3; $$->properties = $5.propertySet.data; $$->numProperties = $5.propertySet.size; } | qualifierExpr TOK_INDICATION TOK_OF identifier alias instanceBody { /* [TODO]: handle alias */ $$ = CALLOC_T(MI_InstanceDecl, 1); $$->flags = 0; $$->name = $4; $$->properties = $6.propertySet.data; $$->numProperties = $6.propertySet.size; $$->qualifiers = $1.data; $$->numQualifiers = $1.size; } instanceBody : '{' valueInitializerList '}' ';' { $$ = $2; } alias : TOK_AS TOK_ALIAS_IDENTIFIER { $$ = $2; } valueInitializerList : valueInitializer { $$.propertySet.data = NULL; $$.propertySet.size = 0; $1->flags = MI_FLAG_PROPERTY; $1->flags |= GetQualFlags($1->qualifiers, $1->numQualifiers); PtrArray_Append((PtrArray*)&$$.propertySet, $1); } | valueInitializerList valueInitializer { if (FindProperty(&$1.propertySet, $2->name)) { yyerrorf(ID_CLASS_FEATURE_ALREADY_DEFINED, "instance property already defined: \"%s\"", $2->name); YYABORT; } $2->flags = MI_FLAG_PROPERTY; $2->flags |= GetQualFlags($2->qualifiers, $2->numQualifiers); PtrArray_Append((PtrArray*)&$$.propertySet, $2); } valueInitializer : identifier '=' initializer ';' { void* value; MI_Type type = InitializerToType(&$3); if (InitializerToValue(&$3, type, &value) != 0) { yyerrorf(ID_INVALID_INITIALIZER, "invalid initializer"); YYABORT; } $$ = CALLOC_T(MI_PropertyDecl, 1); $$->name = $1; $$->type = type; $$->value = value; } | qualifierExpr identifier '=' initializer ';' { void* value; MI_Type type = InitializerToType(&$4); if (InitializerToValue(&$4, type, &value) != 0) { yyerrorf(ID_INVALID_INITIALIZER, "invalid initializer"); YYABORT; } $$ = CALLOC_T(MI_PropertyDecl, 1); $$->name = $2; $$->type = type; $$->value = value; $$->qualifiers = $1.data; $$->numQualifiers = $1.size; } identifier : TOK_IDENT { $$ = $1; } | TOK_ASSOCIATION { $$ = MOF_Strdup(&state.heap, "Association"); } | TOK_INDICATION { $$ = MOF_Strdup(&state.heap, "Indication"); } | TOK_REFERENCE { $$ = MOF_Strdup(&state.heap, "Reference"); } | TOK_PROPERTY { $$ = MOF_Strdup(&state.heap, "Property"); }