Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.89/18: Рейтинг темы: голосов - 18, средняя оценка - 4.89
0 / 0 / 0
Регистрация: 18.03.2019
Сообщений: 689

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

04.09.2020, 21:20. Показов 3705. Ответов 4
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Подскажите, пожалуйста, как делать вообще данное задание на С++?

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

Упрощенный язык программирования должен обязательно включать:
1. Оператор присваивания "=" и только одну из следующих арифметических операций:

+ ( сложение ),
- ( вычитание ),
* ( умножение ),
/ ( деление ),
++ ( логическое сложение ),
** ( логическое умножение),
%% ( сложение по модулю 2).

2. Один из следующих операторов:
• оператор цикла, построенный в соответствии с предложенным синтаксисом конструкции:
FOR <имя параметра цикла>=m TO n <тело цикла> NEXT;

• оператор цикла, построенный в соответствии с предложенным синтаксисом конструкции:
FOR <имя параметра цикла>=m TO n DO BEGIN <тело цикла>
END;
• условный оператор, построенный в соответствии с предложенным синтаксисом конструкции:
IF <условие> THEN BEGIN <операторы> END;
здесь <условие> задается одной из форм: a<b, либо a=b, либо a>b;

• оператор процедуры, построенный в соответствии с предложенным синтаксисом конструкции:

PROCEDURE <имя процедуры> BEGIN <тело процедуры> END
для вызова процедуры используется оператор
CALL <имя процедуры>;

3. Оператор вывода переменных
WRITE ( <список переменных через запятую> );

4. Программа языка имеет структуру
VAR <список переменных через запятую >: INTEGER
BEGIN <операторы программы> END
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
04.09.2020, 21:20
Ответы с готовыми решениями:

ЛЕКСИЧЕСКОГО АНАЛИЗА ТРАНСЛЯТОРОВ ЯЗЫКОВ ПРОГРАММИРОВАНИЯ
Разработать программу лексического сканирования и анализа для заданных языка программирования и типов лексем. Программа должна построить...

Написать программу – оконное приложение, реализующее функцию лексического анализа
Часть 1 Для заданной грамматики написать функции переходов, таблицу переходов, построить диаграмму переходов. В случае если грамматика...

Разработать программу для сравнительного графического анализа алгоритмов сортировки и поиска
Разработать программу для сравнительного графического анализа алгоритмов сортировки и поиска;Задача разработчика сгенерировать массив, над...

4
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
05.09.2020, 00:06
Задачка довольно интересная. Я бы сказал, даже со * звездочкой.

Могу предложить базовый пример парсера из книги Язык С++ ПРОГРАММИРОВАНИЯ Bjarne Stroustrup.
На его основе можно добиться выполнения Ваших задач.

Поставляется КАК ЕСТЬ .

code :
Кликните здесь для просмотра всего текста

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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
// Учебная рограмма 
// собранная по учебнику "Язык С++ ПРОГРАММИРОВАНИЯ специальное издание"
// Bjarne Stroustrup AT&T Labs Murray Hill, New Jersey
// Москва, Издательство БИНОМ, 2011г
//
// Версия 0,0,0,1 однофайловая, функциональная, упрощенная.
// --------------------------------------------------------
 
// ------------- Условие задачи ---------------------------
/* 6.1. Калькулятор
      1 ---------- OK
 *  Мы рассмотрим операторы и выражения языка C++ на примере программы
 * калькулятора, реализующего четыре стандартных арифметических действия в
 * форме инфиксных операций над числами с плавающей запятой.
 * Пользователь может также определять переменные. Например,
 * если на входе калькулятора имеется
 * г=2.5
 * area=pi* г* r
 * (где pi — это предопределенная переменная) то в результате работы
 * программа-калькулятор выдаст
 * 2.5
 * 19.635
 * где 2.5 — это результат обработки первой строки, а 19. 635 — второй.
 * Наш калькулятор состоит из четырех основных частей:
        2 ---------- OK
 *      Модифицируйте программу-калькулятор, чтобы она сообщала номера
 * строк, в которых произошла ошибка.
        3 ----------
 * Разделить парсер, лексический анализатор и обработку ошибок
 * за Именами пространств. Максимально разделить внутреннюю реализацию и
 * пользовательский доступ.
 * Добавить обработку исключений встроенными обработчиками. throw и catch.
 *
 *
 *
*/
 
/* Нкмного о алгоритме и отдельных частях кода :
 *
 *
 * Применяемый нами стиль синтаксического анализа называется рекурсивным спуском
 * (recursive descent).
 * Терминальные символы (например, END, NUMBER, + и -) распознаются лексическим
 * анализатором gettoken()
 * нетерминальные символы распознаются функциями синтаксического анализа,
 * ехрг (), term () и prim ().
 *
 * Функция ехрг () обрабатывает сложение и вычитание.
 *
 * Функция term{) обрабатывает умножение и деление аналогично тому, как
 * ехрг {) обрабатывает сложение и вычитание:
 *
 * Функция prim(), обрабатывающая первичные элементы, похожа на ехрг()
 * и term (), но поскольку тут мы забрались ниже по иерархии вызовов
 * некоторая реальная работа уже выполняется (и цикл не нужен).
 *
 * функции ехрг{),
 * которая вызывает term {), которая вызывает prim {), которая вызывает ехрг {).
 *
 * Входные данные для парсера поставляет функция get token (). Самый
 * последний возврат функции gettokenO хранится в глобальной переменной curr_tok,
 * имеющей тип перечисления Token_value:
 * Когда встречается NUMBER (то есть целый литерал или литерал с плавающей
 * запятой), возвращается его значение. Вводимое функцией get_token () значение
 * помещается в глобальную переменную number value.
 * Аналогично тому, как последнее значение NUMBER хранится в переменной
 * number value, строковое представление последнего NAME хранится в string value.
 * Прежде, чем обработать имя, калькулятору нужно заглянуть вперед и узнать, как
 * это имя используется — читается или оно участвует в операции присваивания.
 * В любом случае происходит обращение к таблице символов, имеющей тип тар
 *
 * Из-за того, что наша программа чрезвычайно проста, обработка ошибок для нее
 * не является предметом первостепенного интереса. Наша функция обработки
 * ошибок просто подсчитывает их количество, выводит сообщение и завершает работу:
 *
 *
 *
 *
 *
 *
 */
#include "m_types.h" // собственные типы данных.
#include <fstream>   // файловые потоки и операции
#include <iostream>  // I/O (ввод/вывод), cin, cout, cerr, и т д.
#include <cstdlib>   // exitQ, и т.д.
#include <string>    // For std::string overloads.
#include <cctype>    // isalphaQ, и т.д.
#include <map>       // map (ассоциативные массивы)
#include <algorithm> // алгоритмы для работы с STL классами vector, map, string и т.д.
//#include <sstream>  // for stringstream
 
using namespace std;
using namespace M_Types;
 
map<string, double>     table;
istream*                input=0; //указатель на поток ввода
ostream*                    output=0;
 
namespace Error
{
    int no_of_errors;   // Подсчет количества ошибок при парсинге.
    struct Zero_divide
    {
        Zero_divide() { no_of_errors++; }
    };
 
    struct Syntax_error
    {
        const char* p ;
        Syntax_error(const char* q) { p = q; no_of_errors++; }
    };
}
 
namespace Lexer
{
    enum Token_value
    {
        NAME, NUMBER, END,
        PLUS='+', MINUS='-', MUL='*',  DIV='/',
        PRINT=';', ASSIGN='=', LP='(', RP=')'
    };
    Token_value             curr_tok = PRINT;
    double                  number_value=0;
    string                  string_value;
    word                        curr_line=0;
    Token_value get_token();
    Token_value get_token ()
    {
        char ch=0;
 
        do
        { // пропустить все пробельные символы кроме '\п'
            if( !input->get(ch) ) return curr_tok = END;
        }while ( ch !='\n' && isspace(ch) ) ;
 
 
        switch (ch)
        {
            case 0:
                return curr_tok=END;
            case ';' :
            case '\n' :
                return curr_tok=PRINT;
            case ':' :
            case '*' :
            case '/' :
            case '+' :
            case '-' :
            case '(' :
            case ')' :
            case '=' :
                return curr_tok=Token_value(ch);
            case '0' : case 'i' : case '2' : case '3' : case '4' :
            case '5' : case 'б' : case '7' : case '#' : case '9' :
            case '.' :
                input->putback(ch);
                (*input)>>number_value;
                return curr_tok=NUMBER ;
            default: //NAME, NAME=, или ошибка
                if (isalpha (ch) )
                {
                    string_value=ch;
                    while ( input->get(ch) && isalnum(ch) )
                        string_value.push_back(ch);
                    input->putback(ch) ;
                    return curr_tok=NAME;
                }
                throw Error::Syntax_error("bad token");
    //          return curr_tok=PRINT;
 
        }
    }
}
namespace Parser
{
    double expr(bool);
    double prim(bool);
    double term(bool);
 
    using namespace Lexer; // сделать все имена из Lexer доступными
    using namespace Error; // сделать все имена из Error доступными
 
 
    double prim (bool get) // обработка первичных выражений
    {
        if (get) get_token();
        switch (curr_tok)
        {
            case NUMBER:
            {
                double v = number_value;
                get_token () ;
                return v;
            }
            case NAME:
            {
                double& v = table[string_value];
                if (get_token () == ASSIGN) v = expr(true) ;
                return v;
            }
            case MINUS: //унарный минус
                return -prim (true) ;
            case LP:
            {
                double e = expr (true) ;
                if(curr_tok != RP) throw Error::Syntax_error(" ' ) ' expected") ;
                get_token(); // пропустить ')'
                return e;
            }
            default:
                throw Error::Syntax_error("primary expected");
        }
    }
 
 
    double term(bool get) //умножение и деление
    {
        double left = prim (get) ;
        for( ; ; )
            switch (curr_tok)
            {
                case MUL :
                    left *= prim (true) ;
                    break;
                case DIV:
                    if (double d = prim (true) )
                    {
                        left /= d;
                        break;
                    }
                    throw Zero_divide();
                default:
                    return left;
            }
    }
 
 
    double expr(bool get) // сложение и вычитание
    {
        double left = term(get);
        for( ; ; ) //"вечно"
            switch (curr_tok)
            {
                case PLUS:
                    left += term(true) ;
                    break;
                case MINUS:
                    left -= term(true) ;
                    break;
                default:
                    return left;
            }
    }
 
}
namespace Parser_Interface
{
    double expr(bool);
 
    double expr(bool get)
    {
        return Parser::expr(get);
    }
}
 
void skip()
{
    while (*input) //пропускать символы, пока не встретятся newline-или;
    {
        char ch ;
        input->get(ch);
        switch (ch)
        {
            case '\n' :
            case ';' :
                return ;
        }
    }
}
 
 
int main(int argc, char* argv[])
{
 
    table[ "pi" ] =3.1415926535897932385; // вводим предопределенные имена
    table[ "е" ] =2.7182818284590452354;
    //input = &cin;
    input  = new ifstream("input.txt");
    output = new ofstream("result.txt", ios_base::trunc);
    double res=0;
 
    using namespace Lexer;
 
 
    while (*input)
    {
        try
        {
 
            get_token();
            if (curr_tok==END) break;
            if (curr_tok==PRINT)    continue;
            curr_line++;
            res = Parser_Interface::expr(false);
            *(output)<<curr_line<<": "<<res<<endl;
        }
        catch(Error::Zero_divide e)
        {
            *(output)<<"error: "<<"Zero Divided"<<". At line : "<<curr_line<<endl;
            if (curr_tok != PRINT)  skip();
        }
        catch(Error::Syntax_error e)
        {
            *(output)<<"error: "<<e.p<<". At line : "<<curr_line<<endl;
            if (curr_tok != PRINT) skip();
        }
    }
 
    if (input != &cin)
        delete input;
    if (output != &cout)
        delete output;
 
    exit(Error::no_of_errors);
    return Error::no_of_errors;
}

