Функция ВычислитьЯчейку(Таб,адрес,старТаб=0,старАдрес=0)
Перем ТабПеременных;
Перем Контроль;
Перем сЗначения;
Перем темпглТабПеременных;
Перем темпглПеременная;
БИ = СоздатьОбъект("БухгалтерскиеИтоги");
сЗначения = СоздатьОбъект("СписокЗначений");
// Создадим таблицу локальных переменных
ТабПеременных = СоздатьОбъект("ТаблицаЗначений");
// Инициализируем таблицу локальных переменных
ТабПеременных.НоваяКолонка("Идентификатор");
ТабПеременных.НоваяКолонка("Значение");
ТекстВыражения = Таб.Область(адрес).Текст;
// Проверим, из скольки строк состоит наше выражение
Если СтрКоличествоСтрок(ТекстВыражения) > 1 Тогда
стр = СтрПолучитьСтроку(ТекстВыражения,1);
Иначе
стр = ТекстВыражения;
КонецЕсли;
глобПоз = 1; // Глобальный указатель в потоке лексем
// Пропустим лидирующие пробелы перед строкой
Пока КодСимв(СРЕД(стр,глобПоз,1)) = 32 Цикл
глобПоз = глобПоз + 1;
КонецЦикла;
// Проверим, это обычный текст или выражение
//Если СРЕД(стр,глобПоз,1) <> "<" Тогда
// Возврат ТекстВыражения;
//КонецЕсли;
Если ((СРЕД(стр,глобПоз,1) <> "=") и (СРЕД(стр,глобПоз,1) <> "<")) Тогда
Возврат ТекстВыражения;
КонецЕсли;
// Сканируем текст
Для инд = 1 по СтрКоличествоСтрок(ТекстВыражения) Цикл
Если флагПрервать = 1 Тогда
флагПрервать = 0;
Прервать;
КонецЕсли;
стр = СтрПолучитьСтроку(ТекстВыражения,инд);
глобПоз =1; текСтрока = инд;
// Проверим строку на пустое значение. Может быть это просто интервал между строками
Если ПустоеЗначение(стр) = 1 Тогда
Продолжить; // Перейдем к следующей строке
КонецЕсли;
// Пропустим лидирующие пробелы перед началом выражения
Пока КодСимв(СРЕД(стр,глобПоз,1)) = 32 Цикл
глобПоз = глобПоз + 1;
КонецЦикла;
// Если инд = 1 (т.е. первая строка) удалим ненавистный нам символ "<" вместе с его пробелами
Если инд = 1 Тогда
стр = СРЕД(стр,глобПоз+1,СтрДлина(стр));
глобПоз = 1;
КонецЕсли;
глСтр = инд;
// Попробуем найти конец выражения
конецВыр = Найти(стр,";");
Если конецВыр = 0 Тогда
Ошибка(10,Адрес,инд,0); // Не найден конец выражения.Это плохо, выдаем ошибку
флагИсключительнойСитуации = 1;
Возврат "Error";
ИначеЕсли конецВыр = 1 Тогда // Это хорошо. Дальше идет комментарий
Продолжить;
КонецЕсли;
Переменная =""; флгПеременной = 0; глПеременная =0;
// Проверим, объявляется ли переменная в этом выражении
позРавно = НайтиСтр(стр,"=");
Если позРавно <> 0 Тогда
// Получим имя переменной. Если перед именем переменной !, значит объявляется глобальная переменная
Переменная = ПолучитьИмяПеременной(стр,глобПоз,позРавно);
глПеременная = Переменная;
Если ((Переменная = "Error") и (флагИсключительнойСитуации =1)) Тогда // Упс !!! Ошибка
Ошибка(20,Адрес,инд,Переменная); // Не найден конец выражения.Это плохо, выдаем ошибку
флагСтоп = 1;
Возврат "Error";
КонецЕсли;
КонецЕсли;
// выделяем выражение
стрВыражение = Сред(стр,глобПоз,(Найти(стр,";")-(глобПоз-1)));
стрШаблон = "";
// Сканируем выражение
Для поз1 = 1 по СтрДлина(стрВыражение) Цикл
символ = НРег(Сред(стрВыражение,поз1,1));
Если ДопустимыйСимвол(символ) = 4 Тогда // игнорируем пробел
Продолжить;
КонецЕсли;
Если СпециальныйСимвол(Символ) = 1 Тогда // Локальная переменная
// Выделим нашу переменную, проверим по таблице переменных, если такой переменной нет,
// сгенерируем ошибку, если есть получим ее значение и подставим в строку шаблон
поз1 = поз1 + 1; вырПеременная = "";
Для поз1 = поз1 по СтрДлина(стрВыражение) Цикл
символ = НРег(Сред(стрВыражение,поз1,1));
ДопустимыйСимвол = ДопустимыйСимвол(символ);
Если ДопустимыйСимвол = 0 Тогда
Ошибка(30,Адрес,инд,поз1); // Недопустимый символ
флагИсключительнойСитуации = 1;
Возврат "Error";
ИначеЕсли ДопустимыйСимвол = 4 Тогда // игнорируем пробел
Продолжить;
ИначеЕсли ДопустимыйСимвол = 1 Тогда // Допустимый символ переменной
вырПеременная = вырПеременная + символ;
ИначеЕсли (ДопустимыйСимвол = 2) или (ДопустимыйСимвол = 3) Тогда // Нашли допустимый разделитель (+,-,/,*,",")
ЗначениеПеременной = ПолучитьПеременную(ТабПеременных,НРег(вырПеременная));
Если ЗначениеПеременной = "Error" Тогда // Нет такой переменной в таблице переменных
Ошибка(40,Адрес,инд,поз1,вырПеременная);
флагИсключительнойСитуации = 1;
Возврат "Error";
Иначе // Есть такая переменная. Подставляем ее значение в шаблон и продолжаем с точки после разделителя
Если (символ = ";") Тогда
// или (символ = ">")
символ = "";
КонецЕсли;
типПеременной = ПолучитьТип(ЗначениеПеременной); // Агрегатный тип данных
Если типПеременной <> 100 Тогда
Если типПеременной = 2 Тогда
ЗначениеПеременной = Симв(34) + ЗначениеПеременной + Симв(34);
ИначеЕсли типПеременной = 1 Тогда // Если число
Если Число(значениеПеременной) < 0 Тогда // Если число отрицательное, в скобочки его
значениеПеременной = "(" + значениеПеременной + ")";
КонецЕсли;
КонецЕсли;
стрШаблон = стрШаблон + Строка(ЗначениеПеременной)+символ;
Иначе
сЗначения.ДобавитьЗначение(ЗначениеПеременной);
ном = сЗначения.РазмерСписка();
стрШаблон = стрШаблон + "сЗначения.ПолучитьЗначение(" + Строка(ном) + ")" + символ;
КонецЕсли;
Прервать;
КонецЕсли;
КонецЕсли;
КонецЦикла;
ИначеЕсли СпециальныйСимвол(Символ) = 2 Тогда // Ссылка на ячейку
// сканируем лексемы помещая их во временную переменную. Если встречаем допустимые разделители,
// считаем, что во временной переменной содержится адрес ячейки текущей таблицы. Проверяем таблицу ячеек,
// если данной ячейки там нет, передаем на вычисление. Если встречаем точку, значит во временной
// переменной хранится имя таблицы. Продолжаем сканировать адрес
поз1 = поз1 + 1; имяТаблицы = ""; АдресЯчейки = ""; темпСтр ="";
Для поз1 = поз1 по СтрДлина(стрВыражение) + глобпоз Цикл
символ = НРег(Сред(стрВыражение,поз1,1));
ДопустимыйСимвол = ДопустимыйСимвол(символ);
Если ДопустимыйСимвол = 1 Тогда // обычный допустимый символ
темпСтр = темпстр + символ;
ИначеЕсли ДопустимыйСимвол = 4 Тогда // игнорируем пробел
Продолжить;
ИначеЕсли ДопустимыйСимвол = 2 Тогда // Заносим адрес ячейки и вываливаемся из цикла
АдресЯчейки = темпСтр;
темпстр = "";
Прервать;
ИначеЕсли (ДопустимыйСимвол = 3) и (ПустоеЗначение(имяТаблицы) = 1) Тогда // точка
ИмяТаблицы = темпСтр;
темпстр = "";
Иначе // Толи точка левая, толи символы недопустимые
Ошибка(50,Адрес,инд,поз1);
флагИсключительнойСитуации = 1;
Возврат "Error";
КонецЕсли;
КонецЦикла;
// Попробуем вычилить ячейку
Если ПустоеЗначение(имяТаблицы) = 1 Тогда
значениеЯчейки = НайтиЯчейку(Таб,АдресЯчейки);
// Даже если ячейка вычислена и вней "Error" ошибки не будет
Если значениеЯчейки = "Error" Тогда
// Проверим цикличность ссылок. Если стар адрес = нов адрес ошибка
Если НРег(АдресЯчейки) = НРег(старАдрес) Тогда
Ошибка(70,Адрес,инд,поз1);
флагИсключительнойСитуации = 1;
Возврат "Error";
КонецЕсли;
темпглТабПеременных = глТабПеременных;
темпглПеременная = глПеременная;
значениеЯчейки = ВычислитьЯчейку(Таб,АдресЯчейки,,Адрес);
глТабПеременных = темпглТабПеременных;
глПеременная = темпглПеременная;
Если ПустоеЗначение(значениеЯчейки) = 1 Тогда
значениеЯчейки =0;
КонецЕсли;
Иначе
// Проверим тип возвращаемого результата
Если ПустоеЗначение(значениеЯчейки) = 1 Тогда
значениеЯчейки =0;
КонецЕсли;
Если ПолучитьТип(значениеЯчейки) = 2 Тогда // Если возвращаемый тип не число
ЗначениеЯчейки =0;
//Ошибка(100,Адрес,инд,поз1);
//флагИсключительнойСитуации = 1;
//Возврат "Error";
КонецЕсли;
КонецЕсли;
Иначе // имя не пустое. Инициализируем таблицу
новТаб = СоздатьОбъект("Таблица");
ПутькТаблице = ПолучитьПутькТаблице(имяТаблицы);
Если ПутькТаблице = "Error" Тогда // Нет такой таблице в базе
Ошибка(60,Адрес,инд,поз1);
флагИсключительнойСитуации = 1;
Возврат "Error";
КонецЕсли;
новТаб.Открыть(ПутькТаблице);
// Теперь текТаб = текущей рассчитываемой таблице
ТекТаб = новТаб;
темпглТабПеременных = глТабПеременных;
темпглПеременная = глПеременная;
значениеЯчейки = ВычислитьЯчейку(новТаб,АдресЯчейки);
// Теперь текТаб = основной таблице
ТекТаб = Таблица;
глТабПеременных = темпглТабПеременных;
глПеременная = темпглПеременная;
КонецЕсли;
Если ПустоеЗначение(значениеЯчейки) = 1 Тогда
значениеЯчейки =0;
КонецЕсли;
Если (значениеЯчейки = "Error") Тогда // Упс, ошибка
Ошибка(0);
флагИсключительнойСитуации = 1;
Возврат "Error";
ИначеЕсли ПолучитьТип(значениеЯчейки) = 2 Тогда // Если озвращаемый тип не число
//Сообщить(значениеЯчейки);
ЗначениеЯчейки =0;
//Ошибка(100,Адрес,инд,поз1);
//флагИсключительнойСитуации = 1;
//Возврат "Error";
Иначе
// Проверим, отрицательный ли результат. Если отрицательный, заключаем его в скобки
Если СРЕД(значениеЯчейки,1,1) = "-" Тогда
значениеЯчейки = "(" + значениеЯчейки + ")";
КонецЕсли;
КонецЕсли;
// Добавим полученное значение в таблицу ячеек только по текущей таблице. По внешней не записываем
//Если ПустоеЗначение(имяТаблицы) = 1 Тогда
// ДобавитьЗначениеВТаблицуЯчеек(АдресЯчейки,значениеЯчейки);
//КонецЕсли;
Если (символ = ";") Тогда
//или (символ = ">") Тогда
символ = "";
КонецЕсли;
// стрШаблон = стрШаблон + НРег(Строка(значениеЯчейки))+символ;
стрШаблон = стрШаблон + значениеЯчейки+символ;
// сканируем дальше
// Прервать;
ИначеЕсли СпециальныйСимвол(символ) = 3 Тогда // Нашли начало текстовой строки двойные кавычки
// Сдесь мы не переводим символы в нижний регистр. Получаем как есть
стрШаблон = стрШаблон + символ;
поз1 = поз1 + 1;
// Пытаемся найти закрывающиеся кавычки
Для поз1= поз1 по СтрДлина(стрВыражение) Цикл
символ = Сред(стрВыражение,поз1,1);
Если (КодСимв(символ) = 34) или (КодСимв(символ) = 59) Тогда
стрШаблон = стрШаблон + символ;
Прервать;
Иначе
стрШаблон = стрШаблон + символ;
конецЕсли;
КонецЦикла;
Если КодСимв(Сред(стрВыражение,поз1,1))= 59 Тогда
Ошибка(110,Адрес,инд,поз1);
флагИсключительнойСитуации = 1;
Возврат "Error";
КонецЕсли;
Иначе // игнорируем
Если (символ = ";") Тогда
//или (символ = ">")
символ = "";
КонецЕсли;
стрШаблон = стрШаблон + НРег(символ);
КонецЕсли;
КонецЦикла;
глТабПеременных = ТабПеременных;
// Попытка
вычисленноеЗначение = Шаблон("[Значение(" + стрШаблон + ")]");
// Исключение
// Сообщить("!!!");
// КонецПопытки;
// /Проверим,что нам возвратила функция шаблон. Если то, что мы ей передали, значит ошибка
Если Сред(вычисленноеЗначение,1,1) = "[" Тогда
флагИсключительнойСитуации = 1;
Ошибка(9999,Адрес,,ОписаниеОшибки());
флагИсключительнойСитуации = 1;
Возврат "Error";
ИначеЕсли вычисленноеЗначение = "Error" Тогда
флагИсключительнойСитуации = 1;
Возврат "Error";
КонецЕсли;
// КонецПопытки;
// Сдесь инициализируем переменюну значением вычисленного выражения
// Проверяем, объявлялась ли в выражении переменная
//Если ((ПустоеЗначение(Переменная) = 0) и (флгПеременной = 0)) Тогда
// ИнициализацияПеременной(ТабПеременных,НРег(Переменная),вычисленноеЗначение);
//КонецЕсли;
КонецЦикла;
// Попробуем определить тип возвращаемого значения
// Если ПолучитьТип(вычисленноеЗначение) = 1 Тогда // Число
//// Поместим значение ячейки в таблицу вычесленных ячеек
// УстановитьЗначениеЯчейки(Таб,Адрес,Число(вычисленноеЗначение));
// Возврат Число(вычисленноеЗначение);
// Иначе // Строка или пустое значение
УстановитьЗначениеЯчейки(Таб,Адрес,вычисленноеЗначение);
Возврат вычисленноеЗначение;
//КонецЕсли;
КонецФункции
Показать