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

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

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

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

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

*****************
Благодаря форуму и 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)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
20.06.2009, 20:03     Пишем свой интерпретатор языка BASIC
Посмотрите здесь:

C++ Написать интерпретатор программного языка -помощь
Написать Интерпретатор Программного Языка(собственного) C++
C++ пишем свой троян с нуля
C++ Интерпретатор небольшого языка программирования на С++
C++ Интерпретатор музыки стандарта BASIC PLAY на С++
Интерпретатор/компилятор ассемблер-подобного языка C++
Пишем свой чекер C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Evg
Эксперт CАвтор FAQ
17391 / 5629 / 352
Регистрация: 30.03.2009
Сообщений: 15,415
Записей в блоге: 26
05.01.2013, 23:07     Пишем свой интерпретатор языка BASIC #461
Мне кажется, что проблема под виндами может быть исключительно с библиотекой SDL, всё остальное - стандартный Си++. Насчёт commit'а - надо у #pragma'ы спрашивать и вкуривать в настройки sourceforge, как там формируются svn-пользователи. #pragma учится, но, судя по профилю, форум посещает. Но для подстраховки спроси его в личку
Tochka
0 / 0 / 0
Регистрация: 31.07.2012
Сообщений: 6
10.01.2013, 18:13     Пишем свой интерпретатор языка BASIC #462
Добрый день.
Решил оживить тему ещё одним вопросом про написание интерпретатора.

У меня есть компилятор, который формирует байт код, и ВМ, которая его читает из файла. Я не могу сообразить как к моей ВМ с байт кодом прикрутить работу с остальным миром (окнами и файловой системой). А то получается она работает в сферическом вакууме.
Вариант предложенный здесь (выделить отдельную лексему) не подходит. Хочется сделать реализацию на подобие Java, .NET. Хотелось бы услышать идею реализации.

Заранее спасибо всем откликнувшимся.
Evg
Эксперт CАвтор FAQ
17391 / 5629 / 352
Регистрация: 30.03.2009
Сообщений: 15,415
Записей в блоге: 26
10.01.2013, 18:46     Пишем свой интерпретатор языка BASIC #463
В любой реализации байт-кода на самом нижнием уровне должен быть выход на родную операционную систему. Потому что 100%-ых байт-кодов не бывает. В случае java есть какая-то одна (а может несколько библиотек), в процессе исполнения которых вместо байт-кода начинают запускаться родные коды на host'овой машине.

Как технически реализована библиотека - не знаю. Маловероятно, что в язык была внесена какая-то конструкция. Скорее всего библиотека как-то реализована на Си и вокруг неё ручками сделан обвес для виртуальной машины
silent_1991
Эксперт С++
4956 / 3032 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
10.01.2013, 20:39     Пишем свой интерпретатор языка BASIC #464
Цитата Сообщение от Tochka Посмотреть сообщение
Хочется сделать реализацию на подобие Java
В джвае такие вещи реализуются через вызовы нативного кода из динамических библиотек. Некоторый метод джава объявляется как native, что говорит виртуальной машине, что он реализован на С/С++/Ассемблере и расположен в динамической библиотеке. Сигнатура метода на языке С++ может быть сгенерирована из файла класса утилитой javah, программист реализует тело метода, компилирует его в динамическую библиотеку, в программе на джава (например, в области статической инициализации класса, содержащего нативный метод) эта библиотека загружается стандартными средствами (через System.load()), и вуаля - метод можно вызывать.
Думаю, в .NET это реализовано идейно так же.
Как видно, без нативного кода не обойтись. Виртуальная машина - всего лишь программа, и доступ к внешнему миру из неё можно получить только так же, как из любой другой программы - через системные вызовы ОС. Их же, в свою очередь, сам программист помещает в разделяемые библиотеки, при этом они должны иметь строго согласованную с ВМ сигнатуру, чтобы ВМ могла их вызвать (фактически, всё это напоминает плагины).
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
13.04.2013, 10:51     Пишем свой интерпретатор языка BASIC
Еще ссылки по теме:

Задание: разработать "Интерпретатор языка". С чего начать? C++
По русскому названию языка программирования определить английское название этого языка C++
C++ Перепишите пожалуйста код программы с языка Visual Basic в C++
Не удается откомпилировать интерпретатор М-языка C++
Пишем свой класс, спецификатор доступа protected C++

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

Или воспользуйтесь поиском по форуму:
Nameless One
13.04.2013, 10:51     Пишем свой интерпретатор языка BASIC
  #465
 Комментарий модератора 
Закрыто. Если кто-то хочет высказаться по теме, пишите в личку.
Yandex
Объявления
13.04.2013, 10:51     Пишем свой интерпретатор языка BASIC
Закрытая тема Создать тему
Опции темы

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