// this combine method is for multi-level macros public GenericScriptItem[] Combine(ScriptMacro macro, int depth) { // if null, we dont even need to bother if (macro == null) { return(Optimized); } // if too deep, just return normally // combine this layer int RangeStart, RangeEnd; if (!macro.GetRange(depth, out RangeStart, out RangeEnd)) { // if too deep, just return normally return(Optimized); } // loop for all for (int i = RangeStart; i <= RangeEnd; i++) { if (Optimized[i] == null) { // nothing here if (depth < macro.pre.Length - 1) { Optimized[i] = new ScriptArrayItem(parent); (Optimized[i] as ScriptArrayItem).Combine(macro, depth + 1); } else { // if last level, just put macro in there Optimized[i] = macro; } } else if (Optimized[i].type == ScriptItemType.ArrayItem) { // if another array, see if we can insert us there (Optimized[i] as ScriptArrayItem).Combine(macro, depth + 1); } } // and finally at the end of the day, we can rest assured everything is sorted. Phew. return(Optimized); }
// function to calculate the optimized arrays of items or array items to quickly return items for certain types of requests public GenericScriptItem[] Optimize() { Optimized = new GenericScriptItem[0x100]; foreach (GenericScriptItem entry in Items) { switch (entry.type) { case ScriptItemType.NULL: screrr(entry.line, "Type of item is NULL! This is most likely a programming error in SMPS2ASM!"); break; case ScriptItemType.Equate: ScriptEquate eq = (entry as ScriptEquate); // only pre-calculated equates are possible to be used if (!eq.CheckEvaluate()) { S2AScript.screrr(entry.line, "Equates that are being optimized into a look-up-table must be possible to be pre-calculated! Equate with contents '" + eq.val + "' failed to be pre-calculated."); } // get offset int v; if (!Parse.DoubleToInt(GetEquate(eq.equ).value, out v)) { screrr(entry.line, "Equate value can not be accurately converted from double floating point to int! Equate with contents '" + eq.val + "' failed to be conveted to 32-bit signed integer."); } // save entry or throw error. if (Optimized[v] == null) { Optimized[v] = entry; } else { screrr(entry.line, "Entity " + entry.identifier + " conflicts with " + Optimized[v].identifier + " at line " + Optimized[v].line + ", both trying to occupy the value " + v + " (0x" + v.ToString("X2") + ")! Optimization requires no such conflicts."); } break; case ScriptItemType.Macro: ScriptMacro ma = (entry as ScriptMacro); // collect range int rangeStart, rangeEnd; if (!ma.GetRange(0, out rangeStart, out rangeEnd)) { S2AScript.screrr(entry.line, "Unable to parse first level macro range. Macro range of '" + (ma.pre.Length > 0 ? ma.pre[0] : "") + "' is not valid."); } // if true, there is only 1 level to this macro bool onlylevel = ma.pre.Length == 1; for (int i = rangeStart; i <= rangeEnd; i++) { if (onlylevel) { if (Optimized[i] == null) { Optimized[i] = ma; } else if (Optimized[i].type == ScriptItemType.ArrayItem) { (Optimized[i] as ScriptArrayItem).CombineFree(ma); } else { screrr(entry.line, "Entity " + entry.identifier + " conflicts with " + Optimized[i].identifier + " at line " + Optimized[i].line + ", both trying to occupy the value " + i + " (0x" + i.ToString("X2") + ")! Optimization requires no such conflicts."); } } else { if (Optimized[i] == null) { Optimized[i] = new ScriptArrayItem(parent); (Optimized[i] as ScriptArrayItem).Combine(ma, 1); } else if (Optimized[i].type == ScriptItemType.ArrayItem) { (Optimized[i] as ScriptArrayItem).Combine(ma, 1); } else { screrr(entry.line, "Entity " + entry.identifier + " conflicts with " + Optimized[i].identifier + " at line " + Optimized[i].line + ", both trying to occupy the value " + i + " (0x" + i.ToString("X2") + ")! Optimization requires no such conflicts."); } } } break; case ScriptItemType.ArrayItem: screrr(entry.line, "Unoptimized list contains a pre-occupied technical element that may not be interpreted. This is likely a programming error, please report to devs!"); break; case ScriptItemType.Import: ScriptArray sc = context.GetSubscript((entry as ScriptImport).name); if (sc.Optimized == null) { sc.Optimize(); } Optimized = ConvertSMPS.context.Combine(new GenericScriptItem[][] { Optimized, sc.Optimized }); break; // all these items are invalid inside the LUT. default: screrr(entry.line, "Optimized look-up-table may only contain unoptimizable elements! Look-up-tables may contain either Equates, or macros."); break; } } return(Optimized); }