Форум программистов, компьютерный форум, киберфорум
Теория и практика программирования
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.72/18: Рейтинг темы: голосов - 18, средняя оценка - 4.72
223 / 37 / 4
Регистрация: 18.11.2012
Сообщений: 1,502
1

Грамматика в программировании

12.10.2017, 21:55. Показов 3417. Ответов 20
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Страуструп в книге даёт вводные данные про грамматику в программировании и даётся схема
Код
Пример простой грамматики выражений:
Выражение:
	Терм
	Выражение "+" Терм //сложение
	Выражение "-" Терм //вычитание 
Терм: 
	Первичное выражение
	Терм "*" Первичное выражение //умножение
	Терм "/" Первичное выражение //деление 
	Терм "%" Первичное выражение //остаток(деление по модулю)
Первичное выражение:
	Число
	"(" Выражение ")" //группировка 
Число: 
	литерал_с_плавающей_точкой
Для простейшего калькулятора по этой схеме создаётся код:

И следом даётся задание:
Кликните здесь для просмотра всего текста
Добавьте оператор вычисления факториала: для его представления используйте знак восклицания, !. Например, выражение 7! означает 7*6*5*4*3*2*1. Присвойте оператору ! более высокий приоритет по сравнению с операторами * и /, т.е. 7*8! должно означать 7* (8!), а не (7*8) !. Начните с модификации грамматики, чтобы учесть оператор с более высоким приоритетом. Для того чтобы учесть стандартное математическое определение факториала,
установите выражение 0! равным 1.


//Выражения
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// deal with + and -
double expression()
{
    double left = term();      // read and evaluate a Term
    Token t = ts.get();        // get the next token from token stream
 
    while(true) {    
        switch(t.kind) {
        case '+':
            left += term();    // evaluate Term and add
            t = ts.get();
            break;
        case '-':
            left -= term();    // evaluate Term and subtract
            t = ts.get();
            break;
        default: 
            ts.putback(t);     // put t back into the token stream
            return left;       // finally: no more + or -: return the answer
        }
    }
}



//Терм
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// deal with *, /, and %
double term()
{
    double left = primary();
    Token t = ts.get();        // get the next token from token stream
 
    while(true) {
        switch (t.kind) 
        {
        case '*':
        {               
            left *= primary();
            t = ts.get();
            break;
        }
        case '/':
            {    
                double d = primary();
                if (d == 0) error("divide by zero");
                left /= d; 
                t = ts.get();
                break;
            }
 
        default: 
            ts.putback(t);     // put t back into the token stream
            return left;
        }
    }
}


//Первичное выражение
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// deal with numbers and parentheses
double primary()
{
    Token t = ts.get();
    
    //double val;
    switch (t.kind) 
    {
        case '(':    // handle '(' expression ')'
        {    
            double d = expression();
            t = ts.get();
            if (t.kind != ')') error("')' expected");
            return d;
        }
        case '{':
        {
            double d = expression();
            t = ts.get();
            if(t.kind != '}')
                error("'}' expeced");
            return d;
        }
        case '8':
        {
            double d = t.value;
            t = ts.get();
            if(t.kind == '!')
                d = factorial(d); -->вот так я реализовал факториал, но меня терзают смутные сомнения!
            else
                ts.putback(t);
            return d;
        }
            /*t.value = factorial(t.value);
        case '8':            // we use '8' to represent a number
            return t.value;*/  // return the number's value
 
        case 'x':
            ts.putback(t);
            break;
        default:
            error("primary expected");
    }
}


//Вспомогательные типы Token, Token_stream и объявления
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include "std_lib_facilities.h"
 
//------------------------------------------------------------------------------
 
class Token {
public:
    char kind;        // what kind of token
    double value;     // for numbers: a value 
    Token(char ch)    // make a Token from a char
        :kind(ch), value(0) { }    
    Token(char ch, double val)     // make a Token from a char and a double
        :kind(ch), value(val) { }
};
 
//------------------------------------------------------------------------------
 
class Token_stream {
public: 
    Token_stream();   // make a Token_stream that reads from cin
    Token get();      // get a Token (get() is defined elsewhere)
    void putback(Token t);    // put a Token back
private:
    bool full;        // is there a Token in the buffer?
    Token buffer;     // here is where we keep a Token put back using putback()
};
 
//------------------------------------------------------------------------------
 
