/// <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> /// Проверка строки с операцией 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> public static TMOEntity searchInTMO(string name) { TMOEntity result = (from TMOEntity te in TMO.entities where te.name == name select te).SingleOrDefault <TMOEntity>(); return(result); }
/// <summary> /// Проверка body макроса на GLOBAL, SET и формирование выходного body /// </summary> /// <param name="se">макрос TMOEntity</param> public static List <SourceEntity> checkMacroBody(TMOEntity te, List <String> operands) { //foreach (SourceEntity se in te.body) //{ // if (TMO.isInTMO(se.operation)) // { // throw new SPException("Макровызовы внутри макроса запрещены: " + se.sourceString); // } //} List <SourceEntity> result = te.invoke(operands.ToArray()); return(result); }
/// <summary> /// Проверяет макрос на наличие меток /// </summary> public static void CheckMacroLabels(TMOEntity te) { List <SourceEntity> result = new List <SourceEntity>(); foreach (SourceEntity se in te.body) { result.Add(se.Clone()); } //// Определяем метки, используемые при AGO //foreach (SourceEntity se in result) //{ // if (se.operation == "AGO" && se.operands.Count > 0 && !te.agoLabels.Contains(se.operands[0])) // { // te.agoLabels.Add(se.operands[0]); // } // if (se.operation == "AIF" && se.operands.Count > 1 && !te.agoLabels.Contains(se.operands[1])) // { // te.agoLabels.Add(se.operands[1]); // } //} //формируется локальная область видимости // Список меток, которые являютс ячастью AGO, и уже найдены //List<string> markedLabels = new List<string>(); //foreach (SourceEntity se in result) //{ //if (!String.IsNullOrEmpty(se.label)) //{ //if (!Utils.isLabel(se.label)) //{ //throw new SPException("Метки внутри макроса " + te.name + " запрещены"); //} //if (!te.agoLabels.Contains(se.label)) //{ // throw new SPException("Метки внутри макроса " + te.name + " запрещены"); //} //else //{ // if (markedLabels.Contains(se.label)) // { // throw new SPException("Повторное описание метки " + se.label + " в макросе " + te.name); // } // markedLabels.Add(se.label); //} // } //} //if (te.agoLabels.Count != markedLabels.Count) //{ // throw new SPException("Ошибка использования директивы AGO или AIF. Метка в пределах макроса " + te.name + " не найдена."); //} }
/// <summary> /// Проверка макроса на IF-ELSE-ENDIF /// </summary> /// <param name="body"></param> public static void checkAIF(TMOEntity te) { List <SourceEntity> body = te.body; try { foreach (SourceEntity str in body) { if (str.operation == "AIF") { if (str.operands.Count != 2) { throw new SPException("Некорректное использование директивы AIF: " + str.sourceString); } if (!String.IsNullOrEmpty(str.label)) { throw new SPException("При директиве AIF метки быть не должно: " + str.sourceString); } if (!Utils.isLabel(str.operands[1])) { throw new SPException("При директиве AIF отсутствует метка для ссылки: " + str.sourceString); } } if (str.operation == "AGO") { if (str.operands.Count != 1) { throw new SPException("Некорректное использование директивы AGO: " + str.sourceString); } if (!String.IsNullOrEmpty(str.label)) { throw new SPException("При директиве AGO метки быть не должно: " + str.sourceString); } if (!Utils.isLabel(str.operands[0])) { throw new SPException("При директиве AGO отсутствует метка для ссылки: " + str.sourceString); } } } } catch (SPException ex) { throw new SPException(ex.Message, ex.errorString); } catch (Exception) { throw new SPException("Некорректное использование директив AIF-AGO"); } }
/// <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> /// Достать предыдущий макрос (Вложенные макроопределния - да) /// </summary> /// <returns></returns> public static TMOEntity GetPrevNotFinishedMacro() { TMOEntity result = (from te in TMO.entities where !te.IsFinished select te).LastOrDefault(); return(result); }
/// <summary> /// Проверка макроса на IF-ELSE-ENDIF /// </summary> /// <param name="body"></param> public static void checkIF(TMOEntity te) { List <SourceEntity> body = te.body; Stack <bool> stackIfHasElse = new Stack <bool>(); //проверка корректности IF-ELSE-ENDIF try { foreach (SourceEntity str in body) { if (str.operation == "IF") { if (str.operands.Count != 1) { throw new SPException("Некорректное использование директивы IF: " + str.sourceString); } if (!String.IsNullOrEmpty(str.label)) { throw new SPException("При директиве IF метки быть не должно: " + str.sourceString); } stackIfHasElse.Push(false); } if (str.operation == "ELSE") { if (str.operands.Count != 0) { throw new SPException("Некорректное использование директивы ELSE: " + str.sourceString); } if (!String.IsNullOrEmpty(str.label)) { throw new SPException("При директиве ELSE метки быть не должно: " + str.sourceString); } if (stackIfHasElse.Peek() == true) { throw new SPException("Лишняя ветка ELSE: " + str.sourceString); } else { stackIfHasElse.Pop(); stackIfHasElse.Push(true); } } if (str.operation == "ENDIF") { if (str.operands.Count != 0) { throw new SPException("Некорректное использование директивы ENDIF: " + str.sourceString); } if (!String.IsNullOrEmpty(str.label)) { throw new SPException("При директиве ENDIF метки быть не должно: " + str.sourceString); } stackIfHasElse.Pop(); } } if (stackIfHasElse.Count > 0) { throw new SPException("Отсутствует директива ENDIF"); } } catch (SPException ex) { throw new SPException(ex.Message, ex.errorString); } catch (Exception) { throw new SPException("Некорректное использование директив IF - ENDIF"); } }
/// <summary> /// Проверка макроса на WHILE-ENDW /// </summary> public static void checkWhileEndw(TMOEntity te) { List <SourceEntity> body = te.body; int whileCount = 0; //проверка корректности WHILE-ENDW try { foreach (SourceEntity str in body) { if (str.operation == "WHILE") { if (str.operands.Count != 1) { throw new SPException("Некорректное количество операндов директивы WHILE: " + str.sourceString); } if (!String.IsNullOrEmpty(str.label)) { throw new SPException("При директиве WHILE метки быть не должно: " + str.sourceString); } whileCount++; } else if (str.operation == "ENDW") { if (str.operands.Count != 0) { throw new SPException("Некорректное количество операндов директивы ENDW: " + str.sourceString); } if (!String.IsNullOrEmpty(str.label)) { throw new SPException("При директиве ENDW метки быть не должно: " + str.sourceString); } whileCount--; if (whileCount < 0) { throw new SPException("Некорректное использование директив WHILE и ENDW"); } } else if ((str.operation == "MACRO" || str.operation == "MEND") && whileCount > 0) { throw new SPException("Объявление макросов в цикле запрещено"); } else if (str.operation == "GLOBAL" && whileCount > 0) { throw new SPException("Объявление глобальных переменных в цикле запрещено"); } } if (whileCount != 0) { throw new SPException("Некорректное использование директив WHILE и ENDW"); } } catch (SPException ex) { throw new SPException(ex.Message, ex.errorString); } catch (Exception) { throw new SPException("Некорректное использование директив WHILE и ENDW"); } }
/// <summary> /// Подстановка значений вместо параметров макроса /// </summary> /// <param name="te"></param> /// <param name="prms"></param> /// <returns></returns> public static List <SourceEntity> InvokeMacroParams(TMOEntity te, string[] prms) { // формируем локальную область видимости (параметры в виде key-value) Dictionary <string, int> dict = new Dictionary <string, int>(); if (prms.Length != te.parameters.Count) { throw new SPException("Количество параметров вызова некорректно, необходимо " + te.parameters.Count + " параметров."); } string[] vals = null; int temp; foreach (string prm in prms) { vals = prm.Split('='); if (vals.Length != 2) { throw new SPException("Параметр '" + prm + "'. Параметры определены некорректно, разделители между '=', названием и значением параметра недопустимы."); } if (!te.parameters.Contains(vals[0])) { throw new SPException("Параметра '" + vals[0] + "' не существует в макроопределении."); } if (!Global.isInGlobal(vals[1]) && !Int32.TryParse(vals[1], out temp)) { throw new SPException("Параметр '" + prm + "' имеет некорректное значение."); } if (Global.isInGlobal(vals[1]) && Global.searchInGlobal(vals[1]).value == null) { throw new SPException("Параметр '" + prm + "' - неинициализованная глобальная переменная!"); } if (dict.Keys.Contains(vals[0])) { throw new SPException("Параметр '" + vals[0] + "' повторяется."); } dict.Add(vals[0], Global.isInGlobal(vals[1]) ? (int)Global.searchInGlobal(vals[1]).value : Int32.Parse(vals[1])); } List <SourceEntity> result = new List <SourceEntity>(); foreach (SourceEntity se in te.body) { //Проверка на использование меток внутри макроса if (!String.IsNullOrEmpty(se.label) && se.operation != "MACRO") { throw new SPException("Метки внутри макроса " + te.name + " запрещены"); } result.Add(se.Clone()); } // замена параметров в макросе на числа foreach (SourceEntity se in result) { if (se.operation == "WHILE") { foreach (string sign in Utils.signs) { string[] t = se.operands[0].Split(new string[] { sign }, StringSplitOptions.None); if (t.Length == 2) { if (te.parameters.Contains(t[0].Trim())) { t[0] = dict[t[0].Trim()].ToString(); } if (te.parameters.Contains(t[1].Trim())) { t[1] = dict[t[1].Trim()].ToString(); } se.operands[0] = t[0] + sign + t[1]; break; } } } else if (se.operation == "IF") { foreach (string sign in Utils.signs) { string[] t = se.operands[0].Split(new string[] { sign }, StringSplitOptions.None); if (t.Length == 2) { if (te.parameters.Contains(t[0].Trim())) { t[0] = dict[t[0].Trim()].ToString(); } if (te.parameters.Contains(t[1].Trim())) { t[1] = dict[t[1].Trim()].ToString(); } se.operands[0] = t[0] + sign + t[1]; break; } } } else { for (int i = 0; i < se.operands.Count; i++) { if (dict.Keys.Contains(se.operands[i])) { se.operands[i] = dict[se.operands[i]].ToString(); } } } } return(result); }