# Distributed under the Ruby license # See http://www.ruby-lang.org/en/LICENSE.txt for the full license text # Copyright (c) 2010 Klaus Kämpf /* * According to appendix A of * http://www.dmtf.org/standards/cim/cim_spec_v22 */ class MOF::Parser prechigh /* nonassoc UMINUS */ left '*' '/' left '+' '-' preclow token PRAGMA INCLUDE IDENTIFIER CLASS ASSOCIATION INDICATION AMENDED ENABLEOVERRIDE DISABLEOVERRIDE RESTRICTED TOSUBCLASS TOINSTANCE TRANSLATABLE QUALIFIER SCOPE SCHEMA PROPERTY REFERENCE METHOD PARAMETER FLAVOR INSTANCE AS REF ANY OF DT_VOID DT_UINT8 DT_SINT8 DT_UINT16 DT_SINT16 DT_UINT32 DT_SINT32 DT_UINT64 DT_SINT64 DT_REAL32 DT_REAL64 DT_CHAR16 DT_STR DT_BOOLEAN DT_DATETIME positiveDecimalValue stringValue realValue charValue booleanValue nullValue binaryValue octalValue decimalValue hexValue rule /* Returns a Hash of filename and MofResult */ mofSpecification : /* empty */ { result = Hash.new } | mofProduction { result = { @name => @result } } | mofSpecification mofProduction { result = val[0] result[@name] = @result } ; mofProduction : compilerDirective | classDeclaration { #puts "Class '#{val[0].name}'" @result.classes << val[0] } | qualifierDeclaration { @result.qualifiers << val[0] @qualifiers[val[0].name.downcase] = val[0] } | instanceDeclaration { @result.instances << val[0] } ; /*** * compilerDirective * */ compilerDirective : "#" PRAGMA INCLUDE pragmaParameters_opt { raise MOF::Helper::Error.new(@name,@lineno,@line,"Missing filename after '#pragma include'") unless val[3] open val[3], :pragma } | "#" PRAGMA pragmaName pragmaParameters_opt | "#" INCLUDE pragmaParameters_opt { raise StyleError.new(@name,@lineno,@line,"Use '#pragma include' instead of '#include'") unless @style == :wmi raise MOF::Helper::Error.new(@name,@lineno,@line,"Missing filename after '#include'") unless val[2] open val[2], :pragma } ; pragmaName : IDENTIFIER ; pragmaParameters_opt : /* empty */ { raise StyleError.new(@name,@lineno,@line,"#pragma parameter missing") unless @style == :wmi } | "(" pragmaParameterValues ")" { result = val[1] } ; pragmaParameterValues : pragmaParameterValue | pragmaParameterValues "," pragmaParameterValue ; pragmaParameterValue : string | integerValue { raise StyleError.new(@name,@lineno,@line,"#pragma parameter missing") unless @style == :wmi } | IDENTIFIER ; /*** * classDeclaration * */ classDeclaration : qualifierList_opt CLASS className alias_opt superClass_opt "{" classFeatures "}" ";" { qualifiers = val[0] features = val[6] # FIXME: features must not include references result = CIM::Class.new(val[2],qualifiers,val[3],val[4],features) } ; classFeatures : /* empty */ { result = [] } | classFeatures classFeature { result = val[0] << val[1] } ; classFeature : propertyDeclaration | methodDeclaration | referenceDeclaration /* must have association qualifier */ ; qualifierList_opt : /* empty */ | qualifierList { result = CIM::QualifierSet.new val[0] } ; qualifierList : "[" qualifier qualifiers "]" { result = val[2] result.unshift val[1] if val[1] } ; qualifiers : /* empty */ { result = [] } | qualifiers "," qualifier { result = val[0] result << val[2] if val[2] } ; qualifier : qualifierName qualifierParameter_opt flavor_opt { # Get qualifier decl qualifier = case val[0] when CIM::Qualifier then val[0].definition when CIM::QualifierDeclaration then val[0] when String then @qualifiers[val[0].downcase] else nil end raise MOF::Helper::Error.new(@name,@lineno,@line,"'#{val[0]}' is not a valid qualifier") unless qualifier value = val[1] raise MOF::Helper::Error.new(@name,@lineno,@line,"#{value.inspect} does not match qualifier type '#{qualifier.type}'") unless qualifier.type.matches?(value)||@style == :wmi # Don't propagate a boolean 'false' if qualifier.type == :boolean && value == false result = nil else result = CIM::Qualifier.new(qualifier,value,val[2]) end } ; flavor_opt : /* empty */ | ":" flavor { result = CIM::QualifierFlavors.new val[1] } ; qualifierParameter_opt : /* empty */ | qualifierParameter ; qualifierParameter : "(" constantValue ")" { result = val[1] } | arrayInitializer ; /* CIM::Flavors */ flavor : AMENDED | ENABLEOVERRIDE | DISABLEOVERRIDE | RESTRICTED | TOSUBCLASS | TRANSLATABLE | TOINSTANCE { case val[0].to_sym when :amended, :toinstance raise StyleError.new(@name,@lineno,@line,"'#{val[0]}' is not a valid flavor") unless @style == :wmi end } ; alias_opt : /* empty */ | alias ; superClass_opt : /* empty */ | superClass ; className : IDENTIFIER /* must be _ in CIM v2.x */ { raise ParseError.new("Class name must be prefixed by '_'") unless val[0].include?("_") || @style == :wmi } ; alias : AS aliasIdentifier { result = val[1] } ; aliasIdentifier : "$" IDENTIFIER /* NO whitespace ! */ { result = val[1] } ; superClass : ":" className { result = val[1] } ; propertyDeclaration : qualifierList_opt dataType propertyName array_opt defaultValue_opt ";" { if val[3] type = CIM::Array.new val[3],val[1] else type = val[1] end result = CIM::Property.new(type,val[2],val[0],val[4]) } ; referenceDeclaration : qualifierList_opt objectRef referenceName array_opt defaultValue_opt ";" { if val[4] raise StyleError.new(@name,@lineno,@line,"Array not allowed in reference declaration") unless @style == :wmi end result = CIM::Reference.new(val[1],val[2],val[0],val[4]) } ; methodDeclaration : qualifierList_opt dataType methodName "(" parameterList_opt ")" ";" { result = CIM::Method.new(val[1],val[2],val[0],val[4]) } ; propertyName : IDENTIFIER | PROPERTY { # tmplprov.mof has 'string Property;' raise StyleError.new(@name,@lineno,@line,"Invalid keyword '#{val[0]}' used for property name") unless @style == :wmi } ; referenceName : IDENTIFIER | INDICATION { result = "Indication" } ; methodName : IDENTIFIER ; dataType : DT_UINT8 | DT_SINT8 | DT_UINT16 | DT_SINT16 | DT_UINT32 | DT_SINT32 | DT_UINT64 | DT_SINT64 | DT_REAL32 | DT_REAL64 | DT_CHAR16 | DT_STR | DT_BOOLEAN | DT_DATETIME | DT_VOID { raise StyleError.new(@name,@lineno,@line,"'void' is not a valid datatype") unless @style == :wmi } ; objectRef : className { # WMI uses class names as data types (without REF ?!) raise StyleError.new(@name,@lineno,@line,"Expected 'ref' keyword after classname '#{val[0]}'") unless @style == :wmi result = CIM::ReferenceType.new val[0] } | className REF { result = CIM::ReferenceType.new val[0] } ; parameterList_opt : /* empty */ | parameterList ; parameterList : parameter parameters { result = val[1].unshift val[0] } ; parameters : /* empty */ { result = [] } | parameters "," parameter { result = val[0] << val[2] } ; parameter : qualifierList_opt typespec parameterName array_opt parameterValue_opt { if val[3] type = CIM::Array.new val[3], val[1] else type = val[1] end result = CIM::Property.new(type,val[2],val[0]) } ; typespec : dataType | objectRef ; parameterName : IDENTIFIER ; array_opt : /* empty */ | array ; parameterValue_opt : /* empty */ | defaultValue { raise "Default parameter value not allowed in syntax style '{@style}'" unless @style == :wmi } ; array : "[" positiveDecimalValue_opt "]" { result = val[1] } ; positiveDecimalValue_opt : /* empty */ { result = -1 } | positiveDecimalValue ; defaultValue_opt : /* empty */ | defaultValue ; defaultValue : "=" initializer { result = val[1] } ; initializer : constantValue | arrayInitializer | referenceInitializer ; arrayInitializer : "{" constantValues "}" { result = val[1] } ; constantValues : /* empty */ | constantValue { result = [ val[0] ] } | constantValues "," constantValue { result = val[0] << val[2] } ; constantValue : integerValue | realValue | charValue | string | booleanValue | nullValue | instance { raise "Instance as property value not allowed in syntax style '{@style}'" unless @style == :wmi } ; integerValue : binaryValue | octalValue | decimalValue | positiveDecimalValue | hexValue ; string : stringValue | string stringValue { result = val[0] + val[1] } ; referenceInitializer : objectHandle | aliasIdentifier ; objectHandle : namespace_opt modelPath ; namespace_opt : /* empty */ | namespaceHandle ":" ; namespaceHandle : IDENTIFIER ; /* * Note : structure depends on type of namespace */ modelPath : className "." keyValuePairList ; keyValuePairList : keyValuePair keyValuePairs ; keyValuePairs : /* empty */ | keyValuePairs "," keyValuePair ; keyValuePair : keyname "=" initializer ; keyname : propertyName | referenceName ; /*** * qualifierDeclaration * */ qualifierDeclaration /* 0 1 2 3 4 */ : QUALIFIER qualifierName qualifierType scope defaultFlavor_opt ";" { result = CIM::QualifierDeclaration.new( val[1], val[2][0], val[2][1], val[3], val[4]) } ; defaultFlavor_opt : /* empty */ | defaultFlavor ; qualifierName : IDENTIFIER | ASSOCIATION /* meta qualifier */ | INDICATION /* meta qualifier */ | REFERENCE /* Added in DSP0004 2.7.0 */ | SCHEMA ; /* [type, value] */ qualifierType : ":" dataType array_opt defaultValue_opt { type = val[2].nil? ? val[1] : CIM::Array.new(val[2],val[1]) result = [ type, val[3] ] } ; scope : "," SCOPE "(" metaElements ")" { result = CIM::QualifierScopes.new(val[3]) } ; metaElements : metaElement { result = [ val[0] ] } | metaElements "," metaElement { result = val[0] << val[2] } ; metaElement : SCHEMA | CLASS | ASSOCIATION | INDICATION | QUALIFIER | PROPERTY | REFERENCE | METHOD | PARAMETER | ANY ; defaultFlavor : "," FLAVOR "(" flavors ")" { result = CIM::QualifierFlavors.new val[3] } ; flavors : flavor { result = [ val[0] ] } | flavors "," flavor { result = val[0] << val[2] } ; /*** * instanceDeclaration * */ instanceDeclaration : instance ";" ; instance : qualifierList_opt INSTANCE OF className alias_opt "{" valueInitializers "}" ; valueInitializers : valueInitializer | valueInitializers valueInitializer ; valueInitializer : qualifierList_opt keyname "=" initializer ";" | qualifierList_opt keyname ";" { raise "Instance property '#{val[1]} must have a value" unless @style == :wmi } ; end # class Parser ---- header ---- # parser.rb - generated by racc require 'strscan' require 'rubygems' require 'cim' require File.join(__dir__, 'result') require File.join(__dir__, 'scanner') require File.join(__dir__, 'case') ---- inner ---- # # Initialize MOF::Parser # MOF::Parser.new options = {} # # options -> Hash of options # :debug -> boolean # :includes -> array of include dirs # :style -> :cim or :wmi # def initialize options = {} @yydebug = options[:debug] @includes = options[:includes] || [] @quiet = options[:quiet] @style = options[:style] || :cim # default to style CIM v2.2 syntax @lineno = 1 @file = nil @iconv = nil @eol = "\n" @fname = nil @fstack = [] @in_comment = false @seen_files = [] @qualifiers = {} end # # Make options hash from argv # # returns [ files, options ] # def self.argv_handler name, argv files = [] options = { :namespace => "" } while argv.size > 0 case opt = argv.shift when "-h" $stderr.puts "Ruby MOF compiler" $stderr.puts "#{name} [-h] [-d] [-I ] []" $stderr.puts "Compiles " $stderr.puts "\t-d debug" $stderr.puts "\t-h this help" $stderr.puts "\t-I include dir" $stderr.puts "\t-f force" $stderr.puts "\t-n " $stderr.puts "\t-o " $stderr.puts "\t-s