Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 1509, средняя оценка - 4.80
#pragma
Временно недоступен
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
#1

Пишем свой интерпретатор языка BASIC - C++

20.06.2009, 20:03. Просмотров 191047. Ответов 464
Метки нет (Все метки)

*****************
Благодаря форуму и Evg в частности интерпретатор развивается, потихоньку превращаясь в простенький интерпретатор QBASIC.
Некоторые из самых старых версий сохранились в теме и ссылки на них будут добавлены в это сообщение,а также ссылки на другие темы,связанные с этой.

Репозиторий с проектом находится тут, там же есть возможность в браузере посмотреть историю ревизий (английский в логах весьма примитивен,комментарии и рекомендации можете писать в личку),а также скачать самый последний архив репозитория в формате .tar.gz
Если кто-то пользуется Subversion,скачать исходники можно так:
Код
svn co https://basin.svn.sourceforge.net/svnroot/basin basin
Эти темы возникли в результате моих вопросов по ходу написания:
Технический приём для формирования согласованных данных
Makefile: как с использованием gcc строить автоматические зависимости от .h файлов?
Вопрос по svn (Subversion)
Создание системы тестирования ПО.
Вопрос про разные реализации бэйсиков
Можно ли выразить порядковый номер элемента массива через индексы?
[C++] Какие флаги указать линкеру для компиляции программы?
Как можно определить переменную в файле configure.in,чтобы её можно было использовать в Makefile?
Странный SIGSEGV, или что зависит от порядка написания интерфейса класса
[C++]Можно ли как-то указать в Makefile,чтобы часть файлов компилировал компилятор C?
Альтернативная версия интерпретатора от Evg на C
Это простая реализация разбора выражений, написанная Evg на C:
Представление выражения в двоичном дереве
*****************
Первое сообщение:
*****************
Задание(Страуструп,из книги,по готовому коду): Введите программу калькулятора и заставьте её работать.Например,при вводе
C++
1
2
r = 2.5
area = pi*r*r
Программа калькулятора выведет:
C++
1
2
2.5
19.635
Получили такой код:
LexicalAnalyzer.h
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
// LexicalAnalyzer.h
#ifndef LEXICALANALYZER_H_INCLUDED
#define LEXICALANALYZER_H_INCLUDED
 
#include <cctype>
#include <string>
#include <map>
#include <iostream>
 
enum Token_value {
    NAME,       NUMBER,      END,
    PLUS = '+', MINUS = '-', MUL = '*', DIV = '/',
    PRINT = ';',ASSIGN = '=',LP = '(',  RP = ')'
};
extern Token_value curr_tok;
extern std::map<std::string,double>table;
extern int no_of_errors;
 
Token_value get_token();
 
double expr(bool);
double term (bool);
double prim (bool);
int error(const std::string&);
 
#endif // LEXICALANALYZER_H_INCLUDED

LexicalAnalyzer.cpp
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
// LexicalAnalyzer.cpp
#include "LexicalAnalyzer.h"
 
 
std::map<std::string,double>table;
Token_value curr_tok=PRINT;
 
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;
        }
}
 
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 /= prim (true);
                     break;
                 }
                 return error("Деление на ноль");
            default:
                 return left;
        }
}
 
double number_value;
std::string string_value;
 
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) return error("Ожидалась )");
            get_token();
            return e;
        }
        default:
            return error("Ожидалось первичное выражение");
    }
}
 
Token_value get_token()
{
    char ch = 0;
 
    do {
        if (!std::cin.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 '=':
             return Token_value(ch);
        case '0':case '1':case '2':case '3':case '4' :
        case '5':case '6':case '7':case '8':case '9':case '.':
             std::cin.putback(ch);
             std::cin>>number_value;
             return curr_tok=NUMBER;
        default:
             if (isalpha(ch)) {
                 string_value = ch;
                 while (std::cin.get(ch)&&isalnum(ch)) string_value.push_back(ch);
                 std::cin.putback(ch);
                 return curr_tok = NAME;
             }
             error ("Неправильная лексема");
             return curr_tok = PRINT;
    }
}
int no_of_errors=0;
int error (const std::string& s)
{
    no_of_errors++;
    std::cerr<<"Ошибка: "<<s<<'\n';
    return no_of_errors;
}

main.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// main.cpp
#include "LexicalAnalyzer.h"
 
 
int main()
{
    table["pi"]=3.1415926535897932385;
    table["e"]=2.7182818284590452354;
    while (std::cin) {
        get_token();
        if (curr_tok==END) break;
        if (curr_tok==PRINT) continue;
        std::cout<<expr(false)<<'\n';
    }
    return no_of_errors;
}

Анализатор-то работает,но конечное значение не вычисляется.Более того,если вводим
C++
1
a = 3 + 6
,то получаем "a", равное первому элементу в выражении,то есть 3.В чём логическая ошибка данной программы?С этими каскадными вызовами она слегка запутана.Уверен,что кто-то уже делал это задание.

Добавлено через 2 часа 5 минут 30 секунд
Пришлось решать влоб с дебаггером.У Страуструпа опечатка (или намеренная ошибка,что более вероятно ) Вот в этом куске кода в функции get_token():
C++
1
2
        case '*':case'/':case '+':case '-':case '(':case ')':case '=':
             return Token_value(ch);
Нехватает смены значения curr_tok,что и приводит к ошибочной работе.
C++
1
2
        case '*':case'/':case '+':case '-':case '(':case ')':case '=':
             return curr_tok=Token_value(ch);
Теперь всё пашет,всем спасибо,вопрос можно считать закрытым,но есть вопрос поважнее: В функциях prim и term возвращается int при ошибке,но ведь они имеют тип double,как вообще это работает?Происходит неявное преобразование типа,так?Мне интересно,почему Страуструп прибег к такому способу,это распространённая практика?

Добавлено через 16 минут 19 секунд
И ещё опечатка была
C++
1
2
3
                 if (double d = prim (true)) {
                     left /= d;// было left /= prim (true)
                     break;
30
Лучшие ответы (1)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
20.06.2009, 20:03
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Пишем свой интерпретатор языка BASIC (C++):

Пишем свой чекер - C++
Я хочу написать свой чекер, но не знаю с чего начать? Кто знает основные принцип работы чекеров прошу объясните.

пишем свой троян с нуля - C++
Всем привет)))соглашусь, что изобретаю велосипед, но хочется сделать все своими ручками не прибегая к open source и т.п. для повышения...

