Rewrite the code generator and parser for the database metalanguage to perform less (or no) parsing in the code generators.
Instead we now have a two phase process: * First parse and build an abstract syntax tree (AST) * Secondly loop over the generated AST to produce useable code for the target language. NOTE: Currently only the C struct definition generator is rewritten to this new architecture. git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@5359 4a71c877-e1ca-e34f-864e-861f7616d084master
parent
9db4235480
commit
3df34aeaa7
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue