Наверх

Пред. След.

 

 

Вызов функций.

 

Перехожу к очень важному моменту – как  запрограммировать вызов функции (не встроенных в язык, а тех, которые программируются на самом создаваемом языке). Пришлось внести в программу довольно большие изменения. В частности, пришлось создать списки для таблицы функций. В отдельных списках хранятся:

1.Названия

2.Адрес функции (в нашем случае это смещение по тексту программы).

3.Количество параметров

4.Строка с именами параметров (где они перечислены через пробел).

Кроме того пришлось создать стек для значений параметров вызываемых функций, возвращаемых значений и адресов возврата.

Был также введен оператор START. При начале прохода программы переменные, которые включают реальное выполнение действий (ToDo,ToDOif,ToDoW) нулевые (а не единичные, как раньше), и лишь когда встретится START , они становятся равными единице (включается реальное выполнение). А до этого лишь анализируются встречающиеся функции, имена их и адреса заносятся в таблицу и так далее. В соответствии с этим тела функций должны быть расположены в начале программы, потом должен идти оператор START, далее – основная программа.

Оператор RETURN закладывает в стек вычисленное функцией значение.

Форму БНФ я не привожу (при программировании вызовов функций я ей уже не пользовался).

Вот измененная функция fact, которая стала весьма громоздкой. Именно здесь происходит вызов функции, а перед этим занесение в стек параметров и адреса возврата.

 

            void fact()  /* Это множитель - конечный пункт рекурсии */

            {

                        int iF;

                        int N1;

                        int er;

                        char ResNum[101];

                        char ResF1[50];

                        char Lex_1[50];

                        *ResF1=0;

                        *Lex_1=0;

                        char St1[102];

                        int res;

                        int iAdr0;

                        int iAdr;

 

            if(*Lex==40)

            {

                        NextLexema();

                        expr2();

                        if(*Lex!=41)

                        {

                        *Res=0;

                        /*sprintf(Res,"Lexema: %d ",J-1);

                        StrCat("ERROR - No Bracket !!!  ",Res);*/

                        ErrorLex(1);

                        }

                        else

                        {

                        NextLexema();

                        }

            }

            else

            {

    if(testnum_p(Lex)==0&&(*Lex>47&&*Lex<58))  /* Проверка - является ли действ. числом */

            {

                        if(ToDo!=0&&ToDoif!=0&&ToDoW!=0)

                        {

                        StrCat(Lex,Res);

                        StrCat(DelimPol,Res); /* Добавляем разделитель в стеке */

                        }

                        NextLexema();

            }

            else

            {

              if(*Lex==34)  /* Кавычка */

              {

        if(lenstr(Lex)<100)  /* Чересчур длинная лексема */

                        {

                        if(ToDo!=0&&ToDoif!=0&&ToDoW!=0)

        {

                        StrCat(Lex,Res);

                        StrCat(DelimPol,Res);

                        }

                        }

                        else

                        {

                        ErrorLex(5);

                        }

                        NextLexema();

              }

              else

              {

                        if(*Lex==0)

                        {

                        *Res=0;

                        /*sprintf(Res,"Lexema: %d ",J-1);

                        StrCat("ERROR - 0-lexema, probably phrase is not finished!  ",Res);*/

                        ErrorLex(2);

                        }

                        else

                        {

                        if(*Lex>=65&&*Lex<=90)  /* Переменная или функция */

                        {

                                    StrCat(Lex,ResF1);

                                    StrCat(Lex,Lex_1);

                                    NextLexema();

                                    if(*Lex==40) /* Значит похоже на функцию */

                                    {

 

            /* Сравниваем с именами существ. функций */

                                    if(COMPstr(ResF1,sFunc1)==0)

                                    {

                                                iF=1;

                                                goto endSF;

                                    }

                                    if(COMPstr(ResF1,sFunc2)==0)

                                    {

                                                iF=1;

                                                goto endSF;

                                    }

                                    if(COMPstr(ResF1,sFunc3)==0)

                                    {

                                                iF=1;

                                                goto endSF;

                                    }

                                    if(COMPstr(ResF1,sFunc4)==0)

                                    {

                                                iF=2;

                                                goto endSF;

                                    }

                                    if(COMPstr(ResF1,sFunc5)==0)

                                    {

                                                iF=2;

                                                goto endSF;

                                    }

 

        if(ToDo!=0&&ToDoif!=0&&ToDoW!=0)

                        {

 

        N1=SEARCHlistP(pLF1,ResF1,0); /* Ищем имя в 1-й таблице функций*/

                        if(N1<0)

                        {

                        *Res=0;

        ErrorLex(26); /* Не найдено имя функции */

                        return;

                        }

                        er=READonPosStrP(pLF2,N1,ResNum); /* Ищем смещение во 2-й таблице (списке) */

                        if(er!=1)

                                                {

                                                            ErrorList(4);

                                                            return;

                                                }

                        iAdr=atoi(ResNum);

                        *ResNum=0;

                        er=READonPosStrP(pLF3,N1,ResNum); /* Ищем число пар-в в 3-й таблице (списке) */

                        if(er!=1)

                                                {

                                                            ErrorList(4);

                                                            return;

                                                }

                        iF=atoi(ResNum);

                        *ResNum=0;

/*****/  /* Обработка вызова внешней ф-ии */

                                    NextLexema();

                                    if(iF>0)

                                    {

                                                expr2();

 

                PostFix(Res,dest);

                                                CpStr(dest,St1);

                                    res=AddArrayToStackNoPart(pStF,St1,100);

                                                if(res!=100)

                                                {

                        ErrorStack(-3);

                                                }

                        *Res=0;

                        *dest=0;

                                    }

                                    while(iF>1)

                                    {

                                                iF--;

                                                if(*Lex!=44)

                                                {

                                    ErrorLex(6); /* Нет запятой в функции */

                                                            return;

                                                }

                                                NextLexema();

                                                expr2();

                        if(ToDo!=0&&ToDoif!=0&&ToDoW!=0)

                                                {

                PostFix(Res,dest);

                                                CpStr(dest,St1);

                                    res=AddArrayToStackNoPart(pStF,St1,100);

                                                if(res!=100)

                                                {

                        ErrorStack(-3);

                                                }

                        *Res=0;

                        *dest=0;

                                                }

                                    }

                                    if(*Lex!=41)

                                    {

                                    WrStr("error.txt",End,"Made...",1);

                                    WrStr("error.txt",End,Lex,1);

 

                       ErrorLex(7); /* Нет 2-й скобки в функции (или слишком много пар-в) */

                                                return;

                                    }

                                    else

                                    {

                        iAdr0=(int)(pProg-Prog); /* Вычисляем, куда возвращаться */

                        sprintf(St1,"%d",iAdr0);

                                    res=AddArrayToStackNoPart(pStF,St1,100);

                                    if(res!=100)

                                    {

                        ErrorStack(-3);

                                    }

 

                        pProg=Prog+iAdr; /* Перемещаемся по тексту программы к функции */

                                    FuncStreamOp(ResF1); /* Вызов */

 

            res=GetArrayFromStack(pStF,St1,100);

                        if(res!=100)

                                    {

                        ErrorStack(-7);

                                    }

                        StrCat(St1,Res); /* Записываем в строку результата */

                        StrCat(DelimPol,Res);

                                    }

                                    goto endSF2;

                                    ;

                                    }

                        else

                                    {

                                                while(1)

                                                {

                                                            NextLexema();

                                                            if(*Lex==41)

                                                            {

                                                            NextLexema();

                                    goto endSF2;

                                                            }

                                                }

                                    }

/*****/  /* Конец обработки вызова внешней ф-ии */

 

 

endSF:

                                    NextLexema();

                                    if(iF>0)

                                    {

                                                expr2();

                                    }

                                    while(iF>1)

                                    {

                                                iF--;

                                                if(*Lex!=44)

                                                {

                                    ErrorLex(6); /* Нет запятой в функции */

                                                            return;

                                                }

                                                NextLexema();

                                                expr2();

                                    }

                                    if(*Lex!=41)

                                    {

                                    WrStr("error.txt",End,"Inline...",1);

                                    WrStr("error.txt",End,Lex,1);

                       ErrorLex(7); /* Нет 2-й скобки в функции (или слишком много пар-в) */

                                                return;

                                    }

                                    else

                                    {

                        if(ToDo!=0&&ToDoif!=0&&ToDoW!=0)

            {

                                    StrCat(ResF1,Res); /* пишем в результ.строку имя функции */

                                    StrCat(DelimPol,Res);

                                    }

                                    *Lex=0;

                                    NextLexema();

                                    }

endSF2:                       ;

                                    ;

                                    }

                                    else

                                    {

/****/

       /* Это просто переменная */

                        if(ToDo!=0&&ToDoif!=0&&ToDoW!=0)

        {

        N1=SEARCHlistP(pL1,ResF1,0); /* Ищем имя в 1-й таблице (списке) функций */

                        if(N1<0)

                        {

                        *Res=0;

        ErrorLex(8);

                        return;

                        }

                        er=READonPosStrP(pL3,N1,ResNum); /* Ищем значение в 3-й таблице (списке) */

                        if(er!=1)

                                                {

                                                            ErrorList(4);

                                                            return;

                                                }

                        if(*ResNum==0)

                        {

                        *Res=0;

        ErrorLex(9);

                        return;

                        }

                       

        /****/

                        StrCat(ResNum,Res); /* Записываем в строку результата */

                        StrCat(DelimPol,Res);

                        }

                        }

                        }

                        else

                        {

                        *Res=0;

                        /*sprintf(Res,"Lexema: %d ",J-1);

                        StrCat("ERROR - Wrong lexema!  ",Res);*/

                        ErrorLex(3);

                        }

                        }

              }

            };

            };

            }

 

