Advertisement
Guest User

Untitled

a guest
Oct 18th, 2019
101
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.93 KB | None | 0 0
  1. #!/bin/bash
  2.  
  3. die () {
  4. echo "$*" >&2
  5. exit 1
  6. }
  7.  
  8. or () {
  9. [[ $1 != *(0) ]]
  10. REPLY=${@:1+$?:1}
  11. }
  12. and () {
  13. [[ $1$2 != *(0) ]] && REPLY=$1 || REPLY=0
  14. }
  15.  
  16. declare -A ops
  17. ops=(
  18. [lt]=\< [gt]=\>
  19. [eq]=== [ne]=!=
  20. )
  21. for op in "${!ops[@]}"; do
  22. eval "$op"' () {
  23. if [[ $1$2 = *([0-9]) ]]; then
  24. REPLY=$(( $1 '"${ops[$op]}"' $2 ))
  25. else
  26. [[ $1 '"${ops[$op]}"' $2 ]]; REPLY=$?
  27. fi
  28. }'
  29. done
  30.  
  31. ops=(
  32. [le]=\< [ge]=\>
  33. )
  34. for op in "${!ops[@]}"; do
  35. eval "$op"' () {
  36. if [[ $1$2 = *([0-9]) ]]; then
  37. REPLY=$(( $1 == $2 || $1 '"${ops[$op]}"' $2 ))
  38. else
  39. [[ $1 == $2 || $1 '"${ops[$op]}"' $2 ]]; REPLY=$?
  40. fi
  41. }'
  42. done
  43.  
  44. ops=(
  45. [add]=+ [sub]=-
  46. [mul]=* [div]=/ [mod]=%
  47. )
  48. for op in "${!ops[@]}"; do
  49. eval "$op"' () {
  50. evaluate "$2"
  51. tmp2=$REPLY
  52. evaluate "$1"
  53. tmp1=$REPLY
  54. [[ $tmp1$tmp2 = *([0-9]) ]] || die non-integer argument
  55. REPLY=$(( $tmp1 '"${ops[$op]}"' $tmp2 ))
  56. }'
  57. done
  58.  
  59. ops=(
  60. [\<]=lt [\<=]=le
  61. [\>]=gt [\>=]=ge
  62. [==]=eq [!=]=ne
  63. [+]=add [-]=sub
  64. [\*]=mul [/]=div
  65. [%]=mod [:]=match
  66. )
  67.  
  68. match () {
  69. evaluate "$2"
  70. tmp2=$REPLY
  71. evaluate "$1"
  72. tmp1=$REPLY
  73. [[ $tmp1 =~ ^$tmp2$ ]]
  74. REPLY=${BASH_REMATCH[1]-${#BASH_REMATCH}}
  75. }
  76. index () {
  77. tmp=${1%%["$2"]*}
  78. REPLY=${#tmp}
  79. }
  80. length () {
  81. REPLY=${#1}
  82. }
  83. substr () {
  84. evaluate "$3"
  85. tmp3=$REPLY
  86. evaluate "$2"
  87. tmp2=$REPLY
  88. [[ $tmp2$tmp3 = *([0-9]) ]] || die non-integer argument
  89. REPLY=${1:$tmp2+1:$tmp3}
  90. }
  91.  
  92. poparg () {
  93. REPLY=()
  94. for (( tmp = ${1-1}; tmp; tmp-- )) do
  95. REPLY+=("${args[-1]}")
  96. unset "args[-1]" || die syntax error
  97. done
  98. }
  99.  
  100. evaluate () {
  101. if [[ $1 = length ]]; then
  102. poparg
  103. length "$REPLY"
  104. elif [[ $1 = @(match|index) ]]; then
  105. poparg 2
  106. "$1" "${REPLY[@]}"
  107. elif [[ ${args[i]} = substr ]]; then
  108. poparg 3
  109. "$1" "${REPLY[@]}"
  110. elif [[ ${ops[$1]} ]]; then
  111. poparg 2
  112. "${ops[$1]}" "${REPLY[@]}"
  113. else
  114. REPLY=$1
  115. fi
  116. }
  117.  
  118. shunting_yard () {
  119. declare -A precedence=(
  120. [|]=1
  121. [&]=2
  122. [=]=3 [!=]=3
  123. [>]=3 [>=]=3
  124. [<]=3 [<=]=3
  125. [+]=4 [-]=4
  126. [\*]=5 [/]=5 [%]=5
  127. [:]=6
  128. )
  129.  
  130. stack=()
  131. for token; do
  132. if [[ $token = *([0-9]) ]]; then
  133. args+=("$token")
  134. elif [[ $token = @(index|length|match|substr) ]]; then
  135. stack+=("$token")
  136. elif [[ ${precedence[$token]} ]]; then
  137. while [[ $stack ]] &&
  138. [[ ${stack[-1]} == @(index|length|match|substr) ||
  139. ${precedence[${stack[-1]}]} -ge ${precedence[token]} ]] &&
  140. [[ ${stack[-1]} != '(' ]]; do
  141. args+=("${stack[-1]}")
  142. unset "stack[-1]"
  143. done
  144. stack+=("$token")
  145. elif [[ $token = '(' ]]; then
  146. stack+=("$token")
  147. elif [[ $token = ')' ]]; then
  148. while [[ $stack && ${stack[-1]} != '(' ]]; do
  149. args+=("${stack[-1]}")
  150. unset "stack[-1]"
  151. done
  152. if [[ $stack && ${stack[-1]} = '(' ]]; then
  153. unset "stack[-1]"
  154. else
  155. die syntax error
  156. fi
  157. else
  158. args+=("$token")
  159. fi
  160. done
  161.  
  162. while [[ $stack ]]; do
  163. if [[ ${stack[-1]} = '(' ]]; then
  164. die syntax error
  165. fi
  166. args+=("${stack[-1]}")
  167. unset "stack[-1]"
  168. done
  169. }
  170.  
  171. expr () {
  172. (( $# )) || die missing operands
  173.  
  174. args=() i=0
  175. shunting_yard "$@"
  176.  
  177. declare -p args
  178. op=${args[-1]}
  179. unset "args[-1]"
  180. evaluate "$op"
  181. echo "$REPLY"
  182. }
  183.  
  184.  
  185. expr "$@"
  186.  
  187.  
  188.  
  189. bash expr \( \( 15 / \( 7 − \( 1 + 1 \) \) \) \* 3 \) − \( 2 + \( 1 + 1 \) \)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement