С Новым годом! Форум программистов, компьютерный форум, киберфорум
Наши страницы

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

Войти
Регистрация
Восстановить пароль
 
xtorne21st
интересующийся
304 / 275 / 19
Регистрация: 25.09.2010
Сообщений: 1,056
#1

Пораздельная компиляция и повоторное переопределением в gcc - C++

06.05.2013, 22:55. Просмотров 385. Ответов 4
Метки нет (Все метки)

Доброго времени суток. Пытаюсь разобрать пример с учебника. Теоритически вроде всё делаю правильно...
Bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ilyuha21st@coldshoot:~/Projects/calc$ g++ calc.cpp -c -o calc.o
ilyuha21st@coldshoot:~/Projects/calc$ g++ main.cpp -c -o main.o
ilyuha21st@coldshoot:~/Projects/calc$ g++ main.o calc.o -o prog
calc.o:(.bss+0x0): multiple definition of `Driver::no_of_errors'
main.o:(.bss+0x0): first defined here
calc.o:(.bss+0x8): multiple definition of `Lexer::string_value'
main.o:(.bss+0x8): first defined here
calc.o:(.bss+0x10): multiple definition of `Lexer::number_value'
main.o:(.bss+0x10): first defined here
calc.o:(.data+0x0): multiple definition of `Lexer::curr_token'
main.o:(.data+0x0): first defined here
calc.o:(.bss+0x20): multiple definition of `Driver::table'
main.o:(.bss+0x20): first defined here
calc.o:(.bss+0x50): multiple definition of `Driver::input'
main.o:(.bss+0x50): first defined here
collect2: error: ld returned 1 exit status
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
// calc.h
#ifndef _CALCULATOR_HEADER_
#define _CALCULATOR_HEADER_
 
#include <string>
#include <iostream>
#include <map>
 
namespace Driver
{
    int no_of_errors = 0;
}
 
namespace Error
{
    struct Zero_divide
    {
        Zero_divide() { Driver::no_of_errors++; }
    };
 
    struct Syntax_error
    {
        Syntax_error(const char* p) { err = p; Driver::no_of_errors++; }
 
        const char* err;
        const char* what()
        {
            return err;
        }
    };
}
 
namespace Lexer
{
    enum Token_value 
    {
        NAME,       NUMBER,     END,       
        PLUS='+',   MINUS='-',  MUL='*',    DIV='/',
        PRINT=';',  ASSIGN='=', LP='(',     RP=')'      
    };
 
    std::string string_value;
    double number_value;
    Token_value curr_token = PRINT;
 
    Token_value get_token();
}
 
namespace Parser
{
    double expr(bool);
    double term(bool);
    double prim(bool);
}
 
namespace Driver
{
    std::map<std::string, double> table;
    std::istream* input;
    void skip();
 
    using Parser::expr;
}
 
#endif
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
//calc.cpp
#include "calc.h"
#include <cctype>
 
Lexer::Token_value Lexer::get_token()
{
    char ch;
    
    do
    {
        if (!Driver::input->get(ch))
        {
            return curr_token = END;
        }
    } while (ch != '\n' && isspace(ch));
 
    switch (ch)
    {
        case 0:
            return curr_token = END;
        case ';':
        case '\n':
            return curr_token = PRINT;
        case '+':
        case '-':
        case '/':
        case '*':
        case '=':
        case '(':
        case ')':
            return curr_token = Token_value(ch);
        case '0':   case '1':   case '2':   case '3':   case '4':
        case '5':   case '6':   case '7':   case '8':   case '9':
        case '.':
            Driver::input->putback(ch);
            *Driver::input >> number_value;
            return curr_token = NUMBER;
        default:
            if (isalpha(ch))
            {
                string_value = ch;
                while (Driver::input->get(ch) && isalnum(ch))
                {
                    string_value.push_back(ch);
                }
                return curr_token = NAME;
            }
            throw Error::Syntax_error("bad token");
    }
}
 
double Parser::expr(bool get)
{
    double left = term(get);
 
    for ( ; ; )
    {
        switch (Lexer::curr_token)
        {
            case Lexer::PLUS:
                left += term(true);
                break;
            case Lexer::MINUS:
                left -= term(true);
                break;
            default:
                return left;
        }
    }
}
 
double Parser::term(bool get)
{
    double left = prim(get);
    
    for ( ; ; )
    {
        switch (Lexer::curr_token)
        {
            case Lexer::MUL:
                left *= prim(true);
                break;
            case Lexer::DIV:
                if (double v = prim(true))
                {
                    left /= v;
                }
                throw Error::Zero_divide();
            default:
                break;
        }
    }
}
 
double Parser::prim(bool get)
{
    if (get)
    {
        Lexer::get_token();
    }
 
    switch (Lexer::curr_token)
    {
        case Lexer::NUMBER:
            {
                double v = Lexer::number_value;
                Lexer::get_token();
                return v;
            }
        case Lexer::NAME:
            {
                double& v = Driver::table[Lexer::string_value];
                if (Lexer::get_token() == Lexer::ASSIGN)
                {
                    v = expr(true);
                }
                return v;
            }
        case Lexer::MINUS:
            return prim(true);
        case Lexer::LP:
            {
                double e = expr(true);
                if (Lexer::curr_token != Lexer::ASSIGN)
                {
                    throw Error::Syntax_error("')' expected");
                }
                Lexer::get_token();
                return e;
            }
        default:
            throw Error::Syntax_error("pimary expected");
    }
}
 
 
void Driver::skip()
{
    char ch;
 
    while (*input)
    {
        input->get(ch);
 
        switch (ch)
        {
            case '\n':
            case ';':
                break;
        }
    }
}
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
 // main.cpp
#include "calc.h"
#include <iostream>
#include <sstream>
 
int main(int argc, const char* argv[])
{
    switch (argc)
    {
        case 1:
            Driver::input = &std::cin;
            break;
        case 2:
            Driver::input = new std::stringstream(argv[1]);
            break;
        default:
            std::cerr << "to many arguments" << std::endl;
            return 1;
    }
 
    while (*Driver::input)
    {
        try
        {
            Lexer::get_token();
            if (Lexer::curr_token == Lexer::END)
            {
                break;
            }
            if (Lexer::curr_token == Lexer::PRINT)
            {
                continue;
            }
            std::cout << Driver::expr(false) << std::endl;
        }
        catch (Error::Zero_divide)
        {
            std::cerr << "divide by zero" << std::endl;
            Driver::skip();
        }
        catch (Error::Syntax_error e)
        {
            std::cerr << "error: " << e.what() << std::endl;
            Driver::skip();
        }
    }
 
    if (Driver::input != &std::cin)
    {
        delete Driver::input;
    }
 
    return Driver::no_of_errors;
}
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
06.05.2013, 22:55
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Пораздельная компиляция и повоторное переопределением в gcc (C++):

gcc компиляция - C++
Проблема возникла при компиляции проекта code::block. При build and run все работает, в папке bin проекта появляется .exe Но...

Компиляция gcc - C++
Подскажите как в VS скомпилировать программу с помощью компилятора gcc

Компиляция (gcc) - C++
Добрый вечер! После компиляции текстовый файл становится вдруг двоичным, как следствие его невозможно открыть для исправлений. Почему? ...

компиляция gcc и MSVC - C++
Привет всем. Объясните, почему один и тот же код #include &quot;stdafx.h&quot; #include &lt;vector&gt; #include &lt;iostream&gt; #include...

Компиляция бинарника на gcc - C++
Задача: нужно скомпилировать сырой бинарник на gcc. Он будет грузиться по адресу 0x10000 и туда же будет передаваться управление. И мне...

Компиляция проекта в gcc - C++
Здравствуйте, форумчане! Прошу помочь разобраться! Есть программа, представленная в 3х файлах. В первом содержится описание класса...

4
diagon
Higher
1932 / 1198 / 49
Регистрация: 02.05.2010
Сообщений: 2,925
Записей в блоге: 2
06.05.2013, 23:18 #2
У вас один и тот же хедер включается в 2 cpp'шника. Линкер не знает, что делать в такой ситуации.
Вы можете помочь ему, если объявите ваши функции как inline либо static.

Ну либо переписать все в ООП-шном стиле через классы.
1
xtorne21st
интересующийся
304 / 275 / 19
Регистрация: 25.09.2010
Сообщений: 1,056
07.05.2013, 00:11  [ТС] #3
Пробую я различные комбинации, но что-то всё равно не получается... Интересно, а как тогда пишутся программы на С? Всё время static использовать?
0
Croessmah
Ушел
Эксперт CЭксперт С++
13558 / 7708 / 872
Регистрация: 27.09.2012
Сообщений: 18,996
Записей в блоге: 3
Завершенные тесты: 1
07.05.2013, 00:14 #4
Цитата Сообщение от xtorne21st Посмотреть сообщение
Теоритически вроде всё делаю правильно...
Теоретически в хедерах только объявляют. Поиск соответствующих объявлениям определений задача линкера.

Добавлено через 1 минуту
Цитата Сообщение от xtorne21st Посмотреть сообщение
Всё время static использовать?
можно для объявления переменных указать extern, прототипы функций по умолчанию extern
1
xtorne21st
интересующийся
304 / 275 / 19
Регистрация: 25.09.2010
Сообщений: 1,056
07.05.2013, 19:20  [ТС] #5
Croessmah, спасибо что напомнили. Также вспомнил, что если использован модификатор const, то extern нужно задавать явно.

Добавлено через 6 минут
Хотя вот только что проверил на gcc и без extern всё ок компилируется.

Добавлено через 36 секунд
Ps. Врут в учебниках

Добавлено через 38 минут
Хотя, это скорей всего зависит от компилятора
0
07.05.2013, 19:20
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
07.05.2013, 19:20
Привет! Вот еще темы с ответами:

Компиляция Objective-C в GCC - Кроссплатформенная разработка
Пытаюсь выполнить компияцию кода Objective-C с помощью GCC на Windows. Для этого: 1. Установил Dev C++. В его состав входит MinGW,...

GCC - компиляция C/C++ программ - Кроссплатформенная разработка
Обсуждение приветствуется , буду рад пожеланиям по улучшению данной статьи.:) Статья в процессе написания, пожелания пишите сюда ...

Компиляция GCC в Windows - Кроссплатформенная разработка
У меня в виндусе GCC для виндуса (портированный) Я хочю на нем (5,1) скомпилировать сам компилятор из исходников. ...

Компиляция файлов с нестандартными расширениями GCC - C++ Linux
Можно ли такое провернуть и если да, то как? Например, я создал ассемблерные листинги: g++ -S example.cpp -o...


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

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Опции темы

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