맨위로가기

차량기지 알고리즘

"오늘의AI위키"는 AI 기술로 일관성 있고 체계적인 최신 지식을 제공하는 혁신 플랫폼입니다.
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.

1. 개요

차량기지 알고리즘은 중위 표기법으로 표현된 수식을 스택과 큐를 사용하여 후위 표기법으로 변환하는 알고리즘이다. 토큰의 종류에 따라 스택 또는 큐로 이동시키며, 연산자 우선순위와 괄호 처리를 통해 수식의 연산 순서를 결정한다. 이 알고리즘은 O(n)의 시간 복잡도를 가지며, 폴란드 표기법 생성에도 적용될 수 있다.

더 읽어볼만한 페이지

  • 파싱 알고리즘 - 하향식 구문 분석
    하향식 구문 분석은 컴파일러나 인터프리터가 소스 코드를 변환할 때 입력 전체가 문법의 최상위 규칙에 일치한다고 가정하고 좌단 기호부터 매칭하며, LL 파서는 생성 규칙을 적용하여 구문 분석을 수행하고 좌측 재귀는 변환 또는 그래프 구조 스택으로 처리한다.
  • 파싱 알고리즘 - 재귀 하향 파서
    재귀 하향 파서는 백트래킹 없이 LL(k) 문법 클래스에서 선형 시간에 동작하며 각 비종단 기호에 대한 프로시저를 가지는 예측 파서이다.
  • 에츠허르 데이크스트라 - 교착 상태
    교착 상태는 둘 이상의 프로세스가 자원을 점유하고 서로의 자원을 요청하여 더 이상 진행할 수 없는 상태를 의미하며, 상호 배제, 점유 대기, 비선점, 순환 대기 네 가지 조건이 모두 충족되어야 발생하고, 운영 체제는 이를 예방, 회피, 무시, 발견하는 방법으로 관리한다.
  • 에츠허르 데이크스트라 - 세마포어
    세마포어는 데이크스트라가 고안한 정수 변수로, P/V 연산을 통해 자원 접근을 제어하고 동기화 문제를 해결하며, 계수 세마포어와 이진 세마포어로 나뉘어 멀티스레드 환경에서 자원 관리 및 스레드 동기화에 기여한다.
차량기지 알고리즘
개요
유형구문 분석 알고리즘
분야컴퓨터 과학
고안자에츠허르 W. 데이크스트라
고안 연도1961년
작동 방식
입력중위 표기법
출력후위 표기법 (역 폴란드 표기법)
자료 구조스택
성능
시간 복잡도O(n)
공간 복잡도O(n)

2. 작동 원리

차량기지 알고리즘은 스택과 라는 두 가지 자료구조를 사용하여 중위 표기법의 수식을 처리한다. 입력된 수식은 낱말 분석을 통해 토큰 단위로 분리되며, 각 토큰은 정해진 규칙에 따라 처리된다.

그림으로 보는 차량기지 알고리즘. 입력은 한 번에 하나씩 들어오며, b), d), f), h)에서처럼 입력이 변수 또는 숫자일 경우 바로 출력으로 옮겨진다. 만약 입력이 연산자라면, 연산자의 우선순위 및 결합 방향에 따라 c), e)처럼 연산자 스택으로 옮겨지거나, g)처럼 즉시 출력으로 옮겨진다. 입력이 모두 완료되면 연산자 스택의 연산자들이 모두 팝되어 출력으로 옮겨진다.


간단한 예시로 '3 + 4'를 처리하는 과정은 다음과 같다.

# 숫자 '3'을 출력 큐에 넣는다.

# 연산자 '+'를 연산자 스택에 푸시한다.

# 숫자 '4'를 출력 큐에 넣는다.

# 입력이 끝났으므로, 연산자 스택에 있는 '+'를 팝하여 출력 큐에 넣는다.

# 최종 출력은 '3 4 +'가 된다.

이처럼 숫자와 연산자는 정해진 규칙에 따라 큐와 스택으로 이동하며, 최종적으로 역폴란드 표기법 수식이 만들어진다.

좀 더 복잡한 수식 '3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3'을 처리하는 과정은 아래 표와 같다.

입력: 3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3
연산자우선순위연산자 결합 방향
^4오른쪽
*3왼쪽
/3왼쪽
+2왼쪽
-2왼쪽



입력 토큰알고리즘의 동작출력 큐 (역폴란드 표기법)연산자 스택비고
3토큰을 출력 큐에 넣음3
+토큰을 연산자 스택에 푸쉬3+
4토큰을 출력 큐에 넣음3 4+
*토큰을 연산자 스택에 푸쉬3 4* +* 의 우선순위가 + 보다 높다
2토큰을 출력 큐에 넣음3 4 2* +
/연산자 스택에서 팝하여 출력 큐에 넣음3 4 2 *+/ 와 * 의 우선순위는 같다
토큰을 연산자 스택에 푸쉬3 4 2 */ +/ 의 우선순위가 + 보다 높다
(토큰을 연산자 스택에 푸쉬3 4 2 *( / +
1토큰을 출력 큐에 넣음3 4 2 * 1( / +
토큰을 연산자 스택에 푸쉬3 4 2 * 1− ( / +
5토큰을 출력 큐에 넣음3 4 2 * 1 5− ( / +
)연산자 스택에서 팝하여 출력 큐에 넣음3 4 2 * 1 5 −( / +"("를 찾을 때까지 반복
스택을 팝함3 4 2 * 1 5 −/ +맞는 괄호를 찾았으므로 괄호를 버림
^토큰을 연산자 스택에 푸쉬3 4 2 * 1 5 −^ / +^ 의 우선순위가 / 보다 높다
2토큰을 출력 큐에 넣음3 4 2 * 1 5 − 2^ / +
^토큰을 연산자 스택에 푸쉬3 4 2 * 1 5 − 2^ ^ / +^ 는 오른쪽 결합 연산자이다
3토큰을 출력 큐에 넣음3 4 2 * 1 5 − 2 3^ ^ / +
입력 종료스택을 팝하여 출력 큐에 넣음3 4 2 * 1 5 − 2 3 ^ ^ / +



이처럼 연산자의 우선순위와 결합 법칙에 따라 연산자 스택에 푸시하거나 팝하는 과정이 진행되며, 괄호는 우선순위를 조절하는 역할을 한다.

차량기지 알고리즘의 실행 시간 복잡도는 O(''n'')이다. 즉, 입력 크기에 비례하여 실행 시간이 결정된다.

2. 1. 처리 규칙


  • 숫자는 출력 에 바로 추가한다.
  • 연산자는 다음과 같이 처리한다.
  • 왼쪽 괄호 '('는 연산자 스택에 추가한다.
  • 오른쪽 괄호 ')'는 연산자 스택에서 왼쪽 괄호가 나올 때까지 모든 연산자를 팝하여 출력 큐에 추가한다. 왼쪽 괄호는 팝하되 출력 큐에는 추가하지 않는다.
  • 함수는 연산자 스택에 추가한다.
  • 함수 인수 구분자 (쉼표)는 스택에서 왼쪽 괄호가 나올 때까지 연산자를 팝하여 출력 큐에 넣는다.
  • 모든 토큰 처리가 끝나면, 연산자 스택에 남아있는 모든 연산자를 팝하여 출력 큐에 추가한다.
  • 입력에서 토큰을 읽어들인다.

:* 만약 토큰이 숫자 또는 변수일 경우 출력 큐에 넣는다.

:* 만약 토큰이 함수일 경우 연산자 스택에 푸쉬한다.

:* 만약 토큰이 함수 인자의 구분자(예: 쉼표)일 경우

::* 스택에서 여는 괄호 '(' 가 나타날 때까지 팝하여 출력 큐에 넣는다. 만약 여는 괄호가 나타나지 않으면 구분자의 위치가 잘못되었거나 여는 괄호와 닫는 괄호가 맞지 않는 것이므로 오류를 출력한다.

:* 토큰이 연산자 o1이라면, 연산자 스택의 맨 위에 연산자가 없을 때까지 다음을 반복한다

::* 만약 스택에 연산자 o2가 있다면

::::: o1이 왼쪽 결합 연산자이고, 연산의 우선순위가 o2와 같거나 그보다 낮을 경우,

::::: 또는 o1이 오른쪽 결합 연산자이고, 우선순위가 o2보다 낮을 경우

:::: o2를 팝하여 출력 큐에 넣는다.

::* 만약 스택에 연산자가 없거나 o2가 조건을 만족하지 않으면 o1을 연산자 스택에 푸쉬한다.

:* 만약 토큰이 여는 괄호 '(' 일 경우 연산자 스택에 푸쉬한다.

:* 만약 토큰이 닫는 괄호 ')' 일 경우

::* 연산자 스택에서 여는 괄호가 나타날 때까지 연산자를 팝하여 출력 큐에 넣는다.

::* 연산자 스택에서 여는 괄호가 나타나면 팝하되, 출력 큐에는 넣지 않는다.

::* 스택을 모두 팝할 때까지 여는 괄호를 찾지 못했다면 괄호가 맞지 않는 것이므로 오류를 출력한다.

::* 여는 괄호를 팝한 후 스택 맨 위에 함수 토큰이 남아있다면 출력 큐에 넣는다.

  • 더 이상 입력 토큰이 남아있지 않다면

:* 연산자 스택이 빌 때까지 토큰을 팝한다.

::* 만약 스택에 여는 괄호나 닫는 괄호가 남아있다면 괄호가 맞지 않는 것이므로 오류를 출력한다.

::* 그 외의 연산자는 출력 큐에 넣는다.

3. 알고리즘 상세

입력이 아직 남아있는 동안 다음을 반복한다.


  • 입력에서 토큰을 읽어들인다.
  • 토큰이 숫자 또는 변수이면 출력 큐에 넣는다.
  • 토큰이 함수이면 연산자 스택에 푸쉬한다.
  • 토큰이 함수 인자의 구분자(예: 쉼표)이면
  • 스택에서 여는 괄호 '(' 가 나타날 때까지 팝하여 출력 큐에 넣는다. 만약 여는 괄호가 나타나지 않으면 구분자의 위치가 잘못되었거나 여는 괄호와 닫는 괄호가 맞지 않는 것이므로 오류를 출력한다.
  • 토큰이 연산자 o1이면, 연산자 스택의 맨 위에 연산자가 없을 때까지 다음을 반복한다.
  • 만약 스택에 연산자 o2가 있다면
  • o1이 왼쪽 결합 연산자이고, 연산의 우선순위가 o2와 같거나 그보다 낮을 경우,
  • 또는 o1이 오른쪽 결합 연산자이고, 우선순위가 o2보다 낮을 경우

o2를 팝하여 출력 큐에 넣는다.

  • 만약 스택에 연산자가 없거나 o2가 조건을 만족하지 않으면 o1을 연산자 스택에 푸쉬한다.
  • 토큰이 여는 괄호 '(' 일 경우 연산자 스택에 푸쉬한다.
  • 토큰이 닫는 괄호 ')' 일 경우
  • 연산자 스택에서 여는 괄호가 나타날 때까지 연산자를 팝하여 출력 큐에 넣는다.
  • 연산자 스택에서 여는 괄호가 나타나면 팝하되, 출력 큐에는 넣지 않는다.
  • 스택을 모두 팝할 때까지 여는 괄호를 찾지 못했다면 괄호가 맞지 않는 것이므로 오류를 출력한다.
  • 여는 괄호를 팝한 후 스택 맨 위에 함수 토큰이 남아있다면 출력 큐에 넣는다.


더 이상 입력 토큰이 남아있지 않다면

  • 연산자 스택이 빌 때까지 토큰을 팝한다.
  • 만약 스택에 여는 괄호나 닫는 괄호가 남아있다면 괄호가 맞지 않는 것이므로 오류를 출력한다.
  • 그 외의 연산자는 출력 큐에 넣는다.


입력과 연산자 스택이 모두 비었다면 알고리즘을 종료한다.

이 알고리즘의 실행 시간 복잡도를 분석하려면 각 토큰이 한 번 읽히고, 각 숫자, 함수 또는 연산자가 한 번 인쇄되며, 각 함수, 연산자 또는 괄호가 한 번 스택에 푸시되고 한 번 스택에서 팝된다는 점에 유의해야 한다. 따라서 토큰당 최대 상수 횟수의 연산이 실행되므로 실행 시간은 O(''n'') — 입력 크기에 비례한다.

차량기지 알고리즘은 접두사 표기법(폴란드 표기법이라고도 함)을 생성하는 데에도 적용할 수 있다. 이렇게 하려면 구문 분석할 토큰 문자열의 끝에서 시작하여 뒤로 작업하고, 출력 큐를 반전(따라서 출력 큐를 출력 스택으로 만듦)하고, 왼쪽 및 오른쪽 괄호 동작을 뒤집으면 된다(이제 왼쪽 괄호 동작이 이제 오른쪽 괄호를 찾을 때까지 팝해야 함을 기억하십시오). 그리고 결합 법칙 조건을 오른쪽으로 변경한다.

4. 예제

차량기지 알고리즘을 적용한 예시는 다음과 같다.

`3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3` 수식을 예로 들면 다음과 같다.

먼저, 연산자 우선순위 및 결합 방향은 다음과 같다.[1]

연산자우선순위결합성
^4오른쪽
*3왼쪽
/3왼쪽
+2왼쪽
-2왼쪽



기호 ^는 지수 연산자를 나타낸다.

이 표를 바탕으로, 각 토큰 별 알고리즘 동작, 출력(역폴란드 표기법) 및 연산자 스택 변화는 다음과 같이 요약할 수 있다.

토큰동작출력
(역폴란드 표기법)
연산자
스택
비고
3토큰을 출력에 추가3
+토큰을 스택에 푸시3+
4토큰을 출력에 추가3 4+
*토큰을 스택에 푸시3 4* +*가 +보다 우선순위가 높다.
2토큰을 출력에 추가3 4 2* +
/스택을 출력에 팝3 4 2 *+/와 *는 우선순위가 같다.
토큰을 스택에 푸시3 4 2 */ +/는 +보다 우선순위가 높다.
(토큰을 스택에 푸시3 4 2 *( / +
1토큰을 출력에 추가3 4 2 * 1( / +
-토큰을 스택에 푸시3 4 2 * 1- ( / +
5토큰을 출력에 추가3 4 2 * 1 5- ( / +
)스택을 출력에 팝3 4 2 * 1 5 -( / +"("가 발견될 때까지 반복
스택 팝3 4 2 * 1 5 -/ +일치하는 괄호 버리기
^토큰을 스택에 푸시3 4 2 * 1 5 -^ / +^는 /보다 우선순위가 높다.
2토큰을 출력에 추가3 4 2 * 1 5 - 2^ / +
^토큰을 스택에 푸시3 4 2 * 1 5 - 2^ ^ / +^는 오른쪽에서 왼쪽으로 평가된다.
3토큰을 출력에 추가3 4 2 * 1 5 - 2 3^ ^ / +
end전체 스택을 출력에 팝3 4 2 * 1 5 - 2 3 ^ ^ / +



결과적으로, 중위 표기법 `3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3`은 차량기지 알고리즘을 통해 역폴란드 표기법 `3 4 2 * 1 5 - 2 3 ^ ^ / +`로 변환된다.

4. 1. 간단한 예제



:입력: 3+4

# 3을 출력 에 추가한다 (숫자는 항상 출력에 그대로 전송된다).

# "+" (또는 그 ID)를 연산자 스택에 푸시한다.

# 4를 출력 큐에 추가한다.

# 식을 다 읽었으므로, 스택에 있는 연산자들을 팝하고, 출력 큐에 추가한다. 이 예에서는 "+"만 스택에 있다.

# 출력: 3 4 +

이 간단한 예제로부터 몇 가지 규칙을 살펴볼 수 있다.

  • 모든 숫자는 읽는 즉시 출력에 추가된다.
  • 식을 다 읽었으면, 스택에서 모든 연산자를 팝하고 출력에 추가해 나간다.

4. 2. 상세한 예제



다음은 입력 `3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3`에 대한 차량기지 알고리즘의 상세한 동작 과정이다.

연산자 우선순위 및 결합 방향
연산자우선순위결합 방향
^4오른쪽
*3왼쪽
/3왼쪽
+2왼쪽
-2왼쪽



차량기지 알고리즘 동작 과정
입력 토큰알고리즘의 동작출력 큐 (역폴란드 표기법)연산자 스택비고
3토큰을 출력 큐에 넣음3
+토큰을 연산자 스택에 푸시3+
4토큰을 출력 큐에 넣음3 4+
*토큰을 연산자 스택에 푸시3 4* +* 의 우선순위가 + 보다 높다.
2토큰을 출력 큐에 넣음3 4 2* +
/연산자 스택에서 팝하여 출력 큐에 넣음3 4 2 *+/ 와 * 의 우선순위는 같다.
토큰을 연산자 스택에 푸시3 4 2 */ +/ 의 우선순위가 + 보다 높다.
(토큰을 연산자 스택에 푸시3 4 2 *( / +
1토큰을 출력 큐에 넣음3 4 2 * 1( / +
-토큰을 연산자 스택에 푸시3 4 2 * 1- ( / +
5토큰을 출력 큐에 넣음3 4 2 * 1 5- ( / +
)연산자 스택에서 팝하여 출력 큐에 넣음3 4 2 * 1 5 -( / +"("를 찾을 때까지 반복.
스택을 팝함3 4 2 * 1 5 -/ +맞는 괄호를 찾았으므로 괄호를 버림.
^토큰을 연산자 스택에 푸시3 4 2 * 1 5 -^ / +^ 의 우선순위가 / 보다 높다.
2토큰을 출력 큐에 넣음3 4 2 * 1 5 - 2^ / +
^토큰을 연산자 스택에 푸시3 4 2 * 1 5 - 2^ ^ / +^ 는 오른쪽 결합 연산자이다.
3토큰을 출력 큐에 넣음3 4 2 * 1 5 - 2 3^ ^ / +
입력 종료스택을 팝하여 출력 큐에 넣음3 4 2 * 1 5 - 2 3 ^ ^ / +



최종적으로, 출력 큐에는 `3 4 2 * 1 5 - 2 3 ^ ^ / +` 와 같은 역폴란드 표기법 수식이 생성된다.

5. 복잡도

모든 연산자, 괄호 및 숫자는 단 한 번만 입력에서 읽고, 최대 한 번만 출력 큐에 입력된다. 연산자 및 괄호는 최대 한 번만 스택에 푸시된 후 팝되므로, 모든 입력 토큰에 대해 최대 몇 개의 연산만이 수행된다. 따라서 알고리즘의 실행 시간은 입력 길이에 비례하며, 대문자 O 표기법으로는 O(''n'')이다. 즉, 입력 데이터가 많아져도 처리 시간은 선형적으로 증가하여 효율적이다.

6. 구현 예시 (C 언어)

cpp

#include

#include

#include

// 연산자 우선순위 반환

int op_preced(const char c)

{

switch (c) {

case '!': return 4;

case '*': case '/': case '%': return 3;

case '+': case '-': return 2;

case '=': return 1;

default: return 0;

}

}

// 연산자 결합성(좌결합성 또는 우결합성) 판별

bool op_left_assoc(const char c)

{

switch (c) {

case '*': case '/': case '%': case '+': case '-': return true; // 좌결합성

case '=': case '!': return false; // 우결합성

default: return false;

}

}

// 연산자의 피연산자 개수 반환

unsigned int op_arg_count(const char c)

{

switch (c) {

case '*': case '/': case '%': case '+': case '-': case '=': return 2;

case '!': return 1;

default: return c - 'A'; // 함수의 경우, A()는 0개, B()는 1개, C()는 2개...

}

}

// 토큰 유형 판별 매크로

#define is_operator(c) (c == '+' || c == '-' || c == '/' || c == '*' || c == '!' || c == '%' || c == '=')

#define is_function(c) (c >= 'A' && c <= 'Z')

#define is_ident(c) ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z'))

// Shunting Yard 알고리즘 구현: 중위 표기법 -> 후위 표기법 변환

bool shunting_yard(const char *input, char *output)

{

const char *strpos = input, *strend = input + strlen(input);

char c, *outpos = output;

char stack[32]; // 연산자 스택

unsigned int sl = 0; // 스택 길이

char sc; // 스택 요소 기록용

while (strpos < strend) {

c = *strpos++;

if (c == ' ') {

continue; // 공백 무시

} else if (is_ident(c)) {


  • outpos++ = c; // 식별자는 출력 큐에 추가

} else if (is_function(c)) {

stack[sl++] = c; // 함수는 스택에 푸시

} else if (c == ',') {

// 콤마: 스택에서 '(' 만날 때까지 팝하여 출력

bool pe = false;

while (sl > 0) {

sc = stack[sl - 1];

if (sc == '(') {

pe = true;

break;

} else {

  • outpos++ = sc;

sl--;

}

}

if (!pe) {

printf("에러:구분자 또는 괄호의 불일치\n");

return false;

}

} else if (is_operator(c)) {

// 연산자: 우선순위 및 결합성에 따라 스택 처리

while (sl > 0) {

sc = stack[sl - 1];

if (is_operator(sc) &&

((op_left_assoc(c) && (op_preced(c) <= op_preced(sc))) ||

(op_preced(c) < op_preced(sc)))) {

  • outpos++ = sc;

sl--;

} else {

break;

}

}

stack[sl++] = c; // 현재 연산자 스택에 푸시

} else if (c == '(') {

stack[sl++] = c; // '('는 스택에 푸시

} else if (c == ')') {

// ')': '(' 만날 때까지 팝하여 출력, '('는 팝하지만 출력하지 않음

bool pe = false;

while (sl > 0) {

sc = stack[--sl];

if (sc == '(') {

pe = true;

break;

} else {

  • outpos++ = sc;

}

}

if (!pe) {

printf("에러:괄호의 불일치\n");

return false;

}

// 함수 토큰이 스택 탑에 있으면 출력

if (sl > 0) {

sc = stack[sl - 1];

if (is_function(sc)) {

  • outpos++ = sc;

sl--;

}

}

} else {

printf("알 수 없는 토큰:%c\n", c);

return false;

}

}

// 남은 연산자 스택에서 모두 팝하여 출력

while (sl > 0) {

sc = stack[--sl];

if (sc == '(' || sc == ')') {

printf("에러:괄호의 불일치\n");

return false;

}

  • outpos++ = sc;

}

  • outpos = 0; // 출력 문자열 종료

return true;

}

// 후위 표기법 수식 바탕으로 실행 순서 생성 및 출력

bool execution_order(const char *input)

{

const char *strpos = input, *strend = input + strlen(input);

char c, res[4];

unsigned int sl = 0, sc, stack[32], rn = 0;

printf("【실행 순서】\n");

while (strpos < strend) {

c = *strpos++;

if (is_ident(c)) {

stack[sl++] = c; // 값 또는 식별자는 스택에 푸시

} else if (is_operator(c) || is_function(c)) {

sprintf(res, "$%d", rn++);

printf("%s = ", res);

unsigned int nargs = op_arg_count(c);

if (sl < nargs) {

return false; // 인수 부족 에러

}

// 함수 또는 연산자 처리

if (is_function(c)) {

printf("%c(", c);

while (nargs > 0) {

sc = stack[sl - nargs];

printf("%s%s", (char*) &sc, (nargs > 1) ? ", " : ");\n");

  • -nargs;

}

sl -= op_arg_count(c);

} else {

if (nargs == 1) {

sc = stack[--sl];

printf("%c %s;\n", c, (char*) &sc);

} else {

sc = stack[sl - 2];

printf("%s %c ", (char*) &sc, c);

sc = stack[sl - 1];

sl -= 2;

printf("%s;\n", (char*) &sc);

}

}

stack[sl++] = *(unsigned int*) res; // 결과 스택에 푸시

}

}

if (sl == 1) {

sc = stack[--sl];

printf("실행 결과는 %s\n", (char*) &sc);

return true;

}

return false; // 스택에 값이 여러 개 남은 경우 에러

}

int main()

{

const char *input = "a = D(f - b * c + d, !e, g)"; // 예제 입력

char output[128];

printf("【입력】\n%s\n\n", input);

if (shunting_yard(input, output)) {

printf("【출력】\n%s\n\n", output);

if (!execution_order(output)) {

printf("\n부정확한 입력\n");

}

}

return 0;

}

```

이 C 언어 코드는 차량기지 알고리즘(Shunting Yard Algorithm)을 구현한 것이다. 주어진 수식(입력 문자열)을 후위 표기법으로 변환하고, 변환된 결과를 바탕으로 연산 실행 순서를 출력한다.
코드 구성:

  • `op_preced` 함수: 연산자의 우선순위를 반환한다.
  • `op_left_assoc` 함수: 연산자의 결합성(좌/우)을 판별한다.
  • `op_arg_count` 함수: 연산자에 필요한 피연산자 개수를 반환한다.
  • `shunting_yard` 함수: 차량기지 알고리즘을 구현하여 중위 표기법을 후위 표기법으로 변환한다.
  • 입력 문자열을 토큰(피연산자, 연산자, 함수, 괄호 등)으로 분리한다.
  • 연산자 우선순위와 결합성에 따라 스택을 조작한다.
  • 후위 표기법으로 변환된 수식을 출력한다.
  • `execution_order` 함수: 후위 표기법 수식을 바탕으로 실행 순서를 생성하고 출력한다.
  • 피연산자는 스택에 푸시, 연산자는 스택에서 피연산자를 팝하여 연산 후 결과를 다시 푸시한다.
  • 각 연산 단계를 출력한다.
  • `main` 함수: 입력 예시를 설정하고, `shunting_yard`와 `execution_order` 함수를 호출한다.

특징:

  • 함수, 식별자, 연산자를 명확히 구분한다.
  • 괄호 불일치, 구분자 오류, 피연산자 부족 등의 오류를 처리한다.
  • `#define` 매크로를 활용하여 코드 가독성을 높였다.

실행 결과 (예시):

  • 입력: `a = D(f - b * c + d, !e, g)`
  • 출력: `afbc*-d+e!gD=`
  • 실행 순서:


```

$0 = b * c;

$1 = f - $0;

$2 = $1 + d;

$3 = ! e;

$4 = D($2, $3, g);

$5 = a = $4;

실행 결과는 $5

참조

[1] 웹사이트 Parsing Expressions by Recursive Descent http://www.engr.mun.[...] 1999-01-01
[2] 간행물 Algol 60 translation : An Algol 60 translator for the X1 and making a translator for Algol 60 https://ir.cwi.nl/pu[...] 1961-11-01
[3] 문서
[4] 논문 Algol 60 translation : An algol 60 translator for the x1 and making a translator for algol 60 http://repository.cw[...] Stichting Mathematisch Centrum 1961-01-01



본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.

문의하기 : help@durumis.com