// The constructor just sets full to indicate that the buffer is empty:
Token_stream::Token_stream()
:full(false), buffer(0)    // no Token in buffer
{
}
 
//------------------------------------------------------------------------------
 
//------------------------------------------------------------------------------
double factorial(double number)
{
    //функция вычисляет факториал числа number
    if(number < 0)
        error("Invalid argument value");
    if(number == 0 || number == 1)
        return 1.0;
    else 
    {
        for(int i = number - 1; i > 1; --i)
        {
            number *= i;
        }
    }
    return number;
}
 
//--------------------------------------------------------------------------------------
 
// The putback() member function puts its argument back into the Token_stream's buffer:
void Token_stream::putback(Token t)
{
    if (full) error("putback() into a full buffer");
    buffer = t;       // copy t to buffer
    full = true;      // buffer is now full
}
 
//------------------------------------------------------------------------------
 
Token Token_stream::get()
{
    if (full) {       // do we already have a Token ready?
        // remove token from buffer
        full=false;
        return buffer;
    } 
    
    char ch;
    cin >> ch;    // note that >> skips whitespace (space, newline, tab, etc.)
 
    switch (ch) {
    case '=':    // for "print"
    case 'x':    // for "quit"
    case '{': case '}': case '(': case ')': case '+': case '-': case '*': case '/': case '!':
        return Token(ch);        // let each character represent itself
    
    case '.':
    case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '8': case '9':
        {    
            cin.putback(ch);         // put digit back into the input stream
            double val;
            cin >> val;              // read a floating-point number
            return Token('8',val);   // let '8' represent "a number"
        }
    default:
        error("Bad token");
    }
}
 
//------------------------------------------------------------------------------
 
Token_stream ts;        // provides get() and putback() 
 
//------------------------------------------------------------------------------
 
double expression();    // declaration so that primary() can call expression()


Не знаю почему, но в тему не могу вникнуть с ходу, нужна помощ!

p.s.
А если я захочу сделать операцию возведения в степень '^', но чтобы преоритет был ниже '+', '-', то как это должно выглядит, может так?
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
double expression()
{
    double left = term();
    Token t = ts.get();
    while(true)
    {
        switch(t.kind)
        {
            case '+':
                left += term();
                t = ts.get();
                break;
            case '-':
                left -= term();
                t = ts.get();
                break;
            case '^':
            {
                double d = term();        ---->Вот так, но приоритет операции такой же как '+', '-'
                left = pow_my(left, d);
                t = ts.get();
                break;
            }
            default:
                ts.putback(t);
                return left;
        }
    }
}
2
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
12.10.2017, 21:55
Ответы с готовыми решениями:

Формальная грамматика
Товарищи программисты, помогите написать на С++ программу которая б проверяла грамматику. Для...

Чем отличается однозначная грамматика от неоднозначной?
Вопрос, чем отличается однозначная грамматика от неоднозначной? Если можно на пальцах. Спасибо.

Математика в программировании
Правда ли, что в ВУЗах, которые занимаются подготовкой программистов идет углубленное изучение...

Самые известные личности в программировании
Хочу создать этот топик чтобы узнать больше и поговорить о самых известных и признанных личностях в...

20
1394 / 1023 / 325
Регистрация: 28.07.2012
Сообщений: 2,813
12.10.2017, 23:49 2
Цитата Сообщение от Liss29 Посмотреть сообщение
Не знаю почему, но в тему не могу вникнуть с ходу, нужна помощ!
В исходной грамматике самым высшим приоритетом обладает Первичное выражение. Логично добавить факториал туда, т.е.
Код
Первичное выражение:
	Число
	"(" Выражение ")"
        Первичное выражение !
Так что в конце обработчика проверяешь наличие токена факториала.
Цитата Сообщение от Liss29 Посмотреть сообщение
А если я захочу сделать операцию возведения в степень '^', но чтобы преоритет был ниже '+', '-'
У тебя кажись проблемы с понятием приоритет. Чем он выше, тем раньше будет выполнена операция. Я наверно не ошибусь, если скажу, что у возведения в степень приоритет должен быть аналогичным факториалу, да и правило вывода наверно
Первичное выражение ^ Первичное выражение
0
223 / 37 / 4
Регистрация: 18.11.2012
Сообщений: 1,502
13.10.2017, 04:48  [ТС] 3
Цитата Сообщение от nonedark2008 Посмотреть сообщение
У тебя кажись проблемы с понятием приоритет.
Нет, тут ты ошибаешься, я пример привёл, возможно, некорректный с '^' , но суть не в этом, я хотел спросить, как быть, если я вдруг решу какую-то операцию сделать с приоритетом ниже, чем у '+', '-'? Пока не придумал такой опреции.

