                         СИСТЕМА ПРОГРАММИРОВАНИЯ MULTI C V10.89
                                               КОМПЛЕКТ ПОСТАВКИ


                          3. СИ-КОМПИЛЯТОР



                         3.1. Описание языка

     Входным  языком Си-компилятора является язык Си, принятый в
версии 7 ОС UNIX с некоторыми отличиями:

     1.  Ключевые слова языка (кроме Psect) и команды препроцес-
         сора можно задавать как  в  нижнем,  так  и  в  верхнем
         регистре.  Кроме  того, для некоторого облегчения жизни
         владельцам терминалов, не отображающих некоторые симво-
         лы ASCII, можно использовать следующие замены:
              \  вместо |
              \( вместо {
              \) вместо }
              \\ вместо ||
              \= вместо |=
              \^ вместо ~

     2.  Если  имя  файла-аргумента команды #include заключено в
         кавычки, препроцессор ищет его на устройстве DK:,  если
         же  оно  заключено  в  угловые  скобки,  файл ищется на
         устройстве с логическим именем C:;

     3.  Компилятор  не поддерживает тип данных double. Ключевое
         слово double воспринимается как синоним float;

     4.  Имена   функций  и  переменных,  описанных  на  внешнем
         уровне,   преобразуются   в   метки   ассемблера,    и,
         следовательно,  переводятся  в  верхний  регистр и усе-
         каются до 6 символов. Таким образом,  внешние  описания
         int cuckoo, cuckoo2;  или  float G, g; будут восприняты
         компилятором как корректные, но вызовут ошибки при  ас-
         семблировании и компоновке. Это ограничение не распрос-
         траняются на имена локальных переменных;

     5.  Компилятор  позволяет описывать функции типа interrupt,
         используемые для  обработки  прерываний.  Указатель  на
         такую   функцию   можно   записать  по  адресу  вектора
         соответствующего  прерывания.  Interrupt-функция  может
         быть  вызвана только по прерыванию, непосредственный ее
         вызов запрещен;

     6.  Компилятор  поддерживает  директиву  Psect NAME;, после
         появления которой в исходном тексте  имена  программных
         секций  в директивах .PSECT, генерируемых компилятором,

     -------------
     Поставщик   не   имеет  возможности  включить  в  настоящее
руководство полное описание языка. Его можно найти  в  следующих
изданиях:

     Уэйт  М.,  Прата  С.,  Мартин  Д.  Язык Си. Руководство для
начинающих.- М.: Мир, 1988.
     Керниган  Б.,  Ритчи Д., Фьюэр А. Язык программирования Си.
Задачи по языку Си.- М.: Финансы и статистика, 1985.
     Болски   М.И.   Язык   программирования   Си.  Справочник.-
М.: Радио и связь, 1988.

                                                           - 4 -
                         СИСТЕМА ПРОГРАММИРОВАНИЯ MULTI C V10.89
                                                   СИ-КОМПИЛЯТОР


     -mXXXX - выводит  карту загрузки в файл XXXX.MAP. Если XXXX
не специфицировано, карта выводится на TT:;
     -xXXXX - по  окончании  всех заданных действий, вызывает на
выполнение командный файл XXXX.COM.
     Ключи  могут быть заданы в любом регистре. Символ '-' может
быть заменен символом  '='.  Ключи  без  аргументов  могут  быть
объединены   в   общую   строчку  без  пробелов  с  единственным
предшествующим символом '-' (-cvfp),  ключ  с  аргументом  может
быть последним в такой строчке (-cvxMCBLD).
     Пример командной строки:
     Run C:CC -VM -dDBG=ON =lGR FOO MX3:FOO2.MAC MX3:FOO3.OBJ

     Драйверы  устройств,  на  которых находятся исходные (.C) и
включаемые (.H) файлы, должны быть загружены перед вызовом  ком-
пилятора.
     Для  проведения  операций ассемблирования и компоновки ком-
пилятор  вызывает   стандартный   макроассемблер   MACRO.SAV   с
устройства с логическим именем MAC:, и компоновщик LINK.SAV *) с
устройства  LNK:. Стандартные Си-библиотеки и стандартные хедеры
должны находиться на  устройстве  C:.  Пользователь  должен  сам
распределить  компоненты  системы  по  имеющимся  у него внешним
устройствам и включить соответствующие  назначения  в  стартовый
командный файл.


                     3.3. Сообщения компилятора

     Формат сообщения компилятора:

     [ФАЙЛ: ][СТРОКА: ]?ПРОХОД-ТЕКСТ СООБЩЕНИЯ

     ФАЙЛ  -  имя  файла,  при  обработке  которого  встретилась
