Модераторы: Poseidon

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> [C++]Калькулятор из Страуструпа 
:(
    Опции темы
OPQ
Дата 10.7.2007, 09:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 31.7.2006

Репутация: нет
Всего: нет



Здрасте! Помогите разобраться, я попытался реализовать этот калькулятор (самый первый в книге), но он не работает smile 
Вот код
Код

#include<iostream>
#include<string>
#include<map>
#include<cctype>
#include<sstream>

enum Token_value{
    NAME, NUMBER, END,
    PLUS = '+', MINUS = '-', MUL ='*', DIV = '/',
    PRINT = ';', ASSIGN = '=', LP = '(', RP = ')'
};

Token_value curr_tok = PRINT;
double number_value;
std::string string_value;
std::map<std::string, double> table;
double expr(bool);
int no_of_errors;
std::istream* input;

int error(const std::string &s)
{
    no_of_errors++;
    std::cerr<<"ERROR: "<<s<<'\n';
    return 1;
}

Token_value get_token()
{
    char ch;
    do{
        if(!std::cin.get(ch))
            return curr_tok = END;
    }while(ch != '\n' && isspace(ch));

    switch(ch){
        case ';':
        case '\n':
            return curr_tok = PRINT;
        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("error lexem");
            return curr_tok = PRINT;
    }
}

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:
                -prim(true);
            case LP:
                {
                    double e = expr(true);
                    if(curr_tok != RP)
                        
                    get_token();
                    return e;
                }
            default:
                return error("pervichnoe virogenie");
    }
}

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("Div 0");
            default:
                return left;
    }
}

double expr(bool get)
{
    double left = term(get);
    for(;;)
        switch(curr_tok){
            case PLUS:
                left += term(true);
                break;
            case MINUS:
                left -= term(true);
                break;
            default:
                return left;
    }
}

int main(int argc, char* argv[])
{
    table["pi"] = 3.14159;
    table["e"] = 2.71828182;

    switch(argc){
        case 1:
            input = &std::cin;
            break;
        case 2:
            input = new std::istringstream(argv[1]);
            break;
        default:
            error("!!!!!!");
            return 1;
    }

    while(input)
    {
        get_token();
        if(curr_tok == END)
            break;
        if(curr_tok == PRINT)
            continue;
        std::cout<<expr(false)<<'\n';
    }

    if(input != &std::cin)
        delete input;

    return no_of_errors;
}



при попытке вычислить 2+3, получаю
Цитата

2+3
ERROR: error lexem
ERROR: error lexem
ERROR: error lexem

PM MAIL   Вверх
Earnest
Дата 10.7.2007, 09:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 2
Всего: 183



Для домашних заданий, курсовых, существует "Центр Помощи".

Тема перенесена! 


--------------------
...
PM   Вверх
Dronchik
Дата 10.7.2007, 12:50 (ссылка)    | (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Звукач ёмаё
**


Профиль
Группа: Участник
Сообщений: 451
Регистрация: 1.5.2007

Репутация: нет
Всего: 37



Во первых скажи, какая у тебя среда разработки?


--------------------
Вместо слов делай дело, от которого ты фанатеешь. (с)

PM MAIL WWW ICQ   Вверх
OPQ
Дата 10.7.2007, 13:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 31.7.2006

Репутация: нет
Всего: нет



VS2005
PM MAIL   Вверх
HoTMetaL
Дата 13.7.2007, 18:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 107
Регистрация: 15.4.2007

Репутация: 1
Всего: 4



Это вообще консольное приложение ANSI C++. Прочитай внимательнее главу, в которой написан данный листинг, особенно про синтаксический анализатор и как он работает.
PM MAIL   Вверх
OPQ
Дата 14.7.2007, 12:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 31.7.2006

Репутация: нет
Всего: нет



HoTMetaL,  я знаю, что это консольное приложение и создаю его как консольное. Кроме того оно работает, но не так как должно smile 

кад тупо перепечатан из книги (толко я использовал ::std вместо глобального объявления).
PM MAIL   Вверх
Dronchik
Дата 26.7.2007, 14:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Звукач ёмаё
**


Профиль
Группа: Участник
Сообщений: 451
Регистрация: 1.5.2007

Репутация: нет
Всего: 37



Расскажи, что оно делает не так. smile 


--------------------
Вместо слов делай дело, от которого ты фанатеешь. (с)

PM MAIL WWW ICQ   Вверх
OPQ
Дата 26.7.2007, 17:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 31.7.2006

Репутация: нет
Всего: нет



Dronchik, при попытке что-нибудь вычислить вызувается функция error
Код

int error(const std::string &s)
{
    no_of_errors++;
    std::cerr<<"ERROR: "<<s<<'\n';
    return 1;
}


ввожу 2+3, получаю
2+3
ERROR: error lexem
ERROR: error lexem
ERROR: error lexem

PM MAIL   Вверх
zkv
Дата 31.7.2007, 22:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


Профиль
Группа: Участник Клуба
Сообщений: 2133
Регистрация: 23.7.2006
Где: Санкт-Петербург

Репутация: 21
Всего: 92



OPQ, у меня нет книги, но я вижу, что программа делает то, что должна делать, судя по коду... чем помочь тебе - не знаю smile
PM MAIL   Вверх
DonJuansMagicPants
Дата 12.8.2007, 17:16 (ссылка)    | (голосов:8) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 49
Регистрация: 16.7.2007

Репутация: -1
Всего: -1



Могу помоч только советом выкинь Страуструпа, купи Р.Лафоре и поставь VC++ 6 и будет тебе счастье, а Страуспур возможно хороший программист, но как преподаватель имхо полное Г*.
p.s И код для простого калькулятора , какой-то аццкий ...

PM MAIL   Вверх
JackYF
Дата 15.8.2007, 19:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


полуавантюрист
****


Профиль
Группа: Участник
Сообщений: 5814
Регистрация: 28.8.2004
Где: страна тысячи озё р

Репутация: 2
Всего: 162



OPQ, неужели в книге нету примера или диска с прогами из книги?


--------------------
Пожаловаться на меня как модератора можно здесь.
PM MAIL Jabber   Вверх
HoTMetaL
Дата 17.8.2007, 20:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 107
Регистрация: 15.4.2007

Репутация: 1
Всего: 4



Попробуй поискать здесь - http://www.research.att.com/~bs/
PM MAIL   Вверх
Arks
Дата 20.8.2007, 15:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 197
Регистрация: 7.5.2006
Где: Барнаул

Репутация: нет
Всего: нет



JackYF, если вам просто нужен код какого-нибудь консольного калькулятора, то могу предложить вот это:
Код

// Calculator.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

using namespace std;

vector<string> oper[3];        // Массив операций рассортированных на приоритеты

// Выделяет из строки лексему
// s - исходный текст
// i - номер символа с которого начинать сканирование
bool Scanner(string &l,int &pr, string &s, bool reload, bool inPoliz)
{
    bool flag = true, fl=true;
    static int i = 0;
    bool delim = false;

    if(reload)
        i = 0;

    l.clear();
    while(flag)
    {
        if(l.empty() && s[i]==' ')
                ++i;    // Игнорировать пробелы
        // Проверить не находятся ли они в начале выражения или после '(', тогда они будут знаком константы...
        if( s[i]=='+' || s[i]=='-')
        {
            if(i==0 || s[i-1]=='(' || (inPoliz && s[i+1]=='0' || s[i+1]=='1' || s[i+1]=='2' || s[i+1]=='3' || s[i+1]=='4' ||
                s[i+1]=='5' || s[i+1]=='6' || s[i+1]=='7'    || s[i+1]=='8' || s[i+1]=='9'))
            {
                l += s[i++];
                fl = false;
            }
        }
        if(    s[i]=='0' || s[i]=='1' || s[i]=='2' || s[i]=='3' || s[i]=='4' || s[i]=='5' || s[i]=='6' || s[i]=='7'
                || s[i]=='8' || s[i]=='9' || s[i]=='.' || s[i]==',')
            {
                fl = false;
                l += s[i];
                if(s[i]=='.' || s[i]==',')
                    if(delim)
                        throw logic_error("Bad number format");
                    else
                        delim = true;
            }
        else
            if(!fl)
                return false;
        if(fl)
        {
            l += s[i];
            for(int j=0; j<3 && flag; j++)
            {
                vector<string>::iterator res = find(oper[j].begin(),oper[j].end(),l);
                if(res!=oper[j].end())
                {
                    flag = false;
                    pr = j;
                }
            }
        }
        ++i;
        if(fl && flag && s[i]=='#')
        {
            l.clear();
            throw logic_error("Unknown lexem");            // Ошибка - не найдена лексема
        }
    }
    return true;
}

// Перевод выражения source в постфиксный вид. Результат помещается в dest
void toPoliz(string &dest, string &source)
{
    stack<pair<string,int> > mag;                // Магазин
    bool flag = true;        // Устанавливается в 0 при завершении или ошибке
    string lex;
    int pr;
    bool f = true;

    dest.clear();

    while(flag)
    {
        if(!Scanner(lex,pr,source,f,false))    // Операнд ?
        {
            // Да
            dest += lex + " ";
        }
        else
        {
            // Операция
            if(mag.empty())
            {
                if(lex=="#")
                {
                    flag = 0;
                }
                else
                {
                    if(lex==")")
                    {
                        // Ошибка 1
                        throw logic_error("Bad parenthesis structure");
                    }
                    else
                    {
                        mag.push(make_pair<string,int>(lex,pr));
                    }
                }
            }
            else
            {
                if(!pr)
                {
                    mag.push(make_pair<string,int>(lex,0));
                }
                else
                {
                    while(!mag.empty() && pr<=mag.top().second)
                    {
                        dest += mag.top().first + " ";
                        mag.pop();
                    }
                    if(lex==")")
                    {
                        if(mag.top().first=="(")
                            mag.pop();
                        else
                        {
                            vector<string>::iterator res = find(oper[0].begin(),oper[0].end(),mag.top().first);
                            if(res!=oper[0].end())        // Функция есть в списке?
                            {
                                // Да, выводим в строку результата
                                dest += mag.top().first + " ";
                                mag.pop();
                            }
                            else
                            {
                                // Ошибка 2
                                throw logic_error("Bad parenthesis structure");
                            }
                        }
                    }
                    else
                    {
                        if(lex=="#")
                        {
                            if(mag.empty())
                                flag = 0;
                            else
                            {
                                // Ошибка 3
                                throw logic_error("Bad parenthesis structure");
                            }
                        }
                        else
                            mag.push(make_pair<string,int>(lex,pr));
                    }
                }
            }
        }
        f = false;
    }
}

double CalcOper(double &o1, double &o2, string &op)
{
    if(op=="sin(")        return sin(o1);
    if(op=="cos(")        return cos(o1);
    if(op=="tan(")        return tan(o1);
    if(op=="log(")        return log(o1);
    if(op=="exp(")        return exp(o1);
    if(op=="sqrt(")        return sqrt(o1);
    if(op=="+")            return o1+o2;
    if(op=="-")            return o1-o2;
    if(op=="*")            return o1*o2;
    if(op=="/")
    {
        if(o2==0)
            throw logic_error("division by zero");
        return o1/o2;
    }
    // Возведение в степень
    if(op=="^")
    {
        return pow(o1,o2);
    }
}

double CalculatePoliz(string &source)
{
    string elem;
    int i=0;
    bool f = true;
    int pr;
    double el, el1;
    stack<double> mag;

    source += "#";
    elem.clear();

    while(elem!="#")
    {
        if(!Scanner(elem,pr,source,f,true))
        {
            // Операнд
            mag.push(strtod(elem.c_str(),NULL));
        }
        else
        if(elem!="#")
        {
            // Производим вычисления
            vector<string>::iterator res = find(oper[0].begin(),oper[0].end(),elem);
            if(res!=oper[0].end())
            {
                // Унарная операция - вызов функции
                if(mag.empty())
                {
                    // Ошибка: лишний знак операции
                    throw logic_error("Too many operators");
                }
                el = mag.top();
                mag.pop();
                el = CalcOper(el,el,elem);
                mag.push(el);
            }
            else
            {
                // Бинарная операция
                if(mag.empty())
                {
                    // Ошибка лишний знак операции
                    throw logic_error("Too many operators");
                }
                el = mag.top();
                mag.pop();
                if(mag.empty())
                {
                    // Ошибка лишний знак операции
                    throw logic_error("Too many operators");
                }
                el1 = mag.top();
                mag.pop();
                el = CalcOper(el1,el,elem);
                mag.push(el);
            }
        }
        f = false;
    }
    el = mag.top();
    mag.pop();
    if(!mag.empty())
    {
        // Ошибка: лишний операнд
        throw logic_error("Too many operands");
    }
    return el;
}

void InitializeLexems(void)
{
    oper[0].push_back("(");
    oper[0].push_back("cos(");
    oper[0].push_back("sin(");
    oper[0].push_back("log(");
    oper[0].push_back("tan(");
    oper[0].push_back("sqrt(");
    oper[0].push_back("exp(");

    oper[1].push_back("+");
    oper[1].push_back("-");
    oper[1].push_back(")");
    oper[1].push_back("#");

    oper[2].push_back("*");
    oper[2].push_back("/");
    oper[2].push_back("^");
}

int _tmain(int argc, _TCHAR* argv[])
{
    string source, dest;

    InitializeLexems();

    cout << "Input expression: ";
    cin >> source;
    source += '#';
    try{
    toPoliz(dest,source);
    //cout << dest;
    double res = CalculatePoliz(dest);
    cout << "The result: "<< res << endl;
    }
    catch(logic_error er)
    {
        cout << er.what();
    }
    catch(...)
    {
        cout << "unkown error";
    }
    getch();
    return 0;
}




Функция Scanner там выполнена из рук вон плохо (хотя и работает), остальное нормально. Моя программка, хотя алгоритм, конечно же не сам придумывал  smile 
PM MAIL ICQ Skype MSN   Вверх
JackYF
Дата 20.8.2007, 18:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


полуавантюрист
****


Профиль
Группа: Участник
Сообщений: 5814
Регистрация: 28.8.2004
Где: страна тысячи озё р

Репутация: 2
Всего: 162



Цитата(Arks @  20.8.2007,  15:04 Найти цитируемый пост)
JackYF, если вам просто нужен код какого-нибудь консольного калькулятора

не, именно _мне_ он не нужен smile посмотри начало темы.

Автор не отвечает, тема, судя по всему, заглохла smile


--------------------
Пожаловаться на меня как модератора можно здесь.
PM MAIL Jabber   Вверх
Arks
Дата 21.8.2007, 08:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 197
Регистрация: 7.5.2006
Где: Барнаул

Репутация: нет
Всего: нет



Цитата(JackYF @  20.8.2007,  18:57 Найти цитируемый пост)
не, именно _мне_ он не нужен smile посмотри начало темы.


и вправду... чего-то я вчера рассеяным был каким-то... 
Ну да ладно, может кому и сгодится код... smile 
PM MAIL ICQ Skype MSN   Вверх
OPQ
Дата 24.8.2007, 08:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 31.7.2006

Репутация: нет
Всего: нет



Не тема не сдохла smile 
Меня просто небыло в инете.

Спасибо всем кто пытался помоч, просто код какого-нибудь консольного калькулятора мне не нужен.
И это не домашнее задание! smile  я просто хотел разобраться.
PM MAIL   Вверх
apook
Дата 31.8.2007, 07:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 794
Регистрация: 12.7.2006

Репутация: 10
Всего: 23



Цитата(OPQ @  26.7.2007,  17:25 Найти цитируемый пост)
Dronchik, при попытке что-нибудь вычислить вызувается функция error


Вобщем функцию error вызывает  функция get_token() происходит ето на этой строчке 
Код
 if( isalpha(ch) )
что означает: ЕСЛИ ЭТО БУКВА ТО TRUE
иначе происойдет именно вызов еррора, зачем это происходит я не понял поменяв условие на 
Код
 if( isdigit(ch) )
 получаем получаем то-же ошибку но менее категоричную вобщем можно покопать но это не единственная путанница, сей уалкулятор толжен уметь брать условия как с командной строки так и с клавы так вот
взяв к примеру 3+4 с командной строки запускает функцию get_token которая честно ждет ввода с клавы при етом обрабатывает тока 2 символа и посылает все это туда где происходит крутое вычисление 3 + получаем почему-то 0 

корочоче при беглом анализе получил вот такое smile



--------------------
Мои руки из дуба, голова из свинца ну и пусть ...
PM MAIL   Вверх
keensky
Дата 29.3.2008, 13:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 2
Регистрация: 29.3.2008

Репутация: нет
Всего: нет



Вот поправил, работает.
Код


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 '/':
        case '+':
        case '-':
        case '(':
        case ')':
        case '=':
            return curr_tok=Token_value(ch);
        case ';':
        case '\n':
            return curr_tok = PRINT;
        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("Error in the lexem. Try again.");
            return curr_tok = PRINT;
    }
}

PM MAIL   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Центр помощи"

ВНИМАНИЕ! Прежде чем создавать темы, или писать сообщения в данный раздел, ознакомьтесь, пожалуйста, с Правилами форума и конкретно этого раздела.
Несоблюдение правил может повлечь за собой самые строгие меры от закрытия/удаления темы до бана пользователя!


  • Название темы должно отражать её суть! (Не следует добавлять туда слова "помогите", "срочно" и т.п.)
  • При создании темы, первым делом в квадратных скобках укажите область, из которой исходит вопрос (язык, дисциплина, диплом). Пример: [C++].
  • В названии темы не нужно указывать происхождение задачи (например "школьная задача", "задача из учебника" и т.п.), не нужно указывать ее сложность ("простая задача", "легкий вопрос" и т.п.). Все это можно писать в тексте самой задачи.
  • Если Вы ошиблись при вводе названия темы, отправьте письмо любому из модераторов раздела (через личные сообщения или report).
  • Для подсветки кода пользуйтесь тегами [code][/code] (выделяйте код и нажимаете на кнопку "Код"). Не забывайте выбирать при этом соответствующий язык.
  • Помните: один топик - один вопрос!
  • В данном разделе запрещено поднимать темы, т.е. при отсутствии ответов на Ваш вопрос добавлять новые ответы к теме, тем самым поднимая тему на верх списка.
  • Если вы хотите, чтобы вашу проблему решили при помощи определенного алгоритма, то не забудьте описать его!
  • Если вопрос решён, то воспользуйтесь ссылкой "Пометить как решённый", которая находится под кнопками создания темы или специальным флажком при ответе.

Более подробно с правилами данного раздела Вы можете ознакомится в этой теме.

Если Вам помогли и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, Poseidon, Rodman

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Центр помощи | Следующая тема »


 




[ Время генерации скрипта: 0.0679 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.