diff --git a/build_tools/code-generators/c_structdef_cg.pm b/build_tools/code-generators/c_structdef_cg.pm index 578743580..ab392328e 100644 --- a/build_tools/code-generators/c_structdef_cg.pm +++ b/build_tools/code-generators/c_structdef_cg.pm @@ -5,147 +5,178 @@ use strict; # Code generator for C struct definitions -my @structQualifierCount; -my @structQualifiers; -my @nestFieldCount; -my @fieldDecls; -my @nestNames; -my @curComment; - -sub blankLine() +sub printStructFieldType { - print "\n"; + my $field = $_[0]; + + $_ = ${$field}{"type"}; + + if (/count/) { print "unsigned int "; } + elsif (/string/) { print "const char* "; } + elsif (/real/) { print "float "; } + elsif (/bool/) { print "bool "; } + elsif (/set/) { print "bool "; } + elsif (/enum/) { print "${$field}{\"enum\"} "; } + else { die "UKNOWN TYPE: $_"; } } -sub beginStructDef() +sub preProcessQualifiers { - push @nestNames, $_[0]; - push @nestFieldCount, 0; - push @structQualifierCount, 0; + my ($field, $comments) = @_; + $_ = ${$field}{"qualifier"}; + $_ = "" unless $_; + + if (/unique/) + { + # Separate this notice from the rest of the comment if there's any + push @{$comments}, "" if @{$comments}; + + push @{$comments}, " Unique across all instances"; + } + elsif (/set/) + { + # Separate this notice from the rest of the comment if there's any + push @{$comments}, "" if @{$comments}; + + push @{$comments}, " \@see ${$field}{\"enum\"} for the meaning of index values"; + } } -sub endStructDef() +sub postProcessQualifiers { - my $name = pop(@nestNames); - my $fieldCount = pop(@nestFieldCount); - my $qualifierCount = pop(@structQualifierCount); + my $field = $_[0]; + my $enumMap = $_[1]; + $_ = ${$field}{"qualifier"}; + $_ = "" unless $_; - # Fetch qualifier list from stack and reverse it - my @qualifiers; - while ($qualifierCount) + if (/set/) { - push @qualifiers, pop(@structQualifiers); + my $enumName = ${$field}{"enum"}; + my $enum = ${$enumMap}{$enumName}; + my $enumSize = @{${$enum}{"values"}}; - $qualifierCount--; + print "\[${enumSize}]" if (/set/); + } +} + +sub printComments +{ + my ($comments, $indent) = @_; + + return unless @{$comments}; + + print "\t" if $indent; + print "/**\n"; + + foreach my $comment (@{$comments}) + { + print "\t" if $indent; + print " *${comment}\n"; } - # Fetch field list from stack and reverse it - my @fields; - while ($fieldCount) - { - push @fields, pop(@fieldDecls); + print "\t" if $indent; + print " */\n"; +} - $fieldCount--; - } +sub printStructFields +{ + my @fields = @{${$_[0]}{"fields"}}; + my $enumMap = $_[1]; - # Start printing the structure - print "typedef struct\n{\n"; - - # Process struct qualifiers - foreach (@qualifiers) - { - if (/^prefix\s+\"([^\"]+)\"$/) - { - $name = $1 . $name; - } - elsif (/^abstract$/) {} - else - { - die "Unknown qualifier: `$_'\n"; - } - } - - # Print fields while (@fields) { - print pop(@fields) . "\n"; + my $field = shift(@fields); + my @comments = @{${$field}{"comment"}}; + + preProcessQualifiers $field, \@comments; + + printComments \@comments, 1; + + print "\t"; + printStructFieldType $field; + print ${$field}{"name"}; + + postProcessQualifiers $field, $enumMap; + print ";\n"; - # Seperate field defintions by blank lines print "\n" if @fields; } - - print "} ${name};\n"; } -sub addStructQualifier() +sub printStruct { - push @structQualifiers, $_[0]; - $structQualifierCount[@structQualifierCount - 1]++; -} + my ($struct, $name, $prefix, $structMap, $enumMap) = @_; -sub fieldDeclaration() -{ - my ($type, $qualifier, $name) = @_; - - my $fieldDecl = ""; - - $_ = $type; - if (/count/) { $type = "unsigned int "; } - elsif (/string/) { $type = "const char* "; } - elsif (/real/) { $type = "float "; } - elsif (/bool/) { $type = "bool "; } - else { die "UKNOWN TYPE: $_"; } - - my $set = ""; - - if ($qualifier) + foreach (keys %{${$struct}{"qualifiers"}}) { - foreach ($qualifier) + $$prefix = ${${$struct}{"qualifiers"}}{$_} if /prefix/ and not $$prefix; + + if (/inherit/) { - if (/set/) - { - $set = "\[]"; - } - elsif (/unique/) - { - # Separate this notice from the rest of the comment if there's any - push @curComment, "" if @curComment; - - push @curComment, " Unique across all instances"; - } - else - { - die "UNKNOWN QUALIFIER: $_"; - } + my $inheritName = ${${$struct}{"qualifiers"}}{"inherit"}; + my $inheritStruct = ${$structMap}{$inheritName}; + + print "\t/* BEGIN of inherited \"$inheritName\" definition */\n"; + printStruct($inheritStruct, $name, $prefix, $structMap, $enumMap) if /inherit/; + print "\t/* END of inherited \"$inheritName\" definition */\n\n"; } } - # If there's a comment, "open" it - $fieldDecl .= "\t/**" if @curComment; + $$name = ${$struct}{"name"}; - while (@curComment) - { - $fieldDecl .= shift(@curComment) . "\n"; - - if (@curComment) - { - $fieldDecl .= "\t * "; - } - else - { - $fieldDecl .= "\t */\n"; - } - } - - $fieldDecl .= "\t${type}${name}${set};"; - - push @fieldDecls, $fieldDecl; - $nestFieldCount[@nestFieldCount - 1]++; + printStructFields($struct, $enumMap); } -sub pushComment() +sub printEnums() { - push @curComment, substr($_[0], 1); + foreach my $enum (@{$_[0]}) + { + printComments ${$enum}{"comment"}, 0; + + print "typedef enum\n{\n"; + + my @values = @{${$enum}{"values"}}; + + while (@values) + { + my $value = shift(@values); + my $name = ${$value}{"name"}; + + printComments ${$value}{"comment"}, 1; + + print "\t${$enum}{\"name\"}_${name},\n"; + + print "\n" if @values; + } + + print "} ${$enum}{\"name\"};\n\n"; + } +} + +sub printStructs() +{ + my ($structList, $structMap, $enumMap) = @_; + + my @structs = @{$structList}; + + while (@structs) + { + my $struct = shift(@structs); + my $name; + my $prefix = ""; + + printComments ${$struct}{"comment"}, 0; + + # Start printing the structure + print "typedef struct\n{\n"; + + printStruct($struct, \$name, \$prefix, $structMap, $enumMap); + + $name = $prefix . $name; + + print "} ${name};\n"; + print "\n" if @structs; + } } 1; diff --git a/build_tools/code-generators/db-lang.pl b/build_tools/code-generators/db-lang.pl index b8d0bceb0..b975db5b5 100755 --- a/build_tools/code-generators/db-lang.pl +++ b/build_tools/code-generators/db-lang.pl @@ -1,19 +1,140 @@ #!/usr/bin/perl -w +# vim: set et sts=4 sw=4: my $out_lang = shift or die "Missing output language"; $out_lang .= "_cg.pm"; require $out_lang or die "Couldn't load $out_lang"; +my %enumMap; +my @enumList; +my %structMap; +my @structList; + +sub parseEnum +{ + my %curEnum = (name => $_[0]); + my @curComment = (); + + @{$curEnum{"comment"}} = @{$_[1]}; + @{$_[1]} = (); + + while (<>) + { + chomp; + + if (/^\s*(\#.*)?$/) + { + push @curComment, substr($1, 1) if $1; + } + elsif (/^\s*(\w+)\s*$/) + { + my %value = (name=>$1); + + @{$value{"comment"}} = @curComment; + @curComment = (); + + push @{$curEnum{"values"}}, \%value; + } + elsif (/^\s*end\s*;\s*$/) + { + # Put the enum at the end of the array + push @enumList, \%curEnum; + + # Also place it in the hash + $enumMap{$curEnum{"name"}} = \%curEnum; + return; + } + else { print "Unmatched line: $_\n"; } + } +} + +sub parseStruct +{ + my %curStruct = (name => $_[0]); + my @curComment = (); + + @{$curStruct{"comment"}} = @{$_[1]}; + @{$_[1]} = (); + + while (<>) + { + chomp; + + if (/^\s*(\#.*)?$/) + { + push @curComment, substr($1, 1) if $1; + } + elsif (/^\s*end\s*;\s*$/) + { + # Put the struct at the end of the array + push @structList, \%curStruct; + + # Also place it in the hash + $structMap{$curStruct{"name"}} = \%curStruct; + + return; + } + # Parse struct-level qualifiers + elsif (/^\s*%(.*)\s*;\s*$/) + { + $_ = $1; + + if (/^prefix\s+\"([^\"]+)\"$/) + { + ${$curStruct{"qualifiers"}}{"prefix"} = $1; + } + elsif (/^abstract$/) + { + ${$curStruct{"qualifiers"}}{"abstract"} = 1; + } + elsif (/^inherit\s+(\w+)$/) + { + ${$curStruct{"qualifiers"}}{"inherit"} = $1; + } + } + # Parse regular field declarations + elsif (/^\s*(count|string|real|bool)\s+(unique\s+)?(\w+)\s*;\s*$/) + { + my %field = (type=>$1, qualifier=>$2, name=>$3); + + @{$field{"comment"}} = @curComment; + @curComment = (); + + push @{$curStruct{"fields"}}, \%field; + } + # Parse set and enum field declarations + elsif (/^\s*(set|enum)\s+(\w+)\s+(\w+)\s*;\s*$/) + { + my %field = (type=>$1, enum=>$2, name=>$3); + + @{$field{"comment"}} = @curComment; + @curComment = (); + + $field{"qualifier"} = "set" if ($1 =~ /set/); + + push @{$curStruct{"fields"}}, \%field; + } + else { print "Unmatched line: $_\n"; } + } +} + +my @curComment = (); + # Read and parse the file my $name; while (<>) { chomp; - if (/^\s*(\#.*)?$/) { CG::blankLine(); if ($1) { CG::pushComment($1); } } - elsif (/^\s*struct\s+(\w+)\s*$/) { CG::beginStructDef($1); } - elsif (/^\s*end\s+struct\s*;\s*$/) { CG::endStructDef() } - elsif (/^\s*%(.*)\s*;\s*$/) { CG::addStructQualifier($1); } - elsif (/^\s*(count|string|real|bool)\s+(unique\s+|set\s+)?(\w+)\s*;\s*$/) { CG::fieldDeclaration($1, $2, $3); } + # Process blank lines, possibly with comments on them + if (/^\s*(\#.*)?$/) + { + push @curComment, substr($1, 1) if $1; + } + elsif (/^\s*struct\s+(\w+)\s*$/) { parseStruct($1, \@curComment); } + elsif (/^\s*enum\s+(\w+)\s*$/) { parseEnum($1, \@curComment); } else { print "Unmatched line: $_\n"; } } + +CG::printEnums(\@enumList); +CG::printStructs(\@structList, \%structMap, \%enumMap); diff --git a/build_tools/code-generators/test_code b/build_tools/code-generators/test_code index 88e09bd69..e21e35de3 100644 --- a/build_tools/code-generators/test_code +++ b/build_tools/code-generators/test_code @@ -8,14 +8,16 @@ struct BASE # short name, describing the component, must be translateable string name; -end struct; +end; +# Enumerates the different technology levels enum TECH_LEVEL ONE TWO THREE -end enum; +end; +# Represents a researchable component statistic struct COMPONENT %inherit BASE; @@ -42,9 +44,11 @@ struct COMPONENT # We'll name it IMD_model for now. # # The "base" IMD model representing this component in 3D space. - IMD_model baseModel; -end struct; + #### IMD_model baseModel; + string baseModel; +end; +# Will contain all data associated with a body struct BODY %inherit COMPONENT; @@ -53,4 +57,4 @@ struct BODY # Engine output of this body's engine real powerOutput; -end struct; +end;