void CTemplateLoader::ConstructTemplateActor(const std::string& actorName, CParamNode& out) { // Load the base actor template if necessary const char* templateName = "special/actor"; if (!LoadTemplateFile(templateName, 0)) { LOGERROR("Failed to load entity template '%s'", templateName); return; } // Copy the actor template out = m_TemplateFileData[templateName]; // Initialise the actor's name and make it an Atlas selectable entity. std::wstring actorNameW = wstring_from_utf8(actorName); std::string name = utf8_from_wstring(CParamNode::EscapeXMLString(actorNameW)); std::string xml = "<Entity>" "<VisualActor><Actor>" + name + "</Actor><ActorOnly/></VisualActor>" // arbitrary-sized Footprint definition to make actors' selection outlines show up in Atlas "<Footprint><Circle radius='2.0'/><Height>1.0</Height></Footprint>" "<Selectable>" "<EditorOnly/>" "<Overlay><Texture><MainTexture>actor.png</MainTexture><MainTextureMask>actor_mask.png</MainTextureMask></Texture></Overlay>" "</Selectable>" "</Entity>"; CParamNode::LoadXMLString(out, xml.c_str(), actorNameW.c_str()); }
void dParserCompiler::GenerateHeaderFile ( const dString& className, const dString& scannerClassName, const char* const outputFileName, const dTree<dTokenInfo, dCRCTYPE>& symbolList, const dString& userVariableClass) { dString templateHeader; LoadTemplateFile("dParserTemplate_h.txt", templateHeader); ReplaceAllMacros (templateHeader, className, "$(className)"); ReplaceAllMacros (templateHeader, scannerClassName, "$(scannerClass)"); ReplaceMacro (templateHeader, userVariableClass, "$(userVariableClass)"); dTree<dTree<dTokenInfo, dCRCTYPE>::dTreeNode*, int> sortToken; dTree<dTokenInfo, dCRCTYPE>::Iterator iter (symbolList); for (iter.Begin(); iter; iter ++) { const dTokenInfo& info = iter.GetNode()->GetInfo(); if ((info.m_type == TERMINAL) && (info.m_tokenId >= 256)) { sortToken.Insert(iter.GetNode(), info.m_tokenId); } } dTree<dTree<dTokenInfo, dCRCTYPE>::dTreeNode*, int>::Iterator iter1 (sortToken); bool first = true; char text[256]; sprintf (text, " = %d, \n", DACCEPTING_TOKEN); dString enumdTokens ("\t\tACCEPTING_TOKEN"); enumdTokens += text; sprintf (text, " = %d, \n", DERROR_TOKEN); enumdTokens += "\t\tERROR_TOKEN"; enumdTokens += text; for (iter1.Begin(); iter1; iter1 ++) { dTree<dTokenInfo, dCRCTYPE>::dTreeNode* const node = iter1.GetNode()->GetInfo(); //const dString& name = node->GetKey(); const dString& name = node->GetInfo().m_name; enumdTokens += "\t\t"; enumdTokens += name; if (first) { first = false; sprintf (text, " = %d, \n", iter1.GetKey()); enumdTokens += text; } else { enumdTokens += ",\n"; } } enumdTokens.Replace(enumdTokens.Size()-2, 2, ""); ReplaceMacro (templateHeader, enumdTokens, "$(Tokens)"); SaveFile(outputFileName, ".h", templateHeader); }
const CParamNode& CTemplateLoader::GetTemplateFileData(const std::string& templateName) { // Load the template if necessary if (!LoadTemplateFile(templateName, 0)) { LOGERROR("Failed to load entity template '%s'", templateName.c_str()); return NULL_NODE; } return m_TemplateFileData[templateName]; }
void dParserCompiler::ScanGrammarFile( const dString& inputRules, dProductionRule& ruleList, dTree<dTokenInfo, dCRCTYPE>& symbolList, dOperatorsPrecedence& operatorPrecedence, dString& userCodeBlock, dString& userVariableClass, dString& endUserCode, int& lastTokenEnum) { dString startSymbol (""); int tokenEnumeration = 256; int operatorPrecedencePriority = 0; dParserLexical lexical (inputRules.GetStr()); LoadTemplateFile("dParserUserVariableTemplate_cpp.txt", userVariableClass); // scan the definition segment for (dToken token = dToken(lexical.NextToken()); token != GRAMMAR_SEGMENT; ) { switch (int (token)) { case START: { token = dToken(lexical.NextToken()); startSymbol = lexical.GetTokenString(); token = dToken(lexical.NextToken()); break; } case TOKEN: { for (token = dToken(lexical.NextToken()); token == LITERAL; token = dToken(lexical.NextToken())) { const char* const name = lexical.GetTokenString(); symbolList.Insert(dTokenInfo (tokenEnumeration, TERMINAL, name), dCRC64 (name)); tokenEnumeration ++; } break; } case LEFT: case RIGHT: { dOperatorsAssociation& association = operatorPrecedence.Append()->GetInfo(); association.m_prioprity = operatorPrecedencePriority; operatorPrecedencePriority ++; switch (int (token)) { case LEFT: association.m_associativity = dOperatorsAssociation::m_left; break; case RIGHT: association.m_associativity = dOperatorsAssociation::m_right; break; } for (token = dToken(lexical.NextToken()); (token == LITERAL) || ((token < 256) && !isalnum (token)); token = dToken(lexical.NextToken())) { association.Append(dCRC64 (lexical.GetTokenString())); } break; } case UNION: { token = dToken(lexical.NextToken()); dAssert (token == SEMANTIC_ACTION); userVariableClass = lexical.GetTokenString() + 1; userVariableClass.Replace(userVariableClass.Size() - 1, 1, ""); token = dToken(lexical.NextToken()); break; } case CODE_BLOCK: { userCodeBlock += lexical.GetTokenString(); token = dToken(lexical.NextToken()); break; } case EXPECT: { token = dToken(lexical.NextToken()); dAssert (token == INTEGER); m_shiftReduceExpectedWarnings = atoi (lexical.GetTokenString()); token = dToken(lexical.NextToken()); break; } default:; { dAssert (0); token = dToken(lexical.NextToken()); } } } int ruleNumber = 1; lastTokenEnum = tokenEnumeration; // scan the production rules segment dToken token1 = dToken(lexical.NextToken()); for (; (token1 != GRAMMAR_SEGMENT) && (token1 != -1); token1 = dToken(lexical.NextToken())) { //dTrace (("%s\n", lexical.GetTokenString())); switch (int (token1)) { case LITERAL: { // add the first Rule; dRuleInfo& rule = ruleList.Append()->GetInfo(); rule.m_token = token1; rule.m_type = NONTERMINAL; rule.m_name = lexical.GetTokenString(); rule.m_nameCRC = dCRC64 (lexical.GetTokenString()); dTree<dTokenInfo, dCRCTYPE>::dTreeNode* nonTerminalIdNode = symbolList.Find(rule.m_nameCRC); if (!nonTerminalIdNode) { nonTerminalIdNode = symbolList.Insert(dTokenInfo (tokenEnumeration, NONTERMINAL, rule.m_name), rule.m_nameCRC); tokenEnumeration ++; } rule.m_ruleId = nonTerminalIdNode->GetInfo().m_tokenId; rule.m_ruleNumber = ruleNumber; ruleNumber ++; token1 = ScanGrammarRule(lexical, ruleList, symbolList, ruleNumber, tokenEnumeration, operatorPrecedence); break; } default: dAssert (0); } } dProductionRule::dListNode* firtRuleNode = ruleList.GetFirst(); if (startSymbol != "") { firtRuleNode = ruleList.Find (dCRC64 (startSymbol.GetStr())); } //Expand the Grammar Rule by adding an empty start Rule; const dRuleInfo& firstRule = firtRuleNode->GetInfo(); dRuleInfo& rule = ruleList.Addtop()->GetInfo(); rule.m_ruleNumber = 0; rule.m_ruleId = tokenEnumeration; rule.m_token = firstRule.m_token; rule.m_type = NONTERMINAL; rule.m_name = firstRule.m_name + dString("__"); rule.m_nameCRC = dCRC64 (rule.m_name.GetStr()); symbolList.Insert(dTokenInfo (tokenEnumeration, rule.m_type, rule.m_name), rule.m_nameCRC); tokenEnumeration ++; dSymbol& symbol = rule.Append()->GetInfo(); symbol.m_token = firstRule.m_token; symbol.m_type = firstRule.m_type; symbol.m_name = firstRule.m_name; symbol.m_nameCRC = firstRule.m_nameCRC; // scan literal use code if (token1 == GRAMMAR_SEGMENT) { endUserCode = lexical.GetNextBuffer(); //endUserCode += "\n"; } }
void dParserCompiler::GenerateParserCode ( const dString& className, const dString& scannerClassName, const char* const outputFileName, const dTree<dTokenInfo, dCRCTYPE>& symbolList, dTree<dState*, dCRCTYPE>& stateList, const dString& userCode, const dString& endUserCode, int lastTerminalTokenEnum) { dString templateHeader (""); LoadTemplateFile("dParserTemplate _cpp.txt", templateHeader); int position = templateHeader.Find ("$(userCode)"); templateHeader.Replace(position, 11, userCode); ReplaceAllMacros (templateHeader, className, "$(className)"); ReplaceAllMacros (templateHeader, scannerClassName, "$(scannerClass)"); char text[256]; sprintf (text, "%d", lastTerminalTokenEnum); ReplaceMacro (templateHeader, text, "&(lastTerminalToken)"); dTree<dState*, dCRCTYPE> sortedStates; dTree<dState*, dCRCTYPE>::Iterator stateIter (stateList); for (stateIter.Begin(); stateIter; stateIter ++) { dState* const state = stateIter.GetNode()->GetInfo(); sortedStates.Insert(state, state->m_number); } dTree<int, dString> actionFilter; dString emptySematicAction (""); dString stateActionsStart (""); dString stateActionsCount (""); dString nextActionsStateList (""); dString sematicActions (""); int entriesCount = 0; int newLineCount = 0; int starAndCountIndex = 0; dTree<dState*, dCRCTYPE>::Iterator sortStateIter (sortedStates); const char* const caseTabs0 = "\t\t\t\t\t\t"; //const char* const caseTabs1 = "\t\t\t\t\t\t\t"; for (sortStateIter.Begin(); sortStateIter; sortStateIter ++) { dState* const state = sortStateIter.GetNode()->GetInfo(); int count = 0; dTree<dActionEntry, int> actionSort; dTree<dAction, dCRCTYPE>::Iterator actionIter (state->m_actions); for (actionIter.Begin(); actionIter; actionIter++) { count ++; dAction& action = actionIter.GetNode()->GetInfo(); if (action.m_type == dSHIFT) { dCRCTYPE actionSymbol = actionIter.GetKey(); dAssert (symbolList.Find(actionSymbol)); dActionEntry entry; entry.m_stateType = char (action.m_type); entry.m_errorRule = state->m_hasErroItem ? 1 : 0; entry.m_ruleIndex = 0; entry.m_ruleSymbols = 0; entry.m_nextState = short (action.m_nextState); entry.m_token = short (symbolList.Find(actionSymbol)->GetInfo().m_tokenId); actionSort.Insert (entry, entry.m_token); } else if (action.m_type == dREDUCE) { dCRCTYPE actionSymbol = actionIter.GetKey(); dAssert (symbolList.Find(actionSymbol)); dRuleInfo& reduceRule = action.m_reduceRuleNode->GetInfo(); dAssert (symbolList.Find(reduceRule.m_nameCRC)); dAssert (symbolList.Find(reduceRule.m_nameCRC)->GetInfo().m_tokenId >= 256); dActionEntry entry; entry.m_stateType = char (action.m_type); entry.m_errorRule = 0; //state->m_hasErroItem ? 1 : 0; entry.m_ruleIndex = short (reduceRule.m_ruleNumber); entry.m_ruleSymbols = short (reduceRule.GetCount()); entry.m_nextState = short (symbolList.Find(reduceRule.m_nameCRC)->GetInfo().m_tokenId - lastTerminalTokenEnum); entry.m_token = short (symbolList.Find(actionSymbol)->GetInfo().m_tokenId); actionSort.Insert (entry, entry.m_token); if (!reduceRule.m_ruleReduced && (reduceRule.m_semanticActionCode != emptySematicAction)) { // issue a sematic action code; reduceRule.m_ruleReduced = true; char text[128]; dString userSematicAction (reduceRule.m_semanticActionCode); int symbolsCount = int (entry.m_ruleSymbols); for (int i = 0; i < symbolsCount; i ++) { sprintf (text, "%d", symbolsCount - i); dString macro ("$"); macro += text; sprintf (text, "%d", symbolsCount - i - 1); dString macroVariable ("parameter["); macroVariable += text; macroVariable += "].m_value"; ReplaceAllMacros (userSematicAction, macroVariable, macro); } ReplaceAllMacros (userSematicAction, "entry.m_value", "$$"); sprintf (text, "%d:", reduceRule.m_ruleNumber); sematicActions += caseTabs0; sematicActions += "case "; sematicActions += text; //sematicActions += "// rule "; sematicActions += "// "; sematicActions += reduceRule.m_name; sematicActions += " : "; for (dRuleInfo::dListNode* node = reduceRule.GetFirst(); node; node = node->GetNext()) { sematicActions+= node->GetInfo().m_name; sematicActions += " "; } sematicActions += "\n"; sematicActions += userSematicAction; sematicActions += "\nbreak;\n\n"; } } else { dAssert (action.m_type == dACCEPT); dActionEntry entry; entry.m_stateType = char (action.m_type); entry.m_errorRule = 0; //state->m_hasErroItem ? 1 : 0; entry.m_ruleIndex = 0; entry.m_ruleSymbols = 0; entry.m_nextState = 0; entry.m_token = DACCEPTING_TOKEN; actionSort.Insert (entry, entry.m_token); } } int actionIndex = entriesCount; dString stateActions (""); dTree<dActionEntry, int>::Iterator iter (actionSort); for (iter.Begin(); iter; iter ++) { const dActionEntry& entry = iter.GetNode()->GetInfo(); sprintf (text, "%d, %d, %d, %d, %d, %d, ", entry.m_token, entry.m_errorRule, entry.m_stateType, entry.m_nextState, entry.m_ruleSymbols, entry.m_ruleIndex); stateActions += text; entriesCount ++; } dTree<int, dString>::dTreeNode* const stateActionNode = actionFilter.Find(stateActions); if (stateActionNode) { entriesCount = actionIndex; actionIndex = stateActionNode->GetInfo(); } else { actionFilter.Insert(actionIndex, stateActions); for (iter.Begin(); iter; iter ++) { if (newLineCount % 4 == 0) { nextActionsStateList += "\n\t\t\t"; } newLineCount ++; const dActionEntry& entry = iter.GetNode()->GetInfo(); sprintf (text, "dActionEntry (%d, %d, %d, %d, %d, %d), ", entry.m_token, entry.m_errorRule, entry.m_stateType, entry.m_nextState, entry.m_ruleSymbols, entry.m_ruleIndex); nextActionsStateList += text; } } if ((starAndCountIndex % 24) == 0) { stateActionsStart += "\n\t\t\t"; stateActionsCount += "\n\t\t\t"; } starAndCountIndex ++; sprintf (text, "%d, ", actionIndex); stateActionsStart += text; sprintf (text, "%d, ", count); stateActionsCount += text; } nextActionsStateList.Replace(nextActionsStateList.Size()-2, 2, ""); stateActionsCount.Replace(stateActionsCount.Size()-2, 2, ""); stateActionsStart.Replace(stateActionsStart.Size()-2, 2, ""); ReplaceMacro (templateHeader, stateActionsCount, "$(actionsCount)"); ReplaceMacro (templateHeader, stateActionsStart, "$(actionsStart)"); ReplaceMacro (templateHeader, nextActionsStateList, "$(actionTable)"); ReplaceMacro (templateHeader, sematicActions, "$(semanticActionsCode)"); dString stateGotoStart (""); dString stateGotoCount (""); dString nextGotoStateList (""); entriesCount = 0; int newLine = 0; int gotoStateCount = 0; for (sortStateIter.Begin(); sortStateIter; sortStateIter ++) { char text[256]; dState* const state = sortStateIter.GetNode()->GetInfo(); int currentEntryuCount = entriesCount; int count = 0; dTree<dState*, dCRCTYPE>::Iterator gotoIter (state->m_goto); dTree<dTree<dState*, dCRCTYPE>::dTreeNode*, int> sortGotoActions; for (gotoIter.Begin(); gotoIter; gotoIter++) { int id = symbolList.Find(gotoIter.GetKey())->GetInfo().m_tokenId; sortGotoActions.Insert(gotoIter.GetNode(), id); } dTree<dTree<dState*, dCRCTYPE>::dTreeNode*, int>::Iterator iter1 (sortGotoActions); for (iter1.Begin(); iter1; iter1++) { count ++; if ((newLine % 5) == 0) { nextGotoStateList += "\n\t\t\t"; } newLine ++; dTree<dState*, dCRCTYPE>::dTreeNode* const node = iter1.GetNode()->GetInfo(); dState* const targetState = node->GetInfo(); dGotoEntry entry; entry.m_nextState = short (targetState->m_number); entry.m_token = short(iter1.GetKey()); sprintf (text, "dGotoEntry (%d, %d), ", entry.m_token, entry.m_nextState); nextGotoStateList += text; entriesCount ++; } if ((gotoStateCount % 24) == 0) { stateGotoStart += "\n\t\t\t"; stateGotoCount += "\n\t\t\t"; } gotoStateCount ++; sprintf (text, "%d, ", currentEntryuCount); stateGotoStart += text; sprintf (text, "%d, ", count); stateGotoCount += text; } nextGotoStateList.Replace(nextGotoStateList.Size()-2, 2, ""); stateGotoCount.Replace(stateGotoCount.Size()-2, 2, ""); stateGotoStart.Replace(stateGotoStart.Size()-2, 2, ""); ReplaceMacro (templateHeader, stateGotoCount, "$(gotoCount)"); ReplaceMacro (templateHeader, stateGotoStart, "$(gotoStart)"); ReplaceMacro (templateHeader, nextGotoStateList, "$(gotoTable)"); templateHeader += endUserCode; SaveFile(outputFileName, ".cpp", templateHeader); }
bool CTemplateLoader::LoadTemplateFile(const std::string& templateName, int depth) { // If this file was already loaded, we don't need to do anything if (m_TemplateFileData.find(templateName) != m_TemplateFileData.end()) return true; // Handle infinite loops more gracefully than running out of stack space and crashing if (depth > 100) { LOGERROR("Probable infinite inheritance loop in entity template '%s'", templateName.c_str()); return false; } // Handle special case "actor|foo" if (templateName.find("actor|") == 0) { ConstructTemplateActor(templateName.substr(6), m_TemplateFileData[templateName]); return true; } // Handle special case "preview|foo" if (templateName.find("preview|") == 0) { // Load the base entity template, if it wasn't already loaded std::string baseName = templateName.substr(8); if (!LoadTemplateFile(baseName, depth+1)) { LOGERROR("Failed to load entity template '%s'", baseName.c_str()); return false; } // Copy a subset to the requested template CopyPreviewSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName], false); return true; } // Handle special case "corpse|foo" if (templateName.find("corpse|") == 0) { // Load the base entity template, if it wasn't already loaded std::string baseName = templateName.substr(7); if (!LoadTemplateFile(baseName, depth+1)) { LOGERROR("Failed to load entity template '%s'", baseName.c_str()); return false; } // Copy a subset to the requested template CopyPreviewSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName], true); return true; } // Handle special case "mirage|foo" if (templateName.find("mirage|") == 0) { // Load the base entity template, if it wasn't already loaded std::string baseName = templateName.substr(7); if (!LoadTemplateFile(baseName, depth+1)) { LOGERROR("Failed to load entity template '%s'", baseName.c_str()); return false; } // Copy a subset to the requested template CopyMirageSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName]); return true; } // Handle special case "foundation|foo" if (templateName.find("foundation|") == 0) { // Load the base entity template, if it wasn't already loaded std::string baseName = templateName.substr(11); if (!LoadTemplateFile(baseName, depth+1)) { LOGERROR("Failed to load entity template '%s'", baseName.c_str()); return false; } // Copy a subset to the requested template CopyFoundationSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName]); return true; } // Handle special case "construction|foo" if (templateName.find("construction|") == 0) { // Load the base entity template, if it wasn't already loaded std::string baseName = templateName.substr(13); if (!LoadTemplateFile(baseName, depth+1)) { LOGERROR("Failed to load entity template '%s'", baseName.c_str()); return false; } // Copy a subset to the requested template CopyConstructionSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName]); return true; } // Handle special case "resource|foo" if (templateName.find("resource|") == 0) { // Load the base entity template, if it wasn't already loaded std::string baseName = templateName.substr(9); if (!LoadTemplateFile(baseName, depth+1)) { LOGERROR("Failed to load entity template '%s'", baseName.c_str()); return false; } // Copy a subset to the requested template CopyResourceSubset(m_TemplateFileData[templateName], m_TemplateFileData[baseName]); return true; } // Normal case: templateName is an XML file: VfsPath path = VfsPath(TEMPLATE_ROOT) / wstring_from_utf8(templateName + ".xml"); CXeromyces xero; PSRETURN ok = xero.Load(g_VFS, path); if (ok != PSRETURN_OK) return false; // (Xeromyces already logged an error with the full filename) int attr_parent = xero.GetAttributeID("parent"); CStr parentName = xero.GetRoot().GetAttributes().GetNamedItem(attr_parent); if (!parentName.empty()) { // To prevent needless complexity in template design, we don't allow |-separated strings as parents if (parentName.find('|') != parentName.npos) { LOGERROR("Invalid parent '%s' in entity template '%s'", parentName.c_str(), templateName.c_str()); return false; } // Ensure the parent is loaded if (!LoadTemplateFile(parentName, depth+1)) { LOGERROR("Failed to load parent '%s' of entity template '%s'", parentName.c_str(), templateName.c_str()); return false; } CParamNode& parentData = m_TemplateFileData[parentName]; // Initialise this template with its parent m_TemplateFileData[templateName] = parentData; } // Load the new file into the template data (overriding parent values) CParamNode::LoadXML(m_TemplateFileData[templateName], xero, wstring_from_utf8(templateName).c_str()); return true; }