В исходной грамматике самым высшим приоритетом обладает Первичное выражение.
Если так, то низшим приоритетом обладает выражение: и тогда, если я решаю какую-то операцию делать с приоритетом ниже, чем '+', '-', то это должно быть, приблизительно так:
Код
Выражение:
Терм
Выржение "какая-то моя оперция" Выражение..
Выражение "+" Терм
Выражение "-Э Терм
Правильно мыслю?

Цитата Сообщение от nonedark2008 Посмотреть сообщение
Логично добавить факториал туда
Я туда и добавил
C++
1
2
3
4
5
6
7
8
9
10
 case '8':
        {
            double d = t.value;
            t = ts.get();
            if(t.kind == '!')
                d = factorial(d); -->вот так я реализовал факториал, но меня терзают смутные сомнения!
            else
                ts.putback(t);
            return d;
        }
Цитата Сообщение от nonedark2008 Посмотреть сообщение
да и правило вывода наверно


Пойду ещё помедитирую.
0
1394 / 1023 / 325
Регистрация: 28.07.2012
Сообщений: 2,813
13.10.2017, 10:05 4
Цитата Сообщение от Liss29 Посмотреть сообщение
Пока не придумал такой опреции.
Посмотри список операций в Си/Си++, там таких полно.

Цитата Сообщение от Liss29 Посмотреть сообщение
если я решаю какую-то операцию делать с приоритетом ниже, чем '+', '-', то это должно быть, приблизительно так
Исходя из исходной грамматики, но по смыслу можно добавить какое-нибудь Низшее выражение...
Цитата Сообщение от Liss29 Посмотреть сообщение
Я туда и добавил
Не туда. Подозреваю, что твоя штука не осилит (1+1)!.
0
223 / 37 / 4
Регистрация: 18.11.2012
Сообщений: 1,502
13.10.2017, 21:52  [ТС] 5
Цитата Сообщение от nonedark2008 Посмотреть сообщение
Низшее выражение
Как? Может как-то так?
Код
Выражение лайт:
Выражение
Выражение лайт "," Выржение

Выражение:
Терм
Выраженеи "+" Терм
Выражение "-" Терм
Цитата Сообщение от nonedark2008 Посмотреть сообщение
Подозреваю, что твоя штука не осилит(1+1)!
Правильно подозреваешь, программа выдала ошибку! Подправил, теперь выводит правильный ответ = 2 Я сделал:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// deal with numbers and parentheses
double primary()
{
    Token t = ts.get();
 
    switch (t.kind) 
    {
        case '(':    // handle '(' expression ')'
        {    
            double d = expression();
            t = ts.get();
            if (t.kind != ')') error("')' expected");
            t = ts.get();    -->вот
            if(t.kind == '!')
                d = factorial(d);
            else 
                ts.putback(t);
            return d;
        }
 
        case '8':
        {
            double d = t.value;
            t = ts.get();
            if(t.kind == '!')
                d = factorial(d);
            else
                ts.putback(t);
            return d;
        }
 
        case 'x':
            ts.putback(t);
            break;
        default:
            error("primary expected");
    }
}


Но, подозреваю, что ты имел ввиду нечто другое, судя по
Код
Первичное выражение:
Число
"(" Выражение ")"
Первичное выражение !
значит нужно вызвать primary() из primary()?
0
1394 / 1023 / 325
Регистрация: 28.07.2012
Сообщений: 2,813
13.10.2017, 23:38 6
Цитата Сообщение от Liss29 Посмотреть сообщение
значит нужно вызвать primary() из primary()?
По такой логике ты должен был вызывать expression() внутри expression().
Думаю, что тебе стоит почитать про типы грамматик, понять к какому типу относится твоя грамматика, и в итоге разобраться с алгоритмом рекурсивного спуска (вроде именно он у тебя фигурирует).
0
223 / 37 / 4
Регистрация: 18.11.2012
Сообщений: 1,502
14.10.2017, 03:29  [ТС] 7
Я и пытаюсь разобраться. Если вызвать expression() внутри expression() получится бесконечная рекурсия. Я не просто так, ради развлечения задаю вопросы, если я не так делаю, можно сказать, и я попытаюсь исправить, если эту схему можно расширять, то почему бы не добавить новое правило, скажем Первичное_выражение_лёгкое, которое будет вызывать Первичное выражение:

