/* **============================================================================== ** ** mof.lex ** ** This file defines a lexigraphical analyzer for the Managed Object Format ** (MOF). See the BNF in the CIM Infrastructure Specification. ** **============================================================================== */ %{ /* Do not read from standard input */ #define YY_NEVER_INTERACTIVE 1 #define MOF_STACK_SIZE 32 #include "config.h" #include "mof.h" #include "types.h" #include "mofyacc.h" #include "buffer.h" #include "ptrarray.h" #include "state.h" #include #include #include extern int yyparse(); int closeIncludeFile(); struct _MOF_Parser { MOF_State state; }; typedef struct _StackItem { char* file; unsigned int line; YY_BUFFER_STATE buffer; } StackItem; /* Stack of parser states for open nested MOF files */ static StackItem s_stack[MOF_STACK_SIZE]; /* Current size of stack s_stack[s_top-1] is the top */ static size_t s_top = 0; %} /* **============================================================================== ** ** Case-insensitive keywords (see CIM Infrastructure specification). ** **============================================================================== */ /* True and false */ TRUE [Tt][Rr][Uu][Ee] FALSE [Ff][Aa][Ll][Ss][Ee] /* Null value */ NULL [Nn][Uu][Ll][Ll] /* Data types */ DT_BOOLEAN [Bb][Oo][Oo][Ll][Ee][Aa][Nn] DT_SINT8 [Ss][Ii][Nn][Tt]8 DT_UINT8 [Uu][Ii][Nn][Tt]8 DT_SINT16 [Ss][Ii][Nn][Tt]16 DT_UINT16 [Uu][Ii][Nn][Tt]16 DT_SINT32 [Ss][Ii][Nn][Tt]32 DT_UINT32 [Uu][Ii][Nn][Tt]32 DT_SINT64 [Ss][Ii][Nn][Tt]64 DT_UINT64 [Uu][Ii][Nn][Tt]64 DT_REAL32 [Rr][Ee][Aa][Ll]32 DT_REAL64 [Rr][Ee][Aa][Ll]64 DT_DATETIME [Dd][Aa][Tt][Ee][Tt][Ii][Mm][Ee] DT_CHAR16 [Cc][Hh][Aa][Rr]16 DT_STRING [Ss][Tt][Rr][Ii][Nn][Gg] /* Ref */ REF [Rr][Ee][Ff] /* Scope */ SCOPE [Ss][Cc][Oo][Pp][Ee] CLASS [Cc][Ll][Aa][Ss][Ss] ASSOCIATION [Aa][Ss][Ss][Oo][Cc][Ii][Aa][Tt][Ii][Oo][Nn] INDICATION [Ii][Nn][Dd][Ii][Cc][Aa][Tt][Ii][Oo][Nn] QUALIFIER [Qq][Uu][Aa][Ll][Ii][Ff][Ii][Ee][Rr] PROPERTY [Pp][Rr][Oo][Pp][Ee][Rr][Tt][Yy] REFERENCE [Rr][Ee][Ff][Ee][Rr][Ee][Nn][Cc][Ee] METHOD [Mm][Ee][Tt][Hh][Oo][Dd] PARAMETER [Pp][Aa][Rr][Aa][Mm][Ee][Tt][Ee][Rr] ANY [Aa][Nn][Yy] /* Flavor */ FLAVOR [Ff][Ll][Aa][Vv][Oo][Rr] ENABLEOVERRIDE [Ee][Nn][Aa][Bb][Ll][Ee][Oo][Vv][Ee][Rr][Rr][Ii][Dd][Ee] DISABLEOVERRIDE [Dd][Ii][Ss][Aa][Bb][Ll][Ee][Oo][Vv][Ee][Rr][Rr][Ii][Dd][Ee] RESTRICTED [Rr][Ee][Ss][Tt][Rr][Ii][Cc][Tt][Ee][Dd] TOSUBCLASS [Tt][Oo][Ss][Uu][Bb][Cc][Ll][Aa][Ss][Ss] TOINSTANCE [Tt][Oo][Ii][Nn][Ss][Tt][Aa][Nn][Cc][Ee] TRANSLATABLE [Tt][Rr][Aa][Nn][Ss][Ll][Aa][Tt][Aa][Bb][Ll][Ee] /* Instance of */ INSTANCE [Ii][Nn][Ss][Tt][Aa][Nn][Cc][Ee] OF [Oo][Ff] /* Object */ OBJECT [Oo][Bb][Jj][Ee][Cc][Tt] /* Alias */ AS [Aa][Ss] /* #pragma */ PRAGMA \#[Pp][Rr][Aa][Gg][Mm][Aa][ ] /* **============================================================================== ** ** Literal productions (see CIM Infrastructure specification). ** **============================================================================== */ simpleChar \'[^\']\' escapedChar \'\\[rntfb\"\'\\]\' hexChar \'\\[xX][A-Fa-f0-9]+\' realValue [+-]?[0-9]*\.[0-9]+([eE][+-]?[0-9]+)? hexValue [+-]?0[xX][A-Fa-f0-9]+ decimalValue [+-]?[1-9][0-9]* octalValue [+-]?0[0-7]+ binaryValue [+-]?[01]+[Bb] blank [ \r\n\t] identifier [A-Za-z_][A-Za-z_0-9]* aliasIdentifier \$[A-Za-z_][A-Za-z_0-9]* whiteSpaceChar [ \r\n\t\b\f] /* **------------------------------------------------------------------------------ ** ** Lex productions: ** **------------------------------------------------------------------------------ */ %% <> { if (s_top == 0) yyterminate(); else { if (closeIncludeFile() != 0) return TOK_ERROR; } } {TRUE} { yylval.boolean = 1; return TOK_BOOLEAN_VALUE; } {FALSE} { yylval.boolean = 0; return TOK_BOOLEAN_VALUE; } {NULL} { return TOK_NULL; } {DT_BOOLEAN} { yylval.identifier = MOF_Strdup(&state.heap, yytext); return TOK_BOOLEAN; } {DT_SINT8} { return TOK_SINT8; } {DT_UINT8} { return TOK_UINT8; } {DT_SINT16} { return TOK_SINT16; } {DT_UINT16} { return TOK_UINT16; } {DT_SINT32} { return TOK_SINT32; } {DT_UINT32} { return TOK_UINT32; } {DT_SINT64} { return TOK_SINT64; } {DT_UINT64} { return TOK_UINT64; } {DT_REAL32} { return TOK_REAL32; } {DT_REAL64} { return TOK_REAL64; } {DT_DATETIME} { yylval.identifier = MOF_Strdup(&state.heap, yytext); return TOK_DATETIME; } {DT_CHAR16} { return TOK_CHAR16; } {DT_STRING} { yylval.identifier = MOF_Strdup(&state.heap, yytext); return TOK_STRING; } {REF} { return TOK_REF; } {SCOPE} { return TOK_SCOPE; } {CLASS} { yylval.identifier = MOF_Strdup(&state.heap, yytext); return TOK_CLASS; } {ASSOCIATION} { yylval.identifier = MOF_Strdup(&state.heap, yytext); return TOK_ASSOCIATION; } {INDICATION} { yylval.identifier = MOF_Strdup(&state.heap, yytext); return TOK_INDICATION; } {QUALIFIER} { yylval.identifier = MOF_Strdup(&state.heap, yytext); return TOK_QUALIFIER; } {PROPERTY} { yylval.identifier = MOF_Strdup(&state.heap, yytext); return TOK_PROPERTY; } {REFERENCE} { yylval.identifier = MOF_Strdup(&state.heap, yytext); return TOK_REFERENCE; } {METHOD} { yylval.identifier = MOF_Strdup(&state.heap, yytext); return TOK_METHOD; } {PARAMETER} { yylval.identifier = MOF_Strdup(&state.heap, yytext); return TOK_PARAMETER; } {ANY} { yylval.identifier = MOF_Strdup(&state.heap, yytext); return TOK_ANY; } {FLAVOR} { yylval.identifier = MOF_Strdup(&state.heap, yytext); return TOK_FLAVOR; } {ENABLEOVERRIDE} { yylval.identifier = MOF_Strdup(&state.heap, yytext); return TOK_ENABLEOVERRIDE; } {DISABLEOVERRIDE} { yylval.identifier = MOF_Strdup(&state.heap, yytext); return TOK_DISABLEOVERRIDE; } {RESTRICTED} { yylval.identifier = MOF_Strdup(&state.heap, yytext); return TOK_RESTRICTED; } {TOSUBCLASS} { yylval.identifier = MOF_Strdup(&state.heap, yytext); return TOK_TOSUBCLASS; } {TOINSTANCE} { yylval.identifier = MOF_Strdup(&state.heap, yytext); return TOK_TOINSTANCE; } {TRANSLATABLE} { yylval.identifier = MOF_Strdup(&state.heap, yytext); return TOK_TRANSLATABLE; } {INSTANCE} { return TOK_INSTANCE; } {OF} { yylval.identifier = MOF_Strdup(&state.heap, yytext); return TOK_OF; } {AS} { return TOK_AS; } {OBJECT} { return TOK_OBJECT; } {PRAGMA} { yylval.identifier = MOF_Strdup(&state.heap, yytext); return TOK_PRAGMA; } \/\* { /* C-sytle comments */ int c; int prev; /* Discard C-style comments. Replace with a single space since * comments may function as token separators. */ for (c = input(), prev = '\0'; EOF != c; prev = c, c = input()) { /* Check for closing comment */ if (prev == '*' && c == '/') break; /* Increment line counter on newlines */ if (c == '\n') state.line++; } /* Inject a blank character into input */ unput(' '); } \/\/ { /* C++-style comments */ int c; /* Discard all characters on this comment line including the newline */ for (c = input(); EOF != c; c = input()) { /* Increment line counter on newlines */ if (c == '\n') { state.line++; break; } } } \" { /* Read a string literal */ int c; Buffer buf = BUFFER_INITIALIZER; /* Scan until the closing quote is found */ for (;;) { c = input(); if (EOF == c || c == '"') break; if (Buffer_AppendChar(&buf, (char)c) != 0) { yyerrorf(ID_OUT_OF_MEMORY, "out of memory"); return TOK_ERROR; } /* If backslash, get next character */ if (c == '\\') { c = input(); if (EOF == c) { yyerrorf(ID_UNTERMINATED_STRING_LITERAL, "unterminated string literal"); return TOK_ERROR; } if (Buffer_AppendChar(&buf, (char)c) != 0) { yyerrorf(ID_OUT_OF_MEMORY, "out of memory"); return TOK_ERROR; } } } /* Append zero-terminator */ if (Buffer_AppendChar(&buf, '\0') != 0) { yyerrorf(ID_OUT_OF_MEMORY, "out of memory"); return TOK_ERROR; } /* Return the string */ yylval.string = buf.data; return TOK_STRING_VALUE; } {simpleChar} { yylval.character = yytext[1]; return TOK_CHAR_VALUE; } {escapedChar} { switch (yytext[2]) { case 'r': yylval.character = '\r'; break; case 'n': yylval.character = '\n'; break; case 't': yylval.character = '\t'; break; case 'f': yylval.character = '\f'; break; case 'b': yylval.character = '\b'; break; case '\"': yylval.character = '"'; break; case '\'': yylval.character = '\''; break; case '\\': yylval.character = '\\'; break; default: yyerrorf(ID_INTERNAL_ERROR, "internal error"); return TOK_ERROR; } return TOK_CHAR_VALUE; } {hexChar} { char* end; if (yyleng - 4 > 4) { yyerrorf(ID_ILLEGAL_HEX_CHARACTER, "illegal hex character"); return TOK_ERROR; } yylval.character = (MI_Char16)strtoul(&yytext[3], &end, 16); if (*end != '\'') { yyerrorf(ID_ILLEGAL_HEX_CHARACTER, "illegal hex character"); return TOK_ERROR; } return TOK_CHAR_VALUE; } [+-]?0 { yylval.integer = 0; return TOK_INTEGER_VALUE; } {decimalValue} { errno = 0; if (yytext[0] == '-') yylval.integer = (MI_Sint64)Strtoll(yytext, NULL, 10); else yylval.integer = (MI_Sint64)Strtoull(yytext, NULL, 10); if (errno == ERANGE) { yyerrorf(ID_INTEGER_OVERFLOW, "integer overflow"); return TOK_ERROR; } return TOK_INTEGER_VALUE; } {realValue} { yylval.real = (double)strtod(yytext, NULL); return TOK_REAL_VALUE; } {hexValue} { errno = 0; if (yytext[0] == '-') yylval.integer = (MI_Sint64)Strtoll(yytext, NULL, 16); else yylval.integer = (MI_Sint64)Strtoull(yytext, NULL, 16); if (errno == ERANGE) { yyerrorf(ID_INTEGER_OVERFLOW, "integer overflow"); return TOK_ERROR; } return TOK_INTEGER_VALUE; } {octalValue} { errno = 0; if (yytext[0] == '-') yylval.integer = (MI_Sint64)Strtoll(yytext, NULL, 8); else yylval.integer = (MI_Sint64)Strtoull(yytext, NULL, 8); if (errno == ERANGE) { yyerrorf(ID_INTEGER_OVERFLOW, "integer overflow"); return TOK_ERROR; } return TOK_INTEGER_VALUE; } {binaryValue} { char* end; if (yytext[0] == '-') yylval.integer = (MI_Sint64)Strtoll(yytext, &end, 2); else yylval.integer = (MI_Sint64)Strtoull(yytext, &end, 2); if (*end != 'B' && *end != 'b') { yyerrorf(ID_ILLEGAL_BINARY_LITERAL, "illegal binary literal"); return TOK_ERROR; } if (errno == ERANGE) { yyerrorf(ID_INTEGER_OVERFLOW, "integer overflow"); return TOK_ERROR; } return TOK_INTEGER_VALUE; } {identifier} { yylval.identifier = MOF_Strdup(&state.heap, yytext); return TOK_IDENT; } {aliasIdentifier} { yylval.identifier = MOF_Strdup(&state.heap, yytext); return TOK_ALIAS_IDENTIFIER; } \= { return '='; } \( { return '('; } \) { return ')'; } \[ { return '['; } \] { return ']'; } \{ { return '{'; } \} { return '}'; } \: { return ':'; } \; { return ';'; } \, { return ','; } {whiteSpaceChar}+ { /* swallow whiteSpaceChar */ int i; for (i = 0; i < yyleng; i++) { if (yytext[i] == '\n') state.line++; } } . { yyterminate(); } %% /* **============================================================================== ** ** Function definitions ** **============================================================================== */ int yywrap() { /* Return 1 to indicate the end of input */ return 1; } static int exists(const char* path) { if (access(path, R_OK) != 0) return -1; return 0; } static char* findIncludeFile(const char* path) { /* First attempt to locate the file relative to the one that included it */ { Buffer buf = BUFFER_INITIALIZER; char* p; p = strrchr(state.path, '/'); if (p) { if (Buffer_Append(&buf, state.path, p - state.path + 1) != 0) return NULL; } if (Buffer_Append(&buf, path, strlen(path) + 1) != 0) return NULL; if (exists((const char*)buf.data) == 0) return (char*)buf.data; } /* Attempt to open the file relative to the current directory */ { if (exists(path) == 0) return MOF_Strdup(&state.heap, path); } /* Search for file using include path array */ { size_t i; for (i = 0; i < state.paths.size; i++) { const char* p = (const char*)state.paths.data[i]; Buffer buf = BUFFER_INITIALIZER; if (Buffer_Append(&buf, p, strlen(p)) != 0) return NULL; if (Buffer_AppendChar(&buf, '/') != 0) return NULL; if (Buffer_Append(&buf, path, strlen(path) + 1) != 0) return NULL; if (exists((char*)buf.data) == 0) return (char*)buf.data; MOF_Free(&state.heap, buf.data); } } /* Not found */ return NULL; } int openIncludeFile(const char* path_) { FILE* is; char* path; if ((path = findIncludeFile(path_)) == NULL) { yyerrorf(ID_FAILED_TO_FIND_INCLUDE_FILE, "failed to find inlude file: \"%s\"", path_); return -1; } /* Check for stack overflow. */ if (s_top >= MOF_STACK_SIZE) { yyerrorf(ID_MOF_STACK_OVERFLOW, "MOF file stack overflow"); return -1; } /* Open the file */ if ((is = File_Open(path, "rb")) == NULL) { yyerrorf(ID_FAILED_TO_OPEN_FILE, "failed to open file: \"%s\"", path); return -1; } /* Push current state onto stack. */ s_stack[s_top].file = state.path; s_stack[s_top].line = state.line; s_stack[s_top].buffer = YY_CURRENT_BUFFER; s_top++; /* Setup state for new file */ yy_switch_to_buffer(yy_create_buffer(is, YY_BUF_SIZE)); state.path = MOF_Strdup(&state.heap, path); state.line = 1; return 0; } int closeIncludeFile() { /* Check for stack underflow. */ if (s_top == 0) { yyerrorf(ID_MOF_STACK_UNDERFLOW, "MOF file stack underflow"); return -1; } /* Release current state */ MOF_Free(&state.heap, state.path); fclose(YY_CURRENT_BUFFER->yy_input_file); yy_delete_buffer(YY_CURRENT_BUFFER); /* Restore state from top of stack */ s_top--; state.path = s_stack[s_top].file; state.line = s_stack[s_top].line; yy_switch_to_buffer(s_stack[s_top].buffer); return 0; } /* **============================================================================== ** ** MOF_Parser ** **============================================================================== */ MOF_Parser* MOF_Parser_New( const char* const* paths, size_t numPaths) { MOF_Parser* self = (MOF_Parser*)PAL_Calloc(1, sizeof(MOF_Parser)); size_t i; char* str; if (!self) return NULL; for (i = 0; i < numPaths; i++) { str = MOF_Strdup(&self->state.heap, paths[i]); if (!str) { MOF_Release(&self->state.heap); PAL_Free(self); return NULL; } /* PtrArray_Append() uses the global state's heap object to * obtain memory, so install self->state as the global state * object temporarily. */ { state = self->state; PtrArray_Append(&state.paths, str); self->state = state; memset(&state, 0, sizeof(state)); } } return self; } void MOF_Parser_SetErrorCallback( MOF_Parser* self, void (*callback)(const char* msg, const wchar_t* wmsg, void* data), void* data) { if (self) { self->state.errorCallback = callback; self->state.errorCallbackData = data; } } void MOF_Parser_SetWarningCallback( MOF_Parser* self, void (*callback)(const char* msg, const wchar_t* wmsg, void* data), void* data) { if (self) { self->state.warningCallback = callback; self->state.warningCallbackData = data; } } void MOF_Parser_SetPragmaCallback( MOF_Parser* self, void (*callback)(const char* pragma, const char* value, void* data), void* data) { if (self) { self->state.pragmaCallback = callback; self->state.pragmaCallbackData = data; } } void MOF_Parser_SetClassDeclCallback( MOF_Parser* self, void (*callback)(const MI_ClassDecl* decl, void* data), void* data) { if (self) { self->state.classDeclCallback = callback; self->state.classDeclCallbackData = data; } } void MOF_Parser_SetInstanceDeclCallback( MOF_Parser* self, void (*callback)(const MI_InstanceDecl* decl, void* data), void* data) { if (self) { self->state.instanceDeclCallback = callback; self->state.instanceDeclCallbackData = data; } } void MOF_Parser_SetQualifierDeclCallback( MOF_Parser* self, void (*callback)(const MI_QualifierDecl* decl, void* data), void* data) { if (self) { self->state.qualifierDeclCallback = callback; self->state.qualifierDeclCallbackData = data; } } void MOF_Parser_Delete(MOF_Parser* self) { if (self) { MOF_Release(&self->state.heap); PAL_Free(self); } } /* Handle multiple calls to this function */ int MOF_Parser_Parse(MOF_Parser* self, const char* path) { /* Reject null parameters */ if (!self || !path) return -1; /* Clear stack */ s_top = 0; /* Set global state */ state = self->state; /* Open input */ yyin = File_Open(path, "rb"); if (!yyin) { yyerrorf(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path); self->state = state; memset(&state.heap, 0, sizeof(state)); return -1; } /* Save path */ state.path = MOF_Strdup(&state.heap, path); /* Set initialize line number */ state.line = 1; /* Clear the parser state */ yy_c_buf_p = 0; yy_last_accepting_cpos = 0; yy_init = 1; /* Run the parser */ if (yyparse() != 0) { fclose(yyin); yy_delete_buffer(YY_CURRENT_BUFFER); self->state = state; memset(&state.heap, 0, sizeof(state)); return -1; } /* Perform post processing (which requires first pass completion) */ if (PerformPostProcessing() != 0) { fclose(yyin); yy_delete_buffer(YY_CURRENT_BUFFER); self->state = state; memset(&state.heap, 0, sizeof(state)); return -1; } /* Close stream and release parse buffer */ fclose(yyin); yy_delete_buffer(YY_CURRENT_BUFFER); /* Restore state */ self->state = state; memset(&state.heap, 0, sizeof(state)); return 0; } /* Parse a MOF string */ int MOF_Parser_ParseString(MOF_Parser* self, const char* mof_string) { YY_BUFFER_STATE bp; /* Reject null parameters */ if (!self || !mof_string) return -1; /* Clear stack */ s_top = 0; /* Set global state */ state = self->state; /* Save path */ state.path = MOF_Strdup(&state.heap, "MOF string"); /* Set initialize line number */ state.line = 1; /* Clear the parser state */ yy_c_buf_p = 0; yy_last_accepting_cpos = 0; yy_init = 1; /* Run the parser */ bp = yy_scan_string(mof_string); yy_switch_to_buffer(bp); if (yyparse() != 0) { yy_delete_buffer(bp); self->state = state; memset(&state.heap, 0, sizeof(state)); return -1; } /* Perform post processing (which requires first pass completion) */ if (PerformPostProcessing() != 0) { yy_delete_buffer(bp); self->state = state; memset(&state.heap, 0, sizeof(state)); return -1; } /* Close stream and release parse buffer */ yy_delete_buffer(bp); /* Restore state */ self->state = state; memset(&state.heap, 0, sizeof(state)); return 0; } void MOF_Parser_Dump(MOF_Parser* self, FILE* file) { size_t i; for (i = 0; i < self->state.qualifierDecls.size; i++) MOF_PrintQualifierDecl(self->state.qualifierDecls.data[i], file); for (i = 0; i < self->state.classDecls.size; i++) MOF_PrintClassDecl(self->state.classDecls.data[i], file); for (i = 0; i < self->state.instanceDecls.size; i++) MOF_PrintInstanceDecl(self->state.instanceDecls.data[i], file); } void MOF_Parser_EnableExtensions(MOF_Parser* self, MI_Boolean enabled) { self->state.extensionsEnabled = enabled; return; }