Программист-прагматик. Путь от подмастерья к мастеру
Шрифт:
Ответ: Поскольку мы хотим, чтобы язык был расширяемым, сделаем таблицу синтаксического анализатора управляемой. Каждый элемент таблицы содержит символ команды, флаг, говорящий о необходимости аргумента, и имя подпрограммы, вызываемой для обработки этой конкретной команды.
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: При использовании 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
Ответ: В нашем примере мы составили программу, используя генератор 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") ,
};
ampm: AM {$$ = AM_MINS;}
| PM {$$ = PM_MINS;)
;
hour num: DIGIT {$$ = $1;)
| DIGIT DIGIT {$$ = $1*10 + $2;}
;
Ответ:
$_ = shift;
/"(\d\d?)(am|pm)$/ && doTime($1, 0, $2, 12);
/"(\d\d?):(\d\d)(am|pm)$/ && doTime($1, $2, $3, 12);
/"(\d\d?):(\d\d)$/ && doTime($1, $2, 0, 24);
die "Invalid time $_\n";
#
# doTime(hour, min, ampm, maxHour)
#
sub doTime($$$$) {
my ($hour, $min, $offset, $maxHour) = @_;
die "Invalid hour: $hour" if ($hour>= $maxHour);
$hour += 12 if ($offset eq "pm")
print $hour*60 + $min, " minutes past midnight\n";
exit(0);
}
Ответ: Ответ должен быть изложен, исходя из нескольких допущений:
• Лента содержит информацию, которую необходимо передать.
• Известна скорость ходьбы человека.
• Известно расстояние между компьютерами.
• Временем, необходимым для переноса информации на ленту и с ленты, можно пренебречь.
• Потери данных при хранении на ленте примерно равны их потерям при передаче по каналу связи.
Ответ: Учитывая допущения ответа 9: Объем информации, содержащейся на стриммерной кассете (4 Гбайт), составляет 32 х 10^9 бит, так что передача эквивалентного объема по каналу со скоростью 1 Мбайт/с заняла бы около 32000 сек. (примерно 9 ч). Если человек движется с постоянной скоростью 3,5 мили в час, то, для того чтобы канал связи превзошел курьера, два компьютера должны располагаться друг от друга на расстоянии не менее 31 мили. Если это расстояние меньше, то победа остается за человеком.