Код
Выражение:
	Терм
	Выражение "+" Терм //сложение
	Выражение "-" Терм //вычитание 
Терм: 
	Первичное выражение лёгкое
	Терм "*" Первичное выражение лёгкое //умножение
	Терм "/" Первичное выражение лёгкое //деление 
	Терм "%" Первичное выражение лёгкое //остаток(деление по модулю)
Первичное выражение лёгкое:
Первичное выражение 
	Первичное выражение "^" Первичное выражение лёгкое
	Первичное выражение "!"
Первичное выражение:
	Число
	"(" Выражение ")" //группировка 
Число: 
	литерал_с_плавающей_точкой
Цитата Сообщение от nonedark2008 Посмотреть сообщение
алгоритмом рекурсивного спуска (вроде именно он у тебя фигурирует).
Думаю, он и есть, Страуструп про названия ничего не пишет, возможно, только пока, но графически это выглядит как рекурсия: expression() --> term() --> primary() --> expression().
0
1394 / 1023 / 325
Регистрация: 28.07.2012
Сообщений: 2,813
14.10.2017, 08:29 8
Liss29, я сам ни разу не открывал Страуструпа, так что не могу знать что там по чем.
Однако теория грамматик - это очень большой раздел который, если хочется в нем разбираться, его нужно дополнительно отдельно изучать.

Цитата Сообщение от Liss29 Посмотреть сообщение
почему бы не добавить новое правило
Можно и добавить. Это наверно будет даже работать. Возьми бумажку, напиши некоторое не самое простое выражение, и посмотри как будет работать метод рекурсивного спуска для грамматики. Я сам это дело не настолько хорошо помню, чтобы кого-то учить.
1
223 / 37 / 4
Регистрация: 18.11.2012
Сообщений: 1,502
16.10.2017, 17:55  [ТС] 9
Цитата Сообщение от nonedark2008 Посмотреть сообщение
Можно и добавить. Это наверно будет даже работать.
Как-то работает через раз. Получаетя, если я добавляю правило, количество рекурсивных вызово увелививается, а это не есть хорошо, тогда я не понимаю, как добавить "!" или "^" в правило Первичное выражение.

Цитата Сообщение от nonedark2008 Посмотреть сообщение
я сам ни разу не открывал Страуструпа, так что не могу знать что там по чем.
Там только некая вводная часть, если так можно выразиться, схема, котору я привёл в вопросе, объяснение её весьма поверхностное и реализация правил в коде.
0
1394 / 1023 / 325
Регистрация: 28.07.2012
Сообщений: 2,813
16.10.2017, 18:42 10
Цитата Сообщение от Liss29 Посмотреть сообщение
количество рекурсивных вызово увелививается, а это не есть хорошо
Вот когда это действительно станет проблемой, тогда и можно задуматься о переделке рекурсии во что-то более приличное. Но этого-то от тебя никто не требует.

Цитата Сообщение от Liss29 Посмотреть сообщение
Но, подозреваю, что ты имел ввиду нечто другое, судя по
КодВыделить код
Первичное выражение:
Число
"(" Выражение ")"
Первичное выражение !
В идеале должно распознаваться выражение вида (1+1)!!, т.е. факториал от результата выполнения факториала. Но это вторично, забей и двигайся дальше по учебнику.
0
mat_for_c
16.10.2017, 19:23
  #11

Не по теме:

Цитата Сообщение от nonedark2008 Посмотреть сообщение
т.е. факториал от результата выполнения факториала
тут спорный вопрос. в математике 4!! = 2*4 = 8, а не 24!

0
nonedark2008
16.10.2017, 19:49
  #12

Не по теме:

Цитата Сообщение от mat_for_c Посмотреть сообщение
тут спорный вопрос.
Это без разницы. Главное, выводится ли такая цепочка в нашей грамматике или нет.

0
223 / 37 / 4
Регистрация: 18.11.2012
Сообщений: 1,502
17.10.2017, 04:04  [ТС] 13
(1+1)!! не выводит, ошибка вылетает, но если написать ((1+1)!)! тода расознаёт выражение, так же выржение вида 18+(2*(2^3)/2-4)+5 выбрасывает исключение, если делаю (2*(2^3)/2), то нормально считает. Так что либо я намудрил с создание лишнего правила, либо реализовал правило не так как надо.

