########################################################## #需求:四则运算混合表达式求值 #描述: # 采用shell实现基于简单的加减乘除的混合表达式求值 #分析: # 0:简单的加减乘除(a+b;a-b;a*b;a/b)直接调用工具计算 # a:算法:先求出逆波兰表达式,然后计算逆波兰表达式 # b:数据结构:采用数组保存(用数组模拟栈) # #脚本说明: #脚本名:rpn.sh #脚本调用: # sh rpn.sh /( 2 /* /( 2 + 4 /) + /( 2 + 4 /* 2 /) /) // 11 #脚本参数: # 表达式(字符数字,+-*/和括号),按空格分开, # “括号”和“*”要注意shell转义 #脚本输出: # 第一行:逆波兰表达式(空格分离) # 第二行:表达式计算值 # #date:2010.6.3 #mail:songbo217@qq.com ########################################################## declare -a stack_rpn #全局变量,保存逆波兰表达式 scale=3; #精度 #1.0数组公函区 #用数组模拟栈 array_push() { local arrayname=$1 local newitem=$2 #"use to avoid '*' transfer eval ${arrayname}'=("${'${arrayname}'[@]}" "$newitem" ) ' } array_pop() { local arrayname=$1 eval ${arrayname}'=("${'${arrayname}'[@]:0:$((${#'${arrayname}'[@]}-1))}") ' } array_top() { local arrayname=$1 eval echo '"${'${arrayname}'[$((${#'${arrayname}'[@]}-1))]}"' } array_shift() { local arrayname=$1 eval ${arrayname}'=( "${'${arrayname}'[@]:1}" )' } array_bt() { local arrayname=$1 eval echo '"${'${arrayname}'[0]}"' } #判断数组索引是否存在 #起始索引是1 array_has_index() { local arrayname=$1 local index=${2-1} local max eval max='${#'${arrayname}'[*]}' eval test "$index" -ge 1 -a "$index" -le "$max" 2>/dev/null echo $? } #中缀表达式切换成逆波兰表达式 #参数:中缀表达式(空格分隔,注意*号转义) #输出:逆波兰表达式 mkrpn() { local item; local -a result; local -a temp; local i; array_push temp "#"; while [ $# -ne 0 ] do item=$1; case "$item" in "+"|"-") while [ "$(array_top temp)" != '(' ] && [ "$(array_top temp)" != '#' ] do i=$(array_top temp); array_pop temp ; array_push result "$i"; done array_push temp "$item"; ;; "*"|"/") # a/b*c*(d+e) : a b / c * d e + * while [ "$(array_top temp)" = '*' ] || [ "$(array_top temp)" = '/' ] #while test "$(array_top temp)" = "*" -o "$(array_top temp)" = "/" do i="$(array_top temp)"; array_pop temp ; array_push result "$i"; done array_push temp "$item"; ;; ")") while test "$(array_top temp)" != "(" do i="$(array_top temp)"; array_pop temp ; array_push result "$i"; done array_pop temp ; ;; "(") array_push temp "$item"; ;; *) #数字 array_push result "$item"; ;; esac shift done while test "$(array_top temp)" != "#" do i="$(array_top temp)"; array_pop temp ; array_push result "$i"; done echo "${result[@]}" stack_rpn=( "${result[@]}" ); } #计算逆波兰表达式 #输入:逆波兰表达式,保存于全局数组stack_rpn #输出:表达式值 calrpn() { local -a dig_stack local i; local op1; local op2; local result; while test "$(array_has_index stack_rpn)" -ne 1 do i=$stack_rpn; array_shift stack_rpn ; case "$i" in "+"|"-"|"*"|"/") op1=$(array_top dig_stack); array_pop dig_stack ; op2=$(array_top dig_stack); array_pop dig_stack ; result=$(echo "scale=$scale;$op2 $i $op1 "|bc); array_push dig_stack "$result"; ;; *) array_push dig_stack "$i"; ;; esac done array_top dig_stack; } #main mkrpn "$@" calrpn