kungfoomasta
06-06-2008 20:51:17
Here is my first draft of the new ScriptReader. I wrote this during break at work, so its written without any Ogre classes. The basic idea is this:
1. Read in all characters line by line
1a. For each line, convert into tokens, update token list
2. Parse Tokens and create ScriptDefinitions and DefinitionProperties.
A ScriptDefinition is anything in between a left and right brace, and has a specific type and id:
A ScriptDefinition can contain a DefinitionProperty, which consists of a property name and 0 to many values:
ScriptDefinitions can contain ScriptDefinitions. The ScriptDefinition class lets you get sub-definition by <type,id>, or a group of sub-definitions by type, or all sub-definitions. You can also get properties by name, or all properties of the ScriptDefinition.
Here is the code for the ScriptReader:
The code has not been tested. If you see any optimizations or errors with the logic, please post them.
1. Read in all characters line by line
1a. For each line, convert into tokens, update token list
2. Parse Tokens and create ScriptDefinitions and DefinitionProperties.
A ScriptDefinition is anything in between a left and right brace, and has a specific type and id:
WidgetSkinType Button
{
}
A ScriptDefinition can contain a DefinitionProperty, which consists of a property name and 0 to many values:
uvcoords 0 0 1 1
ScriptDefinitions can contain ScriptDefinitions. The ScriptDefinition class lets you get sub-definition by <type,id>, or a group of sub-definitions by type, or all sub-definitions. You can also get properties by name, or all properties of the ScriptDefinition.
Here is the code for the ScriptReader:
void ScriptReader::parseScript(std::ifstream& stream, const std::string& groupName)
{
// Read in all data
char str[256];
while(stream.getline(str,256))
{
_convertToTokens(str);
}
mTokens.push_back(Token(QuickGUI::Token::TYPE_EOF,""));
_createDefinitions();
}
void ScriptReader::_convertToTokens(std::string s)
{
int index = 0;
while(index < static_cast<int>(s.length()))
{
if(s[index] == '{')
{
// merge the last two TYPE_TEXT tokens into a "definition" token
int lastTokenIndex = static_cast<int>(mTokens.size() - 1);
if((lastTokenIndex < 2) || (mTokens[lastTokenIndex].type != QuickGUI::Token::TYPE_NEWLINE) || (mTokens[lastTokenIndex].type != QuickGUI::Token::TYPE_NEWLINE))
{
std::cout << "Invalid syntax for Definition!" << std::endl;
return;
}
std::string type = mTokens[lastTokenIndex - 2].value;
std::string id = mTokens[lastTokenIndex - 1].value;
mTokens.pop_back(); // remove newline
mTokens.pop_back(); // remove text
mTokens.pop_back(); // remove text
mTokens.push_back(Token(QuickGUI::Token::TYPE_DEFINITION,type + " " + id)); // add definition
mTokens.push_back(Token(QuickGUI::Token::TYPE_NEWLINE,"\n")); // add newline
mTokens.push_back(Token(QuickGUI::Token::TYPE_OPENBRACE,"{"));
++index;
}
else if(s[index] == '}')
{
mTokens.push_back(Token(QuickGUI::Token::TYPE_CLOSEBRACE,"}"));
++index;
}
else if(!isspace(s[index]))
{
std::string text = "";
while((index < static_cast<int>(s.length())) && !isspace(s[index]) && ((s[index] != '\n') || (s[index] != '\r')))
{
text += s[index];
++index;
}
// Determine if this portion of text is a property name or a property value.
// A property name will have a newline in front of it.
int lastTokenIndex = static_cast<int>(mTokens.size() - 1);
if((lastTokenIndex > 0) && (mTokens[lastTokenIndex].type == QuickGUI::Token::TYPE_NEWLINE))
mTokens.push_back(Token(QuickGUI::Token::TYPE_PROPERTY,text));
else
mTokens.push_back(Token(QuickGUI::Token::TYPE_TEXT,text));
}
else
{
++index;
}
}
mTokens.push_back(Token(QuickGUI::Token::TYPE_NEWLINE,"\n"));
}
void ScriptReader::_createDefinitions()
{
int tokenIndex = 0;
ScriptDefinition* currentDefinition = NULL;
Token* currentToken = &(mTokens[tokenIndex]);
while(1)
{
switch(currentToken->type)
{
case QuickGUI::Token::TYPE_DEFINITION:
{
int index = static_cast<int>(currentToken->value.find_first_of(' '));
std::string type = currentToken->value.substr(0,index);
std::string id = currentToken->value.substr(index+1);
ScriptDefinition* newDefinition = new ScriptDefinition(type,id);
newDefinition->mParentDefinition = currentDefinition;
if(currentDefinition == NULL)
mDefinitions[type][id] = newDefinition;
else
currentDefinition->mSubDefinitions[type][id] = newDefinition;
currentDefinition = newDefinition;
}
break;
case QuickGUI::Token::TYPE_PROPERTY:
{
std::string propertyName = currentToken->value;
DefinitionProperty* newProperty = new DefinitionProperty(propertyName);
// Advance to next Token
++tokenIndex;
currentToken = &(mTokens[tokenIndex]);
while(currentToken->type == QuickGUI::Token::TYPE_TEXT)
{
newProperty->mValues.push_back(currentToken->value);
++tokenIndex;
currentToken = &(mTokens[tokenIndex]);
}
--tokenIndex;
currentToken = &(mTokens[tokenIndex]);
currentDefinition->mProperties[propertyName] = newProperty;
}
break;
case QuickGUI::Token::TYPE_CLOSEBRACE:
currentDefinition = currentDefinition->mParentDefinition;
break;
case QuickGUI::Token::TYPE_EOF:
return;
}
// Advance to next Token
++tokenIndex;
currentToken = &(mTokens[tokenIndex]);
}
}
The code has not been tested. If you see any optimizations or errors with the logic, please post them.