Пишем свой класс, спецификатор доступа protected - C++
Всем привет! Из книги Р. Лафоре относительно спецификатора доступа protected: Далее пишется следующее: Возникает вопросы:...

Не удается откомпилировать интерпретатор М-языка - C++
Задача: взять интерпретатор М-языка на сайте http://cmcmsu.no-ip.info/2course/model.lang.parser.sample.htm и переработать его, добавив в...

Интерпретатор небольшого языка программирования на С++ - C++
Здравствуйте, уважаемые форумчане! Я тут где-то год назад прочитал тему Evg и #pragma о создании интерпретатора, меня эта тема очень...

Написать Интерпретатор Программного Языка(собственного) - C++
Здраствуйте! Кто знает C++ помогите пожалуйста с реализацией данного задания!!! Пожалуйста, очень надо. сроки поджимают. Есть...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Ensase
Флудер
191 / 29 / 5
Регистрация: 23.03.2007
Сообщений: 335
20.06.2009, 20:06 #2
вот сейчас открыл книгу - нет там никакой опечатки, всё верно. это у вас была опечатка
а неявное преобразование для кода ошибки вполне приемлемо
10
#pragma
Временно недоступен
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
21.06.2009, 12:26  [ТС] #3
Значит,у вас версия книги новее))
6
CheshireCat
Эксперт С++
2892 / 1241 / 78
Регистрация: 27.05.2008
Сообщений: 3,370
21.06.2009, 12:30 #4
Странный какой-то дебаггер..... Если условие (1) выполнилось, происходит не переход к switch, а выход из функции get_token() с возвратом значения END.
8
#pragma
Временно недоступен
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
21.06.2009, 12:32  [ТС] #5
Да,я уже понял,что ступил)
6
Evg
Эксперт CАвтор FAQ
17809 / 6019 / 388
Регистрация: 30.03.2009
Сообщений: 16,535
Записей в блоге: 26
21.06.2009, 21:58 #6
#pragma, а ты все задания просто передираешь из книги или всё-таки что-то пытаешься сделать сам? Вопрос задаю НЕ с целью, чтобы сказать "ай-ай-ай". Просто ты уже кучу вопросов вских задавал. Если ты действительно решил серьёзно занаться программированием, то постараюсь отвечать ещё более развёрнуто. Если интерес несерьёзный - то как обычно
9
#pragma
Временно недоступен
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
21.06.2009, 23:27  [ТС] #7
Цитата Сообщение от Evg Посмотреть сообщение
#pragma, а ты все задания просто передираешь из книги или всё-таки что-то пытаешься сделать сам? Вопрос задаю НЕ с целью, чтобы сказать "ай-ай-ай". Просто ты уже кучу вопросов вских задавал. Если ты действительно решил серьёзно занаться программированием, то постараюсь отвечать ещё более развёрнуто. Если интерес несерьёзный - то как обычно
Конечно,пытаюсь делать сам(в этом примере первым порывом было написать вообще по-своему),просто такое задание в книге(я учусь по ней и стараюсь выполнить все задания для начала) - заставьте работать данный код калькулятора,ну что я могу сделать? )) Просто в данном конкретном случае я немного не дотянул до решения,надо было ещё немного поковырять код до понимания(буду стараться впредь).Я даже специальную тему поднял,типа почему нельзя писать [решено] в первом сообщении темы,чтобы другие не тратили на это время.Согласен,некоторые мои вопросы из разряда тех,что "вот тут недодумал,вот тут недонапрягся",но некоторые действительно требуют хороших ответов.Я учусь сам,посоветоваться не с кем,надеюсь только на лучшее,и очень ценю любую помощь,особенно помощь настоящих хакеров.Интерес серьёзный,хочу достигнуть хорошего уровня.Не только в С++,но в программировании вообще.
P.S.Твоё "как обычно" тоже круто для меня )) но мотаю на ус всё сказанное и написанное)
4
Evg
Эксперт CАвтор FAQ
17809 / 6019 / 388
Регистрация: 30.03.2009
Сообщений: 16,535
Записей в блоге: 26
22.06.2009, 12:06 #8
> но мотаю на ус всё сказанное и написанное)

Ну вот это самое главное. Остальное со временем придёт

Добавлено через 12 часов 27 минут 44 секунды
Наверное в страуструпе есть и дальнейшее развитие этой задачи. Со своей стороны могу дыть 3 предложения по дальнейшему апгрейду
4
#pragma
Временно недоступен
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
22.06.2009, 22:28  [ТС] #9
Цитата Сообщение от Evg Посмотреть сообщение
Наверное в страуструпе есть и дальнейшее развитие этой задачи. Со своей стороны могу дыть 3 предложения по дальнейшему апгрейду
Пиши.
3
Evg
Эксперт CАвтор FAQ
17809 / 6019 / 388
Регистрация: 30.03.2009
Сообщений: 16,535
Записей в блоге: 26
22.06.2009, 23:44 #10
По возрастающей сложности (как мне кажется)

1. Работать со входным файлом (т.е. фактически получается некий простенький интерпретатор). Выдавать пользовательские ошибки с прявязкой к исходнику: т.е. печатать имя файла, номер строки, номер позиции в строке (последнее некритично), суть ошибки. Использование неинициализированной переменной считать ошибкой. При этом добавить конструкцию "print <var_name>". На вход программы подаём имя файла с текстом программы, которую будем интерпретировать

2. Заменить плавающий типа (double) на целочисленный и добавить операции битовой арифметики: & | ~ << >>. Приоритет операций такой же, как и в си (можешь посмотреть в том страуструпе).

3. Сделать типизацию. Т.е. понимать как плавающие типы, так и целые. При первой записи в перменную, её тип вычисляется по типу выражения, стоящей в правой части присваивания. Т.е. для "a = 5" переменная a заводится как целочисленная, для "a = 5.0" - как плавающая. Все дальнейшие присваивания в переменную делаются с учётом типа. Т.е. если изначально переменная была как целочисленная, то операция "a = 23.2" означает запись целого значения 23 (потому как a целое).

