home *** CD-ROM | disk | FTP | other *** search
/ Game Audio Programming / GameAudioProgramming.iso / Game_Audio / audio_sdk / src / AudioScript / Script.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2002-05-31  |  8.8 KB  |  401 lines

  1. /***********************************************************\
  2. Copyright (C) James Boer, 2002. 
  3. All rights reserved worldwide.
  4.  
  5. This software is provided "as is" without express or implied
  6. warranties. You may freely copy and compile this source into
  7. applications you distribute provided that the copyright text
  8. below is included in the resulting source code, for example:
  9. "Portions Copyright (C) James Boer, 2002"
  10. \***********************************************************/
  11.  
  12. #include "Script.h"
  13. #include "TokenFile.h"
  14.  
  15. using namespace std;
  16. using namespace Audio;
  17.  
  18. typedef stack<ScriptNode*> NodeStack;
  19. // {00000000-0000-0000-0000-000000000000}
  20. static const GUID SCRIPT_NULL_GUID = 
  21. { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
  22.  
  23.  
  24. //------------------------------------------------------------------------//
  25. Script::Script()
  26. {
  27.     Clear();
  28. }
  29.  
  30. //------------------------------------------------------------------------//
  31. Script::~Script()
  32. {
  33.     // We need a stack for non-recursive tree iteration
  34.     NodeStack nodestack;
  35.     
  36.     ScriptNode* pCurrentNode = m_pRoot;
  37.     ScriptNode* pDeleteNode = m_pRoot;
  38.     m_pRoot = 0;
  39.  
  40.     // Iterate through all nodes and delete them
  41.     while(pCurrentNode)
  42.     {
  43.         // Go down child branch
  44.         if(pCurrentNode->GetChild())
  45.         {
  46.             nodestack.push(pCurrentNode);
  47.             pCurrentNode = pCurrentNode->GetChild();
  48.             pCurrentNode->m_pParent->m_pChild = 0;
  49.             pCurrentNode->m_pParent = 0;
  50.         }
  51.         // Else traverse sibling branch
  52.         else
  53.         {
  54.             pDeleteNode = pCurrentNode;
  55.             pCurrentNode = pCurrentNode->GetSibling();
  56.             if(!pCurrentNode)
  57.             {
  58.                 if(!nodestack.empty())
  59.                 {
  60.                     pCurrentNode = nodestack.top();
  61.                     nodestack.pop();
  62.                 }
  63.             }
  64.             SAFE_DELETE(pDeleteNode);
  65.         }
  66.     }
  67.     Clear();
  68. }
  69.  
  70. //------------------------------------------------------------------------//
  71. void Script::Clear()
  72. {
  73.     m_TokenList.clear();
  74.     m_pRoot = 0;
  75. }
  76.  
  77. //------------------------------------------------------------------------//
  78. ScriptNode* Script::GetRoot()
  79. {
  80.     return m_pRoot;
  81. }
  82.  
  83.  
  84.  
  85.  
  86.  
  87. ScriptNode::ScriptNode()
  88. {
  89.     Clear();
  90. }
  91.  
  92. ScriptNode::~ScriptNode()
  93. {
  94.     Clear();
  95. }
  96.  
  97.  
  98. void ScriptNode::Clear()
  99. {
  100.     m_pName = 0;
  101.     m_pData = 0;
  102.     m_pParent = 0;
  103.     m_pSibling = 0;
  104.     m_pChild = 0;
  105. }
  106.  
  107. bool ScriptNode::HasData()
  108. {
  109.     return (GetDataType() != Script::NO_NODE_DATA);
  110. }
  111.  
  112. const char* ScriptNode::GetName()
  113. {
  114.     assert(m_pName);
  115.     return m_pName->GetVariable();
  116. }
  117.  
  118.  
  119. Script::SCRIPT_TYPE ScriptNode::GetDataType()
  120. {
  121.     if(m_pData)
  122.     {
  123.         switch(m_pData->GetType())
  124.         {
  125.         case Token::VARIABLE:
  126.             return Script::VARIABLE;
  127.         case Token::STRING:
  128.             return Script::STRING;
  129.         case Token::INTEGER:
  130.             return Script::INTEGER;
  131.         case Token::REAL:
  132.             return Script::REAL;
  133.         case Token::BOOLEAN:
  134.             return Script::BOOLEAN;
  135.         case Token::VECTOR:
  136.             return Script::VECTOR;
  137.         };
  138.     }
  139.     return Script::NO_NODE_DATA;
  140. }
  141.  
  142. const char* ScriptNode::GetVariable()
  143. {
  144.     assert(m_pData);
  145.     return m_pData->GetVariable();
  146. }
  147.  
  148. const char* ScriptNode::GetString()
  149. {
  150.     assert(m_pData);
  151.     return m_pData->GetString();
  152. }
  153.  
  154. int ScriptNode::GetInteger()
  155. {
  156.     assert(m_pData);
  157.     return m_pData->GetInteger();
  158. }
  159.  
  160. bool ScriptNode::GetBool()
  161. {
  162.     assert(m_pData);
  163.     return m_pData->GetBoolean();
  164. }
  165.  
  166. double ScriptNode::GetReal()
  167. {
  168.     assert(m_pData);
  169.     return m_pData->GetReal();
  170. }
  171.  
  172. AUDIOVECTOR ScriptNode::GetVector()
  173. {
  174.     assert(m_pData);
  175.     AUDIOVECTOR vec;
  176.     TokenVector3D tvec = m_pData->GetVector();
  177.     vec.x = tvec.x;
  178.     vec.y = tvec.y;
  179.     vec.z = tvec.z;
  180.     return vec;
  181. }
  182.  
  183. GUID ScriptNode::GetGuid()
  184. {
  185.     assert(m_pData);
  186.     return m_pData->GetGuid();
  187. }
  188.  
  189.  
  190. ScriptNode* ScriptNode::GetSibling()
  191. {
  192.     return m_pSibling;
  193. }
  194.  
  195. ScriptNode* ScriptNode::GetChild()
  196. {
  197.     return m_pChild;
  198. }
  199.  
  200. ScriptNode* ScriptNode::GetParent()
  201. {
  202.     return m_pParent;
  203. }
  204.  
  205.  
  206. ScriptLoader::ScriptLoader()
  207. {
  208.     Clear();
  209. }
  210.  
  211. ScriptLoader::~ScriptLoader()
  212. {
  213.     Clear();
  214. }
  215.  
  216.  
  217. void ScriptLoader::Clear()
  218. {
  219.     m_Lexer.Clear();
  220. }
  221.  
  222.  
  223. bool ScriptLoader::Init()
  224. {
  225.     m_Lexer.Init();
  226.     m_Lexer.EnableComments(true);
  227.     m_Lexer.ProcessMacros(true);
  228.     return true;
  229. }
  230.  
  231. void ScriptLoader::Term()
  232. {
  233.     m_Lexer.Term();
  234. }
  235.  
  236.  
  237. bool ScriptLoader::Load(string sFileName, Script& script)
  238. {
  239.     // Process the loaded data and build the node tree
  240.     if(!m_Lexer.Process(sFileName, script.m_TokenList))
  241.         return false;
  242.     return BuildNodeTree(script);
  243. }
  244.  
  245. bool ScriptLoader::Load(uint8* pData, uint32 nDataLength, Script& script)
  246. {
  247.     // Process the loaded data and build the node tree
  248.     if(!m_Lexer.Process(pData, nDataLength, script.m_TokenList))
  249.         return false;
  250.     return BuildNodeTree(script);
  251. }
  252.  
  253.  
  254. bool ScriptLoader::BuildNodeTree(Script& script)
  255. {
  256.  
  257.     DebugOut(4, "Building script tree now");
  258.     enum SCRIPT_BUILD_STATE
  259.     {
  260.         SBS_NEW_NODE,
  261.         SBS_POST_NODE,
  262.         SBS_NODE_VALUE,
  263.         SBS_NODE_TERMINATOR
  264.     };
  265.  
  266.     SCRIPT_BUILD_STATE eState = SBS_NEW_NODE;
  267.  
  268.     // An empty script is not currently defined as being illegal.  If
  269.     // this changes, change this to return false.
  270.     if(!script.m_TokenList.size())
  271.     {
  272.         DebugOut(4, "Found empty script file - returning success");
  273.         return true;
  274.     }
  275.  
  276.     ScriptNode* pCurrentParentNode = 0;
  277.     ScriptNode* pCurrentNode = 0;
  278.  
  279.     for(TokenList::iterator itr = script.m_TokenList.begin(); 
  280.         itr != script.m_TokenList.end(); ++itr)
  281.     {
  282.         DebugOut(5, "Token: %s", itr->GetDescriptiveString());
  283.         switch(eState)
  284.         {
  285.         // Create a new node in the tree
  286.         case SBS_NEW_NODE:
  287.             {
  288.                 // First check for end brackets to end a child set
  289.                 if((itr->GetType() == Token::OPERATOR) && 
  290.                     (strcmp(itr->GetOperator(), "}") == 0))
  291.                 {
  292.                     pCurrentNode = pCurrentParentNode;
  293.                     if(pCurrentParentNode)
  294.                         pCurrentParentNode = pCurrentParentNode->m_pParent;
  295.                     else
  296.                         pCurrentParentNode = 0;
  297.                 }
  298.                 // Otherwise create a node
  299.                 else
  300.                 {
  301.                     if(itr->GetType() != Token::VARIABLE)
  302.                         return Error::Handle("Script syntax error at token: %s", script.m_TokenList.GetDescriptiveString(itr).c_str());
  303.  
  304.                     // Allocate a root node for the script
  305.                     ScriptNode* pNode = new ScriptNode;
  306.                     if(!pCurrentNode && !pCurrentParentNode)
  307.                     {
  308.                         script.m_pRoot = pNode;
  309.                         pCurrentNode = pNode;
  310.                     }
  311.                     // If there is no current node but there is a parent node,
  312.                     // create the first child node of the parent
  313.                     else if(!pCurrentNode && pCurrentParentNode)
  314.                     {
  315.                         pCurrentParentNode->m_pChild = pNode;
  316.                         pCurrentNode = pNode;
  317.                         pCurrentNode->m_pParent = pCurrentParentNode;
  318.                     }
  319.                     else if(pCurrentNode)
  320.                     {
  321.                         pCurrentNode->m_pSibling = pNode;
  322.                         pNode->m_pParent = pCurrentNode->m_pParent;
  323.                         pCurrentNode = pNode;
  324.                     }
  325.  
  326.                     // Assign the name to this node using the current token
  327.                     pCurrentNode->m_pName = &(*itr);
  328.  
  329.                     // Set the state to look for instructions following
  330.                     // the node name
  331.                     eState = SBS_POST_NODE;
  332.                 }
  333.             }
  334.             break;
  335.  
  336.         // Look after the node name to see what we'll be doing
  337.         case SBS_POST_NODE:
  338.             {
  339.                 // The next token must be an operator
  340.                 if(itr->GetType() != Token::OPERATOR)
  341.                     return Error::Handle("Script syntax error at token: %s", script.m_TokenList.GetDescriptiveString(itr).c_str());
  342.                 // If an equals sign, the next token must be
  343.                 // the value
  344.                 if(strcmp(itr->GetOperator(), "=") == 0)
  345.                     eState = SBS_NODE_VALUE;
  346.                 // Otherwise we're creating a set of child nodes
  347.                 else if(strcmp(itr->GetOperator(), "{") == 0)
  348.                 {
  349.                     eState = SBS_NEW_NODE;
  350.                     pCurrentParentNode = pCurrentNode;
  351.                     pCurrentNode = 0;
  352.                 }
  353.                 else if(strcmp(itr->GetOperator(), ";") == 0)
  354.                     eState = SBS_NEW_NODE;
  355.                 // Anything else is an error
  356.                 else
  357.                 {
  358.                     return Error::Handle("Script syntax error at token: %s", script.m_TokenList.GetDescriptiveString(itr).c_str());
  359.                 }
  360.             }
  361.             break;
  362.  
  363.         // We just passed an equal sign, so we know were assigning
  364.         // a value to this node
  365.         case SBS_NODE_VALUE:
  366.             {
  367.                 if(itr->GetType() == Token::OPERATOR)
  368.                     return Error::Handle("Script syntax error at token: %s", script.m_TokenList.GetDescriptiveString(itr).c_str());
  369.                 pCurrentNode->m_pData = &(*itr);
  370.                 eState = SBS_NODE_TERMINATOR;
  371.             }
  372.             break;
  373.  
  374.         // Look at the node terminator to determine if we're going
  375.         // to assign a value or create children
  376.         case SBS_NODE_TERMINATOR:
  377.             {
  378.                 if(itr->GetType() != Token::OPERATOR)
  379.                     return Error::Handle("Script syntax error at token: %s", script.m_TokenList.GetDescriptiveString(itr).c_str());
  380.                 if(strcmp(itr->GetOperator(), ";") == 0)
  381.                     eState = SBS_NEW_NODE;
  382.                 else if(strcmp(itr->GetOperator(), "{") == 0)
  383.                 {
  384.                     eState = SBS_NEW_NODE;
  385.                     pCurrentParentNode = pCurrentNode;
  386.                     pCurrentNode = 0;
  387.                 }
  388.                 else
  389.                 {
  390.                     return Error::Handle("Script syntax error at token: %s", script.m_TokenList.GetDescriptiveString(itr).c_str());
  391.                 }
  392.             }
  393.             break;
  394.         };
  395.     }
  396.  
  397.     DebugOut(4, "Successfully built script tree");
  398.     return true;
  399. }
  400.  
  401.