А вот обработка определения функции (еще когда не включено выполнение):

/* Обработка определения функции */

 

    void FuncOp()

            {

                        int er;

                        int iPar=0;

                        int iAdr;

                        char FPar[500];

 

                        *FPar=0;

 

                        NextLexema();

                        er=ADDendStrP(pLF1,Lex);  /* Заносим имя функции в таблицу */

                if(er!=1)

                                                {

                                                            ErrorList(2);

                                                            return;

                                                }

                NextLexema();

                        /***************/

                if(*Lex!=40)  /* Если не скобка */

                        {

                        *Res=0;

                        ErrorLex(27);

                        return;

                        }

                        while(iPar>-1)

                        {

                        NextLexema();

                        if(*Lex>=65&&*Lex<=90)

                        {

                                    iPar++;

                                    StrCat(Lex,FPar);

                                    StrCat(" ",FPar);

                        }

                        else

                        {

                                    ErrorLex(28);

                                    return;

                        }

                        NextLexema();

                        if(*Lex==41)

                        {

                                    break;

                        }

                        if(*Lex==44)

                        {

                                    continue;

                        }

                                    ErrorLex(28);

                                    return;

                        }

                        er=ADDendStrP(pLF4,FPar);  /* Заносим имя функции в таблицу */

                if(er!=1)

                                                {

                                                            ErrorList(2);

                                                            return;

                                                }

                        sprintf(FPar,"%d",iPar);

                        er=ADDendStrP(pLF3,FPar);  /* Заносим имя функции в таблицу */

                if(er!=1)

                                                {

                                                            ErrorList(2);

                                                            return;

                                                }

                        iAdr=(int)(pProg-Prog); /* Вычисляем, куда переходить */

                        sprintf(FPar,"%d",iAdr);

                        er=ADDendStrP(pLF2,FPar);  /* Заносим имя функции в таблицу */

                if(er!=1)

                                                {

                                                            ErrorList(2);

                                                            return;

                                                }

                        NextLexema();

                        StreamOp();

 

            }

 