При вычислении двухоперандногй операции выражения, второй операнд должен приводиться к типу первого операнда. Т.е. "12 + 34.5" должно вычисляться как (пишу в терминах си) "12 + (int)34.5", а "12.1 + 7" должно вычисляться как "12.1 + (float)7". При попытке построения битовых операций над плавающим типом выдавать ошибку (ибо считаем, что битовые типы разрешены только для целых чисел)

Может быть эти задания тебе покажутся сложными, но всё же рекомендую сделать все три. Потому что это тебе сильно поможет в освоении проектирования программ. Если от этого не устанешь, а меня не заломает - попробуем дальше это дело наворотить. Таким образом, писать программу следует с учётом того, что её функциональность будет расширяться - это ещё добавит экспы в части проектирования. Да и на своих же ошибках, возможно, начнёшь лучше понимать, как НЕ надо делать
5
#pragma
Временно недоступен
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
25.06.2009, 19:10  [ТС] #11
Итак,после длительного биения об стену ,можно подвести предварительный итог:
1)Программа читает входной файл,но как она это делает,я понятия не имею,потому что делал по описанию библиотеки из и-нета http://www.cplusplus.com
2)Есть некое подобие привязки к исходнику,есть сообщение об ошибке,но иногда работает некорректно из-за этих каскадных вызовов...
3)Я попытался добавить возможность программируемых пользователем функций,но в самом конце выяснилось,что это не работет,опять же из-за подобия рекурсии.Так как анализ посимвольный,после знака $ должно происходить вычисление,но при последующем вызове expr(true) происходит дальнейшее чтение строки и в итоге ошибка.
4)В функции get_resulting_expr (она ещё не доделана) ошибка в алгоритме(не заменяется последний параметр).
5)Задания твои я попытаюсь сделать,просто я ещё,например,понятия не имею о битовых операциях.
6)В-общем,пока не знаю,как всё это разгребать.Писалось всё это с целью просто сделать,хотя бы сделать,а не как сделать...На данный момент есть код:

LexicalAnalyzer.h
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
#ifndef LEXICALANALYZER_H_INCLUDED
#define LEXICALANALYZER_H_INCLUDED
 
#include <cctype>
#include <string>
#include <map>
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <fstream>
 
 
extern    std::ifstream source;
 
enum Token_value {
    NAME,       NUMBER,      END,       FUNC = '$',
    PLUS = '+', MINUS = '-', MUL = '*', DIV = '/',
    PRINT = ';',ASSIGN = '=',LP = '(',  RP = ')',
    BEGIN_FUNC = '@',                END_FUNC = '|'
};
 
typedef std::map<std::string,int>Map_of_names;
 
extern Token_value curr_tok;
extern std::map<std::string,double>table;
extern std::string string_value;
extern std::map<std::string,int>func_name;
extern std::vector<std::string>func_value;
extern std::map<std::string,int>func_num_of_param;
extern std::string get_resulting_expr(std::string,std::string,std::string,int);
extern int no_of_errors;
extern int string_number;
 
Token_value get_token();
 
double expr(bool);
double term (bool);
double prim (bool);
int error(const std::string&);
 
#endif // LEXICALANALYZER_H_INCLUDED

LexicalAnalyzer.cpp
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
#include "LexicalAnalyzer.h"
 
 
std::map<std::string,double>table;
Token_value curr_tok=PRINT;
 
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;
        }
}
 
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;
                 }
                 return error("Деление на ноль");
            default:
                 return left;
        }
}
 
double number_value;
std::string string_value;
std::map<std::string,int>func_name;
std::vector<std::string>func_value;
std::map<std::string,int>func_name_to_param;
std::ifstream source;
int string_number=0;
 
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 FUNC:{
            double e = expr(true);
            return e;
        }
        case MINUS:
            return -prim(true);
        case LP:{
            double e = expr(true);
            if (curr_tok!=RP) return error("Ожидалась )");
            get_token();
            return e;
        }
        default:
            return error("Ожидалось первичное выражение");
    }
}
 
