Added scripts for Qt generation.

This commit is contained in:
Matthias Koefferlein
2017-02-21 20:32:40 +01:00
parent eea5da4ba6
commit c15179aa19
21 changed files with 43137 additions and 0 deletions
+414
View File
@@ -0,0 +1,414 @@
#
# Copyright (C) 2006-2017 Matthias Koefferlein
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
require "cpp_classes.rb"
require "cpp_parser_classes.rb"
grammar CPP
rule s
[ \t\n\r]*
end
rule sp
[ \t\n\r]+
end
rule string_const
'"' ( [^\\"] / "\\" . )* '"'
end
rule char_const
"'" ( [^\\'] / "\\" . )* "'"
end
rule numeric_const
"-"? ( [0-9]+ ( "." [0-9]* )? / "." [0-9]+ ) ( [eE] "-"? [0-9]+ )?
end
rule hex_const
"0x" [0-9a-fA-F]+
end
rule attribute_value
"(" ( s ( "," s )? attribute_value )* s ")" / numeric_const / string_const / id
end
rule a
s ( "__attribute__" s attribute_value s / "__asm" s attribute_value s / "__extension__" s )*
end
rule unary_op
"~" / "!" / "-" / "*" / "&"
end
rule bin_op_wo_gt
"+=" / "++" / "+" / "->" / "-=" / "--" / "-" / "()" / "[]" / "&&" / "&=" / "&" / "||" / "|=" / "|" /
"==" / "=" / "!=" / "*=" / "*" / "/=" / "/" / "%=" / "%" / "<=" / "<<=" / "<<" / "<" /
"~=" / "^=" / "^" / "~=" / ">=" / ">>="
end
rule bin_op
bin_op_wo_gt / ">>" / ">"
end
rule id
"operator" s "," /
"operator" s ( bin_op / unary_op / "," ) /
"operator" sp [a-zA-Z\*\& \t\n\r]+ &( s "(" ) /
"~"? [a-zA-Z_] [a-zA-Z_0-9]*
end
rule template_arg_part_any
block_wo_gt <PConst>
end
rule template_arg_part
qualified_id &( ( s ">" / "," ) ) / template_arg_part_any
end
rule template_args
template_arg_part ( s "," s template_arg_part )* <PTemplateArgs>
end
rule id_with_template_args
id:id taspec:( s "<" s ta:template_args s ">" )? <PId>
end
rule qualified_id
globalspec:( "::" s )? id_with_template_args ( s "::" id_with_template_args )* <PQualifiedId>
end
rule int_type_attr
"signed" ![a-zA-Z0-9_] / "unsigned" ![a-zA-Z0-9_] / "long" ( sp "long" )? ![a-zA-Z0-9_] / "short" ![a-zA-Z0-9_]
end
rule int_type
(
( int_type_attr s )* "int" ![a-zA-Z0-9_] /
int_type_attr ( s int_type_attr )* !"char" ( s "int" ![a-zA-Z0-9_] )?
) <PIntType>
end
rule char_type
( "signed" sp / "unsigned" sp )? s !"int" "char" ![a-zA-Z0-9_] <PCharType>
end
rule bool_type
"bool" <PBoolType>
end
rule void_type
"void" <PVoidType>
end
rule float_type
( "long" sp )? ( "double" / "float" ) ![a-zA-Z0-9_] <PFloatType>
end
rule enum_spec
id:id initspec:( s "=" s init:block_wo_comma )? <PEnumSpec>
end
rule enum_body
enum_spec ( s "," s enum_spec )*
end
rule enum_type
"enum" ![a-zA-Z0-9_] a s id:id? bodyspec:( s "{" s body:enum_body s "}" )? <PEnumType>
end
rule virtual_spec
"virtual" <PVirtual>
end
rule member_declaration_wo_semicolon
template:( d:template_decl s )?
attr:( ( "explicit" / "mutable" / storage_class / inline_spec / virtual_spec ) s )*
t:type
# type declaration ends with a } .. does not need a semicolon
# (i.e. nested struct or enum)
&{ |seq| seq[-1].text_value_ends_with_curly_brace }
s
( ":" s block_wo_curly_braces s )?
a
(
"{" s block s "}" /
";"?
) <PDeclaration>
end
rule member_declaration_w_semicolon
template:( d:template_decl s )?
attr:( ( "explicit" / "mutable" / storage_class / inline_spec / virtual_spec ) s )*
t:type
# opposite case (member_see declaration_wo_semicolon)
# (i.e. nested struct or enum)
!{ |seq| seq[-1].text_value_ends_with_curly_brace }
s
( ":" s block_wo_curly_braces s )?
a
(
"{" s block s "}" /
";"
) <PDeclaration>
end
rule member_declaration
a ( member_declaration_wo_semicolon / member_declaration_w_semicolon )
end
rule friend_decl
a template:( d:template_decl s )? "friend" ![a-zA-Z0-9_] s t:member_declaration <PFriendDecl>
end
rule class_struct_body_declarations
( s ";" / s friend_decl / s using / s typedef / s !( "public" / "private" / "protected" ) member_declaration )*
end
rule class_struct_body
class_struct_body_declarations
(
s "public" s ":" d:class_struct_body_declarations <PPublicClassStructBodyDeclarations> /
s "private" s ":" d:class_struct_body_declarations <PPrivateClassStructBodyDeclarations> /
s "protected" s ":" d:class_struct_body_declarations <PProtectedClassStructBodyDeclarations>
)*
end
rule class_id
# In order to easily distinguish between constructor methods without
# a return type and class or typedef names we assume that all "name("
# constructs are considered constructor names but "name (*func_ptr) ()" is not.
qualified_id s !( "(" !( s "*" ) )
end
rule typeof
"__typeof" s "(" s qid:qualified_id s ")" <PTypeOf>
end
rule base_class
attr:( "public" ![a-zA-Z0-9_] s / "private" ![a-zA-Z0-9_] s / "protected" ![a-zA-Z0-9_] s / "virtual" ![a-zA-Z0-9_] s )* a cid:class_id <PBaseClass>
end
rule base_classes
base_class ( s "," s base_classes )?
end
rule class_or_struct_type
stype:( "union" ![a-zA-Z0-9_] / "struct" ![a-zA-Z0-9_] / "class" ![a-zA-Z0-9_] ) a idspec:( s id:class_id )? bcspec:( s ":" s bc:base_classes )? bodyspec:( s "{" s body:class_struct_body s "}" )? <PStructOrClassType>
end
rule concrete_type
( class_or_struct_type / enum_type / float_type / char_type / int_type / bool_type / void_type / typeof / class_id )?
end
rule cv
( "const" ![a-zA-Z0-9_] / "__const" ![a-zA-Z0-9_] / "volatile" ![a-zA-Z0-9_] / "__volatile" ![a-zA-Z0-9_] ) <PCV>
end
rule pointer
cvspec:( cv:cv s )? "*" itspec:( s it:inner_type )? <PPointer>
end
rule reference
cvspec:( cv:cv s )? "&" itspec:( s it:inner_type )? <PReference>
end
rule array_spec
"[" s block_wo_comma s "]" <PArraySpec>
end
rule func_arg_part
t:type_wo_comma !"..." <PFuncArgPart>
end
rule ellipsis
"..." <PEllipsis>
end
rule func_args
&")" /
func_arg_part ( s "," s func_arg_part )* ( s "," s ellipsis )? /
ellipsis
end
rule func_spec
"(" s fa:( a:func_args )? s ")" cvspec:( s cv:cv )? ( s "throw" s "(" s ( type_wo_comma s )? ")" )* a <PFuncSpec>
end
rule member_pointer
cspec:( qid:qualified_id s "::*" s ) itspec:( it:inner_type )? cvspec:( s cv:cv )? <PMemberPointer>
end
rule inner_type_with_cv
cvspec:cv s it:inner_type <PInnerTypeWithCV>
end
rule inner_type
it:(
"(" s inner_type s ")" /
inner_type_with_cv /
pointer /
reference /
member_pointer /
( "__restrict" ![a-zA-Z0-9_] s )? qualified_id
)
pfx:( s spec:( array_spec / func_spec ) )*
<PInnerType>
end
rule type
cvspec:( cv:cv s )?
a
( "typename" ![a-zA-Z0-9_] s )?
ct:concrete_type
a
il:( s t1:inner_type i1:(s "=" s is1:block_wo_comma)? tt:( s "," s t2:inner_type i2:(s "=" s is2:block_wo_comma)? )* )?
# alternative initialization if only a concrete type is given:
pi:( s "=" s is:block_wo_comma )?
<PType>
end
rule type_wo_comma
cvspec:( cv:cv s )?
a
( "typename" ![a-zA-Z0-9_] s )?
ct:concrete_type
il:( s t:inner_type i:(s "=" s is:block_wo_comma)? )?
# alternative initialization if only a concrete type is given:
pi:( s "=" s is:block_wo_comma )?
<PTypeWoComma>
end
rule type_for_template
cvspec:( cv:cv s )?
a
( "typename" ![a-zA-Z0-9_] s )?
ct:concrete_type
il:( s t:inner_type )?
<PTypeForTemplate>
end
rule storage_class
( "static" ![a-zA-Z0-9_] / "extern" ![a-zA-Z0-9_] ( s '"C"' / s '"C++"' / s '"Pascal"' )? ) <PStorageClass>
end
rule inline_spec
"inline" ![a-zA-Z0-9_] <PInline>
end
# parse over blocks as gracefully as possible ...
rule block_atom_wo_gt
"(" s block s ")" / "[" s block s "]" / "<" s block_wo_gt ( s "," s block_wo_gt )* s ">" /
numeric_const / hex_const / string_const / char_const /
id / unary_op / bin_op_wo_gt / "?" / "::" / "." / ":" / ";"
end
rule block_wo_gt
( s block_atom_wo_gt / s "{" s block s "}" )*
end
# parse over blocks as gracefully as possible ...
rule block_atom
"(" s block s ")" / "[" s block s "]" / "<" s block_wo_gt ( s "," s block_wo_gt )* s ">" /
numeric_const / hex_const / string_const / char_const /
id / unary_op / bin_op / "?" / "::" / "." / ":"
end
rule block
( s block_atom / s ";" / s "," / s "{" s block s "}" )*
end
rule block_wo_curly_braces
( s block_atom / s "," )*
end
rule block_wo_comma
( s block_atom / s "{" s block s "}" )*
end
rule using
"using" ![a-zA-Z0-9_] ( s "namespace" )? ![a-zA-Z0-9_] s id:qualified_id a ";" <PUsing>
end
rule typedef
a "typedef" ![a-zA-Z0-9_] s t:type a ";" <PTypedef>
end
rule template_decl_arg
( "class" / "typename" ) ![a-zA-Z0-9_] s id:id dtspec:( s "=" s dt:type_for_template )? <PClassTemplateArg> /
t:type_for_template initspec:( s "=" s init:block_wo_gt )? <PDirectTemplateArg>
end
rule template_decl
"template" s "<" s ( !">" template_decl_arg s ( "," s template_decl_arg )* )? s ">" <PTemplateDecl>
end
rule declaration_w_semicolon
template:( d:template_decl s )?
template_member:( d_member:template_decl s )?
attr:( ( storage_class / inline_spec ) s )*
a
t:type
# type declaration ends with a } .. does not need a semicolon
# (i.e. nested struct or enum)
!{ |seq| seq[-1].text_value_ends_with_curly_brace }
s ( ":" s block_wo_curly_braces s )?
a
(
"{" s block s "}" /
";"
) <PDeclaration>
end
rule declaration_wo_semicolon
template:( d:template_decl s )?
attr:( ( storage_class / inline_spec ) s )*
a
t:type
# opposite case (see declaration_wo_semicolon)
# (i.e. nested struct or enum)
&{ |seq| seq[-1].text_value_ends_with_curly_brace }
s ( ":" s block_wo_curly_braces s )?
a
(
"{" s block s "}" /
";"?
) <PDeclaration>
end
rule declaration
declaration_w_semicolon / declaration_wo_semicolon
end
rule namespace
"namespace" ![a-zA-Z0-9_] s n:id
a "{" decls:( a ( ";" / using / typedef / namespace / declaration ) )* s "}" <PNamespace>
end
rule extern_decl
"extern" s n:( '"C"' / '"C++"' / '"Pascal"' ) s
a "{" decls:( a ( ";" / typedef / namespace / extern_decl / declaration ) )* s "}" <PExternBlock>
end
rule module
( a ( ";" / using / typedef / namespace / extern_decl / declaration ) )* s <PModule>
end
end
+654
View File
@@ -0,0 +1,654 @@
#
# Copyright (C) 2006-2017 Matthias Koefferlein
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
class Module
def def_initializer(*args)
self.class_eval <<END
def initialize(#{args.join(", ")})
#{args.map { |arg| "@#{arg} = #{arg}" }.join("\n")}
end
def initialize_copy(other)
# TODO: is there a better way to check whether dup can be used?
# Implement Hash?
#{args.map { |arg| "a = other.#{arg}\n"+
"if a.is_a?(TrueClass) || a.is_a?(FalseClass) || a.is_a?(NilClass) || a.is_a?(Fixnum) || a.is_a?(Float) || a.is_a?(Symbol)\n"+
" @#{arg} = a\n"+
"elsif a.is_a?(Array)\n"+
" @#{arg} = a.collect { |aa| aa.dup }\n"+
"else\n"+
" @#{arg} = a.dup\n"+
"end"
}.join("\n")}
end
END
end
end
# @brief The base class for all CPP objects
class CPPObject
end
# @brief Denotes type nesting wrappers
# Type nesting provide a modification the renders a different type
# for the inner "user" of the type. For example:
# "int **x" starts with "int", adds a pointer, adds another pointer and
# ends at "x" (the symbol). "int" is the "concrete type", the two
# pointers are type wrappers and "x" is the innermost elements.
# The type s read from the inside out: "x" is a pointer to a pointer to an int.
class CPPOuterType < CPPObject
end
# @brief An array specification
# @attribute inner The inner type (the type which makes use of the array)
# "inner" is either another CPPOuterType or a CPPQualifiedId (the innermost)
# part.
class CPPArray < CPPOuterType
attr_accessor :inner
def_initializer :inner
def to_s
if self.inner.is_a?(CPPPointer)
"(" + self.inner.to_s + ") []"
else
self.inner.to_s + " []"
end
end
def dump(i)
i + "CPPArray\n" + i + " inner:\n" + self.inner.dump(i + " ")
end
end
# @brief A function specification
# @attribute inner The inner type (which makes use of the function)
# @attribute args The function arguments
# @attribute cv A const/voilatile specification if the function is a method (:const, :volatile)
# "inner" is either another CPPOuterType or a CPPQualifiedId (the innermost)
# part.
# "args" is an array of CPPType or CPPInitializedType objects, optionally terminated with
# a CPPEllipsis.
# "cv" is a CPPCV object.
class CPPFunc < CPPOuterType
attr_accessor :inner, :args, :cv
def_initializer :inner, :args, :cv
def to_s
a = self.args
a ||= []
if !a.is_a?(Array)
a = [a]
end
self.inner.to_s + " (" + a.join(", ") + ")" + (self.cv ? " " + self.cv.to_s : "")
end
def dump(i)
i + "CPPFunc\n" + i + " inner:\n" + self.inner.dump(i + " ") + "\n" +
i + " cv: " + self.cv.to_s + "\n" +
i + " args:\n" + (self.args || []).collect { |f| f.dump(i + " ") }.join("\n")
end
end
# @brief A pointer declaration
# @attribute inner The inner type which sees the outer type converted into a pointer
# "inner" is either another CPPOuterType or a CPPQualifiedId (the innermost)
# part.
class CPPPointer < CPPOuterType
attr_accessor :inner
def_initializer :inner
def to_s
"* " + self.inner.to_s
end
def dump(i)
i + "CPPPointer\n" + i + " inner:\n" + self.inner.dump(i + " ")
end
end
# @brief A reference declaration
# @attribute inner The inner type which sees the outer type converted into a reference
# "inner" is either another CPPOuterType or a CPPQualifiedId (the innermost)
# part.
class CPPReference < CPPOuterType
attr_accessor :inner
def_initializer :inner
def to_s
"& " + self.inner.to_s
end
def dump(i)
i + "CPPReference\n" + i + " inner:\n" + self.inner.dump(i + " ")
end
end
# @brief A member/method pointer declaration
# @attribute qid The class of which a member/method is addressed (a CPPQualifiedId object)
# @attribute inner The inner type which sees the outer type converted into a member/method pointer
# @attribute cv A CPPCV object describing whether the method is a const or volatile one
# Functions are converted to method pointers, plain type into member pointers.
# "inner" is either another CPPOuterType or a CPPQualifiedId (the innermost)
# part.
class CPPMemberPointer < CPPOuterType
attr_accessor :qid, :inner, :cv
def_initializer :qid, :inner, :cv
def to_s
self.qid.to_s + "::* " + self.inner.to_s + (self.cv ? " " + self.cv.to_s : "")
end
def dump(i)
i + "CPPMemberPointer\n" + i + " inner:\n" + self.inner.dump(i + " ") +
i + " cv:\n" + self.cv.dump(i + " ") +
i + " qid: " + self.qid.to_s
end
end
# @param Adds const or volatile declaration
# @attribute cv :const or :volatile
# @attribute inner The inner expression which sees the const/volatile declaration
class CPPCV < CPPOuterType
attr_accessor :cv, :inner
def_initializer :cv, :inner
def to_s
(self.cv ? (self.cv.to_s + " ") : "") + self.inner.to_s
end
def dump(i)
i + "CPPCV\n" +
i + " cv: " + self.cv.to_s + "\n" +
i + " inner:\n" + self.inner.dump(i + " ")
end
end
def CPPCV::wrap(cv, inner)
cv ? CPPCV::new(cv, inner) : inner
end
# @brief A constant uses as a template instance argument
# @attribute value A string giving the value
class CPPConst < CPPObject
attr_accessor :value
def_initializer :value
def to_s
self.value
end
def dump(i)
i + "CPPConst\n" + i + " value: " + self.value.to_s
end
end
# @brief A class the template instance arguments
# @attribute args An array of CPPConst (for constants) or CPPType objects (for types)
# This class is used for both template instances or declarations.
class CPPTemplateArgs < CPPObject
attr_accessor :args
def_initializer :args
def to_s
self.args.collect { |a| a.to_s }.join(", ")
end
def dump(i)
i + "CPPTemplateArgs\n" +
i + " args:\n" + (self.args || []).collect { |a| a.dump(i + " ") }.join("\n")
end
end
# @brief An class or namespace name, optionally with template arguments
# @attribute id The basic id (a string)
# @attribute template_args A CPPTemplateArgs object describing the template arguments or nil, if it does not describe a template instance or declaration
class CPPId < CPPObject
attr_accessor :id, :template_args
def_initializer :id, :template_args
def to_s
ta = self.template_args.to_s
if ta =~ />$/
ta += " "
end
self.id + (self.template_args ? ( "<" + ta + ">" ) : "")
end
def dump(i)
i + "CPPId\n" +
i + " id: " + self.id.to_s +
i + " template_args:\n" + self.template_args.dump(i + " ")
end
end
# @brief An anonymous ID
# This object is used in place of CPPQualifiedId if no name is given
class CPPAnonymousId < CPPObject
def to_s
""
end
def dump(i)
i + "CPPAnonymousId"
end
end
# @brief An id, optionally qualified by a namespace
# @attribute global If true, the Id is rooted in the global namespace
# @attribute parts A sequence of CPPId objects forming the namespace sequence
class CPPQualifiedId < CPPObject
attr_accessor :global, :parts
def_initializer :global, :parts
def to_s
(self.global ? "::" : "") + (self.parts || []).collect { |p| p.to_s }.join("::")
end
def dump(i)
n = (self.global ? "::" : "") + (self.parts || []).collect { |p| "[" + p.to_s + "]" }.join("::")
i + "CPPQualifiedId (" + n + ")"
end
end
# @brief A "plain old type" (double, float, int, char, ...)
# @attribute signed Is nil, :signed or :unsigned (for the types supporting that)
# @attribute length Is nil, :short, :long or :longlong for the types supporting that
# @attribute type The basic type (:int, :char, :bool, :float, :double)
class CPPPOD < CPPObject
attr_accessor :signed, :length, :type
def_initializer :signed, :length, :type
def to_s
s = ""
if self.signed == :signed
s += "signed "
elsif self.signed == :unsigned
s += "unsigned "
end
if self.length == :short
s += "short "
elsif self.length == :long
s += "long "
elsif self.length == :longlong
s += "long long "
end
s + self.type.to_s
end
def dump(i)
i + "CPPPOD (" + self.to_s + ")"
end
end
# @brief A base class declarations
# @attribute visibility :default, :public, :private or :protected
# @attribute virtual Is true, if the class is a virtual base class
# @attribute class_id A CPPQualifiedId object pointing to the base class
class CPPBaseClass < CPPObject
attr_accessor :visibility, :virtual, :class_id
def_initializer :visibility, :virtual, :class_id
def to_s
(self.visibility ? self.visibility.to_s + " " : "") + (self.virtual ? "virtual " : "") + self.class_id.to_s
end
def dump(i)
i + "CPPBaseClass\n" +
i + " visibility: " + self.visibility.to_s +
i + " virtual:\n" + self.virtual.to_s +
i + " class_id:\n" + self.class_id.to_s
end
end
# @brief Describes a structure, class or union
# @attribute kind :struct, :class or :union
# @attribute id The name of the struct, class or union
# @attribute base_classes The base class declarations (an array of CPPBaseClass objects)
# @attribute body_decl An array or CPPUsingSpec, CPPFriendDecl, CPPTypedef, CPPEnumDeclaration, CPPStructDeclaration or CPPDeclaration objects
# "body_decl" forms the body of the class. It contains friend declarations, using specs, typedef's, enum's,
# nested struct's or method and member declarations.
class CPPStruct < CPPObject
attr_accessor :kind, :id, :base_classes, :body_decl
def_initializer :kind, :id, :base_classes, :body_decl
def to_s
self.kind.to_s + " " + self.id.to_s
end
def dump(i)
l = i + self.kind.to_s + ": " + self.id.to_s + "\n"
l += (self.base_classes || []).collect { |b| i + " < " + b.to_s + "\n" }.join("")
l += (self.body_decl || []).collect { |b| b.dump(i + " ") }.join("\n")
end
end
# @param Describes a type derived with "__typeof"
# @attribute what The object from which the type is derived (a CPPQualifiedId)
class CPPTypeOf < CPPObject
attr_accessor :what
def_initializer :what
def to_s
"__typeof(" + what.to_s + ")"
end
def dump(i)
i + "CPPTypeOf\n" +
i + " what: " + self.what.to_s
end
end
# @param Describes an ellipsis inside a function argument list
class CPPEllipsis < CPPObject
def to_s
"..."
end
def dump(i)
i + "CPPEllipsis"
end
end
# @brief A general type definition
# @attribute concrete The concrete part of the type: a CPPPOD, CPPStruct, CPPEnum, CPPTypeof or CPPQualifiedId object)
# @attribute inner The "inner part": one of the CPPOuterType-derived classes or CPPQualifiedId
# @attribute init A string indicating the initialization expression
# If the concrete type is a class, struct, union, enum or typedef, a CPPQualifiedId is used for the
# attribute, describing the initial type (which can be complex already in the case of a typedef).
# The "inner" declarations add pointers, references, arrays of functions and finally the identifier.
# Without any further qualification, "inner" is a CPPQualifiedId object.
class CPPType < CPPObject
attr_accessor :concrete, :inner, :init
def_initializer :concrete, :inner, :init
def to_s
i = self.inner.to_s
s = self.concrete.to_s + " " + i
# nicen:
s.gsub(/\s+/, " ").sub(/^\s*/, "").sub(/\s*$/, "").gsub(/ \(/, "(").gsub(/\* /, "*").gsub(/& /, "&")
end
def dump(i)
i + "CPPType\n" +
i + " init: " + (self.init ? self.init.to_s : "nil") + "\n" +
i + " concrete:\n" + (self.concrete ? self.concrete.dump(i + " ") : i + " nil") + "\n" +
i + " inner:\n" + self.inner.dump(i + " ")
end
end
# @brief A "using" instruction
# @attribute qid The qualified Id of the using specification
# @attribute visibility :default, :public, :private or :protected
class CPPUsingSpec < CPPObject
attr_accessor :qid, :visibility
def_initializer :qid, :visibility
def dump(i)
i + "using [" + self.visibility.to_s + "]: " + self.qid.to_s
end
end
# @brief A typedef instruction
# @attribute type The declared type (a CPPType object, the inner name is the name of the defined type)
# @attribute visibility :default, :public, :private or :protected
class CPPTypedef < CPPObject
attr_accessor :type, :visibility
def_initializer :type, :visibility
def dump(i)
i + "typedef [" + self.visibility.to_s + "]: " + self.type.to_s
end
end
# @brief A friend declaration
# @attribute decl An array of friend types (an array of CPPType objects)
class CPPFriendDecl < CPPObject
attr_accessor :decl
def_initializer :decl
def dump(i)
self.decl.collect { |d| i + "friend: " + d.to_s }.join("\n")
end
end
# @brief A type template argument (with an optional initializer)
# @attribute id The name of the argument (a string)
# @attribute def_type The default type (nil or a CPPType object)
class CPPClassTemplateArg < CPPObject
attr_accessor :id, :def_type
def_initializer :id, :def_type
def to_s
self.id + (self.def_type ? ("=" + self.def_type.to_s) : "")
end
end
# @brief A value template argument (with an optional initializer)
# @attribute type A CPPType object describing the type
# @attribute def_expr The initializer expression (a string) or nil if no initializer is given
class CPPDirectTemplateArg < CPPObject
attr_accessor :type, :def_expr
def_initializer :type, :def_expr
def to_s
self.type.to_s + (self.def_expr ? ("=" + self.def_expr.to_s) : "")
end
end
# @brief A template declaration
# @attribute parts An array of CPPClassTemplateArg or CPPDirectTemplateArg objects
# CPPClassTemplateArg objects describe type arguments while CPPDirectTemplateArg objects
# describe value arguments (i.e. int).
class CPPTemplateDecl < CPPObject
attr_accessor :parts
def_initializer :parts
def to_s
(self.parts || []).collect { |p| p.to_s }.join(", ")
end
end
# @brief An internal object, does not appear in the final parsed tree
class CPPAttr < CPPObject
attr_accessor :attr
def_initializer :attr
end
# @brief An struct/class/union declaration inside a namespace or class
# @attribute struct The CPPStruct object describing the class, struct or union
# @attribute template_decl nil or a CPPTemplateDecl object if the declaration is a template declaration
# @attribute visibility :default, :public, :private or :protected
class CPPStructDeclaration < CPPObject
attr_accessor :struct, :template_decl, :visibility
def_initializer :struct, :template_decl, :visibility
def dump(i)
l = i + self.struct.kind.to_s + "_decl [" + self.visibility.to_s + "]: "
if self.template_decl
l += "template<" + self.template_decl.to_s + ">"
end
l += "\n"
l += self.struct.dump(i + " ")
end
end
# @brief An enum declaration inside a namespace or class
# @attribute enum The CPPEnum object describing the enum
# @attribute visibility :default, :public, :private or :protected
class CPPEnumDeclaration < CPPObject
attr_accessor :enum, :visibility
def_initializer :enum, :visibility
def dump(i)
i + "enum_decl [" + self.visibility.to_s + "]:\n" + self.enum.dump(i + " ")
end
end
# @brief A declaration of either a function, a type, a member or a method
# @attribute type the declared type: a CPPType object
# @attribute template_decl nil or a CPPTemplateDecl object if the declaration is a template declaration
# @attribute visibility :default, :public, :private or :protected
# @attribute storage_class nil, :extern or :static
# @attribute virtual Is true for virtual methods
# @attribute inline Is true for inline declarations
class CPPDeclaration < CPPObject
attr_accessor :type, :template_decl, :visibility, :storage_class, :virtual, :inline
def_initializer :type, :template_decl, :visibility, :storage_class, :virtual, :inline
def dump(i)
l = i
l += "decl [" + self.visibility.to_s + "]: "
if self.storage_class
l += self.storage_class.to_s + " "
end
if self.virtual
l += "virtual "
end
if self.inline
l += "inline "
end
if self.template_decl
l += "template<" + self.template_decl.to_s + "> "
end
if self.type.respond_to?(:to_s)
l += self.type.to_s
else
l += self.type.dump(i + " ")
end
l += " #" + self.myself.to_s
l
end
end
# @brief A namespace
# @attribute name The namespace name (a string)
# @attribute members The content of the namespace: an array of CPPTypedef, CPPNamespace (nested namespaces), CPPStructDeclaration, CPPEnumDeclaration or CPPDeclaration objects
class CPPNamespace < CPPObject
attr_accessor :name, :members
def_initializer :name, :members
def dump(i)
l = i + "namespace #{self.name} {\n"
l += (self.members || []).collect { |m| m.dump(i + " ") }.join("\n")
l += i + "}"
end
end
# @brief Describes a single enum constant
# @attribute name The name of the enum constant
# @attribute init The initalizer (not parsed - just a string)
class CPPEnumSpec < CPPObject
attr_accessor :name, :init
def_initializer :name, :init
def to_s
self.name + (self.init ? "=" + self.init : "")
end
end
# @brief Describes an enum declaration
# @attribute name The name of the enum (a string)
# @attribute specs the enum members (an array of CPPEnumSpec objects)
class CPPEnum < CPPObject
attr_accessor :name, :specs
def_initializer :name, :specs
def to_s
"enum " + (self.name || "")
end
def dump(i)
l = i + self.to_s + " {\n"
l += (self.specs || []).collect { |s| i + " " + s.to_s + "\n" }.join("")
l += i + "}"
end
end
# @brief The root object of the declaration tree
# @attribute decls The content of the module: an array of CPPTypedef, CPPNamespace (nested namespaces), CPPStructDeclaration, CPPEnumDeclaration or CPPDeclaration objects
class CPPModule < CPPObject
attr_accessor :decls
def_initializer :decls
def dump
(self.decls || []).collect { |d| d.dump("") }.join("\n")
end
end
@@ -0,0 +1,474 @@
#
# Copyright (C) 2006-2017 Matthias Koefferlein
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
class Treetop::Runtime::SyntaxNode
# An alias which can be used inside a derived cpp implementation
# The default implementation collects all objects emitted by the subnodes.
def get_cpp
a = elements && elements.collect { |e| e.cpp }.select { |e| e }.flatten
(a && !a.empty?) ? a : nil
end
# Returns the CPP objects emitted by this node.
# This method delivers CPP objects or arrays of CPP objects.
def cpp
get_cpp
end
# Returns the single CPP object or nil
def cpp_reduced
a = self.cpp
if a.is_a?(Array)
a.size == 1 || raise("Internal error: more than one syntax tree node")
a = a[0]
end
a
end
# Note: this method is required because curly braces cannot be put
# into parser conditions (treetop syntax flaw?)
def text_value_ends_with_curly_brace
text_value =~ /\}$/
end
end
# These are a couple of emitter extensions to SyntaxNode which produce the definition syntax tree
# through the "cpp" method:
module PTypeOf
def cpp
CPPTypeOf::new(qid.cpp)
end
end
def extract_signed(t)
if t =~ /unsigned/
:unsigned
elsif t =~ /signed/
:signed
else
nil
end
end
def extract_length(t)
if t =~ /long long/
:longlong
elsif t =~ /long/
:long
elsif t =~ /short/
:short
else
nil
end
end
module PIntType
def cpp
CPPPOD::new(extract_signed(text_value), extract_length(text_value), :int)
end
end
module PCharType
def cpp
CPPPOD::new(extract_signed(text_value), nil, :char)
end
end
module PBoolType
def cpp
CPPPOD::new(nil, nil, :bool)
end
end
module PSpecialType
def cpp
# the special type produces an ID
CPPQualifiedId::new(false, [ CPPId::new(id.text_value, nil) ])
end
end
module PFloatType
def cpp
kind = text_value =~ /double/ ? :double : :float
CPPPOD::new(nil, extract_length(text_value), kind)
end
end
module PVoidType
def cpp
CPPPOD::new(nil, nil, :void)
end
end
module PEnumSpec
def cpp
CPPEnumSpec::new(id.text_value, initspec.nonterminal? ? initspec.init.text_value : nil)
end
end
module PEnumType
def cpp
name = id ? id.text_value : nil
specs = bodyspec.nonterminal? ? bodyspec.body.cpp : nil
CPPEnum::new(name, specs)
end
end
module PConst
def cpp
CPPConst::new(text_value)
end
end
module PTemplateArgs
def cpp
decl = self.get_cpp
decl ? CPPTemplateArgs::new(decl) : nil
end
end
module PId
def cpp
CPPId::new(id.text_value, taspec.nonterminal? ? taspec.ta.cpp_reduced : nil)
end
end
module PQualifiedId
def cpp
CPPQualifiedId::new(globalspec.nonterminal?, self.get_cpp)
end
end
module PBaseClass
def cpp
visibility = nil
virtual = false
at = attr.text_value
if at =~ /private/
visibility = :private
elsif at =~ /public/
visibility = :public
elsif at =~ /protected/
visibility = :protected
end
if at =~ /virtual/
virtual = true
end
CPPBaseClass::new(visibility, virtual, cid.cpp_reduced)
end
end
module PStructOrClassType
def cpp
kind = :class
if stype.text_value == "struct"
kind = :struct
elsif stype.text_value == "union"
kind = :union
end
id = idspec.nonterminal? ? idspec.id.cpp_reduced : nil
base_classes = bcspec.nonterminal? ? bcspec.bc.cpp : nil
body_decl = bodyspec.nonterminal? ? bodyspec.body.cpp : nil
CPPStruct::new(kind, id, base_classes, body_decl)
end
end
module PCV
def to_symbol
return self.text_value == "const" ? :const : :volatile
end
end
module PFriendDecl
def cpp
CPPFriendDecl::new(t.cpp)
end
end
module PPointer
def cpp
CPPCV::wrap(cvspec.nonterminal? && cvspec.cv.to_symbol, CPPPointer::new(itspec.nonterminal? ? itspec.it.cpp_reduced : CPPAnonymousId::new))
end
end
module PReference
def cpp
CPPCV::wrap(cvspec.nonterminal? && cvspec.cv.to_symbol, CPPReference::new(itspec.nonterminal? ? itspec.it.cpp_reduced : CPPAnonymousId::new))
end
end
module PMemberPointer
def cpp
CPPMemberPointer::new(cspec.qid.cpp, itspec.nonterminal? ? itspec.it.cpp_reduced : CPPAnonymousId::new, cvspec.nonterminal? && cvspec.cv.to_symbol)
end
end
module PArraySpec
def cpp
CPPArray::new(nil)
end
end
module PFuncArgPart
def cpp
t.cpp_reduced
end
end
module PFuncSpec
def cpp
CPPFunc::new(nil, (fa.nonterminal? && fa.text_value != "void") ? (fa.a.cpp || []) : [], cvspec.nonterminal? && cvspec.cv.to_symbol)
end
end
module PInnerTypeWithCV
def cpp
CPPCV::wrap(cvspec.to_symbol, it.cpp_reduced)
end
end
module PInnerType
def cpp
if pfx.nonterminal?
pfx.elements.inject(it.cpp_reduced) do |r,e|
ee = e.spec.cpp_reduced
ee.inner = r
ee
end
else
it.cpp
end
end
end
module PStorageClass
def cpp
if text_value =~ /^static/
return CPPAttr::new(:static)
elsif text_value =~ /^extern/
return CPPAttr::new(:extern)
else
return nil
end
end
end
module PVirtual
def cpp
return CPPAttr::new(:virtual)
end
end
module PInline
def cpp
return CPPAttr::new(:inline)
end
end
module PType
def cpp
# This is the class/struct/union/enum declaration if there is one
d = ct.cpp
if d.is_a?(Array)
r = d.select { |i| i.is_a?(CPPStruct) || i.is_a?(CPPEnum) }
elsif d.is_a?(CPPStruct) || d.is_a?(CPPEnum)
r = [d]
else
r = []
end
# Create each declaration
ot = CPPCV::wrap(cvspec.nonterminal? && cvspec.cv.to_symbol, ct.cpp_reduced)
if il.nonterminal?
r << CPPType::new(ot, il.t1.cpp_reduced, il.i1.nonterminal? ? il.i1.is1.text_value : nil)
il.tt.elements.each do |t|
r << CPPType::new(ot, t.t2.cpp_reduced, t.i2.nonterminal? ? t.i2.is2.text_value : nil)
end
else
r << CPPType::new(ot, CPPAnonymousId::new, pi.nonterminal? ? pi.is.text_value : nil)
end
r
end
end
module PEllipsis
def cpp
CPPEllipsis::new
end
end
module PTypeWoComma
def cpp
ot = CPPCV::wrap(cvspec.nonterminal? && cvspec.cv.to_symbol, ct.cpp_reduced)
if il.nonterminal?
CPPType::new(ot, il.t.cpp_reduced, il.i.nonterminal? ? il.i.is.text_value : nil)
else
CPPType::new(ot, CPPAnonymousId::new, pi.nonterminal? ? pi.is.text_value : nil)
end
end
end
module PTypeForTemplate
def cpp
ot = CPPCV::wrap(cvspec.nonterminal? && cvspec.cv.to_symbol, ct.cpp_reduced)
CPPType::new(ot, il.nonterminal? ? il.t.cpp_reduced : CPPAnonymousId::new, nil)
end
end
module PUsing
def cpp
CPPUsingSpec::new(id.cpp_reduced, :default)
end
end
module PTypedef
def cpp
t.cpp.collect do |d|
if d.is_a?(CPPStruct)
CPPStructDeclaration::new(d, nil, :default)
elsif d.is_a?(CPPEnum)
CPPEnumDeclaration::new(d, :default)
else
CPPTypedef::new(d, :default)
end
end
end
end
module PPrivateClassStructBodyDeclarations
def cpp
decl = d.cpp
decl && decl.collect do |d|
if d.respond_to?(:visibility)
d.visibility = :private
end
d
end
end
end
module PProtectedClassStructBodyDeclarations
def cpp
decl = d.cpp
decl && decl.collect do |d|
if d.respond_to?(:visibility)
d.visibility = :protected
end
d
end
end
end
module PPublicClassStructBodyDeclarations
def cpp
decl = d.cpp
decl && decl.collect do |d|
if d.respond_to?(:visibility)
d.visibility = :public
end
d
end
end
end
module PTemplateDecl
def cpp
CPPTemplateDecl::new(self.get_cpp)
end
end
module PClassTemplateArg
def cpp
CPPClassTemplateArg::new(id.text_value, dtspec.nonterminal? ? dtspec.cpp : nil)
end
end
module PDirectTemplateArg
def cpp
CPPDirectTemplateArg::new(t.cpp, initspec.nonterminal? ? initspec.text_value : nil)
end
end
module PDeclaration
def cpp
td = nil
if template.nonterminal?
td = template.d.cpp
end
storage_class = nil
virtual = nil
inline = nil
if attr.nonterminal? && attr.cpp
attr.cpp.each do |d|
if d.attr == :virtual
virtual = true
elsif d.attr == :inline
inline = true
elsif d.attr == :static
storage_class = :static
elsif d.attr == :extern
storage_class = :extern
end
end
end
# TODO: abstract declaration determination should be based on initializers on the
# inner types
t.cpp.collect do |d|
if d.is_a?(CPPStruct)
CPPStructDeclaration::new(d, td, :default)
elsif d.is_a?(CPPEnum)
CPPEnumDeclaration::new(d, :default)
else
CPPDeclaration::new(d, td, :default, storage_class, virtual, inline)
end
end
end
end
module PExternBlock
def cpp
self.get_cpp.collect do |d|
if d.is_a?(CPPDeclaration)
d.storage_class = :extern
end
d
end
end
end
module PNamespace
def cpp
CPPNamespace::new(n.text_value, decls.cpp || [])
end
end
module PModule
def cpp
CPPModule::new(self.get_cpp)
end
end
+51
View File
@@ -0,0 +1,51 @@
#!/usr/bin/env ruby
#
# Copyright (C) 2006-2017 Matthias Koefferlein
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
$:.push(File.dirname($0))
require 'oj'
require 'cpp_classes.rb'
require 'reader_ext.rb'
input_file = "all.db"
conf_file = "mkqtdecl.conf"
cls_list = nil
$gen_dir = "generated"
while ARGV.size > 0
o = ARGV.shift
if o == "-i"
input_file = ARGV.shift
else
raise("Invalid option #{o} - usage is 'dump.rb -i all.db'")
end
end
File.open(input_file, "r") do |file|
json = file.read
@root = Oj.load(json)
puts "Reading done."
puts @root.dump
end
@@ -0,0 +1,141 @@
#
# Copyright (C) 2006-2017 Matthias Koefferlein
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# A helper script to detect ambiguous methods
# run with
# klayout -r mkqtdecl_extract_ambigous_methods.rb -z s
events = {}
classes = {}
RBA::Class::each_class do |cls|
classes[cls.name] = true
end
RBA::Class::each_class do |cls|
tc = {
RBA::ArgType.t_void => "",
RBA::ArgType.t_bool => "b",
RBA::ArgType.t_char => "i",
RBA::ArgType.t_schar => "i",
RBA::ArgType.t_uchar => "i",
RBA::ArgType.t_short => "i",
RBA::ArgType.t_ushort => "i",
RBA::ArgType.t_int => "i",
RBA::ArgType.t_uint => "i",
RBA::ArgType.t_long => "i",
RBA::ArgType.t_ulong => "i",
RBA::ArgType.t_longlong => "i",
RBA::ArgType.t_ulonglong => "i",
RBA::ArgType.t_double => "d",
RBA::ArgType.t_float => "d",
RBA::ArgType.t_var => "v",
RBA::ArgType.t_string => "s",
RBA::ArgType.t_qstring => "s",
RBA::ArgType.t_string_ccptr => "s",
}
uc = {
RBA::ArgType.t_void => "",
RBA::ArgType.t_bool => "b",
RBA::ArgType.t_char => "c",
RBA::ArgType.t_schar => "c",
RBA::ArgType.t_uchar => "uc",
RBA::ArgType.t_short => "s",
RBA::ArgType.t_ushort => "us",
RBA::ArgType.t_int => "i",
RBA::ArgType.t_uint => "ui",
RBA::ArgType.t_long => "l",
RBA::ArgType.t_ulong => "ul",
RBA::ArgType.t_longlong => "w",
RBA::ArgType.t_ulonglong => "uw",
RBA::ArgType.t_double => "d",
RBA::ArgType.t_float => "f",
RBA::ArgType.t_var => "v",
RBA::ArgType.t_string => "s",
RBA::ArgType.t_qstring => "qs",
RBA::ArgType.t_string_ccptr => "t",
}
if cls.name =~ /_Native$/ || !classes[cls.name + "_Native"]
m = {}
cls.each_method do |meth|
m[meth.name] ||= {}
csig = ""
if meth.is_static?
csig += "s"
end
if meth.is_const?
csig += "c"
end
if csig != ""
csig += "#"
end
meth.each_argument do |a|
if a.is_ptr? || a.is_cptr?
csig += "p"
end
if a.type == RBA::ArgType::t_vector
csig += "a"
csig += tc[a.inner.type].to_s
elsif a.type == RBA::ArgType::t_object || a.type == RBA::ArgType::t_object_new
csig += "x"
csig += a.cls.name
else
csig += tc[a.type]
end
end
((m[meth.name] ||= {})[csig] ||= []).push(meth)
end
m.each do |n,cs|
cs.each do |csig,m|
if m.size > 1
puts "Ambigous: #{cls.name}::#{n}_#{csig}"
usigs = []
m.each do |mm|
usig = ""
mm.each_argument do |a|
if a.is_ptr? || a.is_cptr?
usig += "p"
end
if a.type == RBA::ArgType::t_vector
usig += "a"
usig += uc[a.inner.type].to_s
elsif a.type == RBA::ArgType::t_object || a.type == RBA::ArgType::t_object_new
usig += "x"
usig += a.cls.name
else
usig += uc[a.type]
end
end
usigs.push(usig)
end
puts "-> #{usigs.join(',')}"
end
end
end
end
end
@@ -0,0 +1,102 @@
#
# Copyright (C) 2006-2017 Matthias Koefferlein
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# A helper script to detect non-const pointers
# (those indicate ownership issues).
# run with
# klayout -r mkqtdecl_extract_nc_pointers.rb -z s
events = {}
classes = {}
RBA::Class::each_class do |cls|
classes[cls.name] = true
end
RBA::Class::each_class do |cls|
uc = {
RBA::ArgType.t_void => "",
RBA::ArgType.t_bool => "b",
RBA::ArgType.t_char => "c",
RBA::ArgType.t_schar => "c",
RBA::ArgType.t_uchar => "uc",
RBA::ArgType.t_short => "s",
RBA::ArgType.t_ushort => "us",
RBA::ArgType.t_int => "i",
RBA::ArgType.t_uint => "ui",
RBA::ArgType.t_long => "l",
RBA::ArgType.t_ulong => "ul",
RBA::ArgType.t_longlong => "w",
RBA::ArgType.t_ulonglong => "uw",
RBA::ArgType.t_double => "d",
RBA::ArgType.t_float => "f",
RBA::ArgType.t_var => "v",
RBA::ArgType.t_string => "s",
RBA::ArgType.t_qstring => "qs",
RBA::ArgType.t_string_ccptr => "t",
}
if cls.name =~ /_Native$/ || !classes[cls.name + "_Native"]
m = {}
cls.each_method do |meth|
m[meth.name] ||= {}
has_ptr = false
has_int = false
csig = ""
if meth.is_static?
csig += "s"
end
if meth.is_const?
csig += "c"
end
if csig != ""
csig += "#"
end
meth.each_argument do |a|
if a.is_ptr? || a.is_cptr?
has_ptr = true
csig += "p"
end
if a.type == RBA::ArgType::t_vector
csig += "a"
c = uc[a.inner.type].to_s
csig += c
elsif a.type == RBA::ArgType::t_object || a.type == RBA::ArgType::t_object_new
csig += "x"
csig += a.cls.name
else
c = uc[a.type]
if c == "i" || c == "ui" || c == "l" || c == "ul"
has_int = true
end
csig += c
end
end
if has_ptr && has_int
puts "#{cls.name}::#{meth.name}_#{csig}"
end
end
end
end
@@ -0,0 +1,40 @@
#
# Copyright (C) 2006-2017 Matthias Koefferlein
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# A helper script to detect potential factory methods
# run with
# klayout -r mkqtdecl_extract_potential_factories.rb -z s
events = {}
RBA::Class::each_class do |cls|
if cls.name =~ /_Native$/
cls.each_method do |meth|
if meth.ret_type.is_ptr?
if meth.name =~ /create/i || meth.name =~ /make/i || meth.name =~ /build/i
puts "#{cls.name}::#{meth.name} -> #{meth.ret_type.to_s}"
end
end
end
end
end
@@ -0,0 +1,163 @@
#
# Copyright (C) 2006-2017 Matthias Koefferlein
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# A helper script to create or update the .properties configuration file.
# This file will specify the methods that will be turned into properties
# with a getter/setter pair or single getter/setter function.
# run with
# klayout -r mkqtdecl_extract_props.rb -b >mkqtdecl.properties
classes = {}
RBA::Class::each_class do |cls|
classes[cls.name] = true
end
puts "# Properties from Qt meta objects:"
setters_sig = {}
getters_sig = {}
RBA::Class::each_class do |cls|
if cls.name =~ /^Q/ && (cls.name =~ /_Native$/ || !classes[cls.name + "_Native"])
b = cls.base
while b && b.name != "QObject_Native"
b = b.base
end
if b
mo = eval("RBA::#{cls.name}.staticMetaObject")
c = cls.name.sub(/_Native$/, "")
valid_sig = {}
(0..(mo.propertyCount-1)).each do |i|
pr = mo.property(i)
ucname = pr.name[0..0].upcase + pr.name[1..-1]
if pr.isReadable
puts "property_reader(\"#{c}\", /::(#{pr.name}|is#{ucname}|has#{ucname})\\s*\\(/, \"#{pr.name}\")"
getters_sig["#{cls.name}##{pr.name}"] = true
getters_sig["#{cls.name}#is#{ucname}"] = true
getters_sig["#{cls.name}#has#{ucname}"] = true
end
if pr.isWritable
puts "property_writer(\"#{c}\", /::set#{ucname}\\s*\\(/, \"#{pr.name}\")"
setters_sig["#{cls.name}#set#{ucname}"] = true
end
end
end
end
end
puts ""
puts "# Synthetic properties"
# strip const and references from types
def normalize_type(s)
if s =~ /^const\s+(.*)$/
s = $1
end
if s =~ /^(.*?)\s*&/
s = $1
end
s
end
RBA::Class::each_class do |cls|
if cls.name =~ /^Q/ && (cls.name =~ /_Native$/ || !classes[cls.name + "_Native"])
# make all methods into properties with the following signatures
# setX(x) + x() -> "setX|x=" + ":x"
# setX(x) + isX() -> "setX|x=" + "isX|:x"
# setX(x) + hasX() -> "setX|x=" + "hasX|:x"
#
getters = {}
setters = {}
c = cls
while c != nil
c.each_method do |m|
is_setter = false
is_getter = false
m.each_overload do |ov|
is_setter ||= setters_sig["#{c.name}##{ov.name}"]
is_getter ||= getters_sig["#{c.name}##{ov.name}"]
end
if ! is_setter && m.accepts_num_args(1) && m.ret_type.to_s == "void"
m.each_overload do |ov|
if ov.name =~ /^set([A-Z])(\w*)$/
pn = $1.downcase + $2
setters[pn] ||= [ ov, c, m ]
end
end
end
if ! is_getter && m.accepts_num_args(0)
m.each_overload do |ov|
if ov.name =~ /^is([A-Z])(\w*)$/ || ov.name =~ /^has([A-Z])(\w*)$/ || ov.name =~ /^([a-z])(\w*)$/
pn = $1.downcase + $2
getters[pn] ||= [ ov, c, m ]
end
end
end
end
c = c.base
end
setters.keys.sort.each do |pn|
s = setters[pn]
g = getters[pn]
if g && (s[1] == cls || g[1] == cls)
a = nil
s[2].each_argument { |aa| a ||= aa }
setter_type = normalize_type(a.to_s)
getter_type = normalize_type(g[2].ret_type.to_s)
if setter_type == getter_type
puts "# Property #{pn} (#{setter_type})"
gc = g[1].name.sub(/_Native$/, "")
sc = s[1].name.sub(/_Native$/, "")
puts "property_reader(\"#{gc}\", /::#{g[0].name}\\s*\\(/, \"#{pn}\")"
puts "property_writer(\"#{sc}\", /::#{s[0].name}\\s*\\(/, \"#{pn}\")"
end
end
end
end
end
@@ -0,0 +1,175 @@
#
# Copyright (C) 2006-2017 Matthias Koefferlein
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# A helper script to extract the signals from the Qt declarations
# It can be used to write the .events configuration file which will
# declare the signals of objects.
# run with
# klayout -r mkqtdecl_extract_signals.rb -z >mkqtdecl.events
classes = {}
RBA::Class::each_class do |cls|
classes[cls.name] = true
end
RBA::Class::each_class do |cls|
if cls.name =~ /^Q/ && (cls.name =~ /_Native$/ || !classes[cls.name + "_Native"])
b = cls.base
while b && b.name != "QObject_Native"
b = b.base
end
if b
mo = eval("RBA::#{cls.name}.staticMetaObject")
c = cls.name.sub(/_Native/, "")
valid_sig = {}
(0..(mo.methodCount-1)).each do |i|
mm = mo.method(i)
if mm.methodType == RBA::QMetaMethod::Signal
n = mm.methodSignature.sub(/\(.*/, "")
s = mm.parameterTypes.join(", ")
valid_sig[n] ||= []
found = false
valid_sig[n] = valid_sig[n].select do |vs|
ret = true
if s.index(vs) == 0
ret = false
elsif vs.index(s) == 0
found = true
end
ret
end
if !found
valid_sig[n].push(s)
end
end
end
valid_sig.each do |n,ss|
ss.each do |s|
match = "::#{n}\\s*\\("
renamed = nil
aliased = nil
if c == "QTabWidget"
if n == "currentChanged" && s =~ /QWidget/
match += ".*QWidget"
renamed = "currentChanged_qw"
elsif n == "currentChanged" && s =~ /int/
match += ".*int"
end
elsif c == "QSignalMapper"
if n == "mapped" && s =~ /QWidget/
renamed = "mapped_qw"
match += ".*QWidget"
elsif n == "mapped" && s =~ /int/
match += ".*int"
elsif n == "mapped" && s =~ /QString/
renamed = "mapped_qs"
match += ".*QString"
elsif n == "mapped" && s =~ /QObject/
renamed = "mapped_qo"
match += ".*QObject"
end
elsif c == "QComboBox" || c == "QFontComboBox"
if n == "activated" && s =~ /QString/
renamed = "activated_qs"
match += ".*QString"
elsif n == "activated" && s =~ /int/
match += ".*int"
elsif n == "currentIndexChanged" && s =~ /QString/
renamed = "currentIndexChanged_qs"
match += ".*QString"
elsif n == "currentIndexChanged" && s =~ /int/
match += ".*int"
elsif n == "highlighted" && s =~ /QString/
renamed = "highlighted_qs"
match += ".*QString"
elsif n == "highlighted" && s =~ /int/
match += ".*int"
end
elsif c == "QCompleter"
if n == "activated" && s =~ /QString/
renamed = "activated_qs"
match += ".*QString"
elsif n == "activated" && s =~ /QModelIndex/
match += ".*QModelIndex"
elsif n == "highlighted" && s =~ /QString/
renamed = "highlighted_qs"
match += ".*QString"
elsif n == "highlighted" && s =~ /QModelIndex/
match += ".*QModelIndex"
end
elsif c == "QTextBrowser"
if n == "highlighted" && s =~ /QString/
renamed = "highlighted_qs"
match += ".*QString"
elsif n == "highlighted" && s =~ /QUrl/
match += ".*QUrl"
end
elsif c == "QDoubleSpinBox"
if n == "valueChanged" && s =~ /QString/
renamed = "valueChanged_qs"
match += ".*QString"
elsif n == "valueChanged" && s =~ /double/
match += ".*double"
end
elsif c == "QSpinBox"
if n == "valueChanged" && s =~ /QString/
renamed = "valueChanged_qs"
match += ".*QString"
elsif n == "valueChanged" && s =~ /int/
match += ".*int"
end
elsif c == "QButtonGroup"
if n == "buttonClicked" && s =~ /QAbstractButton/
renamed = "buttonClicked_qab"
match += ".*QAbstractButton"
elsif n == "buttonClicked" && s =~ /int/
match += ".*int"
elsif n == "buttonPressed" && s =~ /QAbstractButton/
renamed = "buttonPressed_qab"
match += ".*QAbstractButton"
elsif n == "buttonPressed" && s =~ /int/
match += ".*int"
elsif n == "buttonReleased" && s =~ /QAbstractButton/
renamed = "buttonReleased_qab"
match += ".*QAbstractButton"
elsif n == "buttonReleased" && s =~ /int/
match += ".*int"
end
end
puts "event(\"#{c}\", /#{match}/, \"#{s}\")"
if renamed
puts "rename(\"#{c}\", /#{match}/, \"#{renamed}\")"
end
end
end
end
end
end
+70
View File
@@ -0,0 +1,70 @@
#!/usr/bin/env ruby
#
# Copyright (C) 2006-2017 Matthias Koefferlein
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# Usage
# parse.rb -i prep.cpp -o dump.json
#
# prep.cpp: preprocessed .cpp file
# dump.json: output dump
$:.push(File.dirname($0))
require 'oj'
require 'treetop'
Treetop.load "c++"
input="all.e"
output="all.db"
while ARGV.size > 0
o = ARGV.shift
if o == "-i"
input = ARGV.shift
elsif o == "-o"
output = ARGV.shift
else
raise("Invalid option #{o} - usage is 'parse.rb -i prep.cpp -o dump.json'")
end
end
input || raise("No input given (use -i)")
output || raise("No output given (use -o)")
text = nil
File.open(input, "r") do |file|
text = file.read
end
parser = CPPParser.new
parser.root = :module
p = parser.parse(text)
if p
puts "Input #{input} successfully read."
File.open(output, "w") do |file|
file.puts(Oj.dump(p.cpp, :mode => :object))
end
puts "Output file #{output} written."
else
puts "Failure in line: "+parser.failure_line.to_s
puts parser.failure_reason
end
+3059
View File
File diff suppressed because it is too large Load Diff
+521
View File
@@ -0,0 +1,521 @@
#
# Copyright (C) 2006-2017 Matthias Koefferlein
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
class CPPObject
# Propagate setting of the visibility down to the children
# (set_visibility will replace the default visibility with public or private)
def set_visibility
end
# Inject scoped objects (like "class A::B { ... };") into their target
# scope.
def inject_scoped
end
# delivers a string representation of the name or nil if the object does not have a name
# to contribute
def myself
nil
end
# delivers a CPPQualifiedId representation of the object's location or nil if the object
# does not have a location to contribute
def myid
nil
end
# sets the CPPQualifiedId
def setid(id)
end
# supposed to establish the parent link
def set_parent(p)
end
# removes a child from our members
def remove(d)
end
# inserts a child into our members
def insert(d)
end
end
class CPPType
def func
i = self
while i.respond_to?(:inner)
if i.is_a?(CPPFunc) && (i.inner.is_a?(CPPQualifiedId) || i.inner.is_a?(CPPAnonymousId))
return i
end
i = i.inner
end
nil
end
def return_type
rt = self.dup
f = self.func
if f
i = self
idup = rt
while i.respond_to?(:inner)
i = i.inner
if i == f
idup.inner = CPPAnonymousId::new
break
end
idup.inner = i.dup
idup = idup.inner
end
end
rt
end
def name_substituted_type(sub)
rt = self.dup
i = self
idup = rt
while i.respond_to?(:inner)
ii = i.inner
if ii.is_a?(CPPQualifiedId) || ii.is_a?(CPPAnonymousId)
idup.inner = sub
break
end
i = ii
idup.inner = i.dup
idup = idup.inner
end
rt
end
def anonymous_type
name_substituted_type(CPPAnonymousId::new)
end
def renamed_type(name)
name_substituted_type(CPPQualifiedId::new(false, [name]))
end
def name
i = self
while i.respond_to?(:inner)
ii = i.inner
if ii.is_a?(CPPQualifiedId)
return ii.to_s
end
i = ii
end
nil
end
def is_void?
self.concrete.is_a?(CPPPOD) && self.concrete.to_s == "void" && (self.inner.is_a?(CPPAnonymousId) || self.inner.is_a?(CPPQualifiedId))
end
end
module QualifiedNameResolver
attr_accessor :parent
def global_scope
o = self
while o.myself && o.parent
o = o.parent
end
o
end
# requirements
# - children -> must deliver a list of child objects
# - myself -> must deliver my name
def set_parent(parent = nil)
self.parent = parent
@id2obj = {}
self.children.each do |d|
d.myself && (@id2obj[d.myself] = d)
d.set_parent(self)
end
# Add other children, for example contributed by base classes
if self.respond_to?(:other_children)
self.other_children.each do |d|
d.myself && (@id2obj[d.myself] = d)
end
end
end
def dump_ids
@id2obj.keys.sort.each do |k|
puts("--> #{k}")
end
end
# returns a list of names of child objects
def ids
(@id2obj || {}).keys.sort
end
def id2obj(id)
@id2obj && @id2obj[id]
end
def resolve_qid(qid)
qid.is_a?(CPPQualifiedId) || raise("Argument of resolve_qid must be a CPPQualifiedId object")
obj = nil
if qid.global && self.parent
root = self
while root.parent
root = root.parent
end
obj = root.resolve_qid(qid)
else
obj = id2obj(qid.parts[0].id)
if obj && qid.parts.size > 1
# The part may be a typedef: resolve it in that case before we proceed
while obj && obj.is_a?(CPPTypedef)
obj = obj.type.concrete.is_a?(CPPQualifiedId) && self.resolve_qid(obj.type.concrete)
end
if obj
qid_new = qid.dup
qid_new.parts = qid.parts[1 .. -1]
obj = obj.respond_to?(:resolve_qid) && obj.resolve_qid(qid_new)
end
end
if ! obj && self.parent
obj = self.parent.resolve_qid(qid)
end
end
obj
end
def inject_scoped
self.children.each do |d|
d.inject_scoped
qid = d.myid
if qid
qid.is_a?(CPPQualifiedId) || raise("Argument of resolve_qid must be a CPPQualifiedId object")
if qid.parts.size > 1
qid = qid.dup
while qid.parts.size > 1
obj = id2obj(qid.parts[0].id)
if obj
qid.parts = qid.parts[1 .. -1]
else
break
end
end
if obj && qid.parts.size == 1
# This copies the visibility which is not quite correct, since the injection case
# is usually used for providing an implementation outside a class. That does not
# mean the outside implementation will provide the visibility. Instead a forward
# declaration inside the target scope will do. Since that is lost in our implementation
# currently that is not possible.
self.remove(d)
d.setid(qid)
obj.insert(d)
end
end
end
end
end
end
class CPPDeclaration
include QualifiedNameResolver
def children
[]
end
def myself
self.type.name
end
end
class CPPEnumDeclaration
include QualifiedNameResolver
def children
[]
end
def myself
self.enum.name.to_s
end
end
class CPPEnumSpec
include QualifiedNameResolver
def children
[]
end
def myself
self.name.to_s
end
end
class CPPStruct
attr_accessor :parent
def global_scope
self.parent && self.parent.global_scope
end
def set_visibility
(self.body_decl || []).each do |bd|
if bd.respond_to?(:visibility) && bd.visibility == :default
if self.kind == :struct || self.kind == :union
bd.visibility = :public
else
bd.visibility = :private
end
end
bd.set_visibility
end
end
end
class CPPTypedef
include QualifiedNameResolver
def myself
self.type.name
end
def children
[]
end
end
class CPPStructDeclaration
include QualifiedNameResolver
def children
# take this chance to set the parent to struct
self.struct.parent = self
c = self.struct.body_decl || []
# add enum constants (CPPEnumSpec)
(self.struct.body_decl || []).each do |bd|
if bd.is_a?(CPPEnumDeclaration) && bd.enum && bd.enum.specs
c += bd.enum.specs
end
end
c
end
def remove(d)
self.struct.body_decl.delete(d)
end
def insert(d)
self.struct.body_decl << d
end
def other_children
# add base classes both as sub-namespace and individual parts
# and add self so scoping is possible into ourself
c = [ self ]
(self.struct.base_classes || []).each do |bc|
bc_obj = self.parent.resolve_qid(bc.class_id)
# NOTE: it may look strange to test whether the base class is the class itself but
# since we do a half-hearted job of resolving template variants, this may happen
# if we derive a template specialization from another one (specifically
# "template<class T> struct is_default_constructible : is_default_constructible<> { .. }"
if bc_obj != self && bc_obj.is_a?(CPPStructDeclaration)
c << bc_obj
c += bc_obj.children
c += bc_obj.other_children
end
end
c
end
def myself
# forward declarations (struct.body_decl == nil and no base classes) don't produce a name and
# will therefore not contribute
(self.struct.body_decl || self.struct.base_classes) && self.struct.id.to_s
end
def myid
# forward declarations (struct.body_decl == nil and no base classes) don't produce a name and
# will therefore not contribute
(self.struct.body_decl || self.struct.base_classes) && self.struct.id
end
def setid(id)
self.struct.id = id
end
def set_visibility
self.struct && self.struct.set_visibility
end
end
class CPPNamespace
include QualifiedNameResolver
def children
# take this opportunity to join identical namespaces
if self.members
new_members = []
ns = {}
self.members.each do |d|
if d.is_a?(CPPNamespace)
if !ns[d.myself]
ns[d.myself] = d
new_members << d
else
ns[d.myself].members += d.members
end
else
new_members << d
end
end
self.members = new_members
end
self.members || []
end
def other_children
# add self so scoping is possible into ourself
[ self ]
end
def myself
self.name.to_s
end
def remove(d)
self.members.delete(d)
end
def insert(d)
self.members << d
end
def set_visibility
(self.members || []).each do |m|
if m.respond_to?(:visibility) && m.visibility == :default
m.visibility = :public
end
m.set_visibility
end
end
end
class CPPModule
include QualifiedNameResolver
def children
# take this opportunity to join identical namespaces
new_decls = []
ns = {}
self.decls.each do |d|
if d.is_a?(CPPNamespace)
if !ns[d.myself]
ns[d.myself] = d
new_decls << d
else
ns[d.myself].members += d.members
end
else
new_decls << d
end
end
self.decls = new_decls
end
def remove(d)
self.decls.delete(d)
end
def insert(d)
self.decls << d
end
def myself
nil
end
def set_visibility
(self.decls || []).each do |d|
if d.respond_to?(:visibility) && d.visibility == :default
d.visibility = :public
end
d.set_visibility
end
end
end