/* Конец обработки определения функции */

 

А теперь – выполнение функции после ее вызова. Нужно прежде всего достать из стека значения переменных (а также адрес возврата, поскольку он ближе всего):

 

/* Обработка вызова ф-ии (самодельной) */

            void FuncStreamOp(char *Name)

            {

                        int N1,iP,i,er,res,N2;

                        char StrP[500];

                        char StrP1[100];

                        char StP[102];

                        int Adr;

 

        res=GetArrayFromStack(pStF,StP,100);

                        if(res!=100)

                                    {

                        ErrorStack(-7);

                                    }

                        Adr=atoi(StP);

 

        N1=SEARCHlistP(pLF1,Name,0); /* Ищем имя в 1-й таблице функций*/

                        if(N1<0)

                        {

                        *Res=0;

        ErrorLex(29); /* Не найдено имя функции при вызове */

                        return;

                        }

                        er=READonPosStrP(pLF3,N1,StrP); /* Ищем кол-во пар-в в 3-й таблице (списке) */

                        if(er!=1)

                                                {

                                                            ErrorList(4);

                                                            return;

                                                }

                        iP=atoi(StrP);

 

                        er=READonPosStrP(pLF4,N1,StrP); /* Ищем имена пар-в в 4-й таблице (списке) */

                        if(er!=1)

                                                {

                                                            ErrorList(4);

                                                            return;

                                                }

                        i=iP;

                        while(i>0)

                        {

                        CpWordN(StrP,StrP1,32,i);

                        i--;

        res=GetArrayFromStack(pStF,StP,100);

                        if(res!=100)

                                    {

                        ErrorStack(-7);

                                    }

        N2=SEARCHlistP(pL1,StrP1,0); /* Ищем имя в 1-й таблице функций*/

                        if(N2<0)

                        {

        er=ADDendStrP(pL1,StrP1);

                        if(er!=1)

                                                {

                                                            ErrorList(4);

                                                            return;

                                                }

        er=ADDendStrP(pL2,"N");

                        if(er!=1)

                                                {

                                                            ErrorList(4);

                                                            return;

                                                }

        er=ADDendStrP(pL3,"Empty");

                        if(er!=1)

                                                {

                                                            ErrorList(4);

                                                            return;

                                                }

        N2=SEARCHlistP(pL1,StrP1,0);

                        }

/***/

                                    if(*StP==34)

                                    {  /* Если строка */

                                    REPStrP(pL2,"S",N2);  /* Меняем тип на строковый */

                                    REPStrP(pL3,StP,N2); /* Помещаем результат в табл. пер-х */

                                    }

                                    else

                                    {

            if(testnum_p(StP)==0)

                                    {

                                    REPStrP(pL2,"D",N2);  /* Меняем тип на числовой (Double) */

                                    REPStrP(pL3,StP,N2); /* Помещаем результат в табл. пер-х */

                                    }

                                    else

                                    {

                                                ErrorStack(-15);

                                                return;

                                    }

/****/

                                    }

                        }

                        NextLexema();

                        StreamOp();

                        pProg=Prog+Adr; /* Перемещаемся по тексту программы назад*/

                        NextLexema();

 

            }

 

Все эти занесения в стек и вынимания оттуда требуют весьма тщательного и аккуратного программирования. Но все тем не менее заработало. Вот входной пример (на разрабатываемом языке) с вызовом двух функций.

FUNCTION A1(R,D,D1)

;

PRINT  (  "AAAAAAAAAAA");

R1=A2("function");

PRINT(R1);

PRINT(R);

PRINT(D);

PRINT(D1);

PRINT("BBBBBBBBBBB");

;

RETURN(100);

ENDFUNCTION

;

 

FUNCTION A2(HHHH);

PRINT(HHHH);

G=5;

WHILE(1=1)

G=G-1;

PRINT("+++");

IF(G=3)

BREAK;

ENDIF;

ENDWHILE;

RETURN(HHHH+"  Good!");

PRINT("$$$$$$$$$$$$$$$$$$$$$");

ENDFUNCTION

;

 

PRINT("Out!!!");

 

START

A=1;

PRINT( A);

IF(0)

E=5;

PRINT("Inside if");

E=A1(4.5,100,-20);

ENDIF;

PRINT("AFTER");

PRINT(E);

 

В программе уже более трех тысяч строк (не считая библиотек со строковыми функциями, с обработкой стека и списков, в которых хранятся таблицы). Мне уже иногда кажется, что она живет какой-то своей жизнью, поскольку обозреть и осмыслить ее всю уже весьма затруднительно. И иногда на чистой интуиции находится решение – если есть какой-то глюк, добавляем в каком-то (интуитивно найденном) месте вызов сканера (NextLexema();) – и все налаживается.

Хостинг от uCoz