Token_value get_token()
{
    char ch = 0;
 
    do {
        if (!source.get(ch)) return curr_tok = END;
 
    } while (ch!='\n'&&isspace(ch));
 
    switch (ch) {
        case 0:
                 return curr_tok = END;
 
        case ';':
                 return curr_tok = PRINT;
        case '\n':
                 ++string_number;
                 return curr_tok = PRINT;
 
        case '*':case '/':case '+':case '-':case '(':case ')':
        case '=':
                 return curr_tok=Token_value(ch);
 
        case '0':case '1':case '2':case '3':case '4' :
        case '5':case '6':case '7':case '8':case '9':case '.':
                 source.putback(ch);
                 source>>number_value;
                 return curr_tok = NUMBER;
 
        case '@':{
                 // Writing whole string to build a function.
                 // @ - reserved sign for start user function
                 // programming.
 
                 // Copying whole function string to tmp
                 std::string tmp;
                 tmp = ch;
                 while (source.get(ch)&&ch!='\n') tmp.push_back(ch);
                 source.putback(ch);
 
                 // Set useful places in the string
                 unsigned int i = find(tmp.begin(),tmp.end(),'(')-tmp.begin();
                 unsigned int k = find(tmp.begin(),tmp.end(),')')-tmp.begin();
 
                 // There must be parameters list in the function
                 if (i==tmp.size()||k==tmp.size())
                 {
                     error("Ожидался список параметров");
                     return curr_tok = PRINT;
                 }
 
                 // Checking function name for previous declaration
                 std::string s = tmp.substr(1,i-1);
                 Map_of_names::iterator it = ::func_name.find(s);
                 if (it != ::func_name.end())
                 {
                     error("Повторное определение функции");
                     return curr_tok = PRINT;
                 }
                 else
                 {
                    // Declaration
                    unsigned int j = find(tmp.begin(),tmp.end(),'{')-tmp.begin();
 
                    // Function must have body
                    if (j==tmp.size())
                    {
                        error("Ожидалась {");
                        return curr_tok = PRINT;
                    }
 
                    // Not empty body
                    if (tmp.substr(j+1,tmp.size()-j-2).size()<1)
                    {
                        error("Пустая функция");
                        return curr_tok = PRINT;
                    }
 
                    // At start of parameters list,as at the end,
                    // have to be an alphabet character
                    std::string param_list = tmp.substr(i+1,k-i-1);
                    if (isalpha(param_list.at(0))&&isalpha(param_list[param_list.size()-1]))
                    {
                        // Function template creation
                        ::func_name_to_param[s] = count(param_list.begin(),param_list.end(),',')+1;
                        ::func_name[s];
                        ::func_value.push_back(tmp.substr(i,tmp.size()-i));
                        //std::cout<<::func_value[0]<<std::endl;
                    }
                    else
                        error("Неправильный список параметров");
                        return curr_tok = PRINT;
                 }
                 return curr_tok = PRINT;
             }
        case '}':{
                 // End of user function
                 return curr_tok = PRINT;
             }
        case '$':{
                 // $ - reserved for starting to calculate
                 // function that was programmed before
 
                 // Writing function with parameters
                 // that we need to calculate to tmp
                 std::string tmp;
                 tmp = ch;
 
                 while (source.get(ch)&&(ch != '\n')) tmp.push_back(ch);
                 if (ch=='\n') ++string_number;
                 source.putback(ch);
 
                 // Set useful places in the string
                 unsigned int i = find(tmp.begin(),tmp.end(),'(')-tmp.begin();
                 unsigned int k = find(tmp.begin(),tmp.end(),')')-tmp.begin();
 
                 // Checking for function was declared before
                 std::string nm_tmp = tmp.substr(1,i-1);
                 Map_of_names::iterator it = ::func_name.find(nm_tmp);
                 if (it == ::func_name.end())
                 {
                     error("Функция не была объявлена ранее");
                     return curr_tok = PRINT;
                 }
                 else
                 {
                     std::string param_list = tmp.substr(i+1,k-i-1);
                     if (isalnum(param_list[0])&&isalnum(param_list[param_list.size()-1]))
                     {
                         // Count parameters and checking amount of
                         // parameters in declared function
                         int param_count = count(param_list.begin(),param_list.end(),',')+1;
                         if (param_count> ::func_name_to_param[nm_tmp]||
                             param_count< ::func_name_to_param[nm_tmp])
                         {
                             error("Неправильное количество параметров функции");
                             return curr_tok = PRINT;
                         }
                         ///////////////////////////////////////////
                         /**  Our function is "OK".               */
                         ///////////////////////////////////////////
                         std::string main_param_list = ::func_value[::func_name[nm_tmp]].substr(1,
                                                                                         ::func_value[::func_name[nm_tmp]].find_first_of(')',1)-1);
 
                         std::string result_expr = get_resulting_expr(param_list,
                                                                      main_param_list,
                                                                      ::func_value[::func_name[nm_tmp]],
                                                                      ::func_name_to_param[nm_tmp]);
                         result_expr.push_back('\n');
 
                         for (int j = result_expr.size()-1; j >= 0; --j)
                         source.putback(result_expr[j]);
                         return  curr_tok = FUNC;
 
                     }
                     else
                     {
                         error("Неверный параметр функции");
                         return curr_tok = PRINT;
                     }
                 }
                 return curr_tok = FUNC;
             }
        default:
             if (isalpha(ch)) {
                 ::string_value = ch;
                 while (source.get(ch)&&isalnum(ch)) ::string_value.push_back(ch);
                 source.putback(ch);
                 return curr_tok = NAME;
             }
             error ("Неправильная лексема");
             return curr_tok = PRINT;
    }
}
int no_of_errors=0;
int error (const std::string& s)
{
    ::no_of_errors++;
    std::cerr<<"Строка: "<<string_number<<" Ошибка: "<<s<<'\n';
    return 0;
}

param_swapper.cpp
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
#include "LexicalAnalyzer.h"
 
// Function get parameters and temlate in
// strings of two functions and returns
// resulting string as expression for
// future calculation
// Просто жесть
 
std::string get_resulting_expr(std::string s_son_par,
                               std::string s_father_par,
                               std::string s_father_expr,
                               int param_count)
{
    std::string resulting_expr;
    if (param_count==1)
    {
        //To be continued?
    }
    else
    {
        // Store parameters
        std::vector<std::string>tmp_son_par;
        std::vector<std::string>tmp_father_par;
 
        // Using iterators to find parameters
        std::string::iterator iter_s_son = find(s_son_par.begin(),s_son_par.end(),',');
        std::string::iterator iter_s_father = find(s_father_par.begin(),s_father_par.end(),',');
 
        // First parameter
        tmp_son_par.push_back(s_son_par.substr(0,(iter_s_son-s_son_par.begin())));
        tmp_father_par.push_back(s_father_par.substr(0,(iter_s_father-s_father_par.begin())));
 
        if (param_count > 2)
        {
           // All parameters exept first and last
           for (int i = 1; i < param_count-1; ++i)
           {
               iter_s_son = find(iter_s_son,s_son_par.end(),',');
               iter_s_father = find(iter_s_father,s_father_par.end(),',');
               tmp_son_par.push_back(s_son_par.substr(iter_s_son-s_son_par.begin(),
                                                 (find(iter_s_son,s_son_par.end(),',')-iter_s_son)-1));
               tmp_father_par.push_back(s_father_par.substr(iter_s_father-s_father_par.begin(),
                                                 (find(iter_s_father,s_father_par.end(),',')-iter_s_father)-1));
           }
 
           // Last parameter
           tmp_son_par.push_back(s_son_par.substr(iter_s_son-s_son_par.begin(),
                                                  iter_s_son-s_son_par.end()));
           tmp_father_par.push_back(s_father_par.substr(iter_s_father-s_father_par.begin(),
                                                        iter_s_father-s_father_par.end()));
        }
        if (param_count == 2)
        {
           // Second parameter
           tmp_son_par.push_back(s_son_par.substr(iter_s_son-s_son_par.begin(),
                                                  iter_s_son-s_son_par.end()));
 
           tmp_father_par.push_back(s_father_par.substr(iter_s_father-s_father_par.begin(),
                                                        iter_s_father-s_father_par.end()));
        }
 
        // Finally replace parameters from son
        // to father expression
        unsigned int pos   = 0;
        unsigned int l=s_father_expr.size();
        for (int i = 0; i < param_count;++i)
        {
            for (pos = 0;pos < l;)
            {
                // There is a mistake in algorithm.
                // Last parameter isnt getting swapped.
                pos=s_father_expr.find(tmp_father_par.at(i));
                if (pos>l)break;
                s_father_expr.replace(pos,tmp_father_par.at(i).size(),tmp_son_par.at(i));
 
            std::cout<<s_father_expr<<std::endl;
            }
        }
        // Using now useless pos
        pos = s_father_expr.find_first_of('{',0);
        resulting_expr = s_father_expr.substr(pos+1,s_father_expr.size()-pos-2);
    }
    std::cout<<resulting_expr<<std::endl;
    return resulting_expr;
}

