Выбрать главу
Упражнение 3 из раздела «Ортогональность»

Ответ: Здесь есть элемент лукавства. Объектная технология может обеспечить наличие более ортогональной системы, но поскольку она имеет больше средств, которые могут эксплуатироваться с нарушением режима, в реальности легче создать неортогональную систему, используя объекты, чем создавать ее при помощи процедурного языка. Ее особенности – множественное наследование, исключительные ситуации, перегрузка операторов и переопределение родительского метода (через механизм подклассов) – предоставляют достаточные возможности для увеличения связанности не столь очевидными способами.

Применяя объектную технологию и приложив небольшое дополнительное усилие, вы можете добиться наличия более ортогональной системы. И хотя вы всегда можете написать неструктурированную программу на процедурном языке, объектно-ориентированные языки, используемые в малых дозах, могут сделать ее более насыщенной.

Упражнение 4 из раздела «Прототипы и памятные записки»

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

Упражнение 5 из раздела «Языки, отражающие специфику предметной области»

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

typedef struct {

char cmd; /* the command letter */

int hasArg; /* does it take an argument */

void (*func)(int, int); /* routine to call */

} Command;

static Command cmds[] = {

{'P', ARG, doSelectPen},

('V', NO_ARG, doPenUp},

{'D', NO_ARG, doPenDown},

{'N,' ARG, doPenDir},

{'E', ARG, doPenDir},

{'S', ARG, doPenDir},

{'W', ARG, doPenDir}

};

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

while (fgetsfbuff, sizeof(buff), stdin)) {

Command *cmd = findCommand(*buff);

if (cmd) {

  int arg = 0;

  if (cmd->hasAr&& !getArg(buff+1, &arg)) {

     fprintf(stderr,"'%с' needs an argument\n», *buff);

     continue;

  }

cmd->func(*buff, arg);

}

}

Функция, которая ищет команду, исполняет последовательный перебор таблицы, возвращая либо совпадающий элемент, либо NULL.

Command *findCommand(int cmd) {

int i;

for (i = 0; i<ARRAY.SIZE(cmds); i++) {

  if (cmds[i].cmd==cmd)

    return cmds + i;

  }

fprintf(stderr, «Unknown command %c'\n», cmd);

return 0;

}

И наконец, считывание числового аргумента довольно просто, если использовать подпрограмму sscanf.

int getArg(const char *buff, int 'result) {

   return sscanf(buff, «%d», result) == 1;

}

Упражнение 6 из раздела «Языки, отражающие специфику предметной области»

Ответ 6: При использовании BNF спецификация времени могла бы выглядеть следующим образом:

<tlme>::= <hour> <ampm> |

        <hour>: <minute> <ampm> |

        <hour>: <minute>

<ampm>::= am|pm

<hour>::=<digit> |

        <digit>::=<digit>

<mlnute>::=<digit><digit>

<digit>::= 0|1|2|3|4|5|6|7|8|9

Упражнение 7 из раздела «Языки, отражающие специфику предметной области»

Ответ: В нашем примере мы составили программу, используя генератор bison, который представляет собой GNU-версию генератора уасс. Для ясности здесь показано только тело программы синтаксического анализатора. Полная версия есть на сайте www.pragmaticprogrammmer.com.

time: spec EOF

{ if ($1>= 24*60) yyerror("Time is too large»);

   printf("%d minutes past midnight\n», $1);

   exit(0);

}

;

spec:  hour ':' minute

    { $$ = $1 + $3;

    }

  | hour ':' minute ampm

{ if ($1>11*60) yyerrorf «Hour out of range»);

   $$ = $1 + $3 + $4;

}

| hour ampm

  {if ($1>11*60) yyerror("Hour out of range»);

    $$ = $1 + $2;

   }

;

hour: hour_num

    {if ($1>23) yyerror("Hour out of range»);

     $$ = $1 * 60;

    };

minute: DIGIT DIGIT

     {$$ = $1*10 + $2;

     if ($$> 59) yyerrorf «minute out of range») ,