2019-05-13 08:25:22 -04:00
# 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 <kkaempf@suse.de>
/*
* 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
2019-10-30 11:54:50 -04:00
2019-05-13 08:25:22 -04:00
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
}
;
2019-10-30 11:54:50 -04:00
2019-05-13 08:25:22 -04:00
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
*
*/
2019-10-30 11:54:50 -04:00
2019-05-13 08:25:22 -04:00
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
*
*/
2019-10-30 11:54:50 -04:00
2019-05-13 08:25:22 -04:00
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]
}
;
2019-10-30 11:54:50 -04:00
2019-05-13 08:25:22 -04:00
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 <schema>_<classname> in CIM v2.x */
{ raise ParseError.new("Class name must be prefixed by '<schema>_'") 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])
}
;
2019-10-30 11:54:50 -04:00
2019-05-13 08:25:22 -04:00
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
;
2019-10-30 11:54:50 -04:00
2019-05-13 08:25:22 -04:00
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
;
2019-10-30 11:54:50 -04:00
2019-05-13 08:25:22 -04:00
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] }
;
2019-10-30 11:54:50 -04:00
2019-05-13 08:25:22 -04:00
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
*
*/
2019-10-30 11:54:50 -04:00
2019-05-13 08:25:22 -04:00
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
*
*/
2019-10-30 11:54:50 -04:00
2019-05-13 08:25:22 -04:00
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'
2021-09-14 08:38:11 -04:00
require File.join(__dir__, 'result')
require File.join(__dir__, 'scanner')
require File.join(__dir__, 'case')
2019-05-13 08:25:22 -04:00
---- 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
2019-10-30 11:54:50 -04:00
2019-05-13 08:25:22 -04:00
@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 <dir>] [<moffiles>]"
$stderr.puts "Compiles <moffile>"
$stderr.puts "\t-d debug"
$stderr.puts "\t-h this help"
$stderr.puts "\t-I <dir> include dir"
$stderr.puts "\t-f force"
$stderr.puts "\t-n <namespace>"
$stderr.puts "\t-o <output>"
$stderr.puts "\t-s <style> syntax style (wmi,cim)"
$stderr.puts "\t-q quiet"
$stderr.puts "\t<moffiles> file(s) to read (else use $stdin)"
exit 0
when "-f" then options[:force] = true
when "-s" then options[:style] = argv.shift.to_sym
when "-d" then options[:debug] = true
when "-q" then options[:quiet] = true
when "-I"
options[:includes] ||= []
dirname = argv.shift
unless File.directory?(dirname)
files << dirname
dirname = File.dirname(dirname)
end
options[:includes] << Pathname.new(dirname)
when "-n" then options[:namespace] = argv.shift
when "-o" then options[:output] = argv.shift
when /^-.+/
$stderr.puts "Undefined option #{opt}"
else
files << opt
end
end
[ files, options ]
end
include Helper
include Scanner
---- footer ----