응애맘마조
231101 강의 본문
오늘은 언리얼이 아니고 중위 표기법, 후위 표기법을 이용한 스택 계산기를 만들었습니다.
#pragma once
#include <iostream>
using namespace std;
#include <Windows.h>
#include "stdafx.h"
#include <vector>
#define NULLNUM INT_MAX
struct NODE
{
float num;
char c;
};
//비어있는 노드
NODE tempNode;
//연산자와 피연산자를 담을 벡터
vector<NODE> vectorNode;
//후위표기법용 벡터
vector<NODE> clac;
//연산자 벡터
vector<NODE> Char;
void GetPostFix();
int main()
{
FILE* fp = NULL;
//파일 열기
fopen_s(&fp, "calc.txt", "r");
//받아올 문자
char temp;
//방금 저장한값이 2자리 이상의 수인지 비교
float num = NULLNUM;
//소수점 계산에 쓰일 변수 3개
float num2 = NULLNUM;
int num3 = NULLNUM;
int Count = NULLNUM;
while (1)
{
if (feof(fp))break;
fscanf_s(fp, "%c", &temp);
switch (temp)
{
//연산자 및 괄호일 경우
case '(':case ')':case '+':case '*':case '/':
//방금전에 읽었던 값이 숫자였는지
if (num != NULLNUM)
{
//벡터에 숫자로 추가한다
tempNode.num = num;
tempNode.c = NULL;
vectorNode.emplace_back(tempNode);
num2 = NULLNUM;
num = NULLNUM;
}
//숫자를 저장하고 난뒤 연산자를 추가
tempNode.num = NULLNUM;
tempNode.c = temp;
vectorNode.emplace_back(tempNode);
break;
//숫자 일때
//음수인지 연산자 - 인지 구분
case '-':
if (vectorNode.empty() || vectorNode.back().c == '('
|| vectorNode.back().c == '+' || vectorNode.back().c == '/'
|| vectorNode.back().c == '-' || vectorNode.back().c == '*')
{
//뒤에 오는 숫자를 실수형으로 전부다 읽기
fscanf_s(fp, "%f", &num2);
tempNode.num = num2 * -1.0f;
tempNode.c = NULL;
vectorNode.emplace_back(tempNode);
num2 = NULLNUM;
num = NULLNUM;
}
//연산자인 - 경우
else
{
tempNode.num = NULLNUM;
tempNode.c = temp;
vectorNode.emplace_back(tempNode);
}
break;
//소수점일 경우
case '.':
//뒤에 오는 숫자를 실수형으로 전부다 읽기
fscanf_s(fp, "%f", &num2);
num3 = 1;
Count = 0;
//읽어온 num2 자리수 확인
while(num3 > num2)
{
num3 *= 10;
Count++;
}
//소수점 이하 값 만들어주기
for (int i = 0; i < Count + 1; i++)
{
num2 *= 0.1f;
}
num += num2;
tempNode.num = num;
tempNode.c = NULL;
vectorNode.emplace_back(tempNode);
num2 = NULLNUM;
num = NULLNUM;
Count = NULLNUM;
break;
default:
//앞에 숫자가 있었다면
if (num != NULLNUM)
{
num = num * 10.0f + atoi(&temp);
}
//앞에 숫자가 아니였다면
else
{
num= atoi(&temp);
}
break;
}
}
fclose(fp);
//마지막에 한번 더 들어간 빼기
vectorNode.pop_back();
cout << "중위 표기법" << endl;
for (int i = 0; i < vectorNode.size(); i++)
{
if (vectorNode[i].num != NULLNUM)
{
cout << vectorNode[i].num << endl;
}
else
{
cout << vectorNode[i].c << endl;
}
}
GetPostFix();
cout << "후위 표기법" << endl;
for (int i = 0; i < clac.size(); i++)
{
if (clac[i].num != NULLNUM)
{
cout << clac[i].num << endl;
}
else
{
cout << clac[i].c << endl;
}
}
//원래 있던 노드 비우기
vectorNode.clear();
vectorNode.shrink_to_fit();
//역순으로 vectorNode 에 값채우기
while (1)
{
if (clac.size() < 1)break;
vectorNode.emplace_back(clac.back());
clac.pop_back();
}
while (1)
{
if (vectorNode.size() < 1)break;
//숫자인경우
if (vectorNode.back().num != NULLNUM)
{
clac.emplace_back(vectorNode.back());
vectorNode.pop_back();
}
//연산자 일때
else
{
float f1, f2;
f1 = clac.back().num;
clac.pop_back();
f2 = clac.back().num;
clac.pop_back();
switch (vectorNode.back().c)
{
case '+':
tempNode.num = f1 + f2;
tempNode.c = NULL;
clac.emplace_back(tempNode);
break;
case '*':
tempNode.num = f1 * f2;
tempNode.c = NULL;
clac.emplace_back(tempNode);
break;
case '/':
tempNode.num = f2/ f1;
tempNode.c = NULL;
clac.emplace_back(tempNode);
break;
case '-':
tempNode.num = f2 - f1;
tempNode.c = NULL;
clac.emplace_back(tempNode);
break;
}
//마지막에 하나 빼준다.
vectorNode.pop_back();
}
}
cout << "답은" << clac.back().num << endl;
int a;
cin >> a;
return 0;
}
void GetPostFix()
{
for (int i = 0; i < vectorNode.size(); i++)
{
//숫자인 경우 후위 표기법용 벡터에 넣는다(숫자는 그냥출력한다)
if (vectorNode[i].num != NULLNUM)
{
clac.emplace_back(vectorNode[i]);
}
//연산자인경우
else
{
switch (vectorNode[i].c)
{
//여는 괄호를 만나면 조건없이 연산자 벡터에 넣기
case '(':Char.emplace_back(vectorNode[i]);
break;
//닫는 괄호를 만나면 연산자벡터에 ( 만날때까지 꺼내서 출력
case')':
while (Char.back().c!= '(')
{
//연산자벡터 있던 마지막놈을 출력문끝에 넣기
clac.emplace_back(Char.back());
Char.pop_back();
}
Char.pop_back();//마지막인 ( 를 빼준다.
break;
case '+': case '-':
//여는괄호나 연산자 벡터가 비어있지 않을때까지
while (Char.size() != 0 && Char.back().c != '(')
{
//연산자벡터 있던 마지막놈을 출력문끝에 넣기
clac.emplace_back(Char.back());
Char.pop_back();
}
//비교해서 꺼낸다음 자신은 연산자 벡터에 추가
Char.emplace_back(vectorNode[i]);
break;
case '*': case '/':
//여는괄호나 연산자 벡터가 비어있지 않고
//자신과 우선순위 동일한 연산자 까지
while (Char.size() != 0 && Char.back().c != '('
&&(Char.back().c != '*'|| Char.back().c != '/'))
{
//연산자벡터 있던 마지막놈을 출력문끝에 넣기
clac.emplace_back(Char.back());
Char.pop_back();
}
//비교해서 꺼낸다음 자신은 연산자 벡터에 추가
Char.emplace_back(vectorNode[i]);
break;
}
}
}
while (1)
{
//연산자벡터가 빌때까지
if (Char.size() < 1)break;
//출력문에 전부 끝에 붙여주기
clac.emplace_back(Char.back());
Char.pop_back();
}
}
숫자와 연산자를 따로 읽는 방법입니다. 연산자를 배열에 추가하고 빼서 사용하는 방식입니다.
읽어주셔서 감사합니다.
Comments