Цитата Сообщение от nonedark2008 Посмотреть сообщение
забей и двигайся дальше по учебнику.
Я тоже так думаю, может дальше по тексту будет продолжение и тема будет раскрыта более развёрнуто. Спасибо!

Добавлено через 7 часов 24 минуты
Хотя нет, выражение 18+(2*(2^3)/2-4)+5 нормально решается, так что осталось разобраться с (1+1)!!
0
223 / 37 / 4
Регистрация: 18.11.2012
Сообщений: 1,502
18.10.2017, 05:18  [ТС] 14
Если требуется написать грамматики для описания логических выражений, то:

Код
Выражение:
	Терм
	Выражение "|" Терм 
Терм:
	Первичное выражение
	Терм "^" Первичное выражение 

Первичное выражение:
	Унарное выражение 
	Первичное выражение "&" унарное выражение 
Унарное выражение:
	Приоритетное выражение
	~Унарное выражение
	!Унарное выражение
Приоритетное выражение:
	Число 
	"(" Выражение ")"
Число:
	целое_число
такой вариант чем-то напоминает правду?
0
27 / 32 / 14
Регистрация: 08.09.2017
Сообщений: 448
19.10.2017, 17:54 15
Liss29,
вы уверены в том, что знаете операцию "-"?
1. да это бинарная операция вычитания типа 3 - 2
2. да это унарная операция типа - 1.
(её приоритет выше, чем приоритет умножения)
0
223 / 37 / 4
Регистрация: 18.11.2012
Сообщений: 1,502
26.10.2017, 05:55  [ТС] 16
Цитата Сообщение от йот Посмотреть сообщение
вы уверены в том, что знаете операцию "-"?
Я уверен, что знаю операцию "~".

Мы про одно и тоже или как?

Я спрашиваю про последнюю грамматику, а ты про что?
0
27 / 32 / 14
Регистрация: 08.09.2017
Сообщений: 448
26.10.2017, 09:09 17
Liss29
Знаком "-" обозначают две операции
1. бинарную операцию вычитание, пример 4 - 3 = 1
2. унарную операцию минус, пример -(5) = -5
у этих операций и приоритет разный...
...
примечание
кстати таким же свойством обладаем операция "+".
правда большого значения она не имеет.
0
223 / 37 / 4
Регистрация: 18.11.2012
Сообщений: 1,502
27.10.2017, 15:51  [ТС] 18
Цитата Сообщение от йот Посмотреть сообщение
2. унарную операцию минус, пример -(5) = -5
Я в курсе. А () - имеют приоритет гораздо выше чем "-" хоть унарный, хоть бинарный. А про грамматики, я в них плаваю, а не в приоритетах.
0
27 / 32 / 14
Регистрация: 08.09.2017
Сообщений: 448
27.10.2017, 16:24 19
Liss29,
самый высокий приоритет имеют скобки ().
Вам надо определиться с алгоритмом, который
будет определять в какой паре скобок можно
производить вычисления, а где нет
...
(как делаю я)
я всё арифметическое выражение сначала заключаю в ().
Для чего? Чтобы получить результат, надо вычислить
последнюю пару скобок. А раз всё выражение в скобках и
эта последняя пара скобок вычислена, то полученный
результат и есть искомый.
0
[Bicycle Reinventor]
332 / 270 / 109
Регистрация: 19.10.2011
Сообщений: 668
Записей в блоге: 2
27.10.2017, 16:58 20
Рекомендую почитать цикл статей Руслана Спивака по написанию интерпретатора Паскаля. Первые статьи в цикле хорошо описывают грамматику калькулятора и её реализацию в виде кода.
Весьма интересный материал.
0
27.10.2017, 16:58
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
27.10.2017, 16:58
Помогаю со студенческими работами здесь

Какие области в программировании вам интересны?
Здравствуйте! Сейчас решил менять работу, хочу попробовать себя в программировании. Но есть...

КС-грамматика
Необходимо построить контекстно свободную граматику порождающую цепочки вида : xnymzn , где:...

Грамматика
Здравствуйте. Помогите, пожалуйста, составить грамматику для языка логических выражений. Выражения...

Однозначная грамматика без правой и левой рекурсии
Всем привет! Сижу, зубрю системное программирование и наткнулся на такой вопрос: верно ли...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru