Skip to content

Latest commit

 

History

History

infix-notation

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 

中置記法から前置記法への変換

このノートでは、1 + 2 のような中置記法で書かれた式を、 + 1 2 のような前置記法で書かれた式に変換する方法を取り上げます。 ここで説明する内容は、甲州計算機のバージョン 0.41 の Infix.hs モジュールに対応します。

部分式の高さ

1 + 2 は 3 つの部分式 1 + 2 に分解できます。 それぞれの部分式に高さを割り当て、中置演算子の + の高さは 1 で、 演算子以外の部分式の高さは 0 であるとします。 高さを括弧に入れて書くと 1(0) +(2) 2(0) のようになります。 高さをコロン : の数であらわすと、つぎのように想像できます。

     +
     :
 1   :   2

もっとも高い部分式で左右に分割すると考えると、 演算子 + の左の部分式 1 と右の部分式 2 が得られます。 その結果、+ (1) (2) のような前置記法の式へ変形できます。

1 + 2 * 31(0) +(2) 2(0) *(1) 3(0) という 高さが割り当てられるとすると、つぎのように視覚化できます。

     +
     :      *
 1   :   2  :  3

まず、+ (1) (2 * 3) という前置記法に変換され、 さらに、+ (1) (* (2) (3)) に変換されます。

左分割と右分割

+* のように演算子の高さが異なれば、あいまいさは生じませんが、 1 + 2 + 3 のように同じ高さの演算子が使われているときは、 左の演算子で分割し + (1) (2 + 3) とするか、 右の演算子で分割し + (1 + 2) (3) とするかを決める必要があります。

いま、+ の高さが 2 で右分割であるということを、 1(0) +(R2) 2(0) +(R2) 3(0) と書くとします。 高さと向きだけを抜き出すと、0 R2 0 R2 0 と書けます。 高さと左右の組み合わせについて、いくつか例を示します。

  • 0 L1 0 L2 0 → (L2 (0 L1 0) (0)) → (L2 (L1 (0) (0)) 0)
  • 0 L1 0 L1 0 → (L1 (0) (0 L1 0)) → (L1 0 (L1 (0) (0)))
  • 0 R1 0 R1 0 → (R1 (0 R1 0) (0)) → (R1 (R1 (0) (0)) 0)

同じ高さで向きの異なる演算子があるときは、 左分割にするか右分割にするか定まらず、あいまいな式になります。 甲州計算機は、このような式に出会うと処理を中断します。

  • 0 L1 0 R1 0 → あいまい

モジュール

Infix.hs モジュールの構成をかんたんに説明します。

分割のための向き Left Right と高さ h :: IntLeft hRight h であらわします。 この型 Either Int IntInfixHeight という別名を与えると、 トークン a を高さと向きに変換する関数 a -> InfixHeight を定義できます。

トークン a に内包された記号 b に対して ih :: InfixHeight を割り当てる規則 htab :: [(b, ih), ...] と、内包された記号を取り出す extract :: a -> b を組み合わせると、高さ関数 infixHeight extract htab :: a -> Infixheight を実際につくれます。

この高さ関数 ht :: a -> Infixheight を使って、 中置記法のトークン木 tree1 :: CodeTree a を 前置記法のトークン木に変換する関数 infixToPrefix ht tree1 を 定義できます。この関数は、必ず、トークン木を返せるわけではなく、 あいまいな演算子があるとき、その演算子のトークン tok :: a と 高さ ih :: Infixtoprefix のリスト Left [(ih, tok), ...] を返して、どこがあいまいであるかを知らせます。 前置記法に変換できたときは、変換後の tree2 :: CodeTree a を内包した Right tree2 を返します。

コマンド

このディレクトリにある infix.hs を使うと、 中置記法が前置記法に変換された結果を確認できます。 このコマンドは、式を引数に与えると、中置演算子を先頭に移動した上で、 それに対応するトークン木を出力します。たとえば、

$ ./infix.hs "/a * /b + 10"

に対して、つぎの出力が得られます。

** /a * /b + 10
TreeB 1 - -
  TreeL : TWord 1:8 0 "+"
  TreeB 1 - -
    TreeL : TWord 1:3 0 "*"
    TreeL : TTerm 1:0 ["/a"]
    TreeL : TTerm 1:5 ["/b"]
  TreeL : TWord 1:10 0 "10"