/// <summary> /// Проверка строки с операцией INC /// </summary> /// <param name="se">строка с операцией INC</param> public static void checkINC(SourceEntity se, TMOEntity te) { if (!String.IsNullOrEmpty(se.label)) { throw new SPException("В директиве INC метки не должно быть: " + se.sourceString); } if (se.operands.Count == 1) { if (!Global.isInGlobal(se.operands[0])) { throw new SPException("Некорректное имя глобальной переменной: " + se.sourceString); } if (Global.searchInGlobal(se.operands[0]).value == null) { throw new SPException("Глобальной переменной " + se.operands[0] + " не присвоено значение."); } foreach (Dictionary <List <string>, TMOEntity> dict in Global.whileVar) { if (dict.Keys.First().Contains(se.operands[0]) && dict.Values.First() != te) { throw new SPException("Глобальная переменная " + se.operands[0] + " используется как счетчик в цикле: " + se.sourceString); } } } else { throw new SPException("Некорректное количество операндов в директиве INC: " + se.sourceString); } }
/// <summary> /// Проверка вложенностей /// </summary> /// <param name="current"></param> /// <param name="stack"></param> public static void checkInner(SourceEntity current, Stack <Command> stack) { if (current.operation == "IF") { return; } if (current.operation == "ELSE") { if (stack.Count > 0 && stack.Peek() != Command.if_) { throw new SPException("Некорректное использование директивы ELSE"); } return; } if (current.operation == "ENDIF") { if (stack.Count > 0 && stack.Peek() != Command.if_ && stack.Peek() != Command.else_) { throw new SPException("Некорректное использование директивы ENDIF"); } return; } if (current.operation == "WHILE") { return; } if (current.operation == "ENDW") { if (stack.Count > 0 && stack.Peek() != Command.while_) { throw new SPException("Некорректное использование директивы ENDW"); } return; } }
/// <summary> /// Проверка строки с операцией SET /// </summary> /// <param name="se">строка с операцией SET</param> public static void checkSET(SourceEntity se, TMOEntity te) { if (!String.IsNullOrEmpty(se.label)) { throw new SPException("В директиве SET метки не должно быть: " + se.sourceString); } if (se.operands.Count == 2) { if (!Global.isInGlobal(se.operands[0])) { throw new SPException("Некорректное имя глобальной переменной: " + se.sourceString); } int temp; if (Int32.TryParse(se.operands[1], out temp) == false) { throw new SPException("Некорректное значение глобальной переменной: " + se.sourceString); } foreach (Dictionary <List <string>, TMOEntity> dict in Global.whileVar) { if (dict.Keys.First().Contains(se.operands[0]) && dict.Values.First() != te) { throw new SPException("Глобальная переменная " + se.operands[0] + " используется как счетчик в цикле: " + se.sourceString); } } } else { throw new SPException("Некорректное количество операндов в директиве SET: " + se.sourceString); } }
/// <summary> /// Проверка на метку (может быть пустая или много двоеточий) /// </summary> /// <param name="se">строка с операцией меткой</param> public static void checkLabel(SourceEntity se) { if (se.sourceString.Split(':').Length > 2 && se.operation != "BYTE") { throw new SPException("Слишком много двоеточий в строке: " + se.sourceString); } if (se.sourceString.Split(':').Length > 1 && String.IsNullOrEmpty(se.sourceString.Split(':')[0])) { throw new SPException("Слишком много двоеточий в строке: " + se.sourceString); } }
/// <summary> /// Проверка строки с операцией MACRO /// </summary> /// <param name="se">строка с операцией MACRO</param> public static void checkMACRO(SourceEntity se, bool macroFlag) { if (se.sourceString.Contains(":")) { throw new SPException("При объявлении макроса не должно быть меток: " + se.sourceString); } if (String.IsNullOrEmpty(se.label) || !Utils.isLabel(se.label)) { throw new SPException("Имя макроса некорректно: " + se.sourceString); } if (TMO.isInTMO(se.label)) { throw new SPException("Макрос " + se.label + " уже описан: " + se.sourceString); } //if (macroFlag == true) //{ // throw new SPException("Макроопределения внутри макроса запрещены: " + se.sourceString); //} //if (se.operands.Count != 0) //{ // throw new SPException("У макроса не должно быть параметров: " + se.sourceString); //} foreach (string o in se.operands) { if (se.operands.Count(p => p == o) > 1) { throw new SPException("Имя параметра \"" + o + "\" повторяется: " + se.sourceString); } if (!Utils.isLabel(o)) { throw new SPException("Имя параметра \"" + o + "\" некорректно: " + se.sourceString); } foreach (TMOEntity te in TMO.entities) { foreach (string par in te.parameters) { if (par == o) { throw new SPException("Имя параметра " + o + " уже используется в другом макросе: " + se.sourceString); } } } Utils.checkNames(o); if (o == se.label) { throw new SPException("Имя параметра " + o + " некорректно (совпадает с названием макроса): " + se.sourceString); } } Utils.checkNames(se.label); }
/// <summary> /// Проверка строки с операцией MEND /// </summary> /// <param name="se">строка с операцией MEND</param> public static void checkMEND(SourceEntity se, bool macroFlag) { if (se.operands.Count != 0) { throw new SPException("У директивы MEND не должно быть параметров: " + se.sourceString); } if (!String.IsNullOrEmpty(se.label)) { throw new SPException("У директивы MEND не должно быть метки: " + se.sourceString); } if (macroFlag == false) { throw new SPException("Лишняя директива MEND: " + se.sourceString); } }
/// <summary> /// Проверка строки с операцией END /// </summary> /// <param name="se">строка с операцией END</param> public static void checkEND(SourceEntity se, bool macroFlag, string macroName) { if (macroFlag == true) { throw new SPException("Макрос " + macroName + " не описан полностью: " + se.sourceString); } //foreach (TMOEntity te in TMO.entities) //{ // foreach (SourceEntity sse in te.body) // { // if (TMO.isInTMO(sse.operation)) // { // throw new SPException("Макровызовы внутри макроса запрещены"); // } // } //} }
public static SourceEntity print(SourceEntity str) { SourceEntity newStr = str.Clone(); for (int j = 0; j < newStr.operands.Count; j++) { if (Global.isInGlobal(newStr.operands[j])) { if (Global.searchInGlobal(newStr.operands[j]).value.HasValue) { newStr.operands[j] = Global.searchInGlobal(newStr.operands[j]).value.Value.ToString(); } else { throw new SPException("Глобальная переменная " + newStr.operands[j] + " не инициализирована."); } } } return(newStr); }
/// <summary> /// Проверка строки с операцией GLOBAL /// </summary> /// <param name="se">строка с операцией GLOBAL</param> public static void checkGLOBAL(SourceEntity se) { //if (macroFlag == true) //{ // throw new SPException("Глобальные переменные нельзя объявлять в макросе"); //} if (se.operands.Count > 0 && Global.isInGlobal(se.operands[0])) { throw new SPException("Повторное задание глобальной переменной: " + se.sourceString); } if (!String.IsNullOrEmpty(se.label)) { throw new SPException("В описании глобальной переменной метки не нужны: " + se.sourceString); } if (se.operands.Count == 2) { if (!Utils.isLabel(se.operands[0])) { throw new SPException("Некорректное имя глобальной переменной: " + se.sourceString); } int temp; if (Int32.TryParse(se.operands[1], out temp) == false) { throw new SPException("Некорректное значение глобальной переменной: " + se.sourceString); } } else if (se.operands.Count == 1) { if (!Utils.isLabel(se.operands[0])) { throw new SPException("Некорректное имя глобальной переменной: " + se.sourceString); } } else { throw new SPException("Некорректное количество операндов в директиве GLOBAL: " + se.sourceString); } Utils.checkNames(se.operands[0]); }
/// <summary> /// Проверка макроподстановки /// </summary> public static void checkMacroSubstitution(SourceEntity se, TMOEntity te) { if (se.operands.Count != te.parameters.Count) { throw new SPException("Некорректное количество параметров. Введено: " + se.operands.Count + ". Ожидается: " + te.parameters.Count); } //if (se.operands.Count != 0) //{ // throw new SPException("Вызов макроса не должен содержать параметров: " + se.sourceString); //} if (!String.IsNullOrEmpty(se.label)) { throw new SPException("При макровызове макроса не должно быть меток: " + se.sourceString); } int temp; string[] vals = null; foreach (string prm in se.operands) { vals = prm.Split('='); if (vals.Length != 2) { throw new SPException("Параметр '" + prm + "'. Параметры определены некорректно, разделители между '=', названием и значением параметра недопустимы."); } if (!Global.isInGlobal(vals[1]) && !Int32.TryParse(vals[1], out temp)) { throw new SPException("Параметр '" + vals[0] + "' имеет некорректное значение (" + vals[1] + ")"); } if (Global.isInGlobal(vals[1]) && Global.searchInGlobal(vals[1]).value == null) { throw new SPException("Параметр '" + vals[0] + "' - неинициализованная глобальная переменная"); } } //if (!String.IsNullOrEmpty(se.label)) //{ // throw new SPException("При макровызове макрса не должно быть меток: " + se.sourceString); //} }
/// <summary> /// Проверка макроподстановки /// </summary> public static void checkMacroRun(SourceEntity se, TMOEntity parent, TMOEntity child) { //TMOEntity current = parent; //List<TMOEntity> list = new List<TMOEntity>(); //while (current.prev != null) //{ // if (list.Contains(current)) // { // throw new SPException("Перекрестные ссылки и рекурсия запрещены."); // } // list.Add(current); // current = current.prev; //} if (TMO.isInTMO(child.name) && parent.name == child.name) { throw new SPException("Макрос \"" + child.name + "\" не может быть вызван из себя (Рекурсия запрещена)."); } //if (TMO.isInTMO(child.name) && !parent.localTMO.Contains(child)) //{ // throw new SPException("Макрос " + child.name + " не входит в область видимости " + // (parent.name == "root" ? "основной программы" : "тела макроса " + parent.name) + "."); //} }
/// <summary> /// Шаг первого прохода /// </summary> public void firstRunStep(SourceEntity se, TMOEntity te) { String operation = se.operation; String label = se.label; List <String> operands = se.operands; try { CheckSourceEntity.checkLabel(se); if (operation == "END") { CheckSourceEntity.checkEND(se, this.macroFlag, this.macroName); result.Add(Utils.print(se)); } else if (operation == "GLOBAL" && this.macroFlag == false) { CheckSourceEntity.checkGLOBAL(se); if (operands.Count == 1) { Global.entities.Add(new GlobalEntity(operands[0], null)); } else { Global.entities.Add(new GlobalEntity(operands[0], Int32.Parse(operands[1]))); } } else if (operation == "SET" && this.macroFlag == false) { CheckSourceEntity.checkSET(se, te); Global.searchInGlobal(se.operands[0]).value = Int32.Parse(se.operands[1]); } else if (operation == "INC" && this.macroFlag == false) { CheckSourceEntity.checkINC(se, te); Global.searchInGlobal(operands[0]).value++; } else if (operation == "MACRO") { if (te != TMO.root) { throw new SPException("Макроопределения внутри макросов запрещены"); } CheckSourceEntity.checkMACRO(se, macroFlag); TMO.entities.Add(new TMOEntity() { name = label, parameters = se.operands }); this.macroFlag = true; this.macroName = label; } else if (operation == "MEND") { if (te != TMO.root) { throw new SPException("Макроопределения внутри макросов запрещены"); } CheckSourceEntity.checkMEND(se, macroFlag); foreach (SourceEntity mc in mbMacroCall) { if (mc.operation == this.macroName) { TMOEntity currentTe = TMO.searchInTMO(this.macroName); CheckSourceEntity.checkMacroSubstitution(mc, currentTe); List <SourceEntity> res = CheckBody.checkMacroBody(currentTe, operands); // результат макроподстановки List <SourceEntity> macroSubs = new List <SourceEntity>(); foreach (SourceEntity str in res) { macroSubs.Add(Utils.print(str)); } // Заменяем в результате макровызов на результат макроподстановки for (int i = 0; i < this.result.Count; i++) { if (this.result[i].operation == mc.operation && this.result[i].isRemove == "true") { this.result.Remove(this.result[i]); this.result.InsertRange(i, macroSubs); i += macroSubs.Count - 1; } } } } TMOEntity curTe = TMO.searchInTMO(this.macroName); curTe.IsFinished = true; var prevTe = TMO.GetPrevNotFinishedMacro(); if (prevTe != null) { this.macroFlag = true; this.macroName = prevTe.name; } else { this.macroFlag = false; this.macroName = null; } } else { if (this.macroFlag == true) { TMO.searchInTMO(this.macroName).body.Add(se); } else { if (te == TMO.root && (operation == "WHILE" || operation == "ENDW")) { throw new SPException("Использование директивы " + operation + " возможно только в теле макроса: " + se.sourceString); } // макровызов if (TMO.isInTMO(operation)) { TMOEntity currentTe = TMO.searchInTMO(operation); CheckSourceEntity.checkMacroSubstitution(se, currentTe); CheckBody.checkMacroRun(se, te, currentTe); List <SourceEntity> res = CheckBody.checkMacroBody(currentTe, operands); foreach (SourceEntity str in res) { result.Add(Utils.print(str)); } //if (te == TMO.root) //{ //} //else //{ // throw new SPException("Макровызовы внутри макроса запрещены"); //} } else { // Добавляем строку в список подозрительных на макровызов и в результат se = Utils.print(se); if (te == TMO.root && macroFlag == false) { se.isRemove = "true"; mbMacroCall.Add(se); } result.Add(se); } } } } catch (SPException ex) { throw new SPException(ex.Message); } }
/// <summary> /// Парсит массив строк в масссив SourceEntity, но только до появления первого END в качестве операции /// </summary> public static List <SourceEntity> parse(string[] strs) { List <SourceEntity> result = new List <SourceEntity>(); foreach (string s in strs) { // пропускаем пустую строку if (String.IsNullOrEmpty(s.Trim())) { continue; } string currentString = s.ToUpper().Trim(); SourceEntity se = new SourceEntity() { sourceString = currentString }; //разборка метки if (currentString.Contains(':') && (!currentString.Contains("BYTE") || currentString.IndexOf(':') < currentString.IndexOf("C'"))) { se.label = currentString.Split(':')[0].Trim(); currentString = currentString.Remove(0, currentString.Split(':')[0].Length + 1).Trim(); } if (currentString.Split(null as char[], StringSplitOptions.RemoveEmptyEntries).Length > 0) { se.operation = currentString.Split(null as char[], StringSplitOptions.RemoveEmptyEntries)[0].Trim(); currentString = currentString.Remove(0, currentString.Split(null as char[], StringSplitOptions.RemoveEmptyEntries)[0].Length).Trim(); } if (se.operation == "BYTE") { se.operands.Add(currentString.Trim()); } else { for (int i = 0; i < currentString.Split(null as char[], StringSplitOptions.RemoveEmptyEntries).Length; i++) { se.operands.Add(currentString.Split(null as char[], StringSplitOptions.RemoveEmptyEntries)[i].Trim()); } } //название проги или макроса - в поле метки if (se.operands.Count > 0 && se.operands[0] == "MACRO") { se.label = se.operation; se.operation = se.operands[0]; for (int i = 1; i < se.operands.Count; i++) { se.operands[i - 1] = se.operands[i]; } se.operands.RemoveAt(se.operands.Count - 1); } result.Add(se); //Читаем только до энда if (se.operation == "END") { return(result); } } return(result); }
public List <SourceEntity> invoke(string[] prms) { // Подставим значения параметров List <SourceEntity> newBody = CheckMacros.InvokeMacroParams(this, prms); SourceCode sc = new SourceCode(newBody); SourceEntity current = null; // проверки CheckMacros.CheckMacroLabels(this); //заменяем метки на "крутые" уникальные метки this.local = new Dictionary <string, int?>(); foreach (SourceEntity se in sc.entities) { current = se.Clone(); if (!String.IsNullOrEmpty(current.label)) { if (!Utils.isLabel(current.label)) { throw new SPException("Некорректное задание метки в макросе: " + se.sourceString); } Utils.checkNames(current.label); if (this.local.Keys.Contains(current.label)) { throw new SPException("Повторное задание метки в макросе: " + se.sourceString); } this.local.Add(current.label, null); } } // исполнять ли команду дальше Stack <bool> runStack = new Stack <bool>(); runStack.Push(true); // стек комманд, появлявшихся ранее Stack <Command> commandStack = new Stack <Command>(); // стек строк, куда надо вернуться при while Stack <int> whileStack = new Stack <int>(); // bool elseFlag; for (int i = 0; i < sc.entities.Count; i++) { this.counter++; if (this.counter == 1000000) { throw new SPException("Обнаружен бесконечный цикл"); } current = newBody[i].Clone(); CheckMacros.checkInner(current, commandStack); #region IF //if (current.operation == "IF") //{ // CheckMacros.checkIF(this); // commandStack.Push(Command.if_); // runStack.Push(runStack.Peek() && Utils.compare(current.operands[0])); // continue; //} //if (current.operation == "ELSE") //{ // CheckMacros.checkIF(this); // commandStack.Pop(); // commandStack.Push(Command.else_); // elseFlag = runStack.Pop(); // runStack.Push(runStack.Peek() && !elseFlag); // continue; //} //if (current.operation == "ENDIF") //{ // CheckMacros.checkIF(this); // commandStack.Pop(); // runStack.Pop(); // continue; //} #endregion if (current.operation == "WHILE") { CheckMacros.checkWhileEndw(this); commandStack.Push(Command.while_); runStack.Push(runStack.Peek() && Utils.compare(current.operands[0])); whileStack.Push(i); continue; } if (current.operation == "ENDW") { CheckMacros.checkWhileEndw(this); commandStack.Pop(); int newI = whileStack.Pop() - 1; if (runStack.Pop()) { i = newI; } continue; } #region AIF AGO //if (current.operation == "AIF" && Utils.compare(current.operands[0]) || current.operation == "AGO") //{ // CheckMacros.checkAIF(this); // if (runStack.Peek()) // { // string label = current.operation == "AIF" ? current.operands[1] : current.operands[0]; // // находим метку, чтобы туда прыгнуть // bool ready = false; // Stack<bool> agoStack = new Stack<bool>(); // // вверх // for (int j = i; j >= 0; j--) // { // if (this.body[j].operation == "IF" || this.body[j].operation == "WHILE") // { // if (agoStack.Count > 0) // { // agoStack.Pop(); // } // } // if (this.body[j].operation == "ELSE") // { // if (agoStack.Count > 0) // { // agoStack.Pop(); // } // agoStack.Push(false); // } // if (this.body[j].operation == "ENDIF" || this.body[j].operation == "ENDW") // { // agoStack.Push(false); // } // if (this.body[j].label == label && (agoStack.Count == 0 || agoStack.Peek())) // { // i = j - 1; // ready = true; // break; // } // } // // вниз // if (!ready) // { // for (int j = i; j < this.body.Count; j++) // { // if (this.body[j].operation == "IF" || this.body[j].operation == "WHILE") // { // agoStack.Push(false); // } // if (this.body[j].operation == "ELSE") // { // if (agoStack.Count > 0) // { // agoStack.Pop(); // } // agoStack.Push(false); // } // if (this.body[j].operation == "ENDIF" || this.body[j].operation == "ENDW") // { // if (agoStack.Count > 0) // { // agoStack.Pop(); // } // } // if (this.body[j].label == label && (agoStack.Count == 0 || agoStack.Peek())) // { // i = j - 1; // ready = true; // break; // } // } // } // if (!ready) // { // throw new SPException("Метка " + label + " при директиве " + current.operation + " находится вне зоны видимости или не описана"); // } // } // continue; //} #endregion if (runStack.Peek()) { if (!String.IsNullOrEmpty(current.label)) { current.label = current.label + "_" + this.name + "_" + this.count; } for (int j = 0; j < current.operands.Count; j++) { if (this.local.Keys.Contains(current.operands[j])) { current.operands[j] = current.operands[j] + "_" + this.name + "_" + this.count; } } sc.firstRunStep(current, this); } } this.count++; //foreach (SourceEntity se in sc.result) //{ //se.label = null; //} return(sc.result); }