very dirty metacompiler for protocol information code

This commit is contained in:
Max-Wilhelm Bruker 2009-10-26 15:09:17 +01:00
parent dbd3af8265
commit b0841dd6e8
7 changed files with 163 additions and 103 deletions

View file

@ -8,7 +8,7 @@ DEPENDPATH += .
INCLUDEPATH += .
# Input
HEADERS += protocol.h widget.h
SOURCES += main.cpp protocol.cpp widget.cpp
HEADERS += protocol.h widget.h protocol_commands.h
SOURCES += main.cpp protocol.cpp widget.cpp protocol_commands.cpp
CONFIG += qt debug

View file

@ -1,16 +1,14 @@
#include "protocol.h"
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
#include <QDebug>
#include "protocol.h"
#include "protocol_commands.h"
QHash<QString, Command::NewCommandFunction> Command::commandHash;
Command::Command(const QString &_cmdName)
: cmdName(_cmdName)
{
}
void Command::validateParameters()
{
}
bool Command::read(QXmlStreamReader &xml)
@ -22,7 +20,7 @@ bool Command::read(QXmlStreamReader &xml)
} else if (xml.isEndElement()) {
qDebug() << "endElement: " << xml.name().toString();
if (xml.name() == cmdName) {
validateParameters();
extractParameters();
qDebug() << "FERTIG";
deleteLater();
return true;
@ -53,3 +51,10 @@ void Command::write(QXmlStreamWriter &xml)
xml.writeEndElement();
}
Command *Command::getNewCommand(const QString &name)
{
if (!commandHash.contains(name))
return 0;
return commandHash.value(name)();
}

View file

@ -3,7 +3,9 @@
#include <QString>
#include <QMap>
#include <QHash>
#include <QObject>
#include <QDebug>
class QXmlStreamReader;
class QXmlStreamWriter;
@ -11,54 +13,58 @@ class QXmlStreamWriter;
class Command : public QObject {
Q_OBJECT
protected:
typedef Command *(*NewCommandFunction)();
static QHash<QString, NewCommandFunction> commandHash;
QString cmdName;
QMap<QString, QString> parameters;
QString currentElementText;
void setParameter(const QString &name, const QString &value) { parameters[name] = value; }
void setParameter(const QString &name, bool value) { parameters[name] = (value ? "1" : "0"); }
void setParameter(const QString &name, int value) { parameters[name] = QString::number(value); }
virtual void extractParameters() { };
public:
Command(const QString &_cmdName);
static void initializeHash();
static Command *getNewCommand(const QString &name);
virtual bool read(QXmlStreamReader &xml);
virtual void write(QXmlStreamWriter &xml);
void validateParameters();
};
class Command_Ping : public Command {
public:
Command_Ping() : Command("ping") { }
};
class Command_ChatListChannels : public Command {
public:
Command_ChatListChannels() : Command("chat_list_channels") { }
};
class Command_ChatJoinChannel : public Command {
class ChatCommand : public Command {
Q_OBJECT
private:
QString channel;
public:
Command_ChatJoinChannel(const QString &_channel = QString()) : Command("chat_join_channel"), channel(_channel)
protected:
void extractParameters()
{
parameters.insert("channel", channel);
channel = parameters["channel"];
}
};
class Command_ChatLeaveChannel : public Command {
private:
QString channel;
public:
Command_ChatLeaveChannel(const QString &_channel = QString()) : Command("chat_leave_channel"), channel(_channel)
ChatCommand(const QString &_cmdName, const QString &_channel)
: Command(_cmdName), channel(_channel)
{
parameters.insert("channel", channel);
}
};
class Command_ChatSay : public Command {
private:
QString channel;
QString message;
public:
Command_ChatSay(const QString &_channel = QString(), const QString &_message = QString()) : Command("chat_say"), channel(_channel), message(_message)
{
parameters.insert("channel", channel);
parameters.insert("message", message);
setParameter("channel", channel);
}
QString getChannel() const { return channel; }
};
class GameCommand : public Command {
Q_OBJECT
private:
int gameId;
protected:
void extractParameters()
{
gameId = parameters["game_id"].toInt();
}
public:
GameCommand(const QString &_cmdName, int _gameId)
: Command(_cmdName), gameId(_gameId)
{
setParameter("game_id", gameId);
}
int getGameId() const { return gameId; }
};
#endif

View file

@ -1,3 +1,4 @@
0:ping:Ping
0:login:Login:s,username:s,password
0:chat_list_channels:ChatListChannels
0:chat_join_channel:ChatJoinChannel:s,channel

View file

@ -1,56 +0,0 @@
#!/usr/bin/perl
open(file, "protocol_info.dat");
while (<file>) {
s/\s+$//;
@line = split(/:/);
$type = shift(@line);
if ($type == 0) {
$baseClass = 'Command';
} elsif ($type == 1) {
$baseClass = 'ChatCommand';
} else {
$baseClass = 'GameCommand';
}
$name1 = shift(@line);
$className = 'Command_' . shift(@line);
print "class $className : public $baseClass {\n"
. "private:\n";
$paramStr1 = '';
$paramStr2 = '';
$paramStr3 = '';
$paramStr4 = '';
while ($param = shift(@line)) {
($key, $value) = split(/,/, $param);
$prettyVarName = $value;
if (!($paramStr1 eq '')) {
$paramStr1 .= ', ';
}
$paramStr2 .= ", $prettyVarName(_$prettyVarName)";
$paramStr3 .= "\t\tparameters.insert(\"$value\", $prettyVarName);\n";
if ($key == 'b') {
$dataType = 'bool';
$paramStr1 .= "bool _$prettyVarName = false";
} elsif ($key == 's') {
$dataType = 'QString';
$paramStr1 .= "const QString &_$prettyVarName = QString()";
} elsif ($key == 'i') {
$dataType = 'int';
$paramStr1 .= "int _$prettyVarName = -1";
}
$first = substr($prettyVarName, 0, 1);
$first =~ tr/a-z/A-Z/;
$prettyVarName2 = $first . substr($prettyVarName, 1, length($prettyVarName));
$paramStr4 .= "\t$dataType get$prettyVarName2() const { return $prettyVarName; }\n";
print "\t$dataType $value;\n";
}
print "public:\n";
print "\t$className($paramStr1)\n\t\t: $baseClass(\"$name1\")$paramStr2\n"
. "\t{\n";
print $paramStr3;
print "\t}\n";
print $paramStr4;
print "};\n";
}
close(file);

105
common/protocol_mc.pl Executable file
View file

@ -0,0 +1,105 @@
#!/usr/bin/perl
$initializeHash = '';
open(headerfile, ">protocol_commands.h");
print headerfile "#ifndef PROTOCOL_COMMANDS_H\n"
. "#define PROTOCOL_COMMANDS_H\n\n"
. "#include \"protocol.h\"\n\n";
open(cppfile, ">protocol_commands.cpp");
print cppfile "#include \"protocol.h\"\n"
. "#include \"protocol_commands.h\"\n\n";
open(file, "protocol_commands.dat");
while (<file>) {
s/\s+$//;
@line = split(/:/);
$type = shift(@line);
$name1 = shift(@line);
if ($type == 0) {
$baseClass = 'Command';
$parentConstructorCall = "$baseClass(\"$name1\")";
$constructorParamsH = "";
$constructorParamsCpp = "";
} elsif ($type == 1) {
$baseClass = 'ChatCommand';
$parentConstructorCall = "$baseClass(\"$name1\", _channel)";
$constructorParamsH = "const QString &_channel = QString()";
$constructorParamsCpp = "const QString &_channel";
} else {
$baseClass = 'GameCommand';
$parentConstructorCall = "$baseClass(\"$name1\", _gameId)";
$constructorParamsH = "int _gameId = -1";
$constructorParamsCpp = "int _gameId";
}
$className = 'Command_' . shift(@line);
print headerfile "class $className : public $baseClass {\n"
. "\tQ_OBJECT\n"
. "private:\n";
$paramStr2 = '';
$paramStr3 = '';
$paramStr4 = '';
$paramStr5 = '';
while ($param = shift(@line)) {
($key, $value) = split(/,/, $param);
($prettyVarName = $value) =~ s/_(.)/\U$1\E/g;
if (!($constructorParamsH eq '')) {
$constructorParamsH .= ', ';
}
if (!($constructorParamsCpp eq '')) {
$constructorParamsCpp .= ', ';
}
$paramStr2 .= ", $prettyVarName(_$prettyVarName)";
$paramStr3 .= "\tsetParameter(\"$value\", $prettyVarName);\n";
if ($key eq 'b') {
$dataType = 'bool';
$constructorParamsH .= "bool _$prettyVarName = false";
$constructorParamsCpp .= "bool _$prettyVarName";
$paramStr5 .= "\t$prettyVarName = (parameters[\"$value\"] == \"1\");\n";
} elsif ($key eq 's') {
$dataType = 'QString';
$constructorParamsH .= "const QString &_$prettyVarName = QString()";
$constructorParamsCpp .= "const QString &_$prettyVarName";
$paramStr5 .= "\t$prettyVarName = parameters[\"$value\"];\n";
} elsif ($key eq 'i') {
$dataType = 'int';
$constructorParamsH .= "int _$prettyVarName = -1";
$constructorParamsCpp .= "int _$prettyVarName";
$paramStr5 .= "\t$prettyVarName = parameters[\"$value\"].toInt();\n";
}
($prettyVarName2 = $prettyVarName) =~ s/^(.)/\U$1\E/;
$paramStr4 .= "\t$dataType get$prettyVarName2() const { return $prettyVarName; }\n";
print headerfile "\t$dataType $prettyVarName;\n";
}
print headerfile "public:\n"
. "\t$className($constructorParamsH);\n"
. $paramStr4
. "\tstatic Command *newCommand() { return new $className; }\n"
. ($paramStr5 eq '' ? '' : "protected:\n\tvoid extractParameters();\n")
. "};\n";
print cppfile $className . "::$className($constructorParamsCpp)\n"
. "\t: $parentConstructorCall$paramStr2\n"
. "{\n"
. $paramStr3
. "}\n";
if (!($paramStr5 eq '')) {
print cppfile "void $className" . "::extractParameters()\n"
. "{\n"
. "\t$baseClass" . "::extractParameters();\n"
. $paramStr5
. "}\n";
}
$initializeHash .= "\tcommandHash.insert(\"$name1\", $className" . "::newCommand);\n";
}
close(file);
print headerfile "\n#endif\n";
close(headerfile);
print cppfile "void Command::initializeHash()\n"
. "{\n"
. $initializeHash
. "}\n";
close(cppfile);

View file

@ -2,6 +2,7 @@
#include <QDebug>
#include "widget.h"
#include "protocol.h"
#include "protocol_commands.h"
Widget::Widget()
: QMainWindow(), currentCommand(0)
@ -24,6 +25,8 @@ Widget::Widget()
QWidget *central = new QWidget;
central->setLayout(vbox);
setCentralWidget(central);
Command::initializeHash();
}
void Widget::startClicked()
@ -31,6 +34,7 @@ void Widget::startClicked()
currentCommand = 0;
xmlWriter.writeStartDocument();
xmlWriter.writeStartElement("cockatrice_communication");
xmlWriter.writeAttribute("version", "4");
Command *test = new Command_Ping;
test->write(xmlWriter);
@ -63,13 +67,8 @@ void Widget::parseXml()
if (xmlReader.isStartElement()) {
QString cmdStr = xmlReader.name().toString();
qDebug() << "parseXml: startElement: " << cmdStr;
if (cmdStr == "ping")
currentCommand = new Command_Ping;
else if (cmdStr == "chat_leave_channel")
currentCommand = new Command_ChatLeaveChannel;
else if (cmdStr == "chat_say")
currentCommand = new Command_ChatSay;
else
currentCommand = Command::getNewCommand(cmdStr);
if (!currentCommand)
qDebug() << "unrecognized command";
readCurrentCommand();
}