Можете ли вы помочь мне с таблицей состояний символов и вложенным переключателем? Упражнение из иллюстрирования C- Дональд Алкок - PullRequest
8 голосов
/ 25 июля 2011

ОК, сначала спасибо, что нашли время прочитать мой пост !! (^ О ^) / И прежде чем я поставлю всю проблему немного контекста: Я изучаю «C» и нашел книгу «Иллюстрируя C», над которой я работаю. В своей книге Дональд Алкок использовал таблицу состояний символов для логики в программе, которая просит изменить римскую цифру на арабском.

Это код:

#include <stdio.h>
char Symbol [] = { 'M', 'D', 'C', 'L', 'X', 'V', 'I' };
long Table [16] [8] =
{
    { 100000, 50001, 10003, 5007, 1006, 512, 111, 0 },
    {      0,     0, 10002, 5007, 1006, 512, 111, 0 },
    {      0,     0, 10004, 5007, 1006, 512, 111, 0 },
    {  80005, 30005, 10004, 5007, 1006, 512, 111, 0 },
    {      0,     0, 10005, 5007, 1006, 512, 111, 0 },
    {      0,     0,     0, 5007, 1006, 512, 111, 0 },
    {      0,     0,  8010, 3010, 1009, 512, 111, 0 },
    {      0,     0,     0,    0, 1008, 512, 111, 0 },
    {      0,     0,     0,    0, 1009, 512, 111, 0 },
    {      0,     0,     0,    0, 1010, 512, 111, 0 },
    {      0,     0,     0,    0,    0, 512, 111, 0 },
    {      0,     0,     0,    0,  815, 315, 114, 0 },
    {      0,     0,     0,    0,    0,   0, 113, 0 },
    {      0,     0,     0,    0,    0,   0, 114, 0 },
    {      0,     0,     0,    0,    0,   0, 115, 0 },
    {      0,     0,     0,    0,    0,   0,   0, 0 }
};

int main ( void )
{
    long Entry = 1, Number = 0;
    int Column, Row = 0;
    char Ch;
    printf ("\nEnter a number\n");
    while ( ((Ch = getchar()) != '\n') && Entry )
    {
        for ( Column=0; Column<7 && (Ch != Symbol[Column]); ++Column );
        Entry = Table [Row][Column];
        Number += Entry / 100;
        Row = Entry % 100;
        printf(" %li ", Number);
    }
    //printf("%c,%c  ", Ch,'\n' && Entry);
    if (Entry)
        printf ("= %ld in Arabics", Number);
    else
        printf ("\nError");
    printf("\nEnd of run");
    return 0;
}

Вот ссылка на фото книги: roman_2

Ну, там он объясняет логику таблицы.

Позже он написал это о переключателях и таблицах состояний символов:

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

Используя то, что он говорит, этот код можно заменить

while ( ((Ch = getchar()) != '\n') && Entry )
        {
            for ( Column=0; Column<7 && (Ch != Symbol[Column]); ++Column );
            Entry = Table [Row][Column];
            Number += Entry / 100;
            Row = Entry % 100;
            printf(" %li ", Number);
        }

для этого

while ( ((Ch = getchar()) != '\n') && Entry )
     {
       switch (Row)
        {
          case 0:
                switch (Column)
                {
                   case 'M':
                   case 'D':
                   ...
                }
          ...
         }
     }

Я думаю, вы поняли идею сейчас.

Ну, наконец, когда все развалилось. (T.T)

В главе 4.2 упражнения произнесите следующее:

Напишите функцию, используя таблицу состояний символов, для чтения восьмеричного числа. с клавиатуры, преобразовав его в десятичное целое число (типа long) . Разрешить предшествующий знак + или -. Например, программа должна прочитать -74 и получите результат -60. Ваша таблица состояний должна иметь четыре столбца. Это: [0], чтобы иметь дело с ведущими + или -, [1], чтобы иметь дело с любым цифры от 0 до 7, 2 для обозначения пробела, [3] для обозначения с любым другим символом (ошибка). Значение в каждой ячейке должно содержать метку (для использования в соответствующем операторе switch) и номер следующего «состояния» или строки. «Случай», связанный с действительные цифры должны умножить накопленный результат на число base, 8, затем добавьте текущую цифру. Напишите программу тестового стенда для чтения восьмеричные цифры с клавиатуры и отображение их десятичных эквивалентов на экране.