main.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "LexicalAnalyzer.h"
 
 
int main()
{
    table["pi"]=3.1415926535897932385;
    table["e"]=2.7182818284590452354;
    source.open("program.clc",std::ifstream::in);
    while (source.good()) {
        get_token();
        if (curr_tok==END) break;
        if (curr_tok==PRINT) continue;
        std::cout<<expr(false)<<'\n';
    }
    source.close();
    return 0;
}

Входные данные в файле program.clc
program.clc
C++
1
2
3
4
5
a=1
b=2
a+b
@f(c,d){c+d*7}
$f(a,b)
0
Evg
Эксперт CАвтор FAQ
17809 / 6019 / 388
Регистрация: 30.03.2009
Сообщений: 16,535
Записей в блоге: 26
25.06.2009, 19:55 #12
А можешь скомпилить бинарник, а то в этих чёртовых билдарах я не пойму, как консольное приложение сделать. Чисто интересно посотмреть

Цитата Сообщение от #pragma Посмотреть сообщение
1)Программа читает входной файл,но как она это делает,я понятия не имею,потому что делал по описанию библиотеки из и-нета http://www.cplusplus.com
Для порядка разберись. В идеале надо это самому ручками написать, чтобы всё-таки понимать, что же там делается

Цитата Сообщение от #pragma Посмотреть сообщение
2)Есть некое подобие привязки к исходнику,есть сообщение об ошибке,но иногда работает некорректно из-за этих каскадных вызовов...
Вроде бы мелочь, но в результате надо тоже добиться нормальной работы. Как показывает практика, человеческий пользовательский интерфейс зачастую сделать куда труднее, чем внутреннюю логику.

Цитата Сообщение от #pragma Посмотреть сообщение
3)Я попытался добавить возможность программируемых пользователем функций,но в самом конце выяснилось,что это не работет,опять же из-за подобия рекурсии.Так как анализ посимвольный,после знака $ должно происходить вычисление,но при последующем вызове expr(true) происходит дальнейшее чтение строки и в итоге ошибка.
Я бы на твоём месте выхов функций пока отложил. Оно слишком геморно, чтобы аккуратно сделать. Я понятия не имею, как оно у тебя работает, но сильно подозреваю, что у тебя в месте вызова фактически подставляется тело функции. Т.е. вызов по сути нечестный (рекурсию таким образом не сделаешь)

Цитата Сообщение от #pragma Посмотреть сообщение
5)Задания твои я попытаюсь сделать,просто я ещё,например,понятия не имею о битовых операциях.
Суть была не втом, чтобы сделать битовые функции, а втом, чтобы добавить ещё один уровень приоритета. Чтобы понять, насколько хорошо ты усвоил разбор выражений. Ну и вторая часть смысла битовых операций - они только целые, т.е. уметь запрещать класс операций для какого-то типа данных (в данном случае запретить битовые операции для плавающих чисел)

Цитата Сообщение от #pragma Посмотреть сообщение
6)В-общем,пока не знаю,как всё это разгребать.Писалось всё это с целью просто сделать,хотя бы сделать,а не как сделать...На данный момент есть код:
А ты не спеши. И разгребай по-тихоньку. Чем дольше ты будешь сидеть над программой, тем лучше начнёшь её "чувствовать". А начиная с какого-то момента появится стойкое ощущение, что какие-то места надо переделать. В этом случае не ленись и переделай

Добавлено через 1 минуту 52 секунды
Я собственно задание то со следующей целью дал. Вот ты сделал код по книге. А задание - это чтобы доработки сделать самому и без книги
2
#pragma
Временно недоступен
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
25.06.2009, 21:10  [ТС] #13
Ладно,функции пока оставлю,буду потихоньку дальше продвигаться.Бинарник прилагается.
0
Вложения
Тип файла: zip calculator.zip (86.9 Кб, 277 просмотров)
Evg
Эксперт CАвтор FAQ
17809 / 6019 / 388
Регистрация: 30.03.2009
Сообщений: 16,535
Записей в блоге: 26
25.06.2009, 21:43 #14
А сам Exe'шник где? Если Calculator нужно просто переименовать в *.exe, то у меня он что-то завис

Добавлено через 1 минуту 0 секунд
Пишет "Program too big to fit in memoty"

Добавлено через 3 минуты 53 секунды
Под линухом скомпилялось и запустилось. Щас вот только разберусь, как русские сообщения нормально печатать

Добавлено через 10 минут 58 секунд
Когда я делал поставновку задачи, для первого пункта я имел в виду следующее. Ты имеешь файл

Код
a = 1
b = 2
c = a + b
print c
Т.е. печатать только то, что захочет пользователь. А ещё поддержать комментарии. Чтобы всякие разности в файле оставлять и каждый раз заново не писать. Кстати, после ошибки надо завершать работу, а не исполнять дальше

А так для начала очень даже неплохо. Правда пока, насколько я понимаю, тут в основном чужой код, но, тем не менее, начало положено. Я исходники не смотрел, только запускал программу. Даже деление на ноль отловилось. Из ошибок отловил только неправильную реакцию на "a=2.2.2"

