Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
MUMPS СУБД. Практика применения и опыт программирования.pdf
Скачиваний:
0
Добавлен:
07.09.2026
Размер:
2 Мб
Скачать
1.1. КОМАНДЫ 21
где используются уже более осмысленные и значимые идентификаторы.
При использовании макросов препроцессора (в зависимости от того, поддерживается ли препроцессор в используемой MUMPS системе или нет) код может быть приведен к намного более легко воспринимаемому:
#define DATE(%v) $p(%v,4,"~") ... s $$$DATE(rec)=$h w $$$DATE(rec)
Что интересно, существуют реализации MUMPS, в которых трак­товка левосторонних функций была расширена и в качестве аргумента им разрешено принимать не только локальную или глобальную пере­менную, но и указывать другую левостороннюю функцию. В частности, такая возможность была реализована в системе StarMUMPS. В ней раз­решено рекурсивное левостороннее присваивание, например, так:
s $p($p(var,delim1,pos1),delim2,pos2)=expr
В этом случае система оперирует подстрокой, выделенной раздели­телем delim1 из подстроки переменной var, выделенной разделителем delim2, и, при необходимости, выполняет дополнение в обеих подстро­ках. Но такой функционал не входит в стандарт и не поддерживается современными распространенными реализациями MUMPS.
Для копирования переменной с поддеревом нужно указать не зна­чение, а переменную, из которой необходимо скопировать. Копирование выполняет команда merge.
merge var1=var2
В правой и левой части можно указать переменные с индексами, в этом случае будет копироваться соответственно в поддерево и из подде­рева.
У команды merge есть две особенности, важные для систем баз дан­ных. Первая состоит в том, что если в переменной указанной в левой части уже было поддерево, то оно не будет предварительно удалено. Например, если есть переменная
USER>s a(1,1)="a11",a(1,2)="a12"
USER>s b(3,1)="b31"
то при копировании поддерева
22 ГЛАВА 1. СРЕДА ИСПОЛНЕНИЯ
USER>m a(1)=b(3)
часть поддерева a, не существующая в поддереве b, будет сохранена, та часть которая есть в обоих, будет перезаписана, а та часть которая отсутствует в a но присутствует в b, будет добавлена к a:
USER>m a(1)=b(3)
USER>w a(1,1)="b31" a(1,2)="a12" b(3,1)="b31"
Поэтому, при использовании команды merge и при необходимости иметь строгую копию, разработчики на MUMPS должны убедиться, что ход выполнения программы не создает в пременной, указанной слева, посторонних записей.
Второй особенностью команды merge является отношение к неопре­деленным значениям. Если в поддереве источнике копирования нет за­писей, то они не будут копироваться. И не будут копироваться никакие записи, если такой переменной вообще не существует. В этом случае команда merge вообще ничего не делает. И, если переменной указанной слева, не существовало, то она и не будет создаваться.
USER>k
USER>m a(1)=b(2)
USER>w
USER>
Здесь предварительно были удалены все локальные переменные, за­тем присваивается поддерево b(2) в поддерево a(1), но поскольку подде­рева b(2) не существовало, то поддерево для a(1) не создается и пере­менной a по-прежнему не существует. Команда merge, таким образом, при обращении к неопределенным переменным не генерирует ошибку.
Что интересно, команда merge по стандарту языка не допускает ко­пирование поддерева в то же самое поддерево. Если переменные a и b являются по отношению к друг другу поддеревьями, то команда merge генерирует ошибку о невозможности выполнить такую операцию:
USER>m a(1)=a(2)
USER>m a(1)=a(1,2)
<COMMAND>
1.1. КОМАНДЫ 23
Здесь в первом случае переменные a(1) и a(2) не являются друг по отношению к другу поддеревьями и команда merge выполняется без ошибки, а во втором случае переменная a(1,2) является поддеревом для переменной a(1) и команда merge генерирует ошибку.
Для присваивания неопределенного значения в языке предназначена команда kill. Команда удаляет указанную переменную, в результате она становится переменной с неопределенным значением. В языке MUMPS нет отдельного понятия, что переменная существует но не имеет значе­ния, если у переменной нет значения то она не хранится и не существует.
Поведение команды kill определено на момент ее окончания - если переменная существовала, то будет удалена, если не существовала, то команда ничего не делает. Команда может быть применена к локаль­ным и глобальнм переменным. В зависимости от реализации MUMPS системы может дополнительно поддерживаться применение команды к структурной системной переменной, например в реализации MiniM ко­манда
kill ^$JOB(jobnumber)
принудительно завершает процесс с номером jobnumber.
Применение команды kill к чему-либо кроме локальной или глобаль­ной переменной, вообще говоря, не входит в стандарт, и к таким воз­можностям нужно относиться внимательно. В зависимости от ситуации такой случай может означать ошибку, в частности, если при использо­вании косвенной формы команды в прикладной системе предполагается, что команда должна генерировать ошибку если аргумент не является ни локальной ни глобальной переменной.
У команды kill поддерживается безаргументная форма - в этом слу­чае команда применяется ко всем локальным переменным, которые су­ществуют.
Кроме того, у команды kill поддерживается исключающая форма: ес­ли в качестве аргумента указаны имена локальных переменных перечис­ленные в круглых скобках, то команда применяется ко всем локальным переменным кроме указанных. При этом указанные в скобках перемен­ные не затрагиваются и они не могут быть указаны с индексами. Напри­мер
kill (a,b,c)
удаляет все локальные переменные кроме a, b и c.
Если команде kill указывается переменная с индексами, то команда удаляет только указанное поддерево. Если указано имя без индексов, то удаляется дерево переменной целиком.
24 ГЛАВА 1. СРЕДА ИСПОЛНЕНИЯ
В отношении этого совмещенного поведения команды kill стандар­том было предусмотрено предложение реализовать дополнительно еще две команды, kvalue (kv) и ksubscripts (ks), соответственно для удале­ния только указанного имени не затрагивая поддерева и для удаления только поддерева не затрагивая указанного имени. В реализации MiniM эти команды поддерживаются, но другими современными реализациями MUMPS пока еще не поддерживаются. Поэтому при их использовании нужно убедиться, будут ли команды работать на выбранной системе, либо понадобится ли их заменить на комбинацию других команд.
Другая команда, не имеющая прямой задачи сделать значение пере­менной неопределенным, но делающая это побочно, это команда new.
Команда new объявляет, что локальная переменная в случае, если впоследствии будет создаваться, то ее область видимости должна на­чинаться от текущего уровня стека. Если переменная с таким же име­нем уже существовала на другом уровне стека, то она перестает быть видимой и все дальнейшие операции выоплняются с новым положени­ем локальной переменной. В случае, если переменная с этим именем уже была объявлена на этом же уровне стека, то она удаляется. В лю­бом случае, непосредственно после команды new, эта переменная имеет неопределенное значение.
Исключением является расширенная инициализирующая форма ко­манды new, реализованная в системе MiniM - для переменной можно указать значение, которое она должна получить:
new var=expr
при этом команда эквивалентна двум командам:
new var set var=expr
Это расширение, хотя и является практичным, не входит в стан­дарт языка MUMPS и в настоящее время не поддерживается другими MUMPS системами.
У команды new стандартно поддерживается безаргументная форма. В случае, если команде не указано ни одно имя, это означает что вообще все локальные переменные далее имеют область видимости начиная с текущего уровня стека.
Кроме того, у команды new стандартно поддерживается исключаю­щая форма:
new (var1,var2,...)
1.1. КОМАНДЫ 25
В этом случае команда применяется не к перечисленным именам пе­ременных, а ко всем, кроме перечисленных, в том числе еще не создан­ным. Для того, чтобы применить команду new только к определенным именам, их надо просто перечислить через запятую без взятия в скобки:
new var1,var2,var3,...
Команда new не удаляет данные локальных переменных, существо­вавших ранее, на другом уровне стека, и при возврате управления на предыдущий уровень стека действие команды отменяется, и видимость локальных переменных полностью восстанавливается.
Что интересно, в языке MUMPS, если для локальной переменной не объявлялось начало области видимости командой new, то видимость этой переменной всеобщая, и ее можно изменять и читать на любом уровне стека.
Команда new, что может показаться современным разработчикам на MUMPS странным, появилась в стандарте языка MUMPS далеко не сразу, а только в 1990-м году. Вполне возможно, что до сих пор нахо­дятся в эксплуатации модули, при разработке которых предполагалась общая область видимости имен локальных переменных. Вполне возмож­но, что при модернизации таких программ с использованием современной команды new разработчик может внести ошибку, поскольку отдельным фрагментам может понадобиться именно общая область видимости. Хо­тя при современных разработках команда new используется наоборот, как практически стандартное соглашение об изолировании переменных, изменяемых подпрограммой.
Кроме стандартной команды new многие современные реализации MUMPS поддерживают дополнительную расширенную команду znew. Ее отличие от стандартной команды new в том, что, создав для локаль­ной переменной область видимости от текущего уровня стека, команда создает точную копию оригинальной переменной. Дальнейшие операции с этой переменной изменяют лишь ее, и при возврате на предыдущий уровень стека все выполненные изменения, естественно, пропадают. Ко­манда относится к нестандартной, но многие реализации ее поддержива­ют. В случае ее использования в разработке, конечно, нужно проверить поддерживается ли она на целевой MUMPS системе.
Формально говоря, команда чтения из текущего устройства (read) также выполняет присваивание переменной в качестве побоного эффек­та, но отнесена к командам ввода-вывода. Для нее основным действием является ввод, а присваивание - это лишь побочный, но необходимый результат.
26 ГЛАВА 1. СРЕДА ИСПОЛНЕНИЯ

1.1.2 Условные команды

Исполнение команд в программе на MUMPS выполняется построчно, и внутри строки слева направо. Для управления выполнением програм­мы в зависимости от некоторых условий в языке MUMPS определены условные команды.
К условным командам относятся команды if, else и for.
Команды if в безаргументной форме и else (имеет только безаргу­ментную форму) проверяют значение системной переменной $test. По определению операций, эта переменная может быть установлена множе­ством способов. Например, при неудаче получения блокировки в течении определенного таймаутом времени. Поэтому в программах MUMPS ча­сто можно встретить команды if или else как-бы не относящиеся ни к какому явно вычисляемому условию.
Аргументная команда if вычисляет значение аргумента как число и если результат 0, то взводит системную переменную $test в значение 0, иначе взводит $test в значение 1. И выполнение команд продолжается в зависимости от результата.
У команды else есть особенность - для нее синтаксически недопусти­мо указание аргумента, поэтому после нее должно быть обязательно 2 пробельных символа.
Для строчно-ориентированных интерпретаторов условные команды распространяются либо на всю последующую после команды строку, ли­бо на набор команд ограниченных операторной скобкой then - else - end. В языке MUMPS используется первый вариант и отсутствует синтак­сическая конструкция then. Это весьма важная для понимания работы системы особенность. Если условный оператор выполнился, то команды расположенные далее в строке, также выполняются, а если не выполнил­ся, то интерпретатор не выполняет дальнейшие команды, а переходит к следующей строке либо продолжает выполнять цикл, если условная ко­манда находится в цикле.
В частности, в языке MUMPS нет смысла располагать команду else после команды if на той же строке, например так:
if a write 1 else write 2
Если значение переменной a в этом примере не равно 0, то выполня­ется команда write 1, после чего команда else проверяет значение $test взведенное командой if и не выполняет команду write 2. Это как-бы ожи­даемое поведение. Но если значение переменной a равно 0, то команда if не передает управление на последующие команды, расположенные в той
1.1. КОМАНДЫ 27
же строке, и управление в этом случае не будет передано на команду else.
Правильным вариантом вышеприведенного примера будет такой:
if a write 1 else write 2
Формально говоря, в предложения комитета по стандартизации MDC входит предложение реализовать команду then как явно стекующую си­стемную переменную $test, но в настоящее время ни одна MUMPS си­стема такую команду не поддерживает, и программы на MUMPS её не используют.
Системная переменная $test сохраняет свое значение до следующе­го изменения, и её, конечно, можно использовать для передачи инфор­мации, но так обычно не поступают. Традиционно, если в программах требуется проверка переменной $test, то она взводится непосредственно перед проверкой. Поэтому операции, косвенно взводящие значение $test, но игнорирующие полученное значение, не влияют на ход выполнения программ.
Это используется многими разработчиками для вызова системных или пользовательских функций с игнорированием возврата. Вызов функ­ции в этом случае выполняется командой if, но результат сравнения иг­норируется, и далее в строке не ставятся никакие команды. В языке MUMPS, если функция возвращает значение, то оно должно быть ис­пользовано как результат выражения, и если не используется, то MUMPS система генерирует либо синтаксическую ошибку для системных функ­ций, либо ошибку времени исполнения при выполнении команды возвра­та значения.
Нужно отметить, что аргументная форма команды if взводит значе­ние $test, безаргументная форма команды if не взводит, но проверяет, и команда else не взводит, но проверяет значение $test. Если необходимо взвести значение переменной $test, то можно написать просто
... if 1 ... ; $test=1 ...
или
... if 0
28 ГЛАВА 1. СРЕДА ИСПОЛНЕНИЯ
... ; $test=0 ...
Команда for устроена более сложно. Также как и команды if и else она распространяет свое действие на команды, размещенные после нее в этой же строке, но, в отличие от них, использует собственные пра­вила итерации в зависимости от формы команды. В одной строке могут быть несколько команд for, в этом случае расположенные левее будут содержать в своем цикле расположенные правее.
Важно отметить, что если команды if и else управляются систем­ной переменной $test, то команда for не реагирует на значение $test и управляется собственными правилами итерации и окончания цикла.
Команда for продолжает выполнение последующих за собой команд. Если команды расположенные на строке выполнились, то управление пе­редается не на следующую строку, а последней выполнявшейся команде for и команда проверяет собственное условие завершения, и при необхо­димости, итерации. При переходе на следующую строку контекст цикла отменяется, независимо от того, произошло ли прерывание цикла или переход выполнен по команде goto.
Например, при выполнении кода
write "start",! for i=1:1:5 write i," : ",i*i,! write "end",!
после вывода квадрата числа не будет производиться переход на сле­дующую строку. Вместо этого управление передается на команду for, и если ее итерации закончены, то только тогда управление перейдет на следующую строку.
У команды for в языке MUMPS есть несколько форм - безаргумент­ная, одноаргументная, двухаргументная и трехаргументная. При этом, если есть аргументы, то должна быть указана переменная цикла и ар­гументы указываются через запятую не для команды, а для переменной цикла.
Безаргументная форма команды for не имеет ни условия окончания цикла, ни итерации переменной цикла. Выполнение вечного цикла мо­жет быть прервано лишь командой quit, командой goto, либо генерацией ошибки. При этом команда for одновременно налагает требование на команду quit, если она присутствует в теле цикла: допускается только безаргументная форма quit и она трактуется как прерывание текущего исполняемого контекста цикла, а не как возврат из подпрограммы.
1.1. КОМАНДЫ 29
Если команда quit выполнилась в цикле, который вложен в другой, то прерывается только этот внутренний, не затрагивая выполнения внеш­него:
USER>f i=1:1:2 f j=3:1:5 q:j=4 w i,":",j,! 1:3 2:3
Традиционным идиоматическим оборотом для безаргументной формы for является итерация по перечислению, например, значений индексов. Вариант для общего примера:
USER>s a(123)="",a(456)="",a(789)=""
USER>s n="" f s n=$o(a(n)) q:n="" w n,! 123 456 789
Здесь используется не переменная итерации цикла, а просто обыч­ная локальная переменная, которая принимает значения индексов. Веч­ный цикл прекращается командой quit если следующий индекс пустая строка. Для понимания примера важно, что команда for использована в безаргументной форме из-за того, что мы самостоятельно проверяем условие окончания и команда quit использована в безаргументной форме, поскольку из цикла не допускается возврат значения. Безаргументные формы обеих команд обозначены двойными пробелами.
Одноаргументная форма for указывается одним значением для пере­менной цикла:
for var=expr
При этом команда for выполнит итерацию однократно, предваритель­но присвоив переменной var значение вычисленного выражения expr. Например:
USER>for i="a" w i a USER>
У одноаргументной формы for нет итераций и условия окончания, она выполняется строго однократно. В качестве значения итерации мо­жет быть указано любое выражение, никаких сравнений или арифмети­ческих действий с ним в одноаргументной форме команда for не будет выполнять.
30 ГЛАВА 1. СРЕДА ИСПОЛНЕНИЯ
Двухаргументная форма команды for задается начальным значени­ем переменной цикла и приращением. При каждой итерации перемен­ная цикла будет получать указанное приращение. Для двухаргументной формы нет условия окончания итераций и цикл будет выполняться пока не будет прерван командой quit, командой goto или генерацией ошибки. Пример:
USER>for i=1:2 w i q:i>7 13579 USER>
Для двухаргументной формы переменная итерации уже всегда ис­пользуется как число, даже если начальное значение было задано как строка:
USER>for i="a":2 w i q:i>7 02468 USER>
Переменная цикла может быть изменена на любой итерации, и ко­манда for всегда использует строго текущее ее значение, прибавляя зна­чение итерации именно к тому значению, которое досталось команде после очередной итерации:
USER>for i=1:2 w i,! s i=i+0.5 q:i>7 1
3.5 6
8.5
USER>
Трехаргументная форма команды for имеет дополнительно третье зна­чение, условие окончания цикла, задаваемое после значения итерации через двоеточие:
USER>for i=1:1:5 w i,! 1 2 3 4 5
USER>