Add a code generator for my database meta-language

This code generator is still in a prototyping phase. It'll probably get rewritten entirely.


git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@5358 4a71c877-e1ca-e34f-864e-861f7616d084
master
Giel van Schijndel 2008-07-03 18:45:32 +00:00
parent c152583935
commit 9db4235480
4 changed files with 369 additions and 0 deletions

View File

@ -0,0 +1,151 @@
#!/usr/bin/perl -w
package CG;
use strict;
# Code generator for C struct definitions
my @structQualifierCount;
my @structQualifiers;
my @nestFieldCount;
my @fieldDecls;
my @nestNames;
my @curComment;
sub blankLine()
{
print "\n";
}
sub beginStructDef()
{
push @nestNames, $_[0];
push @nestFieldCount, 0;
push @structQualifierCount, 0;
}
sub endStructDef()
{
my $name = pop(@nestNames);
my $fieldCount = pop(@nestFieldCount);
my $qualifierCount = pop(@structQualifierCount);
# Fetch qualifier list from stack and reverse it
my @qualifiers;
while ($qualifierCount)
{
push @qualifiers, pop(@structQualifiers);
$qualifierCount--;
}
# Fetch field list from stack and reverse it
my @fields;
while ($fieldCount)
{
push @fields, pop(@fieldDecls);
$fieldCount--;
}
# 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";
# Seperate field defintions by blank lines
print "\n" if @fields;
}
print "} ${name};\n";
}
sub addStructQualifier()
{
push @structQualifiers, $_[0];
$structQualifierCount[@structQualifierCount - 1]++;
}
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 ($qualifier)
{
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: $_";
}
}
}
# If there's a comment, "open" it
$fieldDecl .= "\t/**" if @curComment;
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]++;
}
sub pushComment()
{
push @curComment, substr($_[0], 1);
}
1;

View File

@ -0,0 +1,19 @@
#!/usr/bin/perl -w
my $out_lang = shift or die "Missing output language";
$out_lang .= "_cg.pm";
require $out_lang or die "Couldn't load $out_lang";
# 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); }
else { print "Unmatched line: $_\n"; }
}

View File

@ -0,0 +1,143 @@
#!/usr/bin/perl -w
package CG;
use strict;
# Code generator for SQL table definitions
my @structQualifierCount;
my @structQualifiers;
my @nestFieldCount;
my @fieldDecls;
my @nestNames;
my @curComment;
sub blankLine()
{
print "\n";
}
sub beginStructDef()
{
push @nestNames, $_[0];
push @nestFieldCount, 0;
push @structQualifierCount, 0;
}
sub endStructDef()
{
my $name = pop(@nestNames);
my $fieldCount = pop(@nestFieldCount);
my $qualifierCount = pop(@structQualifierCount);
# Fetch qualifier list from stack and reverse it
my @qualifiers;
while ($qualifierCount)
{
push @qualifiers, pop(@structQualifiers);
$qualifierCount--;
}
# Fetch field list from stack and reverse it
my @fields;
while ($fieldCount)
{
push @fields, pop(@fieldDecls);
$fieldCount--;
}
# Start printing the structure
print "CREATE TABLE `${name}` (\n";
# Process struct qualifiers
foreach (@qualifiers)
{
if (/^prefix\s+\"([^\"]+)\"$/) {}
elsif (/^abstract$/)
{
print "\t-- Automatically generated ID to link the inheritance hierarchy.\n"
."\tunique_inheritance_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\n\n";
}
else
{
die "Unknown qualifier: `$_'\n";
}
}
# Print fields
while (@fields)
{
print pop(@fields);
# Seperate field defintions by commas and blank lines
print ",\n" if @fields;
# Make sure to terminate lines of field definitions
print "\n";
}
print ");\n";
}
sub addStructQualifier()
{
push @structQualifiers, $_[0];
$structQualifierCount[@structQualifierCount - 1]++;
}
sub fieldDeclaration()
{
my ($type, $qualifier, $name) = @_;
my $fieldDecl = "";
$_ = $type;
if (/count/) { $type = "INTEGER NOT NULL"; }
elsif (/string/) { $type = "TEXT NOT NULL"; }
elsif (/real/) { $type = "NUMERIC NOT NULL"; }
elsif (/bool/) { $type = "INTEGER NOT NULL"; }
else { die "UKNOWN TYPE: $_"; }
my $set = "";
if ($qualifier)
{
foreach ($qualifier)
{
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: $_";
}
}
}
while (@curComment)
{
$fieldDecl .= "\t--" . shift(@curComment) . "\n";
}
$fieldDecl .= "\t${name} ${type}";
push @fieldDecls, $fieldDecl;
$nestFieldCount[@nestFieldCount - 1]++;
}
sub pushComment()
{
push @curComment, substr($_[0], 1);
}
1;

View File

@ -0,0 +1,56 @@
struct BASE
%abstract;
%prefix "STATS_";
# Unique language independant name that can be used to identify a specific
# stats instance
string unique id;
# short name, describing the component, must be translateable
string name;
end struct;
enum TECH_LEVEL
ONE
TWO
THREE
end enum;
struct COMPONENT
%inherit BASE;
# Technology level(s) of this component
set TECH_LEVEL level;
# Power required to build this component
real buildPower;
# Build points (which are rate-limited in the construction units) required
# to build this component.
real buildPoints;
# Weight of this component
real weight;
# Indicates whether this component is "designable" and can thus be used in
# the design screen.
bool designable;
# @TODO devise some kind of type to refer to IMD models; perhaps just
# filenames will suffice?
#
# We'll name it IMD_model for now.
#
# The "base" IMD model representing this component in 3D space.
IMD_model baseModel;
end struct;
struct BODY
%inherit COMPONENT;
# The number of available weaponSlots slots on the body
count weaponSlots;
# Engine output of this body's engine
real powerOutput;
end struct;