ошибка;
     СТРОКА  -  номер  строки,  при обработке которой обнаружена
ошибка;
     ПРОХОД  -  имя  компонента  компилятора,  который обнаружил
ошибку.

        Компилятор состоит из 5 компонентов:
     CC - основная программа компилятора;
     CPP - препроцессор;
     C0 - синтаксический анализатор;
     C1 - генератор кода;
     C2 - оптимизатор.

     Большинство  сообщений компилятора сигнализирует об ошибках
в программе пользователя и не нуждается в дополнительных коммен-
тариях. Однако некоторые сообщения требуют пояснений:
     "Не  хватает  памяти" - компилятору не хватает динамической
памяти. При появлении этого сообщения попробуйте разрешить своп-
инг USR, выгрузить из памяти не нужные в данный момент драйверы,
и еще раз запустить компилятор с ключом -v. Если памяти  все  же
не  хватает, уменьшите количество директив препроцессора в Вашей
программе (если ошибка появляется во время работы препроцессора)
или   разбейте  самую  большую  функцию  в  Вашей  программе  на

     -------------
     *)  Не рекомендуется пользоваться компоновщиком LINK V5.04Е
(размером 29 блоков), т.к. он имеет  необъяснимую  склонность  к
неправильному вычислению стартового адреса программы.

                                                           - 6 -
                         СИСТЕМА ПРОГРАММИРОВАНИЯ MULTI C V10.89
                                                   СИ-КОМПИЛЯТОР


                  SP -> !   свободно    !
                        +---------------+
                        !послед.лок.пер.!
                        +---------------+
                         . . . . . . . .
                        +---------------+
                        ! перв.лок.пер. !
                        +---------------+
                        !   сохр. R2    !
                        +---------------+
                        !   сохр. R3    !
                        +---------------+
                        !   сохр. R4    !
                        +---------------+
                  R5 -> !   сохр. R5    !
                        +---------------+
                        ! адрес возврата!
                        +---------------+
                        ! перв.аргумент !
                        +---------------+
                         . . . . . . . .








































                                                           - 8 -
                         СИСТЕМА ПРОГРАММИРОВАНИЯ MULTI C V10.89
                                                   СИ-БИБЛИОТЕКА


     Пример командной строки:
        abc >lp: 'D E F G'

     Значения аргументов main:
        argc=3;
        argv[0]="Argv:";
        argc[1]="abc";
        argc[2]="D E F G";
     В качестве stdout будет открыто устройство LP:.

     Внешнее  определение sys_noargs=1; в тексте программы поль-
зователя подавляет запрос и ввод командной строки.
     Внешнее определение вида sys_prompt="text"; заменяет промпт
с Argv: на text.


     4.1.2. Функции инициализации и завершения  -

     #include <initia.h>

     Для  выполнения  операций  до вызова функции main или после
вызова  exit  могут  использоваться  функции  инициализации  или
завершения  соответственно. Их может быть несколько, но в каждом
исходном файле может быть описано не более  одной  функции  ини-
циализации  и  одной  функции  завершения. Синтаксис их описания
следующий:


        Initial                         Final
        {                               {
          ... тело                        ... тело
              функции                         функции
           инициализации ...                  завершения ...
        }                               }


     Порядок выполнения функций инициализации и завершения, если
их описано несколько, определяется порядком следования объектных
файлов в командной строке компоновщика.
     В  качестве  функции  завершения  может  быть  использована
функция с именем wrapup, которая будет вызвана сразу после exit,
перед остальными функциями завершения.


                     4.2. Математические функции

     #include <math.h>

     Все  математические функции принимают и возвращают величины
типа float. Угловые  величины  выражаются  в  радианах.  Функции
возвращают:

     atan(x) - арктангенс x;
     atan2(x,y) - азимут точки с координатами x, y;
     cos(x) - косинус x;
     exp(x) - e в степени x;
     fabs(x) - абсолютное значение x;
     log(x) - натуральный логарифм x;



                                                          - 10 -
                         СИСТЕМА ПРОГРАММИРОВАНИЯ MULTI C V10.89
                                                   СИ-БИБЛИОТЕКА


                      4.4. Функции ввода-вывода

     #include <stdio.h>

     FILE  *fopen(filename,  mode); char *filename, *mode; - от-
