728x90
반응형
The Driver
프로그램의 모든 부분이 제자리에 있다면 드라이버만 추가하면 작업을 시작할 수 있다. 실제 계산을 수행하는 calculate()와 실제 수행을 하게 되는 main() 함수로 구성된다.
Token_stream ts {cin}; // use input from cin
void calculate()
{
for (;;) {
ts.get();
if (ts.current().kind == Kind::end) break;
if (ts.current().kind == Kind::print) continue;
cout << expr(false) << '\n';
}
}
int main()
{
table["pi"] = 3.1415926535897932385; // inser t predefined names
table["e"] = 2.7182818284590452354;
calculate();
return no_of_errors;
}
일반적으로 main()은 프로그램이 정상 종료되면 0을 반환하고 그렇지 않으면 0이 아닌 값을 반환한다. main() 내에는 미리 정의된 이름의 기호 테이블을 삽입한다.
calculate()의 루프는 표현식을 읽고 답을 적는 기능을 한다.
cout << expr(false) << '\n';
false 인수는 작동할 토큰을 읽기 위해 ts.get()을 호출할 필요가 없음을 expr()에 알려 준다.
Kind::end에 대한 테스트는 ts.get()이 입력 오류 또는 파일 끝을 만났을 때 루프가 올바르게 종료되는지 확인한다. Kind::print(즉, '\n' 및 ';')에 대한 테스트는 빈 표현식을 처리해야 하는 expr()의 책임을 덜어 준다.
Headers
계산기는 표준 라이브러리 기능을 사용하기 때문에 적절한 헤더 파일이 포함되어야 한다.
#include<iostream> // I/O
#include<string> // strings
#include<map> // map
#include<cctype> // isalpha(), etc
Codes
설명한 예제는 파일은 다음과 같으며, VS2015로 제작되었다.
// Caculator.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <string>
#include <map>
#include <iostream>
using namespace std;
enum class Kind : char
{
name, number, end,
plus = '+', minus = '-', mul = '*', div = '/', print = ';', assign='=', lp='(', rp=')'
};
struct Token
{
Kind kind;
string string_value;
double number_value;
};
double expr(bool get);
double term(bool get);
double prim(bool get);
map<string, double> table;
int no_of_errors;
double error(const string& s)
{
no_of_errors++;
cerr << "error: " << s << '\n';
return 1;
}
class Token_stream
{
public:
Token_stream(istream& s) : ip{ &s }, owns{ false } {}
Token_stream(istream* p) : ip{ p }, owns{ true } {}
~Token_stream() { close(); }
Token get()
{
//char ch = 0;
//*ip >> ch;
char ch;
do {
if (!ip->get(ch))
return ct = { Kind::end };
} while (ch != '\n' && isspace(ch));
switch (ch)
{
case 0:
return ct = { Kind::end };
case '*':
case '/':
case '+':
case '-':
case '(':
case ')':
case '=':
return ct = { static_cast<Kind>(ch) };
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
case '.':
ip->putback(ch);
*ip >> ct.number_value;
ct.kind = Kind::number;
return ct;
case ';':
case '\n':
return ct = { Kind::print };
default:
if (isalpha(ch))
{
ct.string_value = ch;
while (ip->get(ch) && isalnum(ch))
ct.string_value += ch;
ip->putback(ch);
ct.kind = Kind::name;
return ct;
}
error("bad token");
return ct = { Kind::print };
}
}
const Token& current() { return ct; }
void set_input(istream& s) { close(); ip = &s; owns = false; }
void set_input(istream* p) { close(); ip = p; owns = true; }
private:
void close() { if (owns) delete ip; }
istream* ip;
bool owns;
Token ct{ Kind::end };
};
Token_stream ts{ cin };
double prim(bool get)
{
if (get)
ts.get();
switch (ts.current().kind)
{
case Kind::number:
{
double v = ts.current().number_value;
ts.get();
return v;
break;
}
case Kind::name:
{
double& v = table[ts.current().string_value];
if (ts.get().kind == Kind::assign)
v = expr(true);
return v;
}
case Kind::minus:
return -prim(true);
case Kind::lp:
{
auto e = expr(true);
if (ts.current().kind != Kind::rp)
return error("')' expected");
ts.get();
return e;
}
default:
return error("primary expected");
}
}
double term(bool get)
{
double left = prim(get);
for (;;)
{
switch (ts.current().kind)
{
case Kind::mul:
left *= prim(true);
break;
case Kind::div:
if (auto d = prim(true))
{
left /= d;
break;
}
return error("divide by 0");
default:
return left;
}
}
}
double expr(bool get)
{
double left = term(get);
for (;;)
{
switch (ts.current().kind)
{
case Kind::plus:
left += term(true);
break;
case Kind::minus:
left -= term(true);
break;
default:
return left;
}
}
}
void calculate()
{
for (;;)
{
ts.get();
if (ts.current().kind == Kind::end) break;
if (ts.current().kind == Kind::print) continue;
cout << expr(false) << endl;
}
}
int main()
{
table["pi"] = 3.1415926535897932385;
table["e"] = 2.7182818284590452354;
calculate();
return 0;
}
728x90
반응형
'Program Language > C & C++' 카테고리의 다른 글
[C++] token 요약 (0) | 2022.01.06 |
---|---|
[C++] operator 요약 (0) | 2022.01.06 |
[C++] 계산기 만들기 (4) error handling (0) | 2022.01.06 |
[C++] 계산기 만들기 (3) low-level input (0) | 2022.01.06 |
[C++] 계산기 만들기 (2) input (0) | 2022.01.06 |