Добавлено через 2 минуты 31 секунду
Но использование неинициализированной переменной нужно запретить. Скорее для тренировки в отработке ошибочных ситуаций, чем для практики (т.к. большинство интерпретируемых языков позволяет использовать неинициализированные переменные)
1
#pragma
Временно недоступен
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
28.06.2009, 02:43  [ТС] #15
1) Кое-что удалось сделать.Добавил битовые операции &,^,~,|,но способ,которым это сделано,мне не нравится.Вообще,вся эта программа-тихий ужас,не дай бог вот над такими программами придётся когда-нибудь сидеть и разбираться)) Кстати,результат проверить не мешало бы,но я поглядел по аналогии (в отдельной программе),вроде бы корректно.

2) Добавил вывод переменной на экран по желанию пользователя.Это делается командой #<var name> .Я до сих пор не додумался(мало думал?),как сделать интерпретацию нескольких символов подряд,"не теряя при этом нити беседы" - то есть чтобы предотвратить вызов посимвольно во время интерпретации зарезервированных слов.Как-то я поставил на все 300 с лишним строк программы точки разрыва для дебаггера,и у меня получилось,что,например,при попытке вычисления функции (case $: )после записи её тела в строку и возврате строка продолжает читаться,но в предыдущем вызове.Короче там такая путаница,ё-маё Аж дебаггер заглючило.

3)Добавил возможность комментариев,это делается значком "(двойной апостроф),всё,что после значка,игнорируется.

4)Есть ограничение на битовые операции с числами с плавающей точкой.Типизацию пока не сделал.Просто хочется сделать наподобие "int x=1;" но всё упирается в проблему,описанную ранее.

5) Запретил использование неинициализированных переменных,а также программа прерывается после первой ошибки.

6)На данный момент программа такова:
LexicalAnalyzer.h
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
#ifndef LEXICALANALYZER_H_INCLUDED
#define LEXICALANALYZER_H_INCLUDED
 
#include <cctype>
#include <string>
#include <map>
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <fstream>
 
 
extern std::ifstream source;
 
enum Token_value {
    NAME,       NUMBER,      END,       FUNC = '$',
    PLUS = '+', MINUS = '-', MUL = '*', DIV = '/',
    PRINT = ';',ASSIGN = '=',LP = '(',  RP = ')',
    AND = '&',  XOR = '^',   OR = '|',  NOT = '~',
    BEGIN_FUNC = '@',COMMENT = '"'
};
 
enum Printer_state {
    PRINT_VAR,DONT_PRINT_VAR
};
 
enum Error_state {
    BIN_TO_DOUBLE,NO_ERRORS,
    GLOBAL_ERROR
};
 
typedef std::map<std::string,int>Map_of_names;
typedef std::map<std::string,double>Map_of_table;
 
extern Token_value curr_tok;
extern Error_state err_state;
extern Printer_state print_var;
 
extern std::map<std::string,double>table;
extern std::vector<std::string>initialized_vars;
extern std::string string_value;
 
extern std::map<std::string,int>func_name;
extern std::vector<std::string>func_value;
extern std::map<std::string,int>func_num_of_param;
extern std::string result_expr;
extern std::string get_resulting_expr(std::string,std::string,std::string,int);
 
extern int string_number;
 
Token_value get_token();
 
double expr(bool);
double term (bool);
double prim (bool);
int error(const std::string&);
 
#endif // LEXICALANALYZER_H_INCLUDED

LexicalAnalyzer.cpp
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
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
#include "LexicalAnalyzer.h"
 
 
std::map<std::string,double>table;
Token_value curr_tok = PRINT;
Error_state err_state = NO_ERRORS;
Printer_state print_var = DONT_PRINT_VAR;
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;
        }
}
 
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;
                 }
                 err_state=GLOBAL_ERROR;
                 return error("Деление на ноль");
            case AND:
                 if (err_state != BIN_TO_DOUBLE)
                 {
                     left = static_cast<int>(left) & static_cast<int>(prim(true));
                     break;
                 }
                 err_state = GLOBAL_ERROR;
                 return error("Битовые операции могут выполняться только над целыми типами");
            case XOR:
                 if (err_state != BIN_TO_DOUBLE)
                 {
                     left = static_cast<int>(left) ^ static_cast<int>(prim(true));
                     break;
                 }
                 err_state = GLOBAL_ERROR;
                 return error("Битовые операции могут выполняться только над целыми типами");
            case OR:
                 if (err_state != BIN_TO_DOUBLE)
                 {
                     left = static_cast<int>(left) | static_cast<int>(prim(true));
                     break;
                 }
                 err_state = GLOBAL_ERROR;
                 return error("Битовые операции могут выполняться только над целыми типами");
            default:
                 if (err_state != BIN_TO_DOUBLE)
                 return left;
                 err_state = GLOBAL_ERROR;
                 return error("Битовые операции могут выполняться только над целыми типами");
        }
}
 
double number_value;
std::string string_value;
std::map<std::string,int>func_name;
std::vector<std::string>func_value;
std::map<std::string,int>func_name_to_param;
std::vector<std::string>initialized_vars;
std::string result_expr;
std::ifstream source;
int string_number=0;
 
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);
                        ::initialized_vars.push_back(::string_value);
                        return v;
                    }
                    else
                    {
                        std::vector<std::string>::iterator i = find(::initialized_vars.begin(),
                                                                    ::initialized_vars.end(),
                                                                    ::string_value);
                        if (i == ::initialized_vars.end())
                        {
                            err_state=GLOBAL_ERROR;
                            return error("Неинициализированная переменная");
                        }
                    }
                    return v;
        }
        case FUNC:{
                   double e = expr(true);
                   return e;
        }
        case MINUS:
                   return -prim(true);
        case NOT:{
                   if (err_state != BIN_TO_DOUBLE)
                   {
                       int e = ~static_cast<int>(prim(true));
                       if (err_state == BIN_TO_DOUBLE)
                       {
                            err_state = GLOBAL_ERROR;
                            return error("Битовые операции могут выполняться только над целыми типами");
                       }
                       return static_cast<double>(e);
                   }
                   else
                   {
                       err_state = GLOBAL_ERROR;
                       return error("Битовые операции могут выполняться только над целыми типами");
                   }
        }
        case LP:{
                  double e = expr(true);
                  if (curr_tok!=RP)
                  {
                      err_state = GLOBAL_ERROR;
                      return error("Ожидалась )");
                  }
                  get_token();
                  return e;
        }
        case COMMENT:
                     get_token();
                     return 0;
        default:
                  err_state = GLOBAL_ERROR;
                  return error("Ожидалось первичное выражение");
    }
}
 
