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

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

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 1509, средняя оценка - 4.80
#pragma
Временно недоступен
 Аватар для #pragma
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
20.06.2009, 20:03     Пишем свой интерпретатор языка BASIC #1
*****************
Благодаря форуму и Evg в частности интерпретатор развивается, потихоньку превращаясь в простенький интерпретатор QBASIC.
Некоторые из самых старых версий сохранились в теме и ссылки на них будут добавлены в это сообщение,а также ссылки на другие темы,связанные с этой.

Репозиторий с проектом находится тут, там же есть возможность в браузере посмотреть историю ревизий (английский в логах весьма примитивен,комментарии и рекомендации можете писать в личку),а также скачать самый последний архив репозитория в формате .tar.gz
Если кто-то пользуется Subversion,скачать исходники можно так:
Код
svn co https://basin.svn.sourceforge.net/svnroot/basin basin
Эти темы возникли в результате моих вопросов по ходу написания:
Технический приём для формирования согласованных данных
Makefile: как с использованием gcc строить автоматические зависимости от .h файлов?
Вопрос по svn (Subversion)
Создание системы тестирования ПО.
Вопрос про разные реализации бэйсиков
[C/C++] Можно ли выразить порядковый номер элемента массива через индексы?
[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;
Лучшие ответы (1)
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16827 / 5248 / 321
Регистрация: 30.03.2009
Сообщений: 14,132
Записей в блоге: 26
12.07.2009, 23:11     Пишем свой интерпретатор языка BASIC #41
По поводу вот этой темы Разыменование итератора
Я бы не стал в переменной хранить непосредственно значение (без дополнительного класса Value). Это чисто к сведению. Если тебе видится, что так будет лучше - реализовывай именно так. Из вариантов "блее правильный" и "более понятный" в данном случае уместен "более понятный"
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
#pragma
Временно недоступен
 Аватар для #pragma
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
12.07.2009, 23:49  [ТС]     Пишем свой интерпретатор языка BASIC #42
Хм,я объясню,почему выбрал этот вариант. Сначала я делал именно с Value как членом класса,но потом выяснилось,что необходим вызов конструктора Value,то есть требовалась запись вроде такой
C++
1
Variable a(paser_CurTokenStr,CONST_INT)
Чтобы сделать возможной вызов конструктора Value,причём получается что нужно,чтобы в paser_CurTokenStr было не имя переменной,а строка для константы. Я не нашёл другого способа,кроме как перегрузить оператор = для Variable. А как тебе видится решение?
#pragma
Временно недоступен
 Аватар для #pragma
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
13.07.2009, 01:36  [ТС]     Пишем свой интерпретатор языка BASIC #43
Хочу поделиться дальнейшим ходом написания.Некоторые рассуждения написаны в комментариях.
Ещё подумалось,что лучше бы сделать отдельный модуль types.h,и вырезать туда все перечисления,мне кажется,так будет правильней.Промежуточный результат такой пока:
driver.h
C++
1
2
3
4
5
6
7
8
9
#ifndef DRIVER_H_INCLUDED
#define DRIVER_H_INCLUDED
 
#include <fstream>
 
 
extern std::ifstream source;
 
#endif // DRIVER_H_INCLUDED

driver.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
#include <iostream>
#include "driver.h"
#include "debugger.h"
#include "parser.h"
#include "syntax_parser.h"
#include "value_class.h"
#include "variable_class.h"
 
 
   using std::ifstream;
   using std::cout;
   using std::endl;
 
   std::ifstream source;
 
   int main()
   {
       parser_Init("source.bsc");
       if (DEBUG == 1) debugger_Start();
 
       //Value x("123",CONST_VAL_INT);
 
       //Value y("2",CONST_VAL_INT);
 
       //x = x*y;
 
       //cout << x;
       Variable a("a");
       initialized_vars.push_back(a);
       return 0;
   }

debugger.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
#ifndef DEBUGGER_H_INCLUDED
#define DEBUGGER_H_INCLUDED
 
// This switch is to enable
// program global debugging
// mode.1 is enabled and 0
// is disabled.
#define DEBUG 1
 
// Enable and disable of
// debugging print of
// different components
// of the program
#define PARSER_DEBUG 1
#define SYNTAX_PARSER_DEBUG 1
#define VALUE_CLASS_DEBUG 1
 
// When SILENT is 1 printing
// to a file,when 0 - to console.
#define SILENT 1
 
// Printing of full variables names
// 1 - enabled.
#define FULL_NAMES 1
 
// Print on commented and empty lines
// 1 - enabled.
#define PRINT_COMMENTED_LINES 1
#define PRINT_EMPTY_LINES     1
 
#include <fstream>
 
   // Each value of this enum
   // represent function which
   // debugging process is
   // working in.
   enum debug_CurFunc {
       PARSER_INIT,            // parser_Init (const std::string file_name)
       PARSER_GET_TOKEN,       // parser_TokenType parser_GetToken ()
       SYNTAX_PARSER_PRIMARY  // Value syntax_parserPrimary();
   };
 
  /** @brief Clearing the debugging log. */
   extern void debugger_Start();
 
  /** @brief Global printing of variables.
   *  @param debug_CurFunc is name of the function,
   *  that debugger is working with. */
   extern void debugger_Print(debug_CurFunc);
 
   extern std::ofstream debug_data_file;
   extern debug_CurFunc debug_CurFuncName;
 
#endif // DEBUGGER_H_INCLUDED

debugger.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
#include "debugger.h"
#include "parser.h"
#include "value_class.h"
 
//
 
   using std::ofstream;
 
 
   ofstream debug_data_file;
 
 
   void debugger_Start()
   {
       if (SILENT == 0)
             ;
       else
       {
           debug_data_file.open("data_file.dat");
           debug_data_file.clear();
           debug_data_file.close();
       }
   }
 
   void debugger_Print(debug_CurFunc debug_CurFuncName)
   {
           switch (debug_CurFuncName)
           {
                case PARSER_INIT: {
 
                    if (SILENT == 0)
                        parser_PrintCurToken ();
 
                    else
                    {
                        debug_data_file.open("data_file.dat",ofstream::app);
 
                        if (debug_data_file.is_open())
 
                            parser_PrintCurToken (&debug_data_file);
 
                        debug_data_file.close();
                    }
                }
                break;
                case PARSER_GET_TOKEN: {
 
                    if (SILENT == 0)
                        parser_PrintCurToken ();
 
                    else
                    {
 
                       debug_data_file.open("data_file.dat",ofstream::app);
 
                       if (debug_data_file.is_open())
 
                           parser_PrintCurToken (&debug_data_file);
 
                       debug_data_file.close();
                    }
                }
                break;
                case SYNTAX_PARSER_PRIMARY: {
                    if (SILENT == 0);
                }
                default: //Error
                ;
          }
   }

parser.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
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
#ifndef PARSER_H_INCLUDED
#define PARSER_H_INCLUDED
 
#include <string>
#include <map>
 
   enum parser_TokenType
   {
     TOKEN_NULL = 0,
 
     TOKEN_CONST_INT,   // Integer constant
     TOKEN_CONST_FLOAT, // Floating point constant
 
     TOKEN_IDENT,       // Identificator
 
     TOKEN_KW_LET,      // Keyword LET
     TOKEN_KW_PRINT,    // Keyword PRINT
 
     TOKEN_DELIM_EQUAL, // Sign "="
     TOKEN_DELIM_PLUS,  // Sign "+"
     TOKEN_DELIM_MINUS, // Sign "-"
 
     TOKEN_EOL,         // End of line
     TOKEN_EOF,         // End of file
 
     TOKEN_LAST
   };
 
   const std::string parser_TokenTypeNames[] =
   {
     "TOKEN_NULL    ",
 
     "TOKEN_CONST_INT",       // Integer constant
     "TOKEN_CONST_FLOAT",     // Floating point constant
 
     "TOKEN_IDENT    ",           // Identificator
 
     "TOKEN_KW_LET    ",          // Keyword LET
     "TOKEN_KW_PRINT",        // Keyword PRINT
 
     "TOKEN_DELIM_EQUAL",     // Sign "="
     "TOKEN_DELIM_PLUS",      // Sign "+"
     "TOKEN_DELIM_MINUS",     // Sign "-"
 
     "TOKEN_EOL    ",         // End of line
     "TOKEN_EOF    ",         // End of file
 
     "TOKEN_LAST"
   };
 
  /** @brief Parser initialization.
   *  @param file_name contains path
   *  to file with source code,wich parser is working with.
   *  @return In case of problem with lile opening return false,
   *  and true if file was opened */
   extern bool parser_Init (std::string file_name);
 
  /** @brief Procedure parser_GetToken get's the next token from
   *  input stream.
   *  @param As a result writing variables parser_CurToken and
   *  parser_LastTokenStr.
   *  @return Procedure parser_GetToken return value of
   *  parser_CurToken. */
   extern parser_TokenType parser_GetToken ();
 
  /** @var Variables parser_CurFile, parser_CurLine contain
   *  information about place of current token in source
   *  code for debug purposes,parser_CurToken is the current
   *  token in line.parser_CurTokenStr contains value of
   *  token,if available. */
   extern std::string parser_CurFile;
   extern unsigned parser_CurLine;
   extern parser_TokenType parser_CurToken;
   extern parser_TokenType parser_NextToken;
   extern std::string parser_CurTokenStr;
 
  /** @var parser_ResWords contain reserved words
   *  for parser.Initialization is in
   *  parser_Init (std::string file_name) */
   extern std::map<const std::string,int>parser_ResWord;
   extern std::map<const char,int>parser_ResSign;
 
  /** @brief Printer for debugging purposes
   *  of current token state.
   *  @param parser_CurFile is name of the
   *  file,that is being parced. */
   extern void parser_PrintCurToken (std::ofstream *);
   extern void parser_PrintCurToken ();
 
  /** @brief End of parser's work */
   extern void parser_Finish ();
 
#endif // PARSER_H_INCLUDED

parser.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
#include <iostream>
#include <cctype>
#include "parser.h"
#include "debugger.h"
#include "driver.h"
 
//
 
   using std::ofstream;
   using std::endl;
   using std::map;
   using std::string;
   using std::cout;
 
   parser_TokenType parser_CurToken;
   parser_TokenType parser_NextToken;
   string parser_CurTokenStr;
   string parser_CurFile;
   unsigned parser_CurLine;
 
   map<const string,int>parser_ResWord;
   map<const char,int>parser_ResSign;
 
   bool parser_Init (const std::string file_name)
   {
       parser_ResWord[ "LET" ] = parser_TokenType(TOKEN_KW_LET);
       parser_ResWord["PRINT"] = parser_TokenType(TOKEN_KW_PRINT);
 
       parser_ResSign[  ' '  ] = parser_TokenType(TOKEN_NULL);
       parser_ResSign[  '='  ] = parser_TokenType(TOKEN_DELIM_EQUAL);
       parser_ResSign[  '+'  ] = parser_TokenType(TOKEN_DELIM_PLUS);
       parser_ResSign[  '-'  ] = parser_TokenType(TOKEN_DELIM_MINUS);
       parser_ResSign[  ';'  ] = parser_TokenType(TOKEN_EOL);
       parser_ResSign[  '\n' ] = parser_TokenType(TOKEN_EOL);
 
       source.open(file_name.c_str());
 
       if (source.is_open())
       {
           ::parser_CurFile  = file_name;
           ::parser_CurLine  = 1;
           ::parser_CurToken = TOKEN_NULL;
           ::parser_NextToken = TOKEN_NULL;
           ::parser_CurTokenStr = "";
 
           return true;
       }
       else
           return false;
   }
 
 
   parser_TokenType parser_GetToken ()
   {
       char c = 0;
       ::parser_CurTokenStr = "";
 
       //if ((PARSER_DEBUG == 1)&&(DEBUG == 1)) debugger_Print(PARSER_GET_TOKEN);
 
       while (!source.eof())
       {
           source.get(c);
 
           // Identificator or
           // reserved word
           if (isalpha(c))
           {
               while (!source.eof()&&isalpha(c))
               {
                    ::parser_CurTokenStr.push_back(c);
                    source.get(c);
               }
 
               map<const char,int>::iterator i = parser_ResSign.find(c);
 
               if (i!=parser_ResSign.end())
                   ::parser_NextToken = parser_TokenType(parser_ResSign[c]);
 
               else
                   ;//Error
 
               map<const string,int>::iterator ii = parser_ResWord.find(::parser_CurTokenStr);
 
               if (ii!=parser_ResWord.end())
                   ::parser_CurToken = parser_TokenType(parser_ResWord[::parser_CurTokenStr]);
 
               else
                   ::parser_CurToken = TOKEN_IDENT;
 
               if (::parser_NextToken == TOKEN_EOL) ++::parser_CurLine;
 
               if ((PARSER_DEBUG == 1)&&(DEBUG == 1)) debugger_Print(PARSER_GET_TOKEN);
 
               return ::parser_CurToken;
           }
           else
 
           // Number
           if (isdigit(c))
           {
               while (!source.eof()&&isdigit(c))
               {
                    ::parser_CurTokenStr.push_back(c);
                    source.get(c);
               }
               // Float
               if (c == '.')
               {
                    ::parser_CurTokenStr.push_back(c);
                    source.get(c);
 
                    if (isdigit(c))
                        while (!source.eof()&&isdigit(c))
                        {
                             ::parser_CurTokenStr.push_back(c);
                             source.get(c);
                        }
                    else
                       ;//Error
 
                    map<const char,int>::iterator i = parser_ResSign.find(c);
 
                    if (i!=parser_ResSign.end())
                        ::parser_NextToken = parser_TokenType(parser_ResSign[c]);
                    else
                       ;//Error
 
                    ::parser_CurToken = TOKEN_CONST_FLOAT;
 
                    if (::parser_NextToken == TOKEN_EOL) ++::parser_CurLine;
 
                    if ((PARSER_DEBUG == 1)&&(DEBUG == 1)) debugger_Print(PARSER_GET_TOKEN);
 
                    return ::parser_CurToken;
               }
 
               // Integer
               map<const char,int>::iterator i = parser_ResSign.find(c);
 
               if (i!=parser_ResSign.end())
                    ::parser_NextToken = parser_TokenType(parser_ResSign[c]);
 
               else
                   ;//Error
 
               ::parser_CurToken = TOKEN_CONST_INT;
 
               if (::parser_NextToken == TOKEN_EOL) ++::parser_CurLine;
 
               if ((PARSER_DEBUG == 1)&&(DEBUG == 1)) debugger_Print(PARSER_GET_TOKEN);
 
               return ::parser_CurToken;
           }
           else
 
           // !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
           if (ispunct(c))
           {
               map<const char,int>::iterator i = parser_ResSign.find(c);
 
               if (i!=parser_ResSign.end())
               {
                   ::parser_CurToken = parser_TokenType(parser_ResSign[c]);
 
                   if ((PARSER_DEBUG == 1)&&(DEBUG == 1)) debugger_Print(PARSER_GET_TOKEN);
 
                   return ::parser_CurToken;
               }
               else
 
               // Comment
               if (c == '#')
               {
                   while (!source.eof()&&c!='\n') source.get(c);
 
                   if (c == '\n')
                   {
                       ::parser_CurToken = TOKEN_EOL;
                       ::parser_NextToken = TOKEN_NULL;
                       ++::parser_CurLine;
                   }
                   else
                   {
                       ::parser_CurToken = TOKEN_EOF;
                       ::parser_NextToken = TOKEN_NULL;
 
                   }
 
                   // When on commented line
                   // we don't want to return
                   // from function
                   if ((PARSER_DEBUG == 1)&&
                       (DEBUG == 1)&&
                       (PRINT_COMMENTED_LINES == 1)) debugger_Print(PARSER_GET_TOKEN);
 
                   continue;
               }
 
               // ...
           }
 
           else
 
           // ' ' and '\n'
           if (isspace(c))
           {
               if (c == ' ') continue;
               else
               if (c == '\n')
               {
                   ::parser_CurToken = TOKEN_EOL;
                   ::parser_NextToken = TOKEN_NULL;
                   ++::parser_CurLine;
               }
               if ((PARSER_DEBUG == 1)&&
                   (DEBUG == 1)&&
                   (PRINT_EMPTY_LINES ==1)) debugger_Print(PARSER_GET_TOKEN);
 
               continue;
           }
 
           else ;//Error
       }
 
       ::parser_CurToken = TOKEN_EOF;
       ::parser_NextToken = TOKEN_NULL;
 
       if ((PARSER_DEBUG == 1)&&(DEBUG == 1)) debugger_Print(PARSER_GET_TOKEN);
 
       return ::parser_CurToken;
   }
 
 
   void parser_PrintCurToken (std::ofstream *)
   {
       switch (FULL_NAMES)
       {
           case 0: {
 
                debug_data_file << "File: "        << ::parser_CurFile     << ' '
                                << "Line: "        << ::parser_CurLine     << ' '
                                << "CurToken: "    << ::parser_CurToken    << ' '
                                << "NextToken: "   << ::parser_NextToken   << ' '
                                << "TokenStr: "    << ::parser_CurTokenStr << ' '
                                << endl;
           }
           break;
           case 1: {
 
                debug_data_file << "File: "        <<                                          ::parser_CurFile     << ' '
                                << "Line: "        <<                                          ::parser_CurLine     << '\t'
                                << "CurToken: "    << parser_TokenTypeNames[parser_TokenType(::parser_CurToken)]    << '\t'
                                << "NextToken: "   << parser_TokenTypeNames[parser_TokenType(::parser_NextToken)]   << '\t'
                                << "TokenStr: "    <<                                          ::parser_CurTokenStr << ' '
                                << endl;
           }
           break;
           default:  //Some error will be here
               debug_data_file << "Check value of FULL_NAMES in debugger.h";
       }
   }
 
   void parser_PrintCurToken ()
   {
       switch (FULL_NAMES)
       {
           case 0: {
 
                cout << "File: "        << ::parser_CurFile     << ' '
                     << "Line: "        << ::parser_CurLine     << ' '
                     << "CurToken: "    << ::parser_CurToken    << ' '
                     << "NextToken: "   << ::parser_NextToken   << ' '
                     << "TokenStr: "    << ::parser_CurTokenStr << ' '
                     << endl;
           }
           break;
           case 1: {
 
                cout << "File: "        <<                                          ::parser_CurFile     << ' '
                     << "Line: "        <<                                          ::parser_CurLine     << '\t'
                     << "CurToken: "    << parser_TokenTypeNames[parser_TokenType(::parser_CurToken)]    << '\t'
                     << "NextToken: "   << parser_TokenTypeNames[parser_TokenType(::parser_NextToken)]   << '\t'
                     << "TokenStr: "    <<                                          ::parser_CurTokenStr << ' '
                     << endl;
           }
           break;
           default:  //Some error will be here
                cout << "Check value of FULL_NAMES in debugger.h";
       }
   }
Вложения
Тип файла: rar Interpreter.rar (6.2 Кб, 135 просмотров)
#pragma
Временно недоступен
 Аватар для #pragma
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
13.07.2009, 01:37  [ТС]     Пишем свой интерпретатор языка BASIC #44
Всё сообщение уже не влазит в одно. А есть сервисы такие,что можно тексты вставлять туда?

value_class.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
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
#ifndef CONST_CLASS_H_INCLUDED
#define CONST_CLASS_H_INCLUDED
 
 
#include "syntax_parser.h"
#include "parser.h"
#include <string>
#include <iostream>
 
 
 
   // Contain all types of
   // constants,that constructor
   // will get in create of
   // class object.
   enum Types {
       CONST_VAL_INT,   // Тип константы,передаваемый
       CONST_VAL_FLOAT  // конструктору класса
   };
 
   // For debug printing only
   const std::string value_CurType   [] =
   {
       "CONST_VAL_INT  ",   // Тип константы,передаваемый
       "CONST_VAL_FLOAT"  // конструктору класса
   };
 
   // For debug printing only.
   // Indicates current action,
   // being performed over the object
   enum Action {
       ACT_CONSTRUCTOR,
       ACT_PLUS,
       ACT_MINUS,
       ACT_MULTIPLY,
       ACT_DIVIDE,
       ACT_ASSIGN
   };
 
   // For debug printing only.
   // Indicates current action,
   // being performed over the object
   const std::string value_classCurActionName [] =
   {
       "ACT_CONSTRUCTOR",
       "ACT_PLUS       ",
       "ACT_MINUS      ",
       "ACT_MULTIPLY   ",
       "ACT_DIVIDE     ",
       "ACT_ASSIGN     "
   };
 
 
   class Value
   {
       private:
              // value_TypeName will be used for
              // setting type of the constant
              Types value_type; // Тип переменной
 
              // "Pure optimisation"
              // Depends of is_float
              union
              {
                  long ival; // здесь храним целое значение, если константа целая
                  double fval; //  здесь храним плавающее значение, если константа плавающая
              } value;
 
       public:
            /** @brief Costructor receive string from parser
             *  and turn it into variable.The type of variable
             *  depends on VarType value(syntax_parser.h).*/
             Value(const std::string str,Types ValType);
 
            /** Standart destructor */
            ~Value(){};
 
            /** Operators overloading */
             Value operator +  (const Value& prev);
             Value operator -  (const Value& prev);
             Value operator *  (const Value& prev);
             Value operator /  (const Value& prev);
             Value operator =  (const Value& prev);
 
             long   Get_ival() const {return value.ival;};
             double Get_fval() const {return value.fval;};
 
            /** @brief Debugging print.void value_classDbgPrint ()
             *  printing to std::cout,or to output file
             *  stream (debug_data_file in debugger.h)  */
             void value_classDbgPrint ();
 
             Types GetTypeName () const {return value_type;};
   };
 
 
 
   extern Action value_classCurAction;
 
 
   extern std::ostream& operator << (std::ostream& os,const Value& curr);
 
 
#endif // CONST_CLASS_H_INCLUDED

value_class.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
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
#include "value_class.h"
#include "syntax_parser.h"
#include "debugger.h"
#include <iostream>
#include <cstdlib>
#include <fstream>
 
 
//
 
   using std::ofstream;
   using std::string;
   using std::cout;
   using std::endl;
 
 
   Action value_classCurAction;
 
 
   Value::Value(const string str, Types ValType)
   {
       value_classCurAction = ACT_CONSTRUCTOR;
 
       switch (ValType)
       {
           case CONST_VAL_INT: {
 
               value_type = CONST_VAL_INT;
 
               value.ival = atol(str.c_str());
 
               value_classDbgPrint ();
 
           break;
           }
           case CONST_VAL_FLOAT: {
 
               value_type =  CONST_VAL_FLOAT;
 
               value.fval = atof(str.c_str());
 
               value_classDbgPrint ();
 
           break;
           }
           default:; // Error;
       }
   }
 
 
   Value Value::operator = (const Value& prev)
   {
       value_classCurAction = ACT_ASSIGN;
 
       if (value_type == CONST_VAL_FLOAT&&prev.GetTypeName () == CONST_VAL_FLOAT)
       {
           value.fval = prev.Get_fval();
 
           value_classDbgPrint ();
 
           return *this;
       }
       else
         if (value_type == CONST_VAL_INT&&prev.GetTypeName () == CONST_VAL_INT)
         {
             value.ival = prev.Get_ival();
 
             value_classDbgPrint ();
 
             return *this;
         }
         else ;
            // Types messing Error?
         return *this;
   }
 
 
   Value Value::operator + (const Value& prev)
   {
       value_classCurAction = ACT_PLUS;
 
       if (value_type == CONST_VAL_FLOAT&&prev.GetTypeName () == CONST_VAL_FLOAT)
       {
           value.fval += prev.Get_fval();
 
           value_classDbgPrint ();
 
           return *this;
       }
       else
       if (value_type == CONST_VAL_INT&&prev.GetTypeName () == CONST_VAL_INT)
       {
           value.ival += prev.Get_ival();
 
           value_classDbgPrint ();
 
           return *this;
       }
       else
       if (value_type == CONST_VAL_INT&&prev.GetTypeName () == CONST_VAL_FLOAT)
       {
           value.ival += prev.Get_fval();
 
           value_classDbgPrint ();
 
           return *this;
       }
       else
       if (value_type == CONST_VAL_FLOAT&&prev.GetTypeName () == CONST_VAL_INT)
       {
           value.fval += prev.Get_ival();
 
           value_classDbgPrint ();
 
           return *this;
       }
            // Types messing Error?
       return *this;
   }
 
 
   Value Value::operator - (const Value& prev)
   {
       value_classCurAction = ACT_MINUS;
 
       if (value_type == CONST_VAL_FLOAT&&prev.GetTypeName () == CONST_VAL_FLOAT)
       {
           value.fval -= prev.Get_fval();
 
           value_classDbgPrint ();
 
           return *this;
       }
       else
       if (value_type == CONST_VAL_INT&&prev.GetTypeName () == CONST_VAL_INT)
       {
           value.ival -= prev.Get_ival();
 
           value_classDbgPrint ();
 
           return *this;
       }
       else
       if (value_type == CONST_VAL_INT&&prev.GetTypeName () == CONST_VAL_FLOAT)
       {
           value.ival -= prev.Get_fval();
 
           value_classDbgPrint ();
 
           return *this;
       }
       else
       if (value_type == CONST_VAL_FLOAT&&prev.GetTypeName () == CONST_VAL_INT)
       {
           value.fval -= prev.Get_ival();
 
           value_classDbgPrint ();
 
           return *this;
       }
            // Types messing Error?
       return *this;
   }
 
 
   Value Value::operator * (const Value& prev)
   {
       value_classCurAction = ACT_MULTIPLY;
 
       if (value_type == CONST_VAL_FLOAT&&prev.GetTypeName () == CONST_VAL_FLOAT)
       {
           value.fval *= prev.Get_fval();
 
           value_classDbgPrint ();
 
           return *this;
       }
       else
       if (value_type == CONST_VAL_INT&&prev.GetTypeName () == CONST_VAL_INT)
       {
           value.ival *= prev.Get_ival();
 
           value_classDbgPrint ();
 
           return *this;
       }
       else
       if (value_type == CONST_VAL_INT&&prev.GetTypeName () == CONST_VAL_FLOAT)
       {
           value.ival *= prev.Get_fval();
 
           value_classDbgPrint ();
 
           return *this;
       }
       else
       if (value_type == CONST_VAL_FLOAT&&prev.GetTypeName () == CONST_VAL_INT)
       {
           value.fval *= prev.Get_ival();
 
           value_classDbgPrint ();
 
           return *this;
       }
            // Types messing Error?
       return *this;
   }
 
 
   Value Value::operator / (const Value& prev)
   {
       value_classCurAction = ACT_DIVIDE;
 
       if (value_type == CONST_VAL_FLOAT&&prev.GetTypeName () == CONST_VAL_FLOAT)
       {
           value.fval /= prev.Get_fval();
 
           value_classDbgPrint ();
 
           return *this;
       }
       else
       if (value_type == CONST_VAL_INT&&prev.GetTypeName () == CONST_VAL_INT)
       {
           value.ival /= prev.Get_ival();
 
           value_classDbgPrint ();
 
           return *this;
       }
       else
       if (value_type == CONST_VAL_INT&&prev.GetTypeName () == CONST_VAL_FLOAT)
       {
           value.ival /= prev.Get_fval();
 
           value_classDbgPrint ();
 
           return *this;
       }
       else
       if (value_type == CONST_VAL_FLOAT&&prev.GetTypeName () == CONST_VAL_INT)
       {
           value.fval /= prev.Get_ival();
 
           value_classDbgPrint ();
 
           return *this;
       }
            // Types messing Error?
       return *this;
   }
 
 
   void Value::value_classDbgPrint ()
   {
       switch (DEBUG)
       {
           case 1: {
 
                 switch (VALUE_CLASS_DEBUG)
                 {
                      case 1: {
 
                            switch (SILENT)
                            {
                                 case 0: {
 
                                       switch (FULL_NAMES)
                                       {
                                            case 1: {
                                                  cout << "Current action with value: "
                                                       << value_classCurActionName[Action(value_classCurAction)] << ' '
                                                       << "Type of value: "                                      << ' '
                                                       << value_CurType[Types(GetTypeName())]                    << ' '
                                                       << "The value is: "                                       << ' ';
 
                                                  if (GetTypeName() == CONST_VAL_INT)
 
                                                      cout  << Get_ival()
                                                            << endl;
                                                  else
                                                  if  (GetTypeName() == CONST_VAL_FLOAT)
 
                                                      cout  << Get_fval()
                                                            << endl;
 
                                            }
                                            break;
                                            case 0: {
                                                  cout << "Current action with value: "
                                                       << Action(value_classCurAction) << ' '
                                                       << "Type of value: "            << ' '
                                                       << Types(GetTypeName())         << ' '
                                                       << "The value is: "             << ' ';
 
                                                  if (GetTypeName() == CONST_VAL_INT)
 
                                                      cout  << Get_ival()
                                                            << endl;
                                                  else
                                                  if  (GetTypeName() == CONST_VAL_FLOAT)
 
                                                      cout  << Get_fval()
                                                            << endl;
 
                                            }
                                            break;
                                            default: {
                                                  cout << "check FULL_NAMES value in debugger.h"
                                                       << endl;
                                            }
                                            break;
                                       }
                                 }
                                 break;
                                 case 1: {
 
                                       debug_data_file.open("data_file.dat",ofstream::app);
 
                                       if (debug_data_file.is_open())
 
                                       switch (FULL_NAMES)
                                       {
                                            case 1: {
                                                  debug_data_file << "Current action with value: "
                                                                  << value_classCurActionName[Action(value_classCurAction)] << ' '
                                                                  << "Type of value: "                                      << ' '
                                                                  << value_CurType[Types(GetTypeName())]                    << ' '
                                                                  << "The value is: "                                       << ' ';
 
                                                  if (GetTypeName() == CONST_VAL_INT)
 
                                                      debug_data_file  << Get_ival()
                                                                       << endl;
                                                  else
                                                  if  (GetTypeName() == CONST_VAL_FLOAT)
 
                                                      debug_data_file  << Get_fval()
                                                                       << endl;
 
                                                  debug_data_file.close();
                                            }
                                            break;
                                            case 0: {
                                                  debug_data_file << "Current action with value: "
                                                                  << Action(value_classCurAction) << ' '
                                                                  << "Type of value: "            << ' '
                                                                  << Types(GetTypeName())         << ' '
                                                                  << "The value is: "             << ' ';
 
                                                  if (GetTypeName() == CONST_VAL_INT)
 
                                                      debug_data_file  << Get_ival()
                                                                       << endl;
                                                  else
                                                  if  (GetTypeName() == CONST_VAL_FLOAT)
 
                                                      debug_data_file  << Get_fval()
                                                                       << endl;
 
                                                  debug_data_file.close();
                                            }
                                            break;
                                            default: {
                                                  debug_data_file << "check FULL_NAMES value in debugger.h"
                                                                  << endl;
                                            }
                                            break;
                                       }
 
                                       else
 
                                          ; // Error opening the file
                                 }
                                 break;
                                 default: {
                                        cout << "check SILENT value in debugger.h"
                                             << endl;
                                 }
                                 break;
                            }
                      }
                      break;
 
                      case 0:
                      break;
 
                      default: {
                             cout << "check VALUE_CLASS_DEBUG value in debugger.h"
                                  << endl;
                      }
                      break;
                 }
           }
           break;
 
           case 0:
           break;
 
           default: {
                  cout << "check DEBUG value in debugger.h"
                       << endl;
           }
           break;
       }
   }
 
   /*************************END OF CLASS MEMBERS***************************/
 
   std::ostream& operator << (std::ostream& output_stream,const Value& curr)
   {
       switch (curr.GetTypeName ())
       {
           case CONST_VAL_FLOAT:
 
                output_stream << curr.Get_fval();
                return cout;
           break;
           case CONST_VAL_INT:
 
                output_stream << curr.Get_ival();
                return cout;
           break;
           default:;
                //Something
           return cout;
       }
   }

variable_class.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
#ifndef VARIABLE_CLASS_H_INCLUDED
#define VARIABLE_CLASS_H_INCLUDED
 
#include <string>
   using std::string;
#include <vector>
   using std::vector;
#include <map>
   using std::map;
#include <algorithm>
   // find()
 
#include "value_class.h"
 
 
 
   class Variable
   {
       private:
 
              Types var_type;
 
              union {
                     long   i;
                     double f;
                    } var_value;
 
              string var_name;
 
       public:
              Variable (const string);
             ~Variable (){};
 
              void SetVarValue ();
 
              string GetVarName () const {return var_name;};
              Types GetTypeName () const {return value_type;};
 
              long   GetVar_ival () const {return var_value.i;};
              double GetVar_fval () const {return var_value.f;};
 
              Variable operator = (const Value& val);
 
   };
 
 
   extern vector<class Variable>initialized_vars;
 
   // Find position of variable if it was initialized before
   /// @return On success,return position of variable in vector,
   /// on failure return -1
   extern int FindNameOverVector (const string str);
 
 
#endif // VARIABLE_CLASS_H_INCLUDED

variable_class.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
#include <string>
   using std::string;
 
#include "variable_class.h"
#include "value_class.h"
 
 
//
 
 
   vector<class Variable>initialized_vars;
 
   Variable::Variable (const string name)
   {
       var_name = name;
   }
 
 
   Variable Variable::operator = (const Value& val)
   {
       switch (val.GetTypeName ())
       {
           case CONST_VAL_INT: {
 
               var_type = CONST_VAL_INT;
 
               var_value.i = val.Get_ival();
 
               return *this;
           }
           case CONST_VAL_FLOAT: {
 
               var_type = CONST_VAL_FLOAT;
 
               var_value.f = val.Get_fval();
 
               return *this;
           }
           default:
              ; // Error;
       }
       return *this;
   }
 
 
   int FindNameOverVector (const string str)
   {
       for (vector<class Variable>::iterator i = initialized_vars.begin();
                                             i < initialized_vars.end();
                                           ++i                             )
       if ( (*i).GetVarName()  == str)
          return i-initialized_vars.begin();
       return -1;
   }

syntax_parser.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef SYNTAX_PARSER_H_INCLUDED
#define SYNTAX_PARSER_H_INCLUDED
 
 
   #include "value_class.h"
   class Value;
 
 
  /** @brief Function creates object
   *  of specific type,that got from
   *  parser_GetToken(),also used string
   *  value parser_CurTokenStr
   *  @return Object of Value class,
   *  implemented in value_class.h    */
   extern Value syntax_parserPrimary ();
 
 
   extern Value syntax_parserTerm ();
 
#endif // SYNTAX_PARSER_H_INCLUDED

syntax_parser.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
#include <cstdlib>
    // atof(),atol()
#include <fstream>
    using std::ofstream;
#include <iostream>
    using std::cout;
    using std::endl;
#include <vector>
    using std::vector;
#include <algorithm>
    // find()
 
#include "syntax_parser.h"
#include "parser.h"
#include "debugger.h"
#include "variable_class.h"
 
 
 
 
    Value syntax_parserPrimary()
    {
        switch (parser_GetToken ())
        {
            case TOKEN_EOL: {
 
                // Error:Primary expression expected
 
            break;
            }
            case TOKEN_CONST_INT: {
 
                Value int_x(::parser_CurTokenStr,CONST_VAL_INT);
 
                return int_x;
            }
            case TOKEN_CONST_FLOAT: {
 
                Value float_x(::parser_CurTokenStr,CONST_VAL_FLOAT);
 
                return float_x;
            }
            case TOKEN_IDENT: {
 
                int i = FindNameOverVector (parser_CurTokenStr);
 
                if (i >= 0)
                {
                    // Если находим переменную,создаём константу с нужным
                    // значением,и возвращаем его.
 
                    if (initialized_vars.at(i).GetTypeName() == CONST_VAL_INT)
                    {
                        Value v (initialized_vars.at(i).GetVarName(),CONST_VAL_INT);
 
                        return v;
                    }
                    else
                    {
                        Value v (initialized_vars.at(i).GetVarName(),CONST_VAL_FLOAT);
 
                        return v;
                    }
 
                }
                else
                {
                    // Если не находим,то создаём константу,
                    // приравниваем её к выражению,создаём переменную,
                    // передаём данные туда и возвращаем константу.
 
 
                }
            }
            default: ;
                //Error:(EOF??)
        }
        // This is bad
        //это просто чтобе не получать предупр.компилятора
        Value null_x("0",CONST_VAL_INT);
        return null_x;
    }
 
 
    Value syntax_parserTerm ()
    {
        while ((parser_GetToken()) != TOKEN_EOL)
        {
            switch (parser_CurToken)
            {
                // Тут у нас все операции,у которых приоритет
                // сразу после возврата значений констант
                // и переменных.Операции с приоритетом ниже
                // находятся на более "высоких этажах" рекурсии.
                // Ключевые слова имеют самый низкий приоритет,
                // а потому будут в самом начале рекурсивного спуска.
                default:  ;
            }
        }
        // This is bad
        //это просто чтобе не получать предупр.компилятора
        Value null_x("0",CONST_VAL_INT);
        return null_x;
    }
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16827 / 5248 / 321
Регистрация: 30.03.2009
Сообщений: 14,132
Записей в блоге: 26
13.07.2009, 09:36     Пишем свой интерпретатор языка BASIC #45
Цитата Сообщение от #pragma Посмотреть сообщение
Хм,я объясню,почему выбрал этот вариант. Сначала я делал именно с Value как членом класса,но потом выяснилось,что необходим вызов конструктора Value,то есть требовалась запись вроде такой
C++
1
Variable a(paser_CurTokenStr,CONST_INT)
Чтобы сделать возможной вызов конструктора Value,причём получается что нужно,чтобы в paser_CurTokenStr было не имя переменной,а строка для константы. Я не нашёл другого способа,кроме как перегрузить оператор = для Variable. А как тебе видится решение?
А в каких случаях тебе нужно создавать переменную со значением? Просто для конструкции "LET a=5" получается что-то типа того:

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* Ожидаем конструкцию вида Ident "=" Expr */
void
syntax_StmtLET (void)
{
  Variable *var;
  Value val;
 
  /* Читаем имя переменной (девая часть присваивания) */
  var = syntax_Ident(); // <--- здесь реализовано синтаксическое правило Ident
 
  /* Знак "=" */
  if (parser_GetToken() != TOKEN_DELIM_EQUAL)
    error ("syntax error near %s", parser_CurTokenStr);
 
  /* Значение выражения (правая часть присваивания) */
  val = syntax_Expr(); // <--- здесь реализовано синтаксическое правило Expr
 
  /* Строим присваивание */
  var->SetValue(val);
}
Добавлено через 22 минуты 36 секунд
syntax_parser.c строки 49-50. Ты пишешь, что создаёшь переменную, но это не правильно. Ты в данный момент парсишь ПРАВУЮ часть присваивания, т.е. там, где нужно читать значения. Т.е. все переменные уже должны быть созданы, а ты в этот момент НЕ создаёшь новую переменую, а достаёшь в таблице уже СУЩЕСТВУЮЩУЮ переменную и берёшь от неё значение. Если переменная не существует, то тут выбираешь как действовать: либо выдавать ошибку, либо считать, что для несуществующеё переменной значение равно нулю. Я бы выбрал первый вариант.

Возможно мне следовало пояснить момент, который для тебя совсем неочевиден. Имя переменной (в нашем случае это синтаксическое правило Ident) может встретиться в присваивании в правой части или в левой. В этих двух случаях оно трактуется по разному. Устоявшиеся технические термины для этого lvalue (от слова left) и rvalue (от right).

Когда имя переменной стоИт в позиции rvalue, то это означает, что нам нужно прочитать ЗНАЧЕНИЕ этой переменной, а когда в позиции lvalue (т.е. фактически мы хотим записать в переменную), то говорят, что нужно АДРЕС переменной. Адрес не в буквальном смысле слова, а в абстрактном - т.е. это нечто, при помощи которого мы можем записать значение в переменную. Иногда rvalue и lvalue называют соотвественно VALUE POSITION и NAME POSITION, но это несколько неудобная терминология из-за слова NAME

Вот примеры того, как переменная "AAA" находится в разных позициях

PureBasic
1
2
3
4
5
6
7
b = 1 + AAA    <--- rvalue (значение)
b = COS (AAA)  <--- rvalue (значение), имеем значение среди параметров
         (а необязательно после знака присваивания
 
AAA = 1  <--- lvalue (адрес)
INPUT AAA  <--- lvalue (адрес), т.е. здесь знака присваивания нет, но семантика
         оператора INPUT такова, что в переменную нужно записывать
Поэтому технически над синтаксическим правилом Ident можно сделать две настройки

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
Variable*
syntax_Ident (void)
{
  // Разгребаем имя переменной. Создаём переменную и возвращаем
  // на неё указатель. У меня была идея избавиться от создания
  // переменных без константы, но такой вариант принесёт больше гемора,
  // чем пользы. Лучше в переменной иметь дополнительный признак,
  // инициализирована переменная или нет. Поэтому вданной процедуре
  // мы просто заводим неинициализированную переменную
}
 
// Разбор имени переменной в левой части присваивания. Именно эту
// процедуру надо подставить в мой вышестоящий код. Здесь нам нужен
// только АДРЕС переменной (в том понятии, котором я описал выше),
// а поэтому просто возвращаем ссылку на созданную переменную
Variable*
syntax_IdentLValue (void)
{
  return syntax_Ident();
}
 
// Разбор имени переменной в левой части присваивания. Здесь
// нам нужно вернуть значение переменной
Value
syntax_IdentRValue (void)
{
  Variable *var;
 
  var = syntax_Ident();
 
  if (var неинициализирована)
    error ("неинициализированная переменная %s", var->GetName());
 
  return var->GetValue();
}
Вот что-то типа того

============================================

Ещё момент по твоему коду: value_class.h строки 85 и 86.
Именно то место, где слодовало бы поставить ASSERT (внутренний контроль), что от целой переменной нельзя брать плавающее значение и наоборот. Хотя в теории эти методы вообще не должны использоваться за пределами модуля Value (потому как все операции перегружены, печать значения реализована в виде интерфейса, больше снаружи вроде бы как незачем)

Добавлено через 5 минут 59 секунд
Я понял, почему у тебя получалось создание переменной непосредственно со значением. Но нужно было бы это делать с Value (т.е. распарсили строковое имя переменной, вытащили правую часть в виде Value, создали переменную с Value). Но засада в том, что тут переменную надо НЕ создавать, а записывать в неё (т.е. если переменная уже создана, то новая переменная не нужна)
#pragma
Временно недоступен
 Аватар для #pragma
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
13.07.2009, 09:42  [ТС]     Пишем свой интерпретатор языка BASIC #46
Цитата Сообщение от Evg Посмотреть сообщение
А в каких случаях тебе нужно создавать переменную со значением?

Добавлено через 22 минуты 36 секунд
syntax_parser.c строки 49-50. Ты пишешь, что создаёшь переменную, но это не правильно. Ты в данный момент парсишь ПРАВУЮ часть присваивания, т.е. там, где нужно читать значения. Т.е. все переменные уже должны быть созданы, а ты в этот момент НЕ создаёшь новую переменую, а достаёшь в таблице уже СУЩЕСТВУЮЩУЮ переменную и берёшь от неё значение. Если переменная не существует, то тут выбираешь как действовать: либо выдавать ошибку, либо считать, что для несуществующеё переменной значение равно нулю. Я бы выбрал первый вариант.


Добавлено через 5 минут 59 секунд
Я понял, почему у тебя получалось создание переменной непосредственно со значением. Но нужно было бы это делать с Value (т.е. распарсили строковое имя переменной, вытащили правую часть в виде Value, создали переменную с Value). Но засада в том, что тут переменную надо НЕ создавать, а записывать в неё (т.е. если переменная уже создана, то новая переменная не нужна)
Да нет же я же написал,что создаю константу,то есть Value ,передаю в неё значение готовой переменной,и сам объект константы возвращаю .Но я понял твою мысль,можно просто сделать Value внутри класса Variable,и просто перегрузить конструктор класса Value,чтобы был и по умолчанию,что позволит создание пустой Value внутри Variable.

Я сделал перегрузку оператора = в классе Variable,так что можно будет просто записать Variable a = syntax_parserExpr();
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16827 / 5248 / 321
Регистрация: 30.03.2009
Сообщений: 14,132
Записей в блоге: 26
13.07.2009, 09:44     Пишем свой интерпретатор языка BASIC #47
Тогда ещё раз поясни ситуацию из поста #44. При каких условиях возникает необходимость в таком действии?
#pragma
Временно недоступен
 Аватар для #pragma
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
13.07.2009, 10:00  [ТС]     Пишем свой интерпретатор языка BASIC #48
Уже не возникает,то есть я перегрузил оператор = в классе переменных,а также сделал своё поле значений внутри переменной,и теперь правомерна запись Variable a = syntax_parserPrimary();
Но раз лучше всё-таки сделать членом класса экземпляр Value,то я просто переделаю,перегружу конструктор Value,и всё будет ок.
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16827 / 5248 / 321
Регистрация: 30.03.2009
Сообщений: 14,132
Записей в блоге: 26
13.07.2009, 10:07     Пишем свой интерпретатор языка BASIC #49
Цитата Сообщение от #pragma Посмотреть сообщение
Уже не возникает,то есть я перегрузил оператор = в классе переменных,а также сделал своё поле значений внутри переменной,и теперь правомерна запись Variable a = syntax_parserPrimary();
Так в том-то и дело, я это уже объяснял, но особого внимания не заострял. Здесь у тебя "a" - локальный объект в твоей процедуре (в интерпретаторе). Т.е. при выходе из этой процедуры "a" разрушится, и в при разборе следующих конструкций у тебя переменная (которая уже на бэйсике) пропадёт
#pragma
Временно недоступен
 Аватар для #pragma
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
13.07.2009, 10:10  [ТС]     Пишем свой интерпретатор языка BASIC #50
Наверное,ты просто не заметил,все мои переменные будут храниться в контейнере,а он же в динамической памяти,так?
(variable_class.h)
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16827 / 5248 / 321
Регистрация: 30.03.2009
Сообщений: 14,132
Записей в блоге: 26
13.07.2009, 11:00     Пишем свой интерпретатор языка BASIC #51
А... или initialized_vars это у тебя глобальная таблица. Т.е. ты сначала создаёшь локальный объект для переменной, а потом его засовываешь в таблицу? Ну можно и так. В этомс случае у тебя получается избыточный код в syntax_parser.cpp в строках 49-64 (я его понять особо не смог). Вместо всего этого паровоза должно стоять что-то типа того, что я обозначал как Var.GetValue(); Потому как в этом месте ты не должен пытаться понять тип переменной. А то добавишь ещё один тип и во все такие места ндо будет втыкать дополнительный код, а так дополнитеельный код будет только внутри модуля value

Кстати, по поводу отдельного модуля для типов. В теории так и надо делать, но реально у тебя тип используется только в модуле value. Да и если выносить, то кроме enum'а пока вынести больше нечего

Добавлено через 38 секунд
Цитата Сообщение от #pragma Посмотреть сообщение
Наверное,ты просто не заметил,все мои переменные будут храниться в контейнере,а он же в динамической памяти,так?
(variable_class.h)
Я не сразу это понял. Просто я в других терминах мыслю, а потому с ходу не догнал

Добавлено через 45 минут 46 секунд
Прогнал твои исходники, gcc выдаёт warning'и
Я обычно в gcc подаю опции -Wall -Werror
Первая опция выдаёт абсолютно все предепреждения, а вторая ломается в случае их (предупреждений) наличии. Временами это задалбывает по мелочи, но хорошо чистит программу от мусора

Код
value_class.cpp: In member function 'Value Value::operator+(const Value&)':
value_class.cpp:102: warning: converting to 'long int' from 'double'
value_class.cpp: In member function 'Value Value::operator-(const Value&)':
value_class.cpp:146: warning: converting to 'long int' from 'double'
value_class.cpp: In member function 'Value Value::operator*(const Value&)':
value_class.cpp:190: warning: converting to 'long int' from 'double'
value_class.cpp: In member function 'Value Value::operator/(const Value&)':
value_class.cpp:234: warning: converting to 'long int' from 'double'
#pragma
Временно недоступен
 Аватар для #pragma
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
13.07.2009, 19:26  [ТС]     Пишем свой интерпретатор языка BASIC #52
У меня тоже эта опция стоит,но предупреждений нет.Странно,почему?... В принципе можно использовать static_cast (я их пока путаю,какой из них какими особенностями обладает).
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16827 / 5248 / 321
Регистрация: 30.03.2009
Сообщений: 14,132
Записей в блоге: 26
13.07.2009, 21:08     Пишем свой интерпретатор языка BASIC #53
dynamic_cast имеет смысл только тогда, когда есть виртуальное наследование коассов, во всех осатльных случаях можно static_cast. У меня есть предупреждения, а у теюя нет вероятно потому, что у нас версии gcc разные. Мне вот наоборот кажется, что это мой gcc не по делу warning выдаёт
#pragma
Временно недоступен
 Аватар для #pragma
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
13.07.2009, 21:23  [ТС]     Пишем свой интерпретатор языка BASIC #54
Сделаю со static_cast.Версия "gcc версия 4.3.3 ".У тебя более ранняя?
P.S. Я установил svn - по ней целая книга есть,довольно сложная система управления.Пока мне удалось просто на одном диске слелать хранилище,создать рабочую копию.Но пока не понятно,как обновляется хранилище? Там читать и читать...
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16827 / 5248 / 321
Регистрация: 30.03.2009
Сообщений: 14,132
Записей в блоге: 26
13.07.2009, 22:04     Пишем свой интерпретатор языка BASIC #55
у меня где-то 4.1.3
Про svn - я всё по online документации разбирался. Правда у меня был опыт работы с cvs, так что там проще всё пошло. Если ссылку найду - кину. Если что непонятно - спрашивай, но создай лучше отдельную тему тут http://www.cyberforum.ru/linux/
Там и другие помогут, а в эту тему врядли кроме нас с тобой смотрит

Добавлено через 3 минуты 25 секунд
Если я ничего не путаю, то читал я здесь http://svnbook.red-bean.com/
Далее тыкаешь в "Открыть многостраничную HTML версию книги". Что там хорошо, чуть ниже версия на английском языке. Перевод вроде нормальный, но временами бывает, что пока оригинал не увидишь - не поймёшь
#pragma
Временно недоступен
 Аватар для #pragma
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
14.07.2009, 02:57  [ТС]     Пишем свой интерпретатор языка BASIC #56
Кажется,до меня дошло,что ты хотел мне донести.В функции syntax_parserPrimary()
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
            case TOKEN_IDENT: {
 
                int i = FindNameOverVector (::parser_CurTokenStr);
 
                if (i >= 0)
                {
                    // Если находим переменную,создаём константу с нужным
                    // значением,и возвращаем его.
                    Value v = initialized_vars.at(i).GetValue();
                    return v;
                }
                else
                {
                    // Если не находим,то создаём константу,                      
                    // приравниваем её к выражению,создаём переменную,
                    // передаём данные туда и возвращаем константу. 
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                   // Вместо того,что выше,видимо,должна быть ошибка инициализации.       
                }
            }
Я так понимаю,на данном этапе парсинга вообще не должно быть варианта else,а должна быть ошибка неинициализированной переменной. Потому что если мы встретим внутри выражения неинициализированную переменную,будет попытка её создания. Так же мы не можем знать,была ли эта находка новой переменной после ключевого слова LET или просто посередине строки.Поэтому,нужно,чтобы у stmnt_kw_LET() была своя ветка рекурсии. Я правильно понял?

Добавлено через 1 час 13 минут 50 секунд
P.S.Да,насчёт сообщения #47, я как-то пропустил,прочитал просто,но сейчас вник и согласен,лучше разделить всё это на функции (я про syntax_IdentLValue (void),syntax_IdentRValue (void) и syntax_Ident() ) ,то есть лучше следовать принципу "разделяй и властвуй",так понятнее код.Я это учту и переделаю.
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16827 / 5248 / 321
Регистрация: 30.03.2009
Сообщений: 14,132
Записей в блоге: 26
14.07.2009, 09:49     Пишем свой интерпретатор языка BASIC #57
Цитата Сообщение от #pragma Посмотреть сообщение
Я так понимаю,на данном этапе парсинга вообще не должно быть варианта else,а должна быть ошибка неинициализированной переменной. Потому что если мы встретим внутри выражения неинициализированную переменную,будет попытка её создания.
Именно так

Цитата Сообщение от #pragma Посмотреть сообщение
Так же мы не можем знать,была ли эта находка новой переменной после ключевого слова LET или просто посередине строки.Поэтому,нужно,чтобы у stmnt_kw_LET() была своя ветка рекурсии. Я правильно понял?
Судя по всему, ты уже понял про концепции rvalue и lvalue, так что ответ на этот вопрос тебе вроде бы уже понятен. Где-то я уже писал, что на каждый statement по хорошему должна быть своя процедура. Да и вообще. ка каждое синтаксическое правило нужна своя процедура. Ибо так будет проще, особенно если имя процедуры содержит в себе название правила, а в исходнике где-то в головной части или в отдельном текстовом файле ты аккуратно выпишешь все лексические и синтаксические правила, а в комментариях будешь ссылаться на них

Цитата Сообщение от #pragma Посмотреть сообщение
P.S.Да,насчёт сообщения #47, я как-то пропустил,прочитал просто,но сейчас вник и согласен,лучше разделить всё это на функции (я про syntax_IdentLValue (void),syntax_IdentRValue (void) и syntax_Ident() ) ,то есть лучше следовать принципу "разделяй и властвуй",так понятнее код.Я это учту и переделаю.
Потому я тебе и не навязываю свои варианты, а лишь выкладываю "к размышлению". После того, как сделаешь неправильно, только тогда на уровне ощущений начнёшь понимать, как делать правильно. Именно поэтому говорю, что не надо бояться переделывать код, ибо это единственный способ научиться делать правильно

Добавлено через 10 минут 1 секунду
Кстати, в 30-м посте я ошибся с правилом. Правильно вот так:

LetStatement = LET IDENT "=" Expr

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

================================================

Лексика:

Код
Const = ConstInt | ConstFloat
ConstInt = Digit { Digit }
ConstFloat = Digit { Digit } "." Digit { Digit }
Ident = Letter { Letter | Digit }
Letter = "A" | "B" | ... | "y" | "z"
Digit = "0" | "1" | ... | "9"
KeywordLet = "LET"
KeywordPRINT = "PRINT"
================================================

Синтаксис. Сделаны следующие изменения:

1. Поправлена ошибка в LetStatement
2. IDENT (лексическая конструкция) заменил на Ident (синтаксическая конструкция), потому как в Ident будет ещё и элемент массива (а то и структуры, если осилим). Аналогично с CONST'ом
3. В Expr добавил унарные плюс и минус

Ранее я забыл упомянуть. Слова с заглавной буквы - синтаксические правила, из всех заглавных букв или в кавычках - лексические единицы. Лексические и синтаксические правила НЕ живут в одном пространстве. Т.е. Ident в лексических правилах и Ident в синтаксических - это разные вещи

Код
StatementList = Statement { EOL Statement } EOF
Statement = LetStatement | PrintStatement
LetStatement = "LET" Ident "=" Expr  <-- здесь Ident на позиции Lvalue
PrintStatement = "PRINT" Expr
Expr = ["+"|"-"] Term { "+" | "-" Term }
Term = Factor { "*" | "/" Factor }
Factor = Const | Ident | "(" Expr ")"  <-- здесь Ident на позиции Rvalue
Const = CONST
Ident = IDENT  <-- в теории в будущем здесь будет ещё и элемент массива
Добавлено через 10 минут 53 секунды
Кстати, пока не забыл, если в моё отсутсвие нечем будет заняться, то напишу дальнейшее развитие. Да и чтобы сам потом вспомнил, что хотел.
  1. Ввести строковые константы
    Лексика: ConstString = <знак "> { Any symbols } <знак ">
    Синтаксис не меняется - всё это попадает под правило CONST

    Итого получается, что у тебя появляется ещё один тип констант. Т.е. в теории модификации следующие:
    • поддерживаешь в парсере
    • в синтаксисе правка минимальная - только в правиле Const добавть ещё проверку на TOKEN_CONST и всё
    • поддерживаешь операции над строковыми константами. При этом можно работать в таком варианте:
      "abc" + "def" = "abcdef"
      "abc" + 1 = "abc1"
      "abc" + 5.5 = "abc5.5"
      1 + "abc" - запрещённая операция
      5.5 + "abc" - запрещённая операция
      все остальные арифметические операции над строками запрещены
  2. Добавляем операцию INPUT. Синтаксис:
    Код
    InputStatement = INPUT Ident <-- Здесь Ident в позиции Lvalue
  3. Подумай над тем, как реализовывать условное исполнение. Синтаксис:
    Код
    IfStatement = IF RelationExpr THEN Statemen [ ELSE Statement ]
#pragma
Временно недоступен
 Аватар для #pragma
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
14.07.2009, 17:51  [ТС]     Пишем свой интерпретатор языка BASIC #58
Не могу оставить без внимания один момент. Делаю функцию Variable syntax_parserIdentLValue (); ,находится она должна,понятное дело,в парсере,чтобы поддержать модульность.
Но вот только вписать её туда не получается .Ошибки кросс компиляции.
Что я пытаюсь сделать
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
#ifndef SYNTAX_PARSER_H_INCLUDED
#define SYNTAX_PARSER_H_INCLUDED
 
 
 
   #include "value_class.h"
   class Value;
   #include "variable_class.h"  // вот тут я пытаюсь сделать её доступной.
   class Variable;                 
 
 
 
  /** @brief Function creates object
   *  of specific type,that got from
   *  parser_GetToken(),also used string
   *  value parser_CurTokenStr,or return
   *  initialized variable value.
   *  @return Object of Value class,
   *  implemented in value_class.h    */
   extern Value syntax_parserPrimary ();
 
   extern Value syntax_parserTerm ();
 
   extern Value syntax_parserExpr ();
 
  /** @brief Only for inside expression parsing.
   *  Will find variable in container.
   *  In case of variable not found
   *  error will be generated.
   *  @return Return variable's value,
   *  that found over the container */
   extern Value syntax_parserIdentRValue ();
 
   extern Variable syntax_parserIdentLValue (); // вот она
 
#endif // SYNTAX_PARSER_H_INCLUDED
И получаю такое
Код
/home/user/svn/variable_class.h|19|ошибка: поле ‘val’ имеет неполный тип|
/home/user/svn/variable_class.h||In member function ‘Value Variable::GetValue() const’:|
/home/user/svn/variable_class.h|30|ошибка: тип результата ‘struct Value’ неполный|
/home/user/svn/variable_class.h|30|ошибка: нет декларации ‘val’ в этой области видимости|
||=== Build finished: 3 errors, 0 warnings ===|
Ошибку указывает в интерфейсе класса Variable.
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
#ifndef VARIABLE_CLASS_H_INCLUDED
#define VARIABLE_CLASS_H_INCLUDED
 
#include <string>
   using std::string;
#include <vector>
   using std::vector;
#include <map>
   using std::map;
#include <algorithm>
   // find()
 
#include "value_class.h"
 
   class Variable
   {
       private:
 
              Value val;
 
              string var_name;
 
       public:
              Variable ();
              Variable (const string);
             ~Variable (){};
 
              string GetVarName () const {return var_name;};
 
              Value GetValue () const {return val;};
 
 
              Value operator = (const Value& val);
 
   };
 
   extern vector<class Variable>initialized_vars;
 
   // Find position of variable if it was initialized before
   /// @return On success,return position of variable in vector,
   /// on failure return -1
   extern int FindNameOverVector (const string str);
 
#endif // VARIABLE_CLASS_H_INCLUDED
Как тут быть? Как разрешаются подобные конфликты? Можно,конечно,поместить эту функцию в файлы класса Variable,но мне не по душе такая мешанина.
Evg
Эксперт С++Автор FAQ
 Аватар для Evg
16827 / 5248 / 321
Регистрация: 30.03.2009
Сообщений: 14,132
Записей в блоге: 26
14.07.2009, 17:54     Пишем свой интерпретатор языка BASIC #59
Такое ощущение, что в value_class.h ты не описал класс Value
Или кинь все исходники в архиве, а то так на воздухе что-то непонятно. Дома попробоую скомпилить
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
14.07.2009, 17:57     Пишем свой интерпретатор языка BASIC
Еще ссылки по теме:

Пишем свой чекер C++
Не удается откомпилировать интерпретатор М-языка C++
Пишем свой класс, спецификатор доступа protected C++

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

Или воспользуйтесь поиском по форуму:
#pragma
Временно недоступен
 Аватар для #pragma
952 / 223 / 6
Регистрация: 12.04.2009
Сообщений: 921
14.07.2009, 17:57  [ТС]     Пишем свой интерпретатор языка BASIC #60
Вот
Вложения
Тип файла: rar interpreter.rar (5.8 Кб, 104 просмотров)
Yandex
Объявления
14.07.2009, 17:57     Пишем свой интерпретатор языка BASIC
Закрытая тема Создать тему
Опции темы

Текущее время: 08:15. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru