BS(1) BS(1) НАЗВАНИЕ bs - компилятор/интерпретатор программ умеренных разме- ров СИНТАКСИС |bs [файл [аргумент ...]] ОПИСАНИЕ Язык bs - отдаленный потомок Бейсика и Снобола-4 с не- которыми дополнениями из языка C. Язык bs создан для тех задач программирования, в которых время разработки так же важно, как и полученная в результате скорость выполнения. Формальности объявления данных и манипуля- ции с файлами и процессами минимизированы. Построчная отладка, операторы trace и dump, а также подробные со- общения об ошибках выполнения упрощают тестирование программ. Более того, можно отлаживать незавершенные программы; внутренние функции могут тестироваться до того, как написаны внешние функции, и наоборот. Если в командной строке указан аргумент файл, ввод на- чинается из него и продолжается с терминала. По умолча- нию, операторы, прочитанные из файла, компилируются для последующего выполнения. Операторы, введенные с терми- нала, обычно выполняются немедленно (см. ниже операторы compile и execute). Если последняя операция - не прис ваивание, результат оператора-выражения печатается. Программы на языке bs состоят из строк. Символом про- должения является \ в конце строки. Язык допускает строки следующего вида: |оператор |метка оператор Метка - это имя (см. ниже), за которым следует двоето- чие. Метки и переменные могут иметь одни и те же имена. Оператор языка bs - это выражение или ключевое слово, за которым следует 0 или более выражений. Некоторы ключевые слова (clear, compile, !, execute, include, ibase, obase и run) всегда выполняются, как только они откомпилированы. Синтаксис операторов выражение Целью выполнения выражения являются его побочные эффекты (значение, присваивание или вызов функ ции). Детали приводятся ниже, после описания типов операторов. break Выйти из самого внутреннего for/while цикла. clear Выполняется немедленно. Очистить таблицу имен и удалить скомпилированные операторы. compile [выражение] Выполняется немедленно. Откомпилировать последую щие операторы (не принимая во внимание установлен- ный режим немедленного выполнения). Необязательное выражение вычисляется и используется в качестве имени файла для последующего ввода. В последнем случае выполняется clear. continue Перейти к следующей итерации текущего for/while цикла. dump [имя] Напечатать имена и текущие значения всех нелокаль ных переменных. Если указана опция имя, сообщается только о данной переменной. После ошибки или пре- рывания выводится номер последнего оператора и (возможно) трассировка пользовательских функций. exit [выражение] Вернуться на системный уровень. Выражение возвра- щается в качестве кода завершения. execute Изменить режим выполнения на немедленный (прерыва- ние дает аналогичный эффект). Эта команда не вызы вает выполнения запомненных операторов (см. ниже команду run). |for имя = выражение выражение оператор |for имя = выражение выражение | ... |next |for выражение, выражение, выражение оператор |for выражение, выражение, выражение | ... |next Циклически выполнять оператор (первая форма) или группу операторов (вторая форма) под управлением переменной с указанным именем. Переменная принима- ет значение первого выражения, затем она увеличи- вается на единицу в каждом цикле, пока не превзой- дет значения второго выражения. Третьей и четвер- той формам требуются три выражения, разделенные запятыми. Первое из них - инициализация, второе - условие (если истинно, то продолжать), и третье - действие при переходе к следующей итерации (обычно приращение). |fun f([a, ...]) [v, ...] | ... |nuf Определить имя, аргументы и локальные переменные написанной пользователем функции. Допускается до 10 аргументов и локальных переменных. Эти имена не могут быть массивами, а также не могут быть связа- ны по вводу и выводу. Определения функций не могут быть вложенными. freturn Сигнализировать о неудачном завершении пользова- тельской функции. См. ниже операцию опроса (?). Если опрос отсутствует, freturn возвращает 0. Ког- да опрос активен, freturn возвращается к соот ветствующему выражению (возможно, выполняя возвра ты из вложенных функций). goto имя Передать управление на хранящийся в памяти опера тор с соответствующей меткой. ibase N Установить основание системы счисления при вводе чисел равным N. Поддерживаются только следующие значения N: 8, 10 (по умолчанию) и 16. Шестнадца- теричные значения 10-15 вводятся как a-f. Первой должна стоять цифра (то есть f0a следует вводить как 0f0a). Ibase (и, ниже, obase) выполняются не- медленно. |if выражение оператор |if выражение | ... | [else | ...] |fi Выполнить оператор (первая форма) или группу опе раторов (вторая форма), если результат вычисления выражения ненулевой. Цепочки символов 0 и "" (пус тая) считаются нулевыми. Во второй форме допуска- ется дополнительная группа операторов, которая должна выполняться, когда не выполняется первая группа. Единственный оператор, допустимый в той же строке, что и else, - это if; только другие fi мо- гут быть в той же строке, что и fi. Поддерживается сокращение else и if в elif. Чтобы закрыть после- довательность if ... elif ... [ else ... ], требу- ется только одно fi. include выражение Выражение должно определять имя файла. Файл должен содержать bs-операторы. Такие операторы становятся частью компилируемой программы. Операторы include не могут быть вложенными. obase N Установить основание системы счисления при выводе чисел равным N (см. выше ibase). |onintr метка |onintr Программная обработка прерываний. В первой форме после прерывания управление передается на указан ную метку, в точности так, как если бы в момент прерывания был выполнен оператор goto. После нача- ла обработки прерывания установленная реакция от- меняется. Во второй форме прерывание вызывает за- вершение выполнения. return [выражение] Вычислить выражение и возвратить его значение в качестве результата вызова функции. Если выражение не указано, возвращается 0. run Перезапустить генератор случайных чисел. Передать управление на первый скомпилированный оператор. Если оператор run содержится в файле, он должен быть последним оператором. stop Прекратить выполнение скомпилированных операторов. Bs возвращается в режим немедленного выполнения. trace [выражение] Управление трассировкой функций. Если выражение не указано (или имеет нулевое значение), трассировка выключается; в противном случае печатается прото- кол вызовов пользовательских функций и возвратов из них. Каждый возврат уменьшает на единицу значе- ние выражения, указанного в операторе trace. |while выражение оператор |while выражение | ... |next Оператор while аналогичен for за исключением того, что указывается условие продолжения цикла. ! команда shell'а Выполнить команду shell'а. # ... Этот оператор игнорируется. Он используется для включения в программу комментариев. Синтаксис выражений имя Имя используется для того, чтобы указать перемен- ную. Имена состоят из буквы (прописной или строч- ной), за которой могут следовать буквы и цифры. Только первые шесть символов в имени являются зна- чащими. За исключением имен, объявленных в опера торах fun, все имена являются глобальными. Значе- ниями имен могут быть числа (вещественные двойной точности) и цепочки символов; кроме того, имена могут быть связаны по вводу/выводу (см. ниже встроенную функцию open). имя ([выражение [, выражение] ...]) К функциям можно обращаться по имени, за которым следуют аргументы в скобках, разделенные запятыми. За исключением встроенных функций (описанных ни- же), имя должно быть определено при помощи опера- тора fun. Аргументы функций передаются по значе- нию. имя [выражение [, выражение] ...] Такой синтаксис используется для обращения к мас- сивам или таблицам (см. ниже описание встроенных функций для работы с таблицами). Для массивов каж- дое выражение урезается до целого и используется как спецификатор для имени. Результирующее обраще ние синтаксически эквивалентно имени (то есть мо жет употребляться в тех же местах, что и имя); за- писи a[1,2] и a[1][2] обозначают одно и то же. Значения урезанных выражений должны быть в преде лах от 0 до 32767. число Число используется для представления константного значения. Число записывается в стиле Фортрана и содержит цифры, десятичную точку (не обязательно) и, возможно, масштабный множитель, состоящий из символа e, за которым может следовать характерис- тика со знаком. цепочка_символов Цепочки_символов ограничиваются знаками ". Знак \ позволяет вставлять в цепочку следующие символы: кавычка (\"), перевод строки (\n), возврат каретки (\r), пробел (\b) и табуляция (\t). В остальных случаях символ \ обозначает сам себя. (выражение) Скобки используются для того, чтобы изменить поря- док вычислений. (выражение, выражение [, выражение ...]) [выражение] Последнее выражение используется как индекс, чтобы выбрать один элемент из взятого в круглые скобки списка выражений, разделенных запятыми. Элементы списка нумеруются слева, начиная с нуля. Выраже- ние: |(False, True)[a == b] имеет значение True, если a равно b. ? выражение Операция опроса проверяет "успех" вычисления выра- жения, а не его значение. Ее целесообразно исполь- зовать для проверки выхода на конец файла (см. ни- же ПРИМЕРЫ), результата вычисления встроенной функции и для проверки возврата из определенных пользователем функций (см. freturn). "Реакция на прерывание", устанавливаемая данной операцией (например, конец файла), приводит к немедленному переходу к самому последнему опросу с возможным пропуском операторов присваивания или переходом через уровни вложенности функций. - выражение Результатом является значение выражения с обратным знаком. ++ имя Увеличивает на единицу значение переменной (или элемента массива). Результатом является новое зна- чение. -- имя Уменьшает на единицу значение переменной. Резуль- татом является новое значение. ! выражение Логическое отрицание значения выражения. Будьте осторожны, такое выражение может быть воспринято как запрос на выполнение команды shell'а. выражение операция выражение Обращения к общеупотребимым функциям двух аргумен- тов обозначаются двумя аргументами, которые разде- ляются операцией, указывающей функцию. За исключе- нием присваивания, конкатенации и операций сравне- ния, перед тем, как выполняется операция, оба опе- ранда преобразуются к целому типу. Бинарные операции (упорядочены по возрастанию приорите- та): = Операция присваивания. Левый операнд должен быть именем или элементом массива. Результатом является правый операнд. Последовательные присваивания вы- полняются справа налево; все другие операции - слева направо. _ (подчеркивание). Операция конкатенации. & | Результатом & (логическое и) является 0, если ка- кой-нибудь из ее аргументов - 0; результат равен 1, если оба аргумента ненулевые; результатом | (логическое или) является 0, если оба аргумента равны нулю; результат равен 1, если какой-нибудь из аргументов ненулевой. Обе операции трактуют пустую цепочку символов как 0. |< <= > >= == != Операции сравнения (меньше, меньше или равно, больше, больше или равно, равно, не равно) возвра щают 1, если их аргументы находятся в указанном отношении. В противном случае они возвращают 0. Допустимы выражения, подобные a>b>c (что эквива лентно a>b & b>c). Если оба аргумента являются це- почками символов, проверяется лексикографическая упорядоченность. + - Сложение и вычитание. |* / % Умножение, деление и остаток. ^ Возведение в степень. Встроенные функции Работа с аргументами arg(i) Значение i-го фактического аргумента текущего уровня вызова функции. На нулевом уровне arg возвращает i-ый аргумент командной строки (arg (0) возвращает bs). narg( ) Возвращает число переданных аргументов. На нулевом уровне возвращается число аргументов командной строки. Математические функции abs(x) Абсолютная величина x. atan(x) Арктангенс x. Значение между - /2 и /2. ceil(x) Минимальное целое, не меньшее x. cos(x) Косинус x (Углы задаются в радианах). exp(x Экспонента x. floor(x) Наибольшее целое число, не превосходящее x. log(x) Натуральный логарифм x. rand( ) Равномерно распределенное между 0 и 1 случайное число. sin(x) Синус x. sqrt(x) Квадратный корень из x. Операции с цепочками символов size(s) Размер (длина в байтах) цепочки s. format(f, a) Возвращает отформатированное значение a. Предпола- гается, что f - это спецификация формата в смысле printf(3S). Рекомендуется использовать только сле- дующие типы спецификаторов формата: %...f, %...e и %...s. index(x, y) Номер первого символа в x, совпадающего с каким- либо символом из y. Если такого нет, возвращается 0. trans(s, f, t) Сопоставляет символы источника s с символами f, и заменяет их на символы, стоящие в той же позиции цепочки t. Символы источника, которые не встреча- ются в f, копируются в результат. Если f длиннее, чем t, символы источника, которые сопоставляются с избыточной частью f, не помещаются в результат. substr(s, начало, ширина) Подцепочка s с заданными началом и шириной. |match(цепочка_символов, шаблон) |mstring(n) Шаблон имеет синтаксис, аналогичный регулярным вы ражениям команды ed(1). Символы ., [, ] (внутрен- ние скобки), ^, * и $ являются специальными. Функ ция mstring возвращает n-ую (1 n 10) подцепочку обрабатываемой цепочки_символов, которая успешно сопоставлена с фрагментом шаблона, заключенного между парами символов \( и \), из последнего обра- щения к match. Шаблоны сопоставляются с началом цепочки_символов (как если бы все они начинались символом ^). Функция match возвращает число успеш- но сопоставленных символов. Пример: |match("a123ab123", ".*\([a-z]\)") == 6 |mstring(1) == "b" Работа с файлами |open(имя, файл, тип) |close(имя) Аргумент имя должен быть именем переменной в смыс- ле bs (переданным как цепочка символов). При обра- щении к функции open в качестве аргумента файл можно задавать: 1. 0, 1, или 2, что означает стандартный ввод, стандартный вывод и стандартный протокол соот- ветственно. 2. Цепочку символов, представляющую имя файла. 3. Цепочку символов с ! в начале, представляющую команду, которая должна быть выполнена (пос- редством sh -c). Аргумент тип должен быть одним из следующих: r (читать), w (писать), W (писать без перевода стро ки), a (добавлять). После того как выполнена функ- ция close, имя становится обычной переменной. На- чальные связывания таковы: |open("get", 0, "r") |open("put", 1, "w") |open("puterr", 2, "w") Примеры приведены ниже. access(s, m) Выполняет вызов access(2). ftype(s) Возвращает односимвольный индикатор типа файла: f для обычного файла, p для именованного канала, d для каталога, b для блочного устройства, c для символьного устройства. Таблицы table(имя, размер) Таблица в bs - это одномерный массив с ассоциатив- ным доступом. "Индексами" (их называют также клю- чами) являются цепочки символов (числа преобразу ются в цепочки). Аргумент имя должен быть именем переменной в смысле bs (переданным как цепочка символов). Аргумент размер устанавливает минималь- ное число элементов, которое должно быть размеще- но. Bs печатает сообщение об ошибке и завершает работу, когда таблица переполняется. |item(имя, номер) |key( ) Функция item осуществляет доступ к элементам таб- лицы по их номерам (обычно множество значений клю- чей не допускает систематического перебора). После того, как функция item возвратит значение элемента таблицы, результатом функции key будет "индекс" (ключ) этого элемента. Аргумент имя нельзя брать в кавычки. Так как точные размеры таблицы не опреде- лены, надо использовать операцию опроса, чтобы об- наружить конец таблицы, например: |table("t", 100) | ... |# Если значением переменной word является слово, |# следующее выражение добавляет единицу |# к счетчику этого слова: |++t[word] | ... |# Напечатать пары ключ/значение: |for i = 0, ?(s = item(t, i)), ++i if key() \ | put = key()_":"_s iskey(имя, слово) Проверяет, есть ли ключ слово в таблице имя; возв ращает 1, если есть, и 0, если нет. Прочие функции eval(цепочка_символов) Вычисляет свой аргумент как выражение в смысле bs. Эта функция удобна для преобразования числовых строк во внутреннюю числовую форму. Eval также мо жет использоваться как грубый метод косвенной ад- ресации. Например, после выполнения операторов |name = "xyz" |eval("++"_name) значение переменной xyz увеличится на 1. Кроме то- го, функция eval с предшествующей операцией опроса позволяет управлять обработкой ошибочных ситуаций. Результатом выполнения оператора |?eval("open(\"X\", \"XXX\", \"r\")") будет 0, если файла с именем "XXX" нет (вместо аварийного завершения программы пользователя). Следующий фрагмент выполняет переход на метку L (если она существует): |label="L" |if !(?eval("goto "_label)) puterr = "no label" plot(запрос, аргументы) Формирует вывод для устройств, которые поддержива- ются программой tplot(1G). Допустимы следующие запросы: plot(0, терминал) Определяет, что дальнейший вывод программы plot должен направляться программе tplot(1G) с аргу- ментом -Tтерминал. plot(4) "Очищает" плоттер. plot(2, метка) Ставит метку на текущую точку. plot(3, x1, y1, x2, y2) Рисует отрезок между (x1,y1) и (x2,y2). plot(4, x, y, r) Рисует круг с центром (x,y) и радиусом r. plot(5, x1, y1, x2, y2, x3, y3) Рисует дугу с центром (x1,y1) и концами (x2,y2) и (x3,y3). plot(6) Не реализован. plot(7, x, y) Делает точку (x,y) текущей. plot(8, x, y) Рисует отрезок из текущей точки в (x,y). plot(9, x, y) Рисует точку в (x,y). plot(10, режим) Устанавливает заданный режим проведения линий. plot(11, x1, y1, x2, y2) Устанавливает левый нижний угол области рисова- ния в (x1,y1), а правый верхний - в (x2,y2). plot(12, x1, y1, x2, y2) Определяет, что соответствующие x (y) координа- ты должны умножаться на x1 (y1) и затем склады- ваться с x2 (y2) перед тем, как они изобража- ются. Первоначальный масштаб - plot(12, 1.0, 1.0, 0.0, 0.0). Некоторые запросы применимы не ко всем плоттерам. Все запросы, кроме 0 и 12, реализованы на основе передачи символов программе tplot(1G). Чтобы полу- чить дополнительную информацию, см. plot(4). last( ) В режиме немедленного выполнения возвращает пос- леднее вычисленное значение. ПРИМЕРЫ 1. Использование bs в качестве калькулятора: |$ bs |# Расстояние (в дюймах), которое свет |# проходит за наносекунду. |186000 * 5280 * 12 / 1e9 |11.78496 |# Сложный процент (из 6% за 5 лет |# с 1000 долларов). |int = .06 / 4 |bal = 1000 |for i = 1 5*4 bal = bal + bal*int |bal - 1000 |346.855007 |exit 2. Общий вид типичных bs-программ: |# Инициализация: |var1 = 1 |open("read", "infile", "r") |... |# Вычисление: |while ?(str = read) | ... |next |# Завершение |close("read") |... |# Последний выполняемый оператор (exit или stop): |exit |# Последняя входная строка |run 3. Примеры ввода/вывода: |# Копировать "oldfile" в "newfile". |open("read", "oldfile", "r") |open("write", "newfile", "w") |... |while ?(write = read) ... |... |# закрыть "read" и "write": |close("read") |close("write") |# Канал между командами. |open("ls", "!ls *", "r") |open("pr", "!pr -2 -h 'List'", "w") |while ?(pr = ls) ... |... |# Закрыть файлы: |close("ls") |close("pr") СМ. ТАКЖЕ ed(1), sh(1), tplot(1G). access(2), printf(3S), stdio(3S), plot(4) в Справочнике программиста. Более полное описание математических функций см. в раз- деле 3M Справочника программиста (для возведения в сте- пень используется функция pow, описанная в exp(3M); па- кет ввода/вывода используется стандартный. СЮРПРИЗЫ "Индексами" неинициализированных элементов таблицы яв- ляются цепочки из двух символов с восьмеричными кодами 43 и 300, поэтому приведенный пример печати пар ключ/з- начение будет работать неверно. В цепочке символов нельзя употребить знак #, поскольку он служит началом комментария.