Новые книги

Наше знание о медиа пиратстве обычно начинается и часто заканчивается исследованием, финансируемым отраслью. Для этого есть весомые основания.

Американские ассоциации отраслей программного обеспечения, фильмов и музыки финансировали обширные усилия по глобальному исследованию пиратства за прошлые два десятилетия, по большей части, для себя. Пиратство, несмотря на его вездесущность, было непаханым полем для независимого исследования. Эмпирические работы за прошлые десять лет, исключая отчасти исследования совместного использования файлов (файлшеринга), были редки и сосредоточены в узких областях. Сообщество интересов было столь мало, что, когда мы начали планировать этот проект в 2006, значительная его часть была включена в нашу работу. Это сообщество росло, но все еще остается ничем по масштабу сопоставлений относительно глобального, сравнительного, постоянного внимания отраслевых групп. И возможно, что еще более важно, нет ничего сопоставимого жесткой интеграции отраслевых исследований с лоббированием и кампаниями в СМИ, которые усиливают его присутствие в публичных и политических дискуссиях.

#i_001.png
Даже в самые тяжелые времена ваш бизнес необходимо рекламировать. Вы считаете, что это дорого? У вас нет денег на рекламу? Оказывается, рекламировать вашу компанию, товар, услугу можно и нужно даже тогда, когда бюджет на рекламу отсутствует. К счастью, бесплатные способы рекламы действительно существуют.

О них и пойдет речь в этой книге — ПЕРВОЙ книге, где подробно рассматриваются рекламные приемы, доступные любому бизнесу.

Текстовая обработка.

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
    */

© Copyright А. Богатырев, 1992-95
Си в UNIX

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