7.60.

Разработайте простую версию препроцессора для обработки операторов #include. В качестве прототипа такой программы можно рассматривать такую (она понимает директивы вида #include имяфайла - без <> или "").


    #include <stdio.h>

    #include <string.h>

    #include <errno.h>

    char KEYWORD[] = "#include ";   /* with a trailing space char */

    void process(char *name, char *from){

            FILE *fp;

            char buf[4096];

            if((fp = fopen(name, "r")) == NULL){

                    fprintf(stderr, "%s: cannot read \"%s\", %s\n",

                                     from, name, strerror(errno));

                    return;

            }

            while(fgets(buf, sizeof buf, fp) != NULL){

                    if(!strncmp(buf, KEYWORD, sizeof KEYWORD - 1)){

                            char *s;

                            if((s = strchr(buf, '\n')) != NULL) *s = '\0';

                            fprintf(stderr, "%s: including %s\n",

                                             name, s = buf + sizeof KEYWORD - 1);

                            process(s, name);

                    } else  fputs(buf, stdout);

            }

            fclose(fp);

    }

    int main(int ac, char *av[]){

            int i;

            for(i=1; i < ac; i++)

                    process(av[i], "MAIN");

            return 0;

    }

7.61.

Разработайте простую версию препроцессора для обработки операторов #define. Сначала реализуйте макросы без аргументов. Напишите обработчик макросов вида


    #macro имя(аргу,менты)

      тело макроса - можно несколько строк

    #endm

7.62.

Напишите программу, обрабатывающую определения #ifdef, #else, #endif. Учтите, что эти директивы могут быть вложенными:


    #ifdef    A

    # ifdef   B

       ...             /*  defined(A) && defined(B) */

    # endif /*B*/

       ...             /*  defined(A) */

    #else   /*not A*/

       ...             /* !defined(A) */

    # ifdef   C

       ...             /* !defined(A) && defined(C) */

    # endif /*C*/

    #endif  /*A*/

7.63.

Составьте программу моделирования простейшего калькулятора, который считывает в каждой строчке по одному числу (возможно со знаком) или по одной операции сложения или умножения, осуществляет операцию и выдает результат.

7.64.

Составьте программу-калькулятор, которая производит операции сложения, вычитания, умножения, деления; операнды и знак арифметической операции являются строковыми аргументами функции main.

7.65.

Составьте программу, вычисляющую значение командной строки, представляющей собой обратную польскую запись арифметического выражения. Например, 20 10 5 + * вычисляется как 20 * (10 + 5) .

7.66.

Составьте функции работы со стеком:

  • добавление в стек
  • удаление вершины стека (с возвратом удаленного значения)

Используйте два варианта: стек-массив и стек-список.

7.67.

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


    /*#!/bin/cc $* -lm

     * Калькулятор. Иллюстрация алгоритма превращения выражений

     * в польскую запись по методу приоритетов.

     */

    #include <stdio.h>

    #include <stdlib.h> /* extern double atof();            */

    #include <math.h>   /* extern double sin(),  ...        */

    #include <ctype.h>  /* isdigit(), isalpha(), ...        */

    #include <setjmp.h> /* jmp_buf                          */

    jmp_buf AGAIN;             /* контрольная точка */

    err(n){ longjmp(AGAIN,n);} /* прыгнуть в контрольную точку */

    /* ВЫЧИСЛИТЕЛЬ --------------------------------------- */

    /* Если вместо помещения операндов в стек stk[] просто

     * печатать операнды, а вместо выполнения операций над

     * стеком просто печатать операции, мы получим "польскую"

     * запись выражения:

     *      a+b       ->      a b +

     *      (a+b)*c   ->      a b + c *

     *      a + b*c   ->      a b c * +

     */

    /* стек вычислений */

    #define MAXDEPTH 20 /* глубина стеков */

    int sp;             /* указатель стека (stack pointer) */

    double stk[MAXDEPTH];

    double dpush(d) double d; /* занести число в стек */

    {

       if( sp == MAXDEPTH ){ printf("Стек операндов полон\n");err(1);}

       else return( stk[sp++] = d );

    }

    double dpop(){            /* взять вершину стека */

       if( !sp ){ printf("Стек операндов пуст\n"); err(2); }

       else return stk[--sp];

    }

    static double r,p; /* вспомогательные регистры */

    void add()    { dpush( dpop() + dpop()); }

    void mult()   { dpush( dpop() * dpop()); }

    void sub()    { r = dpop(); dpush( dpop() - r); }

    void divide() { r = dpop();

      if(r == 0.0){ printf("Деление на 0\n"); err(3); }

      dpush( dpop() / r );

    }

    void pwr() { r = dpop(); dpush( pow( dpop(), r )); }

    void dup() { dpush( dpush( dpop())); }

    void xchg(){ r = dpop(); p = dpop(); dpush(r); dpush(p); }

    void neg() { dpush( - dpop()); }

    void dsin(){ dpush( sin( dpop())); }

    void dcos(){ dpush( cos( dpop())); }

    void dexp(){ dpush( exp( dpop())); }

    void dlog(){ dpush( log( dpop())); }

    void dsqrt(){ dpush( sqrt( dpop())); }

    void dsqr(){ dup(); mult(); }

    /* M_PI и M_E определены в <math.h> */

    void pi()  { dpush( M_PI /* число пи */ ); }

    void e()   { dpush( M_E  /* число e  */ ); }

    void prn() { printf("%g\n", dpush( dpop())); }

    void printstk(){

      if( !sp ){ printf("Стек операндов пуст\n"); err(4);}

      while(sp) printf("%g ", dpop());

      putchar('\n');

    }

    /* КОМПИЛЯТОР ---------------------------------------- */

    /* номера лексем */

    #define END        (-3)         /* = */

    #define NUMBER     (-2)         /* число */

    #define BOTTOM      0           /* псевдолексема "дно стека" */

    #define OPENBRACKET   1         /* (  */

    #define FUNC          2         /* f( */

    #define CLOSEBRACKET  3         /* )  */

    #define COMMA         4         /* ,  */

    #define PLUS          5         /* +  */

    #define MINUS         6         /* -  */

    #define MULT          7         /* *  */

    #define DIV           8         /* /  */

    #define POWER         9         /* ** */

    /* Приоритеты */

    #define NOTDEF    333   /* не определен */

    #define INFINITY 3000   /* бесконечность */

    /* Стек транслятора */

    typedef struct _opstack {

            int cop;        /* код операции */

            void (*f)();    /* "отложенное" действие */

    } opstack;

    int osp;        /* operations stack pointer */

    opstack ost[MAXDEPTH];

    void push(n, func) void (*func)();

    {

       if(osp == MAXDEPTH){ printf("Стек операций полон\n");err(5);}

       ost[osp].cop = n;  ost[osp++].f = func;

    }

    int pop(){

       if( !osp ){ printf("Стек операций пуст\n"); err(6); }

       return ost[--osp].cop;

    }

    int top(){

       if( !osp ){ printf("Стек операций пуст\n"); err(7); }

       return ost[osp-1].cop;

    }

    void (*topf())(){

       return ost[osp-1].f;

    }

    #define drop()          (void)pop()

    void nop(){ printf( "???\n" ); } /* no operation */

    void obr_err(){ printf( "Не хватает )\n" ); err(8); }

    /* Таблица приоритетов */

    struct synt{

            int inp_prt;    /* входной приоритет     */

            int stk_prt;    /* стековый приоритет    */

            void (*op)();   /* действие над стеком вычислений */

    } ops[] = {

      /* BOTTOM       */  {NOTDEF,   -1,     nop    },

      /* OPENBRACKET  */  {INFINITY,  0,     obr_err},

      /* FUNC         */  {INFINITY,  0,     obr_err},

      /* CLOSEBRACKET */  {1,        NOTDEF, nop    },  /* NOPUSH */

      /* COMMA        */  {1,        NOTDEF, nop    },  /* NOPUSH */

      /* PLUS         */  {1,         1,     add    },

      /* MINUS        */  {1,         1,     sub    },

      /* MULT         */  {2,         2,     mult   },

      /* DIV          */  {2,         2,     divide },

      /* POWER        */  {3,         3,     pwr    }

    };

    #define stkprt(i)    ops[i].stk_prt

    #define inpprt(i)    ops[i].inp_prt

    #define perform(i) (*ops[i].op)()

    /* значения, заполняемые лексическим анализатором */

    double value; void (*fvalue)();

    int tprev;  /* предыдущая лексема */

    /* Транслятор в польскую запись + интерпретатор */

    void reset(){ sp = osp = 0; push(BOTTOM, NULL); tprev = END;}

    void calc(){

      int t;

      do{

            if( setjmp(AGAIN))

                    printf( "Стеки после ошибки сброшены\n" );

            reset();

            while((t = token()) != EOF && t != END){

                    if(t == NUMBER){

                            if(tprev == NUMBER){

                                 printf("%g:Два числа подряд\n",value);

                                 err(9);

                            }

                            /* любое число просто заносится в стек */

                            tprev = t; dpush(value); continue;

                    }

                    /* иначе - оператор */

                    tprev = t;

            /* Выталкивание и выполнение операций со стека */

                    while(inpprt(t) <= stkprt( top()) )

                            perform( pop());

            /* Сокращение или подмена скобок */

                    if(t == CLOSEBRACKET){

                            if( top() == OPENBRACKET || top() == FUNC ){

                                    void (*ff)() = topf();

                                    drop(); /* схлопнуть скобки */

                                    /* обработка функции */

                                    if(ff)        (*ff)();

                            }else{ printf( "Не хватает (\n"); err(10); }

                    }

            /* Занесение операций в стек (кроме NOPUSH-операций) */

                    if(t != CLOSEBRACKET && t != COMMA)

                            push(t,   t == FUNC ? fvalue : NULL );

            }

            if( t != EOF ){

              /* Довыполнить оставшиеся операции */

                while( top() != BOTTOM )

                    perform( pop());

                printstk();     /* печать стека вычислений (ответ) */

            }

      } while (t != EOF);

    }

    /* Лексический анализатор ---------------------------- */

    extern void getn(), getid(), getbrack();

    int token(){    /* прочесть лексему */

            int c;

            while((c = getchar())!= EOF && (isspace(c) || c == '\n'));

            if(c == EOF) return EOF;

            ungetc(c, stdin);

            if(isdigit(c)){  getn(); return NUMBER; }

            if(isalpha(c)){ getid(); getbrack(); return FUNC; }

            return getop();

    }

    /* Прочесть число (с точкой) */

    void getn(){

            int c, i;  char s[80];

            s[0] = getchar();

            for(i=1; isdigit(c = getchar()); i++ )  s[i] = c;

            if(c == '.'){   /* дробная часть */

               s[i] = c;

               for(i++; isdigit(c = getchar()); i++)  s[i] = c;

            }

            s[i] = '\0'; ungetc(c, stdin); value = atof(s);

    }

    /* Прочесть операцию */

    int getop(){

            int c;

            switch( c = getchar()){

            case EOF:       return EOF;

            case '=':       return END;

            case '+':       return PLUS;

            case '-':       return MINUS;

            case '/':       return DIV;

            case '*':       c = getchar();

                            if(c == '*') return POWER;

                            else{ ungetc(c, stdin); return MULT; }

            case '(':       return OPENBRACKET;

            case ')':       return CLOSEBRACKET;

            case ',':       return COMMA;

            default:        printf( "Ошибочная операция %c\n", c);

                            return token();

            }

    }

    struct funcs{   /* Таблица имен функций */

            char *fname; void (*fcall)();

    } tbl[] = {

            { "sin", dsin }, { "cos",   dcos  },

            { "exp", dexp }, { "sqrt",  dsqrt },

            { "sqr", dsqr }, { "pi",    pi    },

            { "sum", add  }, { "ln",    dlog  },

            { "e",   e    }, { NULL,    NULL  }

    };

    char *lastf;    /* имя найденной функции */

    /* Прочесть имя функции */

    void getid(){

            struct funcs *ptr = tbl;

            char name[80]; int c, i;

            *name = getchar();

            for(i=1; isalpha(c = getchar()); i++) name[i] = c;

            name[i] = '\0'; ungetc(c, stdin);

            /* поиск в таблице */

            for( ; ptr->fname; ptr++ )

                    if( !strcmp(ptr->fname, name)){

                            fvalue = ptr->fcall;

                            lastf =  ptr->fname; return;

                    }

            printf( "Функция \"%s\" неизвестна\n", name ); err(11);

    }

    /* прочесть открывающую скобку после имени функции */

    void getbrack(){

      int c;

      while((c = getchar()) != EOF && c != '(' )

      if( !isspace(c) && c != '\n' ){

          printf("Между именем функции %s и ( символ %c\n", lastf, c);

          ungetc(c, stdin); err(12);

      }

    }

    void main(){ calc();}

    /* Примеры:

            ( sin( pi() / 4 + 0.1 ) + sum(2, 4 + 1)) * (5 - 4/2) =

                    ответ: 23.3225

            (14 + 2 ** 3 * 7 + 2 * cos(0)) / ( 7 - 4 ) =

                    ответ: 24

    */

[Назад][Содержание][Вперед]

Используются технологии uCoz