крывает файл с именем  filename  в  режиме,  задаваемом  строкой
mode :  mode="r"  открывает  файл  на  чтение,  "w" - на запись.
Вместе с "r" или "w" может быть задан модификатор "n" - файл от-
крывается   как   двоичный   (не   текстовый),   то  есть  можно
вводить/выводить  нулевые  байты,  и  <ПС>  не  растягивается  в
<ВК><ПС>  (и наоборот). Функция возвращает указатель на открытый
файл, или 0 в случае невозможности его открытия. Внешний  массив
defext[2] служит для задания расширений по умолчанию для входных
и выходных файлов в  коде  RADIX50  (defext[0]  -  для  входных,
defext[1] - для выходных).

        Пример :
        FILE *fp; extern defext[];
        ascr50(3,"dat",&defext[0]);
        if((fp=fopen("cuckoo","rn")) == NULL)
                                        error("Can't open");

     В  приведенном примере открывается для чтения двоичный файл
cuckoo.dat.
     FILE  *freopen(filename,  mode,  stream);  char  *filename,
*mode; FILE *stream; -  переназначает  ввод-вывод  с  некоторого
ранее  открытого  файла,  на который указывает stream, на файл с
именем filename в режиме mode. Файл, на который  ранее  указывал
stream,  закрывается. Возвращает stream, если все в порядке, или
0, если файл не может быть открыт.
     fclose(stream)  FILE  *stream;  - закрывает указанный файл,
возвращая 0, если все в порядке, и -1 при ошибке.
     fflush(stream)  FILE  *stream;  - выводит в файл содержимое
буфера ввода-вывода.
     delete(filename) char *filename; - удаляет файл filename из
каталога устройства.

     feof(stream) FILE *stream; - возвращает ненулевое значение,
если при чтении файла stream обнаружен конец файла.
     ferror(stream)   FILE   *stream;   -  возвращает  ненулевое
значение, если на файле stream произошла ошибка ввода-вывода.
     clearerr(stream)  FILE *stream; - сбрасывает признак ошибки
на файле stream.
     fileno(stream) FILE *stream; - возвращает номер канала вво-
да-вывода ОС RT-11, связанного с указанным файлом.
     isatty(chan)  int  chan;  -  возвращает ненулевое значение,
если файл, открытый по каналу с номером chan представляет  собой
терминал.
     char  *fgetname(stream,buff)  FILE  *stream;  char *buff; -
помещает имя файла, открытого как stream, в  buff  и  возвращает
указатель на него.

     getc(stream)  FILE  *stream; - возвращает символ, введенный
из файла stream или EOF, если обнаружен  конец  файла.  Синоним:
fgetc.
     getchar() эквивалентно getc(stdin).
     getw(stream) FILE *stream; - возвращает 16-разрядное слово,
введенное из файла stream.



                                                          - 12 -
                         СИСТЕМА ПРОГРАММИРОВАНИЯ MULTI C V10.89
                                                   СИ-БИБЛИОТЕКА


     4.4.1. Функции терминального ввода-вывода  -

     Функции  терминального  ввода-вывода  осуществляют  обмен с
терминалом  без  буферизации  и  взаимодействия  с   библиотекой
файлового   ввода-вывода.  Они  могут  использоваться  в  режиме
sys_small (см. далее) для  получения  компактных  и  эффективных
программ.

     ttyin()   -   вводит   символ   с   клавиатуры  посредством
макрокоманды .TTYIN; возвращает код введенного символа.
     kbhit()  -  возвращает ненулевое значение, если была нажата
любая  клавиша.  Код  введенного  символа  может  быть   получен
обращением к функции ttgetc.
     ttyout(c)  char c; - выводит символ на терминал посредством
макрокоманды .TTYOUT.
     ttgetc() - вводит символ с клавиатуры или из буфера ¤¤ttbf,
если он не пуст.  Последовательность  <ВК><ПС>  сворачивается  в
<ПС> ('\n') для совместимости с getc.
     ttungetc(c) - помещает символ c в буфер ¤¤ttbf. Последующее
обращение к ttgetc введет этот символ.
     ttputc(c)  -  выводит  символ  c  на  терминал. Символ '\n'
(<ПС>) растягивается в <ВК><ПС> для совместимости с putc.
     ttprintf(fmt,[arg  ..])  char  *fmt; - производит форматное
преобразование своих аргументов и вывод результатов на  терминал
(см. описание функции prf).
     ttscanf(fmt,[ptr  ..]) char *fmt; - вводит данные с клавиа-
туры и преобразует во  внутреннее  представление  (см.  описание
функции scf).

     ttspc()   -   включает   спецрежим   терминала   (отключает
эхо-печать и буферизацию).
     ttnospc() - выключает спецрежим терминала.
     Функции  ttspc  и ttnospc могут использоваться и в файловом
режиме обмена с терминалом совместно с getchar, putchar и т.п..


               4.5. Функции форматного преобразования


     ascr50(count,input,output) int *output; char *input; - пре-
образует count символов буфера input из кода ASCII в код RADIX50
и помещает результат в output.
     r50toa(output,input,count) char *output; int *input; - пре-
образует count слов кода RADIX50 из буфера input в код  ASCII  и
помещает результат в output.

     float  atof(s)  char  *s;  -  преобразует строку символов в
число с плавающей точкой. Синоним: atod.
     atoi(s)  char  *s;  -  преобразует  строку символов в целое
число.
     long atol(s) char *s; - преобразует строку символов в число
типа long.

     itoa(val,s)  char  *s;  -  преобразует  val  в  строку  s в
десятичном формате.
     itoa8(val,s)  char *s; - преобразует val в строку s в вось-
меричном формате.
     itoax(val,s)  char *s; - преобразует val в строку s в шест-
надцатиричном формате.


                                                          - 14 -
                         СИСТЕМА ПРОГРАММИРОВАНИЯ MULTI C V10.89
                                                   СИ-БИБЛИОТЕКА


     %f(%F) - число типа float в любом формате.
     %e(%E) - число типа float в любом формате.
     %c(%C) - отдельный символ.
     %s(%S) - строка символов.
     %[abc]   -  строка,  состоящая  из  символов,  указанных  в
квадратных  скобках.  Считывание  прекращается   по   достижении
первого символа, не входящего в множество разрешенных.
     %[^abc]  -  строка, состоящая из любых символов, кроме ука-
занных в квадратных скобках.  Считывание  прекращается  по  дос-
тижении первого символа, входящего в множество запрещенных.
     Между символом '%' и типом спецификации могут быть:
     - символ  '*', который подавляет присвоение, т.е. очередной
входной элемент  считывается,  но  не  присваивается  очередному
аргументу;
     - число,  задающее  максимальную  ширину  поля  ввода, т.е.
вводится не превышающее этой ширины количество символов входного
элемента.

     sscanf(buf,fmt[,addr  ..]) char *buf, *fmt; - считывает ар-
гументы для преобразования из строки buf.


               4.6. Функции обработки символов и строк

     char  *strcat(s1,  s2) char *s1, *s2; - "подцепляет" строку
s2 к концу строки s1, возвращает s1.
     char  *strncat(s1,  s2,  n)  char  *s1, *s2; - "подцепляет"
строку s2 к концу строки s1, причем из строки s2  копируется  не
более n символов.
     strcmp(s1,  s2)  char  *s1, *s2; - сравнивает строки в лек-
сикографическом порядке.
     strncmp(s1,  s2,  n)  char  *s1, *s2; - сравнивает n первых
символов строк.
     char  *strcpy(s1, s2) char *s1, *s2; - копирует строку s2 в
строку s1, возвращает s1.
     char *strncpy(s1, s2, n) char *s1, *s2; - копирует не более
n первых символов строки s2 в строку s1.
     strlen(s) char *s; - возвращает длину строки (без '\0').
     streq(s1,   s2)  char  *s1,  *s2;  -  возвращает  ненулевое
значение, если строки одинаковы.
     strneq(s1,  s2,  n)  char  *s1, *s2; - возвращает ненулевое
значение, если n первых символов строк одинаковы.
     char  *strupr(s)  char  *s;  - переводит символы строки s в
верхний регистр.
     char  *strnupr(s,n)  char *s; - переводит n первых символов
строки s в верхний регистр.
     char  *strlwr(s)  char  *s;  - переводит символы строки s в
нижний регистр.
     char  *strnlwr(s,n)  char *s; - переводит n первых символов
строки s в нижний регистр.
     char  *strchr(s,  c)  char *s, c; - возвращает указатель на
первое вхождение символа c в строку s  или  0,  если  символ  не
входит в строку.
     char  *strrchr(s,  c) char *s, c; - возвращает указатель на
последнее вхождение символа c в строку s или 0, если  символ  не
входит в строку.

     tolower(c)  char  c;  - возвращает c, переведенное в нижний
регистр, если c - буква верхнего регистра.


                                                          - 16 -
                         СИСТЕМА ПРОГРАММИРОВАНИЯ MULTI C V10.89
                                                   СИ-БИБЛИОТЕКА


адреса. Если subr возвращает значение, функция call должна  быть
описана соответствующим образом. subr не должна осуществлять ни-
каких операций ввода-вывода.

     sleep(delay) - спит delay секунд (если монитор поддерживает
макрокоманду .TWAIT).

     char  *memmov(out,  in,  count)  char *in, *out; - копирует
count байт из массива in в массив out; возвращает out.  Синоним:
memcpy.
     char  *memset(out,  ch,  count)  char  *in, ch; - заполняет
count байт массива out байтом ch; возвращает out.
     char *memclr(addr, count) char *addr; - обнуляет count байт
памяти, начиная с addr; возвращает addr.

     setjmp(buffer)  int buffer[6]; - сохраняет текущий контекст
функции в buffer для последующего возврата  с  помощью  longjmp,
возвращает 0.
     longjmp(buffer,retval) int buffer[6]; - возвращается к кон-
тексту,  сохраненному  в  buffer  вызовом  setjmp.   Имитируется
возврат из setjmp с возвращаемым значением retval.

     perror(text)  char *text; - выводит на терминал стандартное
сообщение о происшедшей  ошибке  в  формате  "text:  стандартное
сообщение".  Переменная  sys_nerr  содержит  общее  число  кодов
ошибок, распознаваемых системой. Массив sys_errlist[] состоит из
указателей   на   стандартные   сообщения   об   ошибках,   т.е.
sys_errlist[errno]   указывает   на   сообщение   о    последней
происшедшей ошибке.


     4.7.1. Управление динамической памятью  -

     char  *sbrеаk(incr)  - сдвигает верхнюю границу памяти про-
граммы на incr байт и возвращает указатель на выделенную область
памяти. Синоним: sbrk.
     char *calloc(n, m) - выделяет и обнуляет область памяти под
n элементов длиной m байт каждый и возвращает указатель на нее.
     char  *malloc(size) - выделяет область памяти размером size
байт и возвращает указатель на нее.
     realloc(addr,  size)  char  *addr;  -  меняет  размер ранее
выделенного  блока  памяти  и  возвращает  указатель  на   новый
(возможно  перемещенный) блок. Содержимое остается неизменным (в
пределах меньшего из старого и нового размеров).
     Все функции возвращают 0, если память не может быть выделе-
на.
     free(addr)   char   *addr;   -  освобождает  память,  ранее
выделенную malloc или calloc.













                                                          - 18 -
                         СИСТЕМА ПРОГРАММИРОВАНИЯ MULTI C V10.89
                                                   СИ-БИБЛИОТЕКА


           4.9. Рекомендации по размещению программ в ПЗУ

     При  размещении  программы  в  ПЗУ  секции .PROG., .DATA. и
****.D должны попасть в область ПЗУ, а  секция  .BSS. -  в  ОЗУ.
Нормальным распределением адресов является следующее:
     секция . ABS. (ОЗУ) - вектора прерываний и стек;
     секция .BSS.  (ОЗУ) - переменные;
     секция .PROG. (ПЗУ) - код;
     секция .DATA. (ПЗУ) - константы;
     секции ****.D (ПЗУ) - служебная информация.
     При  написании  программ следует помнить, что явно инициал-
изированные глобальные и статические переменные (секция  .DATA.)
попадают  в  ПЗУ, и следовательно, во время выполнения программы
могут использоваться только для чтения (т.е. как константы).

     Для   обеспечения   правильного  порядка  следования  PSECT
рекомендуется создать ассемблерный файл следующего вида:

        .PSECT  .BSS.
        .PSECT  .PROG.
        JMP     ¤¤MAIN  ; Если управление при запуске системы
                        ; передается на начальный адрес ПЗУ
        .END

     ассемблировать  его  и  включать  в  командную  строку ком-
поновщика перед всеми  остальными  файлами.  Начальное  значение
стека   (начало   секции  .BSS.)  задается  ключом  компоновщика
/B:NNNNNN, а начало ПЗУ (секции .PROG.) - ключом /U:NNNNNN  (или
другими средствами).
     Программы,  предназначенные для работы в ПЗУ, должны содер-
жать строку "extern sys_small;" и не должны вызывать стандартных
функций ввода-вывода, отладки, распределения динамической памяти
и других, требующих поддержки ОС.




























                                                          - 20 -