Token_value get_token()
{
    char ch = 0;
 
 
    if (curr_tok == COMMENT)
        do {
               if (!source.get(ch))
               return curr_tok = END;
 
           }
        while (ch!='\n');
 
    if (curr_tok == FUNC)
        do {
               if (!source.get(ch))
               return curr_tok = END;
           }
        while (ch!='\n');
 
    do {
        if (!source.get(ch)) return curr_tok = END;
 
    } while (ch!='\n'&&isspace(ch));
 
    switch (ch) {
        case 0:
                 return curr_tok = END;
 
        case ';':
                 return curr_tok = PRINT;
 
        case '\n':
                 ++string_number;
                 return curr_tok = PRINT;
 
        case '"':return curr_tok =COMMENT;
 
        case '*':case '/':case '+':case '-':case '(':case ')':
        case '=':case '~':case '&':case '^':case '|':
                 return curr_tok=Token_value(ch);
 
        case '0':case '1':case '2':case '3':case '4' :
        case '5':case '6':case '7':case '8':case '9':
                 source.putback(ch);
                 source>>number_value;
                 if(number_value-static_cast<int>(number_value)!=0)
                 err_state = BIN_TO_DOUBLE;
                 return curr_tok = NUMBER;
        case '@':{
                 // Writing whole string to build a function.
                 // @ - reserved sign for start user function
                 // programming.
 
                 // Copying whole function string to tmp
                 std::string tmp;
                 tmp = ch;
                 while (source.get(ch)&&ch!='\n') tmp.push_back(ch);
                 source.putback(ch);
 
                 // Set useful places in the string
                 unsigned int i = find(tmp.begin(),tmp.end(),'(')-tmp.begin();
                 unsigned int k = find(tmp.begin(),tmp.end(),')')-tmp.begin();
 
                 // There must be parameters list in the function
                 if (i==tmp.size()||k==tmp.size())
                 {
                     err_state = GLOBAL_ERROR;
                     error("Ожидался список параметров");
                     return curr_tok = PRINT;
                 }
 
                 // Checking function name for previous declaration
                 std::string s = tmp.substr(1,i-1);
                 Map_of_names::iterator it = ::func_name.find(s);
                 if (it != ::func_name.end())
                 {
                     err_state = GLOBAL_ERROR;
                     error("Повторное определение функции");
                     return curr_tok = PRINT;
                 }
                 else
                 {
                    // Declaration
                    unsigned int j = find(tmp.begin(),tmp.end(),'{')-tmp.begin();
 
                    // Function must have body
                    if (j==tmp.size())
                    {
                        err_state = GLOBAL_ERROR;
                        error("Ожидалась {");
                        return curr_tok = PRINT;
                    }
 
                    // Not empty body
                    if (tmp.substr(j+1,tmp.size()-j-2).size()<1)
                    {
                        err_state = GLOBAL_ERROR;
                        error("Пустая функция");
                        return curr_tok = PRINT;
                    }
 
                    // At start of parameters list,as at the end,
                    // have to be an alphabet character
                    std::string param_list = tmp.substr(i+1,k-i-1);
                    if (isalpha(param_list.at(0))&&isalpha(param_list[param_list.size()-1]))
                    {
                        // Function template creation
                        ::func_name_to_param[s] = count(param_list.begin(),param_list.end(),',')+1;
                        ::func_name[s];
                        ::func_value.push_back(tmp.substr(i,tmp.size()-i));
                        return curr_tok = PRINT;
                    }
                    else
                    {
                        err_state = GLOBAL_ERROR;
                        error("Неправильный список параметров");
                        return curr_tok = PRINT;
                    }
                 }
                 return curr_tok = PRINT;
             }
        case '}':case '{':{
                 // End of user function
                 source.putback(ch);
                 return curr_tok = PRINT;
             }
        case ',':return curr_tok = PRINT;
        case '#':
                 print_var = PRINT_VAR;
                 return curr_tok = PRINT;
 
        case '$':{
                 // $ - reserved for starting to calculate
                 // function that was programmed before
 
                 // Writing function with parameters
                 // that we need to calculate to tmp
                 std::string tmp;
                 tmp = ch;
 
                 while (source.get(ch)&&(ch != '\n')) tmp.push_back(ch);
                 if (ch=='\n') ++string_number;
                 source.putback(ch);
 
                 // Set useful places in the string
                 unsigned int i = find(tmp.begin(),tmp.end(),'(')-tmp.begin();
                 unsigned int k = find(tmp.begin(),tmp.end(),')')-tmp.begin();
 
                 // Checking for function was declared before
                 std::string nm_tmp = tmp.substr(1,i-1);
                 Map_of_names::iterator it = ::func_name.find(nm_tmp);
                 if (it == ::func_name.end())
                 {
                     err_state = GLOBAL_ERROR;
                     error("Функция не была объявлена ранее");
                     return curr_tok = PRINT;
                 }
                 else
                 {
                     std::string param_list = tmp.substr(i+1,k-i-1);
                     if (isalnum(param_list[0])&&isalnum(param_list[param_list.size()-1]))
                     {
                         // Count parameters and checking amount of
                         // parameters in declared function
                         int param_count = count(param_list.begin(),param_list.end(),',')+1;
                         if (param_count> ::func_name_to_param[nm_tmp]||
                             param_count< ::func_name_to_param[nm_tmp])
                         {
                             err_state = GLOBAL_ERROR;
                             error("Неправильное количество параметров функции");
                             return curr_tok = PRINT;
                         }
                         ///////////////////////////////////////////
                         /**  Our function is "OK".               */
                         ///////////////////////////////////////////
                         std::string main_param_list = ::func_value[::func_name[nm_tmp]].substr(1,
                                                                                         ::func_value[::func_name[nm_tmp]].find_first_of(')',1)-1);
 
                         ::result_expr = get_resulting_expr(param_list,
                                                            main_param_list,
                                                            ::func_value[::func_name[nm_tmp]],
                                                            ::func_name_to_param[nm_tmp]);
                         //::result_expr.push_back('\n');
 
                         for (int j = ::result_expr.size()-1; j >= 0; --j)
                         source.putback(::result_expr[j]);
                         return  curr_tok = FUNC;
 
                     }
                     else
                     {
                         err_state = GLOBAL_ERROR;
                         error("Неверный параметр функции");
                         return curr_tok = PRINT;
                     }
                 }
                 return curr_tok = PRINT;
             }
        default:
             if (isalpha(ch)) {
                 ::string_value = ch;
                 while (source.get(ch)&&isalnum(ch)) ::string_value.push_back(ch);
                 source.putback(ch);
                 return curr_tok = NAME;
             }
             err_state = GLOBAL_ERROR;
             error ("Неправильная лексема");
             return curr_tok = PRINT;
    }
}
int error (const std::string& s)
{
    std::cerr<<"Строка: "<< ::string_number<<" Ошибка: "<<s<<'\n';
    return 0;
}