пример входного файла и результат :
input.txt :
Кликните здесь для просмотра всего текста

r=2.5
area = pi*r*r;
bad_line=45)123
el=45+345.12354;
t=5/0;


result.txt :
Кликните здесь для просмотра всего текста

1: 2.5
2: 19.635
error: bad token. At line : 3
4: 390.124
error: Zero Divided. At line : 5

Искренне желаю удачи.
0
Модератор
2131 / 1000 / 170
Регистрация: 23.07.2018
Сообщений: 3,349
Записей в блоге: 3
05.09.2020, 04:53
Катя6, лексический анализ - это выделение в тексте лексем ( "слов" ) языка,
и определение, к кому классу лексем ( "части речи" ) они относятся.
Пропуск ( игнорирование ) ничего не обозначающих последовотельностей букв и знаков ( например, комментариев и цепочек пробелов ).
А также диагностика ошибок, выявление последовательностей символов, которые не могут быть правильными словами языка ( содержат недопустимые символы или недопустимые последовательности допустимых букв ).
( К "словам" языков программирования относятся и таки "составные" знаки, как ++, :=, -> и т.п. )

В приведённом SmallEvil, примере это приблизительно то, чем занимается Lexer.

Например лексический анализатор с++ мог бы выделить в следующем тексте
C++
1
2
3
4
5
6
7
8
9
10
namespace Lexer
{
    enum Token_class
    {
        VAR,  переменная,  FOR,     
        L_PLUS ='++',
        PLUS='+',  COMMA = ',',
    };
 
}
такую последовательность лексем:
Code
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
зарезервированное_ключевое_слово_namespace
идентификатор ( "Lexer" )
{
зарезервированное_ключевое_слово_enum
идентификатор ( "Token_class" )
{
идентификатор ( "VAR" )
,
идентификатор ( "переменная" )
,
идентификатор ( "FOR" )
,
идентификатор ( "L_PLUS" )
=
символьная_константа ("++" )
,
идентификатор ( "PLUS" )
=
символьная_константа ("+"идентификатор ( "PLUS" )
=
символьная_константа ("+" )
,
 
 )
,
идентификатор ( "COMMA" )
=
символьная_константа ("," )
,
}
;
}
Теоретически, чтобы выполнить данное задание на С++, должно быть достаточно знакомства с регулярными выражениями (regexp).
Но для начала нужно уточнить правила языка, который Вы будете разбирать.
Определиться с алфавитом языка : допустимы в нём смайлики или нет ?
А если допустимы, то можно ли их использовать в именах параметров циклов и процедур.

Ещё желательно уточнить, по какому курсу это задание.
Это просто упражнение по c++ или предполагается дальнейшее развитие проекта на основе выполненного лексического анализатора?
0
0 / 0 / 0
Регистрация: 18.03.2019
Сообщений: 689
05.09.2020, 21:06  [ТС]
politoto, Ну я думаю, что про смайлики не нужно ничего придумывать в этом задании, потому что там нет об этом ничего. Задание это по курсу "Теория автоматов, формальных языков и транляции". И да, это просто упражнение по с++ из лабораторной работы
0
Модератор
2131 / 1000 / 170
Регистрация: 23.07.2018
Сообщений: 3,349
Записей в блоге: 3
06.09.2020, 12:40
Если курс "формальных языков и транляции", а не просто программирования на с++, то за этой работой могут последовать работа по синтаксическому анализу, а за ней другая, и вся серия лабораторных работ может завершиться курсовой работой по разработке упрощённого компилятора или интерпретатора упрощённого языка.

Поэтому к этой работе есть смысл подготовиться с учётом возможного продолжения.
про смайлики не нужно ничего придумывать в этом задании, потому что там нет об этом ничего
В требованиях ничего не написано и о таких конструкциях языка, как <операторы программы>, <список переменных через запятую >, <тело процедуры>, <операторы>, тело цикла>, <имя параметра цикла>,<имя процедуры>.
А для реализации класса лексического анализатора нужно, как минимум, знать, какие лексемы могут встретиться в этих конструкциях.

Так, из требования 4 очевидно, что в языке есть лексемы VAR, INTEGER, BEGIN, END, :, а также все те лексемы, которые могут встретиться в конструкциях <список переменных через запятую > и <операторы программы>.

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

Например, такую тестовую программку:
Code
1
2
3
VAR a,b,: INTEGER  BEGIN 
    IF a<b THEN BEGIN  END
END
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
06.09.2020, 12:40
Помогаю со студенческими работами здесь

Разработать имитационную программу для анализа работы склада в течение календарного года
ЗАДАНИЕ: a b c e 12 330 45 9 GPSS не нашел PARKING_OUT storage 5 PARKING_IN storage 3 STORE storage 330

Друзья, подскажите где найти исходник лексического анализатора для языка C++!
Очень нужен исходник лексического анализатора языка С++. Есть он где-то в открытом доступе? Может знает кто-нибудь где его скачать можно?...

С помощью языка программирования С++ разработать тестовую оболочку
Как с помощью языка программирования С++ разработать тестовую оболочку? Пожалуйста помогите...

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

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


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

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Новые блоги и статьи
Отправка уведомления на почту при изменении наименования справочника
Maks 24.03.2026
Программная отправка письма электронной почты на примере изменения наименования справочника "Склады" в конфигурации БП3. Перед реализацией необходимо выполнить настройку системной учетной записи. . .
модель ЗдравоСохранения 5. Меньше увольнений- больше дохода!
anaschu 24.03.2026
Теперь система здравосохранения уменьшает количество увольнений. 9TO2GP2bpX4 a42b81fb172ffc12ca589c7898261ccb/ https:/ / rutube. ru/ video/ a42b81fb172ffc12ca589c7898261ccb/ Слева синяя линия -. . .
Midnight Chicago Blues
kumehtar 24.03.2026
Такой Midnight Chicago Blues, знаешь?. . Когда вечерние улицы становятся ночными, а ты не можешь уснуть. Ты идёшь в любимый старый бар, и бармен наливает тебе виски. Ты смотришь на пролетающие. . .
Контроль уникальности заводского номера - вариант №2
Maks 24.03.2026
В отличие от предыдущего варианта добавлено прерывание циклов, также добавлены новые переменные для сохранения контекста ошибки перед прерыванием цикла: Процедура ПередЗаписью(Отказ, РежимЗаписи,. . .
SDL3 для Desktop (MinGW): Вывод текста со шрифтом TTF с помощью библиотеки SDL3_ttf на Си и C++
8Observer8 24.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-text-sdl3-c. zip finish-text-sdl3-cpp. zip
Жизнь в неопределённости
kumehtar 23.03.2026
Жизнь — это постоянное существование в неопределённости. Например, даже если у тебя есть список дел, невозможно дойти до точки, где всё окончательно завершено и больше ничего не осталось. В принципе,. . .
Модель здравоСохранения: работники работают быстрее после её введения.
anaschu 23.03.2026
geJalZw1fLo Корпорация до введения программа здравоохранения имела много невыполненных работниками заданий, после введения программы количество заданий выросло. Но на выплатах по больничным это. . .
Контроль уникальности заводского номера - вариант №1
Maks 23.03.2026
Алгоритм контроля уникальности заводского (или серийного) номера на примере документа выдачи шин для спецтехники с табличной частью в конфигурации КА2. Данные берутся из регистра сведений, по. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru