Commit 0d76db2b authored by D-AIRY's avatar D-AIRY

Added CLogicExpression class

parent 99e5d7ee
......@@ -174,6 +174,7 @@
<ClCompile Include="..\..\..\source\common\file_utils.cpp" />
<ClCompile Include="..\..\..\source\common\string.cpp" />
<ClCompile Include="..\..\..\source\common\string_utils.cpp" />
<ClCompile Include="..\..\..\source\mtrl\LogicExpression.cpp" />
<ClCompile Include="..\..\..\source\mtrl\material.cpp" />
<ClCompile Include="..\..\..\source\mtrl\MaterialSystem.cpp" />
<ClCompile Include="..\..\..\source\mtrl\ml_data.cpp" />
......@@ -189,6 +190,7 @@
<ClInclude Include="..\..\..\source\mtrl\IXMaterial.h" />
<ClInclude Include="..\..\..\source\mtrl\IXMaterialSystem.h" />
<ClInclude Include="..\..\..\source\mtrl\IXTexture.h" />
<ClInclude Include="..\..\..\source\mtrl\LogicExpression.h" />
<ClInclude Include="..\..\..\source\mtrl\material.h" />
<ClInclude Include="..\..\..\source\mtrl\XMaterialProperty.h" />
<ClInclude Include="..\..\..\source\mtrl\MaterialSystem.h" />
......
......@@ -45,6 +45,9 @@
<ClCompile Include="..\..\..\source\mtrl\ShaderVariant.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\source\mtrl\LogicExpression.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\source\mtrl\sxmtrl.h">
......@@ -86,5 +89,8 @@
<ClInclude Include="..\..\..\source\mtrl\XMaterialProperty.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\source\mtrl\LogicExpression.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
\ No newline at end of file
Subproject commit fbe5e2fb6e490683a20689ec7c4d8666d83958ba
Subproject commit 523705dc6e0e30948db066891526e7ad98032716
#include "LogicExpression.h"
CLogicExpression::CLogicExpression()
{}
CLogicExpression::~CLogicExpression()
{
free(m_szExpression);
}
bool CLogicExpression::setExpression(const char *szExpression)
{
free(m_szExpression);
m_szExpression = strdup(szExpression);
m_aVariables.clearFast();
m_aTokens.clearFast();
m_pRootNode = NULL;
m_szError = false;
const char *szTokenStart = NULL;
char ch, cn = 0;
for(int i = 0, l = strlen(m_szExpression); i <= l; ++i)
{
ch = m_szExpression[i];
if(!ch)
{
ch = ' ';
}
if(i < l)
{
cn = m_szExpression[i + 1];
}
if(
(ch >= 'a' && ch <= 'z')
|| (ch >= 'A' && ch <= 'Z')
|| (ch >= '0' && ch <= '9')
|| ch == '_')
{
if(!szTokenStart)
{
szTokenStart = m_szExpression + i;
}
continue;
}
else if(szTokenStart)
{
m_szExpression[i] = 0;
if(!strcmp(szTokenStart, "true") || (szTokenStart[0] >= '1' && szTokenStart[0] <= '9'))
{
m_aTokens.push_back({TOKEN_TRUE});
}
else if(!strcmp(szTokenStart, "false") || szTokenStart[0] == '0')
{
m_aTokens.push_back({TOKEN_FALSE});
}
else
{
int idx = m_aVariables.indexOf(szTokenStart, [](const Param &a, const char *b){
return(!fstrcmp(a.szName, b));
});
if(idx < 0)
{
idx = m_aVariables.size();
m_aVariables.push_back({szTokenStart});
}
m_aTokens.push_back({TOKEN_IDENT, idx});
}
szTokenStart = NULL;
}
if(isspace(ch))
{
continue;
}
switch(ch)
{
case '(':
m_aTokens.push_back({TOKEN_LBRACE});
break;
case ')':
m_aTokens.push_back({TOKEN_RBRACE});
break;
case '!':
m_aTokens.push_back({TOKEN_NOT});
break;
case '&':
if(cn == '&')
{
m_aTokens.push_back({TOKEN_AND});
++i;
}
else
{
m_szError = "Unexpected token near '&'";
return(false);
}
break;
case '|':
if(cn == '|')
{
m_aTokens.push_back({TOKEN_OR});
++i;
}
else
{
m_szError = "Unexpected token near '|'";
return(false);
}
break;
default:
m_szError = "Unexpected token";
return(false);
}
}
Array<Token*> aStack;
Array<Token*> aOut;
for(UINT i = 0, l = m_aTokens.size(); i < l; ++i)
{
Token *pCur = &m_aTokens[i];
if(pCur->type == TOKEN_FALSE || pCur->type == TOKEN_TRUE || pCur->type == TOKEN_IDENT)
{
aOut.push_back(pCur);
}
else
{
if(aStack.size())
{
if(getPriority(aStack[aStack.size() - 1]->type) >= getPriority(pCur->type))
{
while(aStack.size())
{
if(aStack[aStack.size() - 1]->type == TOKEN_LBRACE)
{
if(pCur->type == TOKEN_RBRACE)
{
aStack.erase(aStack.size() - 1);
}
break;
}
else
{
aOut.push_back(aStack[aStack.size() - 1]);
aStack.erase(aStack.size() - 1);
}
}
}
}
if(pCur->type != TOKEN_RBRACE)
{
aStack.push_back(pCur);
}
}
}
while(aStack.size())
{
aOut.push_back(aStack[aStack.size() - 1]);
if(aStack[aStack.size() - 1]->type == TOKEN_LBRACE)
{
m_szError = "Mismatched braces";
return(false);
}
aStack.erase(aStack.size() - 1);
}
for(UINT i = 0, l = aOut.size(); i < l; ++i)
{
Token *pCur = aOut[i];
if(pCur->type == TOKEN_FALSE || pCur->type == TOKEN_TRUE || pCur->type == TOKEN_IDENT)
{
aStack.push_back(pCur);
}
else if(pCur->type == TOKEN_NOT)
{
if(aStack.size() < 1)
{
m_szError = "Invalid expression";
return(false);
}
pCur->pLeft = aStack[aStack.size() - 1];
aStack[aStack.size() - 1] = pCur;
}
else
{
if(aStack.size() < 2)
{
m_szError = "Invalid expression";
return(false);
}
pCur->pLeft = aStack[aStack.size() - 2];
pCur->pRight = aStack[aStack.size() - 1];
aStack[aStack.size() - 2] = pCur;
aStack.erase(aStack.size() - 1);
}
}
if(aStack.size() != 1)
{
m_szError = "Invalid expression";
return(false);
}
m_pRootNode = aStack[0];
return(true);
}
const char* CLogicExpression::getError()
{
return(m_szError);
}
bool CLogicExpression::evaluate()
{
if(!m_pRootNode)
{
return(false);
}
return(evalNode(m_pRootNode));
}
void CLogicExpression::resetParams()
{
for(UINT i = 0, l = m_aVariables.size(); i < l; ++i)
{
m_aVariables[i].bValue = false;
}
}
void CLogicExpression::setParam(const char *szName, bool bValue)
{
int idx = m_aVariables.indexOf(szName, [](const Param &a, const char *b){
return(!fstrcmp(a.szName, b));
});
if(idx >= 0)
{
m_aVariables[idx].bValue = bValue;
}
}
int CLogicExpression::getPriority(TOKEN token)
{
switch(token)
{
case CLogicExpression::TOKEN_OR:
return(7);
case CLogicExpression::TOKEN_AND:
return(8);
case CLogicExpression::TOKEN_LBRACE:
return(11);
case CLogicExpression::TOKEN_NOT:
return(10);
case CLogicExpression::TOKEN_RBRACE:
return(0);
}
return(0);
}
bool CLogicExpression::evalNode(Token *pToken)
{
switch(pToken->type)
{
case TOKEN_TRUE:
return(true);
case TOKEN_FALSE:
return(false);
case TOKEN_IDENT:
return(m_aVariables[pToken->idVar].bValue);
case TOKEN_NOT:
return(!evalNode(pToken->pLeft));
case TOKEN_OR:
return(evalNode(pToken->pLeft) || evalNode(pToken->pRight));
case TOKEN_AND:
return(evalNode(pToken->pLeft) && evalNode(pToken->pRight));
}
return(false);
}
#ifndef __LOGICEXPRESSION_H
#define __LOGICEXPRESSION_H
#include <gdefines.h>
class CLogicExpression
{
public:
CLogicExpression();
~CLogicExpression();
bool setExpression(const char *szExpression);
const char* getError();
bool evaluate();
void resetParams();
void setParam(const char *szName, bool bValue);
protected:
enum TOKEN
{
TOKEN_LBRACE,
TOKEN_RBRACE,
TOKEN_AND,
TOKEN_NOT,
TOKEN_OR,
TOKEN_FALSE,
TOKEN_TRUE,
TOKEN_IDENT
};
struct Token
{
TOKEN type;
ID idVar;
Token *pLeft;
Token *pRight;
};
struct Param
{
const char *szName;
bool bValue;
};
private:
char *m_szExpression = NULL;
const char *m_szError = NULL;
Array<Token> m_aTokens;
Array<Param> m_aVariables;
Token *m_pRootNode;
int getPriority(TOKEN token);
bool evalNode(Token *pToken);
};
#endif
......@@ -3,6 +3,8 @@
#include <xcommon/resource/IXResourceManager.h>
#include <xcommon/resource/IXResourceTexture.h>
#include "LogicExpression.h"
CMaterialSystem::CMaterialSystem()
{
if(SGCore_GetDXDevice())
......@@ -441,6 +443,12 @@ XMaterialShaderHandler* XMETHODCALLTYPE CMaterialSystem::registerMaterialShader(
{
sizeTotal += strlen(stack.get(i)) + 1;
}
CLogicExpression le;
le.setExpression("A && !(B && C || D) || E");
le.setParam("A", true);
bool res = le.evaluate();
if(sizeTotal)
{
char *szTemp = (char*)malloc(sizeTotal);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment