SHARE
TWEET

Untitled

a guest Oct 18th, 2019 87 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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 \) \)
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top