排程場演算法

排程場演算法（Shunting Yard Algorithm）是一個用於將中綴表示式轉換為字尾表示式的經典演算法，由艾茲格・迪傑斯特拉引入，因其操作類似於火車編組場而得名。

簡例

輸入：3+4

將 3 入輸出佇列（每當輸入一個數字時，直接進入輸出佇列）
將 + 號壓入運算堆疊
將 4 入輸出佇列
輸入結束，將運算子堆疊中剩餘運算子入輸出佇列
在本情況下只有 + 號
輸出

透過這個例子可以看出兩條規則：

當讀入一個數字時直接入輸出佇列
當輸入結束後，運算子佇列中所有運算子入輸出佇列

詳細的演算法

當還有記號可以讀取時：
讀取一個記號。
如果這個記號表示一個數字，那麼將其新增到輸出佇列中。
如果這個記號表示一個函式，那麼將其壓入棧當中。
如果這個記號表示一個函式引數的分隔符（例如，一個半形逗號，）：

:* 從棧當中不斷地彈出運算子並且放入輸出佇列中去，直到棧頂部的元素為一個左括號為止。如果一直沒有遇到左括號，那麼要麼是分隔符放錯了位置，要麼是括號不匹配。

如果這個記號表示一個運算子，記做 o1，那麼：

:* 只要存在另一個記為 o2 的運算子位於棧的頂端，並且

:::: 如果 o1 是左結合性的並且它的運算子優先順序要小於或者等於 o2 的優先順序，或者

:::: 如果 o1 是右結合性的並且它的運算子優先順序比 o2 的要低，那麼

::: 將 o2 從棧的頂端彈出並且放入輸出佇列中（迴圈直至以上條件不滿足為止）；

:* 然後，將 o1 壓入棧的頂端。

如果這個記號是一個左括號，那麼就將其壓入棧當中。
如果這個記號是一個右括號，那麼：

:* 從棧當中不斷地彈出運算子並且放入輸出佇列中，直到棧頂部的元素為左括號為止。

:* 將左括號從棧的頂端彈出，但並不放入輸出佇列中去。

:* 如果此時位於棧頂端的記號表示一個函式，那麼將其彈出並放入輸出佇列中去。

:* 如果在找到一個左括號之前棧就已經彈出了所有元素，那麼就表示在表示式中存在不匹配的括號。

當再沒有記號可以讀取時：
如果此時在棧當中還有運算子：

:* 如果此時位於棧頂端的運算子是一個括號，那麼就表示在表示式中存在不匹配的括號。

:* 將運算子逐個彈出並放入輸出佇列中。

退出演算法。

更詳細的例子

中綴表示法 及 結果：
: 逆波蘭表示法：

C++ 程式實現

include
define opleftassoc (c) (c == '+'

c == '-'

c == '/'

c == '*'

c == '%')

define is_operator (c) (c == '+'

c == '-'

c == '/'

c == '*'

c == '!'

c == '%'

c == '=')

define is_function (c) (c>= 'A' && c = '0' && c = 'a' && c 0)

{

sc = stacksl - 1;

// 掃描到左括號

// 跳出輸出迴圈，此時左括號作為函式邊界判定，所以不出棧

if (sc == '(')

{

pe = true;

break;

}

else {

// 棧頂元素不是左括號

// 將棧頂元素依次出棧並放入輸出佇列

outpos = sc;

++outpos;

sl--;

}

}

// 如果沒有遇到左括號，則有可能是符號放錯或者不匹配

if (!pe)

{printf ("Error: separator or parentheses mismatched\n");

return false;

}

}

// 如果輸入符號為運算子，然後:

else if (is_operator (c))

{while (sl> 0)

{

sc = stacksl - 1;

//sc 為其棧頂元素

// 如果 c 是左結合性的且它的優先順序小於等於棧頂運算子 sc 的優先順序

// 或者 c 是右結合性且它的優先順序小於棧頂運算子 sc 的優先順序

// 將棧頂元素 sc 出棧，否則 sc 進棧

if (isoperator (sc) && ((opleftassoc (c) && (oppreced (c) 0)

{

sc = stacksl - 1;

if (sc == '(')

{

pe = true;

break;

}

else

{

outpos = sc;

++outpos;

sl--;

}

}

// 如果沒有掃描到左括號，則有可能是符號放錯或者不匹配

if (!pe)

{printf ("Error: parentheses mismatched\n");

return false;

}

// 左括號出棧且不放入輸出佇列

sl--;

// 掃描完左括號後

// 如果棧頂元素是函式運算子

// 則將其出棧並放入輸出佇列

if (sl> 0)

{

sc = stacksl - 1;

if (is_function (sc))

{

outpos = sc;

++outpos;

sl--;

}

}

}

// 未知運算子 c

else printf ("Unknown token % c\n", c);

}

++strpos;

}

// 當所有元素已經讀完

// 棧中還有剩餘運算子

while (sl> 0)

{

sc = stacksl - 1;

// 如果剩餘括號，則符號放錯或者不匹配

if (sc == '('

sc == ')')

{printf ("Error: parentheses mismatched\n");

return false;

}

// 出棧並放入輸出佇列

outpos = sc;

++outpos;

--sl;

}

outpos = 0;// 指標置零

return true;

}

bool execution_order (const char* input)

{printf ("order: (arguments in reverse order)\n");

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

char c, res4;

unsigned int sl = 0, sc, stack32, rn = 0;

// While there are input tokens left

while (strpos 0)

{

sc = stacksl - 1;

sl--;

if (nargs> 1) printf ("% s,", &sc);

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

--nargs;

}

}

else

{if (nargs == 1)

{

sc = stacksl - 1;

sl--;

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

}

else

{

sc = stacksl - 1;

sl--;

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

sc = stacksl - 1;

sl--;

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

}

}

// Push the returned results, if any, back onto the stack.

stacksl = (unsigned int) res;

++sl;

}

++strpos;

}

// If there is only one value in the stack

// That value is the result of the calculation.

if (sl == 1)

{

sc = stacksl - 1;

sl--;

printf ("% s is a result\n", &sc);

return true;

}

// If there are more values in the stack

// (Error) The user input has too many values.

return false;

}

int main

{//functions: A B (a) C (a, b), D (a, b, c) ...

//identifiers: 0 1 2 3 ... and a b c d e ...

//operators: = - + / * % !

const char input = "a = D (f - b c + d, !e, g)";

char output128;

printf ("input: % s\n", input);

if (shunting_yard (input, output))

{printf ("output: % s\n", output);

if (!execution_order (output))

printf ("\nInvalid input\n");

}

return 0;

}