и это то, что я имею до этого:

#include <stdio.h>

char Simbol [] = {'0', '1', '2', '3', '4', '5', '6', '7'};
char   Sign [] = {'+', '-'};

long Table [8] [4] =
{
    {  143,  100,   132,  0},
    {  145,  101,     0,  0},
    {    0,  102,     0,  0},
    {    0,  103,     0,  0},
    {    0,  104,     0,  0},
    {    0,  105,     0,  0},
    {    0,  106,     0,  0},
    {    0,  107,     0,  0}
};

int main ( void )
{
    long Entry = 1, Number = 0, Simbo;
    int Column=0, Row;
    int base = 8;
    char Ch;

    printf ("\nEnter a number in base 8 (Octal)\n");
    while ( ((Ch = getchar()) != '\n') && Entry )
    {
        if( (Ch == '+') || ( Ch == '-') )
        {
            for ( Row=0; Row<2 && (Ch != Sign[Row]); ++Row );
        }
        else
        {
           for ( Row=0; Row<8 && (Ch != Simbol[Row]); ++Row );
           Column = 1;
        }

        Entry = Table [Row][Column];
        Simbo = Entry % 100;


        printf("Number %li Simbo %li Column %i \n", Number, Simbo, Column);
        switch (Row)
        {
          case 0:
                switch (Simbo)
                {
                   case 43:{
                           printf("In and is a +\n");
                           Entry = Table [Row][Column];
                           Column = Entry / 100;
                           Number= (+1)*Number;
                           break;}
                   case 0: {
                          Number = ((Number*base) +Simbo);
                          Entry = Table [Row][Column];
                          Column = Entry / 100;
                          break;
                          }
                   case 2: break;
                   case 3: break;
                   default: printf("case 0\n");
                }
                break;

          case 1:
                switch (Simbo)
                {
                   case 45:{
                           printf("In and is a  -\n");
                           Entry = Table [Row][Column];
                           Column = Entry / 100;
                           Number= (-1)*Number;
                           break;
                           }
                   case 1: {
                          Number = ((Number*base) +Simbo);
                          Entry = Table [Row][Column];
                          Column = Entry / 100;
                          break;
                          }
                   case 2: break;
                   case 3: break;
                   default: printf("case 1\n");
                }
                break;

          case 2:
                switch (Simbo)
                {
                   case 0: break;
                   case 2:{
                          Number = ((Number*base) +Simbo);
                          Entry = Table [Row][Column];
                          Column = Entry / 100;
                          break;
                          }
                   default: printf("case 2\n");
                }
                break;

          case 3:
                switch (Simbo)
                {
                   case 0: break;
                   case 3:{
                          Number = ((Number*base) +Simbo);
                          Entry = Table [Row][Column];
                          Column = Entry / 100;
                          break;
                          }
                   default: printf("case 3\n");
                }
                break;

          case 4:
                switch (Simbo)
                {
                   case 0: break;
                   case 4:{
                          Number = ((Number*base) +Simbo);
                          Entry = Table [Row][Column];
                          Column = Entry / 100;
                          break;
                          }

                   default: printf("case 4\n");
                }
                break;

          case 5:
                switch (Simbo)
                {
                   case 0: break;
                   case 5:{
                          Number = ((Number*base) +Simbo);
                          Entry = Table [Row][Column];
                          Column = Entry / 100;
                          break;
                          }

                   default: printf("case 5\n");
                }
                break;

          case 6:
                switch (Simbo)
                {
                   case 0: break;
                   case 6:{
                          Number = ((Number*base) +Simbo);
                          Entry = Table [Row][Column];
                          Column = Entry / 100;
                          break;
                          }
                   default: printf("case 6\n");
                }
                break;

          case 7:
                switch (Simbo)
                {
                   case 0:  break;
                   case 7:{
                          Number = ((Number*base) + Simbo);
                          Entry = Table [Row][Column];
                          Column = Entry / 100;
                          break;
                          }
                   default: printf("case 7\n");
                }
                break;

        default: printf("\ndefault\n");
        }

        printf("\n---Number %li\n\n", Number);

    }
     if (Entry)
         printf ("\n\n= %ld Decimal", Number);
     else
        printf ("\nError");
     return 0;
}

Хорошо работает с небольшими проблемами, но преобразует восьмеричное в десятичное.

Проблема в том, что я не могу понять, как использовать таблицу с переключателем и удалить здесь if и for:

while ( ((Ch = getchar()) != '\n') && Entry )
    {
        if( (Ch == '+') || ( Ch == '-') )
        {
            for ( Row=0; Row<2 && (Ch != Sign[Row]); ++Row );
        }
        else
        {
           for ( Row=0; Row<8 && (Ch != Simbol[Row]); ++Row );
           Column = 1;
        }

        Entry = Table [Row][Column];
        Simbo = Entry % 100;
    ...
   }

И символ пробела ... Я просто не знаю, что с этим делать !!!!.

В двух словах:

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

Извините, что сделал это слишком долго, и за любую ошибку, найденную в грамматике, английский не мой родной язык.

Еще раз спасибо!

1 Ответ

2 голосов
/ 25 июля 2011

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

        Number += Entry / 100;
        Row = Entry % 100;

Значения, хранящиеся в таблице, имеют 2 «поля» в упакованном десятичном представлении.Есть небольшой цикл для поиска входного символа в массиве символов (strchr был бы более распространенным способом сделать это).Затем значение из таблицы раскладывается с использованием / и%, чтобы получить место «десятки» и место «единицы», которые указывают следующее состояние (значение строки для следующей итерации большого цикла), а также место «сотни» иболее высокие места, которые при делении на 100 дают сумму, которую этот символ вносит в выходное значение.

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

Тем не менее, я собираюсь сам попробовать написать такую ​​программу.Не уверен, что вы ищете полное решение или просто небольшую помощь.Я проверю, когда получу больше.

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

/* the state transition table: +-, 0-7, ' ', ERR */
              /* 01234567890 */
char symbol[] = "+-01234567 ";
int table[][] = {
        /*  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,10,11 */
/* 0*/  {   2,   1, 002, 102, 202, 302, 402, 502, 602, 702, 0, 0 },
/* 1*/  {   0,   0,-001,-101,-201,-301,-401,-501,-601,-701, 0, 0 },
/* 2*/  {   0,   0, 002, 102, 202, 302, 402, 502, 602, 702, 0, 0 },
};

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

Редактировать: Использование макроса помогает сделать поля более удобными для просмотра.

#define T(x,y) ((x*100)+y)
/* the state transition table: +-, 0-7, ' ', ERR */
              /* 01234567890 */
char symbol[] = "+-01234567 ";
int table[][] = {
{ T(0,2), T(0,1), T(0,02), T(1,02), T(2,02), T(3,02), T(4,02), T(5,02), T(6,02), T(7,02), T(0,0), 
    T(0,0) },
{ T(0,0), T(0,0), T(0,01),T(-1,01),T(-2,01),T(-3,01),T(-4,01),T(-5,01),T(-6,01),T(-7,01), T(0,0), 
    T(0,0) },
{ T(0,0), T(0,0), T(0,02), T(1,02), T(2,02), T(3,02), T(4,02), T(5,02), T(6,02), T(7,02), T(0,0), 
    T(0,0) },
};

Позже ... Недавно я использовал ту же структуру данных и алгоритм для сканера для языка программирования в стиле APL ( опубликовано для обзора ).

...