#THU20161C. 表达式求值
表达式求值
时间限制: 1.0 秒
空间限制: 512 MB
题目描述
在本题当中,你需要设法描述一个表达式的计算过程。这个表达式可能含有四则运算(加、减、乘、除,不会出现负号)、括号、函数调用(普通函数调用和成员函数调用),和一些常量。
例如,(a+f((b-c+e)*d/c.h(d,d)).g(e)).g(d).h(f(a,c),f(b)/f(c),f(d)) 就是一个可能出现的表达式,其中 a, b, c, d, e 是常量,f 是普通函数,g, h 是成员函数。
运算的优先级为:括号 > 函数调用 > 乘除法 > 加减法。注意运算的优先级的大小不代表计算顺序的先后。
你不需要求出这个表达式的具体值,你只需要描述它的计算过程,即将这个表达式分解为若干次四则运算与函数调用,且每次运算或调用的操作数都是常量或之前的运算或调用的结果。
你可能需要一些编译原理的相关知识来解决这道题目。
表达式的定义
首先,一个常量、普通函数、成员函数只可能是一个小写英文字母。在任何一个表达式中,一个字母至多只可能是常量、普通函数、成员函数的一种。
我们用递归的方式定义合法的表达式:
-
单独的一个常量是一个合法的表达式。
-
如果
[EXPR]是一个合法的表达式,那么([EXPR])是一个合法的表达式,其值与[EXPR]相同。 -
如果
[EXPR_1]、[EXPR_2]、……、[EXPR_n]是 个合法的表达式( 至少为 ),[FUNC]是一个普通函数,那么[FUNC]([EXPR_1],[EXPR_2],……,[EXPR_n])是一个合法的表达式,其值为将[EXPR_1]、[EXPR_2]、……、[EXPR_n]依次作为参数,调用普通函数[FUNC]所得的结果。注意同一个函数在不同的调用中可能接受不同个数的参数。 -
如果
[EXPR]是一个上述三条规则和本条规则或只由本条规则定义的一个合法的表达式,[EXPR_1]、[EXPR_2]、……、[EXPR_n]是 个合法的表达式( 至少为 ),[FUNC]是一个成员函数,那么[EXPR].[FUNC]([EXPR_1],[EXPR_2],……,[EXPR_n])是一个合法的表达式,其值为将[EXPR_1]、[EXPR_2]、……、[EXPR_n]依次作为参数,调用[EXPR]的成员函数[FUNC]所得的结果。注意同一个函数在不同的调用中可能接受不同个数的参数。 -
如果
[EXPR_0]、[EXPR_1]、……、[EXPR_n]是 个上述四条规则定义的合法的表达式( 至少为 ),[OPR_1]、[OPR_2]、……、[OPR_n]是 个乘号或除号运算符,那么[EXPR_0][OPR_1][EXPR_1][OPR_2]……[OPR_n][EXPR_n]是一个合法的表达式,其值为将[EXPR_0]、[EXPR_1]、……、[EXPR_n]依次进行[OPR_1]、[OPR_2]、……、[OPR_n]运算的结果。 -
如果
[EXPR_0]、[EXPR_1]、……、[EXPR_n]是 个上述五条规则定义的合法的表达式( 至少为 ),[OPR_1]、[OPR_2]、……、[OPR_n]是 个加号或减号运算符,那么[EXPR_0][OPR_1][EXPR_1][OPR_2]……[OPR_n][EXPR_n]是一个合法的表达式,其值为将[EXPR_0]、[EXPR_1]、……、[EXPR_n]依次进行[OPR_1]、[OPR_2]、……、[OPR_n]运算的结果。 -
只有符合以上几条定义的表达式才是合法的。
容易看到,这样定义的每个合法的表达式都有唯一一种解读方式,即不会引起歧义。
计算顺序的规定
上述规定确定了一个表达式的值,接下来我们确定一个表达式的求值顺序。我们用与定义类似的方式规定这个顺序:
-
对于单独的一个常量,不需要计算。
-
对于
([EXPR]),只需计算[EXPR]。 -
对于
[FUNC]([EXPR_1],[EXPR_2],……,[EXPR_n]),先依次计算[EXPR_1]、[EXPR_2]、……、[EXPR_n],再调用[FUNC]。 -
对于
[EXPR].[FUNC]([EXPR_1],[EXPR_2],……,[EXPR_n]),先依次计算[EXPR]、[EXPR_1]、[EXPR_2]、……、[EXPR_n],再调用[FUNC]。 -
对于
[EXPR_0][OPR_1][EXPR_1][OPR_2]……[OPR_n][EXPR_n](其中[OPR_1]、[OPR_2]、……、[OPR_n]全为乘除或全为加减),先计算[EXPR_0],再计算[EXPR_1],再调用[OPR_1]得出中间结果,再计算[EXPR_2],再用上述中间结果和[EXPR_2]的结果调用[OPR_2]……直到计算完毕。
可以看出,除函数外,上述运算顺序均与我们日常使用的顺序相同;函数的运算顺序在不同的标准中不同,这里我们规定为从左至右。
输入格式
从标准输入读入数据。
输入文件只有一行(以换行符结束),只包含一个需要处理的表达式。
表达式的长度不超过 ,不会出现任何空格等多余字符。
输出格式
输出到标准输出。
按计算顺序输出每一次的运算符与函数调用。每次调用的参数只能是常量或之前某一次的运算结果,其中运算结果我们用从小到大的正整数依次表示。即:我们用单个英文字母(与输入中的相同)表示一个常量,用一个正整数表示之前某一次的运算结果,设第 次的调用产生的结果为 。
以下用 [VALUE] 表示一个参数,[OPR] 表示一个运算符,[FUNC] 表示一个函数。
如果是运算符调用,设这次要计算的是 [VALUE_1][OPR][VALUE_2],则你需要输出一行 [OPR][空格][VALUE_1][空格][VALUE_2]。
如果是普通函数调用,设这次要计算的是 [FUNC]([VALUE_1],[VALUE_2],……,[VALUE_n]),则你需要输出一行 [FUNC][空格][VALUE_1][空格][VALUE_2][空格]……[空格][VALUE_n]。
如果是成员函数调用,设这次要计算的是 [VALUE_0].[FUNC]([VALUE_1],[VALUE_2],……,[VALUE_n]) ,则你需要输出一行 [FUNC][空格][VALUE_0][空格][VALUE_1][空格][VALUE_2][空格]……[空格][VALUE_n]。
(a+f((b-c+e)*d/c.h(d,d)).g(e)).g(d).h(f(a,c),f(b)/f(c),f(d))
- b c
+ 1 e
* 2 d
h c d d
/ 3 4
f 5
g 6 e
+ a 7
g 8 d
f a c
f b
f c
/ 11 12
f d
h 9 10 13 14
样例 1 解释
- b c // 1 b-c
+ 1 e // 2 b-c+e
* 2 d // 3 (b-c+e)*d
h c d d // 4 c.h(d,d)
/ 3 4 // 5 (b-c+e)*d/c.h(d,d)
f 5 // 6 f((b-c+e)*d/c.h(d,d))
g 6 e // 7 f((b-c+e)*d/c.h(d,d)).g(e)
+ a 7 // 8 a+f((b-c+e)*d/c.h(d,d)).g(e)
g 8 d // 9 (a+f((b-c+e)*d/c.h(d,d)).g(e)).g(d)
f a c // 10 f(a,c)
f b // 11 f(b)
f c // 12 f(c)
/ 11 12 // 13 f(b)/f(c)
f d // 14 f(d)
h 9 10 13 14 // 15 (a+f((b-c+e)*d/c.h(d,d)).g(e)).g(d).h(f(a,c),f(b)/f(c),f(d))
a+b+c+d+e*f*g*h*i*(j-k-l-m-n)
+ a b
+ 1 c
+ 2 d
* e f
* 4 g
* 5 h
* 6 i
- j k
- 8 l
- 9 m
- 10 n
* 7 11
+ 3 12
(a+a+a)+a+a+a+(a+a+a)
+ a a
+ 1 a
+ 2 a
+ 3 a
+ 4 a
+ a a
+ 6 a
+ 5 7
子任务
- 测试点 :包含常量、加减号
- 测试点 :包含常量、四则运算符
- 测试点 :包含常量、加减号、括号
- 测试点 :包含常量、四则运算符、括号
- 测试点 :包含常量、普通函数调用
- 测试点 :包含常量、成员函数调用
- 测试点 :包含常量、普通函数调用、成员函数调用、括号
- 测试点 :包含常量、四则运算符、普通函数调用、括号
- 测试点 :包含常量、四则运算符、成员函数调用、括号
- 测试点 :包含常量、四则运算符、普通函数调用、成员函数调用、括号