# DEM to C++ translator Chris Houser 96.4.25 # Find flow. sub related { # List of arcs (with inverted bases) in graph leaving class @_ map $$_[0] eq $_[0] && $$_[1] ? $_ : $$_[2] eq $_[0] && ! $$_[1] ? [$$_[2],'',$$_[0]] : (), @graph } sub related0 { # List of arcs in flow leaving class @_ map $$_[0] eq $_[0] && $$_[1] ? $_ : $$_[2] eq $_[0] && ! $$_[1] ? [$$_[2],'',$$_[0]] : (), @flow } sub samearc { join(':',@{$_[0]}) eq join(':',@{$_[1]}) } sub arcmatch { my ( $pattern, @arc ) = @_; join( ':', @arc ) =~ /$pattern/ } sub intersect { ( $patterns, @arcs ) = @_; map { my $p = $_; grep arcmatch( $p, @$_ ), @arcs } @$patterns } sub flow { # read @$T @$I @$X @flow argument is path: list of (refs to) arcs return 0 if 1 < grep samearc( $_[$#_], $_ ), @_; # loop return 0 if grep arcmatch( $_, @{$_[$#_]} ), @$X; # X arc my $next = $_[$#_]->[2]; # target of last arc in path my $hit = !@$T || grep $_ eq $next, @$T; # T class $hit = 0 if $hit and @$I and !intersect $I, @_; # I arc map $hit |= &flow( @_, $_ ), related $next; push @flow, $_[$#_] if $hit and ! grep samearc( $_[$#_], $_ ), @flow; $hit } # Generate class definition. sub ownslots { grep $$_[0] eq $_[0] && $$_[1], @graph } # Data members of @_ sub bases { map $$_[2], grep $$_[0] eq $_[0] && !$$_[1], @graph } sub allslots { # Data members of @_, included inherited members $_[0] && ( map( allslots($_), bases $_[0] ), ownslots $_[0] ) } sub comma { join ',', @_ } sub comma1 { join ', ', @_ } sub ctype { # C++ type of slot @_ local ($home, $name, $_, $list ) = @{$_[0]}; s/(^[A-Z]\w*)/ref($1)/; s/(.*)/ref(vector<$1>)/ if $list; $_ } sub constructor { # Code string for C++ constructor for class $_ my @b = bases $_; my $b = comma1 map "$_(" . comma(map " $$_[1]",allslots $_) . ' )', @b; my $s = comma1 map "$$_[1]( $$_[1] )", ownslots $_; "\t$_(" . comma( map " ${\ctype $_} $$_[1] = 0", allslots $_ ) . ' )' . ( $b || $s and "\n\t\t: " ) . $b . ( $b and $s and ",\n\t\t " ) . "$s { }\n" } sub declare { # Emit header for class $_. print "class $_ "; print ': ', comma1 map "public $_", @b if @b = bases $_; print "\n{\npublic:\n", constructor; print map { /^void \w+::(.*)/; "\tvirtual void $1;\n" } @{$methods{$_}}; print "private:\n", map "\t${\ctype $_} $$_[1];\n", ownslots $_; print "};\n\n" } sub call { $_[3] ? "for(\tvector::iterator each_$_[2] = ${_[1]}->begin(); each_$_[2] < ${_[1]}->end();\n\t\t(*each_$_[2]++)->$call )" : $_[1] ? "${_[1]}->$call" : "$_[2]::$call" } # Parse data and event definitions. while(<>){ if( /^([A-Z]\w+)/ ){ # data definition local ( $class, @related ) = split; push @classes, $class; for( @related ){ last if m'//'; # comment if( /^[A-Z]\w+$/ ){ push @graph, [$class,'',$_,'']; # base } elsif( local ( $name, $_ ) = /^(\w+)(.*)/ ){ # member s/#/int/; s/\$/string/; s/:(\w+)/$1/; /^$/ and $name =~ /(\w+)s$/ and $_ = "\@\u$1"; my $list = s/@(\w+)/$1/; push @graph, [$class,$name,$_||"\u$name",$list] }} } elsif( /^[a-z]/ ){ # event definition chomp; local ( $", @flow ) = ''; my ( $sig, %code, %impl ) = $_; while( $_=<> and /([\w ]+)(-> ([\w ]+))(\+ ([\w: ]+))?(- ([\w: ]+))?/ ){ local ( $F, $T, $I, $X ) = map [split /\s+/, $_], ($1, $3, $5, $7); map flow($_), map related($_), @$F } while( ( $class, $type, $code ) = /^(\w+)\s+([<=>])\s+(.*)/ ){ $code .= "\n$&" while $_ = <> and /^\t.*/; $code{$class}{$type} = "\t$code\n" } ( local $call = $sig ) =~ s/ [\w<&*>]+ (\w+,?)/ $1/g; @impl{ keys %code, map @$_[0,2], @flow } = 1; for( keys %impl ){ # Build methods (member functions) for this event. $code{$_}{'='} ||= join '', map "\t${\call @$_};\n", related0 $_; push @{$methods{$_}}, "void ${_}::$sig\n{\n@{$code{$_}}{'<','=','>'}}\n\n" }}} # Emit C++ code. map print("class $_;\n"), @classes; print "\n"; map declare, @classes; map print, map @{$methods{$_}}, @classes;