1. paizaラーニングトップ
  2. レベルアップ問題集
  3. 構文解析メニュー(言語選択)
  4. 問題一覧 CoffeeScript(Beta)編
  5. 逆ポーランド記法への書き換え#1 CoffeeScript(Beta)編

構文解析メニューのサムネイル
逆ポーランド記法への書き換え#1 CoffeeScript(Beta)編(paizaランク B 相当)

問題にチャレンジして、ユーザー同士で解答を教え合ったり、コードを公開してみよう!

問題

下記の問題をプログラミングしてみよう!

字句解析済みの数式 S の n 個の字句とその字句の種類 (a1, t1) 〜 (an, tn) が中置記法の順で文字列で与えられます。


(a1, t1) 〜 (an, tn) を後置記法(逆ポーランド記法)に書き換えて n 行で出力してください。


数式は以下のEBNFに従います。



EBNF


<expr>   ::= <number> ( '+' <number> )* 
<number> ::= [0-9]+


※ただし、 0 を除いて整数の先頭に 0 がある数字はないものとします。


例)000、001、023






EBNFについて


EBNFとはBNFと正規表現の組み合わせによって記述される文法で、言語の構文を定義するために用いられます。



BNFの記法について


EBNFは非終端記号と終端記号を用いた生成規則によって記述されます。



・ 非終端記号とは

角括弧で囲まれた記号で表されたもので、ある規則で定義されるシンボルとなります。


・ 終端記号とは

実際に使用される数字、文字、文字列です。

BNFの場合は引用符 ("") によって囲まれます。


記述例は以下の通りです。



<paiza> ::= <string>; 
<string> ::= <char> | <string> <char>;
<char> ::= "p" | "a" | "i" | "z";


左辺のシンボルは右辺によって定義されます。






正規表現について


正規表現は文字列の集合(パターン)を表す汎用的な記法です。メタ文字が定義され、その組み合わせによって文字列の部分的なマッチングを検索することができます。



メタ文字の例


・ '*'

直前の文字が 0 回以上繰り返される文字列にマッチ


・ '+'

直前の文字が 1 回以上繰り返される文字列にマッチ


・ '|'

前後の文字列の論理和を取る文字列にマッチ


・ '( )'

'('と')'の中の文字列をグループとして扱う


・ '[ ]'

'['と']'の中の文字列のいずれかにマッチ



今回の場合、式 <expr> は 1 つの <number> と 0 個以上の ( '+' <number> ) の組み合わせで構成されていることを表しています。


また、<number> は 0 から 9 のいずれかの文字が 1 つ以上連続で繋がったものです。






中置記法について


中置記法は、演算子を操作対象の間に記述する方法です。


例1)1+2は 1 に 2 を足すことを意味します。


例2)123*456-789は 123 に 456 を掛けた結果から 789 を引くことを意味します。






後置記法について


後置記法は、演算子を操作対象の後ろに記述する方法です。


例1)1 2 + は 1 に 2 を足すことを意味します。


例2)123 456 * 789 - は 123 に 456 を掛けた結果から 789 を引くことを意味します。






回答にはEBNF記法に沿った下記のコードを用いることができます。


C++の場合
#include <iostream>
#include <string>
#include <vector>
using namespace std;

void expr(vector<pair<string, string>> &a, vector<pair<string,string>> &t, int &i);
void number(vector<pair<string, string>> &a, vector<pair<string,string>> &t, int &i);

void expr(vector<pair<string, string>> &a, vector<pair<string,string>> &t, int &i) {
number(a, t, i);

/* ここを埋める */

return;
}

void number(vector<pair<string, string>> &a, vector<pair<string,string>> &t, int &i) {

/* ここを埋める */

return;
}

int main(void) {
int n;
cin >> n;
vector<pair<string,string>> a(n);
for(int i = 0; i < n; i++) {
string v, t;
cin >> v >> t;
a[i] = make_pair(v,t);
}
int i = 0;
vector<pair<string,string>> t;
expr(a, t, i);
cout << t.size() << endl;
for(pair<string,string> c : t) {
cout << c.first << " " << c.second << endl;
}

return 0;
}


Pythonの場合
def expr(a, t, i):
i = number(a, t, i)

""" ここを埋める """

return

def number(a, t, i):

""" ここを埋める """

return i

if __name__ == "__main__":
n = int(input())
a = []
for _ in range(n):
v, t = input().split()
a.append((v, t))
i = 0
t = []
expr(a, t, i)
print(len(t))
for c in t:
print(c[0], c[1])

入力される値

1 行目に、数式の字句数 n が与えられます。

2 ~ n+1 行目に、数式の字句 ai(1 ≦ i ≦ n)、字句の種類 ti(1 ≦ i ≦ n) が空白区切りで与えられます。



n
a1 t1
a2 t2
.
.
.
an tn


入力値最終行の末尾に改行が1つ入ります。
文字列は標準入力から渡されます。 標準入力からの値取得方法はこちらをご確認ください
期待する出力

整数と演算子の総数を n とします。合計で n+1 行の出力をしてください。

1 行目には式に含まれる整数と演算子の総数を出力してください。

2 行目以降の n 行には、1 行ごとに数式に含まれる整数または演算子およびそのタイプを後置記法の順に空白区切りで出力してください。

また、末尾に改行を入れ、余計な文字、空行を含んではいけません。



入力例
5
1 number
+ operator
2 number
+ operator
3 number


出力例
5
1 number
2 number
+ operator
3 number
+ operator

条件

すべてのテストケースにおいて、数式は以下の条件をみたします。

・ 1 ≦ n ≦ 105

・ ai、ti は全て文字列

・ ai に含まれるものは整数と演算子のみ

・ ai が整数である場合、0 ≦ ai ≦ 106

・ S は式として正しいことが保証されている

・ 演算子の種類は '+' の 1 種類のみ

・ 式の値は常に 10-9 < 式の値 < 109 の範囲を超えない

入力例1

5
1 number
+ operator
2 number
+ operator
3 number

出力例1

5
1 number
2 number
+ operator
3 number
+ operator

問題一覧へ戻る

ページの先頭へ戻る