param_swapper.cpp
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
#include "LexicalAnalyzer.h"
 
// Function get parameters and temlate in
// strings of two functions and returns
// resulting string as expression for
// future calculation
// Просто жесть
 
std::string get_resulting_expr(std::string s_son_par,
                               std::string s_father_par,
                               std::string s_father_expr,
                               int param_count)
{
    std::string resulting_expr;
    if (param_count==1)
    {
        //To be continued?
    }
    else
    {
        // Store parameters
        std::vector<std::string>tmp_son_par;
        std::vector<std::string>tmp_father_par;
 
        // Using iterators to find parameters
        std::string::iterator iter_s_son = find(s_son_par.begin(),s_son_par.end(),',');
        std::string::iterator iter_s_father = find(s_father_par.begin(),s_father_par.end(),',');
 
        // First parameter
        tmp_son_par.push_back(s_son_par.substr(0,(iter_s_son-s_son_par.begin())));
        tmp_father_par.push_back(s_father_par.substr(0,(iter_s_father-s_father_par.begin())));
 
        if (param_count > 2)
        {
           // All parameters exept first and last
           for (int i = 1; i < param_count-1; ++i)
           {
               iter_s_son = find(iter_s_son,s_son_par.end(),',');
               iter_s_father = find(iter_s_father,s_father_par.end(),',');
               tmp_son_par.push_back(s_son_par.substr(iter_s_son-s_son_par.begin(),
                                                 (find(iter_s_son,s_son_par.end(),',')-iter_s_son)-1));
               tmp_father_par.push_back(s_father_par.substr(iter_s_father-s_father_par.begin(),
                                                 (find(iter_s_father,s_father_par.end(),',')-iter_s_father)-1));
           }
 
           // Last parameter
           tmp_son_par.push_back(s_son_par.substr(iter_s_son-s_son_par.begin(),
                                                  iter_s_son-s_son_par.end()));
           tmp_father_par.push_back(s_father_par.substr(iter_s_father-s_father_par.begin(),
                                                        iter_s_father-s_father_par.end()));
        }
        if (param_count == 2)
        {
           // Second parameter
           tmp_son_par.push_back(s_son_par.substr(iter_s_son-s_son_par.begin(),
                                                  iter_s_son-s_son_par.end()));
 
           tmp_father_par.push_back(s_father_par.substr(iter_s_father-s_father_par.begin(),
                                                        iter_s_father-s_father_par.end()));
        }
 
        // Finally replace parameters from son
        // to father expression
        unsigned int pos   = 0;
        unsigned int l = s_father_expr.size();
        for (int i = 0; i < param_count;++i)
        {
            for (pos = 0;pos <s_father_expr.size();)
            {
                // There is a mistake in algorithm.
                // Last parameter isnt getting swapped.
                pos = s_father_expr.find(tmp_father_par.at(i));
                if (pos>l)break;
                s_father_expr.replace(pos,tmp_father_par.at(i).size(),tmp_son_par.at(i));
 
            std::cout<<"DEBUG "<<s_father_expr<<std::endl;
            }
        }
        // Using now useless pos
        pos = s_father_expr.find_first_of('{',0);
        resulting_expr = s_father_expr.substr(pos+1,s_father_expr.size()-pos-2);
    }
    std::cout<<"DEBUG "<<resulting_expr<<std::endl;
    return resulting_expr;
}

main.cpp
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
#include "LexicalAnalyzer.h"
 
 
int main()
{
    table["pi"]=3.1415926535897932385;
    table["e"]=2.7182818284590452354;
    source.open("program.clc",std::ifstream::in);
    while (source.good()) {
        get_token();
        if (err_state==GLOBAL_ERROR)break;
        if (curr_tok==END) break;
        if (curr_tok==PRINT) continue;
        if (print_var==PRINT_VAR)
        {
           std::cout<<expr(false)<<'\n';
           print_var = DONT_PRINT_VAR;
        }
        else
        {
            expr(false);
        }
    }
    source.close();
    return 0;
}

Входные данные:
program.clc
#~0 "Печатаем дополнение нуля
a=3
b=4
"This is comment
"Это комментарий
#a "Ура!Каменты! : )
"Это тоже комментарий
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
28.06.2009, 02:43
Привет! Вот еще темы с ответами:

Написать интерпретатор программного языка -помощь - C++
Здраствуйте! Ребят, кто хорошо разбирается в C++ помогите пожалуйста с реализацией данного задания или хотя бы подтолкните к решению,...

Интерпретатор/компилятор ассемблер-подобного языка - C++
Привет! Чую, что изобрёл велисипед, даже скорее велопарк, но всё же, поделюсь: Некоторое время назад начал изучать кресты, в целом...

Интерпретатор музыки стандарта BASIC PLAY на С++ - C++
У кого нибудь есть функция или класс, который сможет воспроизводить в С++ напрямую музыкальные строки, записанные в стандарте оператора...

Задание: разработать "Интерпретатор языка". С чего начать? - C++
Здравствуйте, вручили темку на курсовик, ну точнее как вручили, не успел взять то, что хотел - пришлось брать то, что осталось. Плоховато...


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

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
28.06.2009, 02:43
Закрытая тема Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru