• walmart calc

    From Michael Sanders@porkchop@invalid.foo to comp.unix.shell on Sun Nov 2 21:51:38 2025
    From Newsgroup: comp.unix.shell

    Earlier I was attempting to wrap bc in a friendly way,
    but the order of operations kicked my *ss =)

    As an example, consider:

    echo '2+50%' | bc
    (standard_in) 2: syntax error

    So why not an attempt closer to a standard, hand-held calc?
    You know the kind, just cheap dollar-store calculators.

    Likely needs more work, but its a start.

    examples...

    exp 2+50%
    3.00

    exp 500*75.3/25%
    150600.00

    exp -980*3+876%
    -28694.40

    #!/bin/sh

    <<'NOTES'

    simple walmart breed of calculator

    Michael Sanders 2025

    ops: add +, subtract -, multiply *, divide /, percentage %

    NOTES

    exp() {

    e=$(echo "$1" | tr -d '[:space:]') # compress
    [ -z "$e" ] && { echo "usage: exp <expression>"; return 1; }
    # allow only valid characters
    echo "$e" | grep -Eq '^[0-9./+*%-]+$' || { echo "invalid expression"; return 1; }
    # reject if % is first or followed by a digit
    echo "$e" | grep -Eq '(^%)|%[0-9]' && { echo "invalid expression"; return 1; }
    # reject if % is used standalone before operator
    echo "$e" | grep -Eq '[0-9]%[+*/-]' && { echo "0"; return 1; }

    DEC="${DEC:-2}" # use global $DEC, default 2

    tmp=$(awk -v e="$e" -v dec="$DEC" '
    function calc(e,dec,res,i,c,sign,t,val,op,n) {

    dec = (dec=="") ? 2 : dec
    n = length(e)
    i = 1
    res = 0
    sign = 1
    op = "+"

    while (i <= n) {
    c = substr(e,i,1)
    if (c=="-" && (i==1 || substr(e,i-1,1) ~ /[\+\-\*\/]/)) {
    sign = -1
    i++
    continue
    }
    if (c ~ /[0-9.]/) {
    t = ""
    while (i<=n && substr(e,i,1) ~ /[0-9.]/) { t = t substr(e,i,1); i++ }
    val = sign * t
    sign = 1
    # percentage handling
    if (i<=n && substr(e,i,1)=="%") {
    if (op=="+" || op=="-") val = res * val / 100
    else val = val / 100
    i++
    }
    if (op=="+") res = res + val
    else if (op=="-") res = res - val
    else if (op=="*") res = res * val
    else if (op=="/") res = res / val
    } else if (c ~ /[\+\-\*\/]/) {
    op = c
    i++
    } else { i++ }
    }
    fmt = "%." dec "f"
    return sprintf(fmt, res)
    }
    BEGIN { print calc(e ,dec) }')

    y=0
    [ -z "$tmp" ] && { y=1; tmp='invalid expression'; }
    echo "$tmp"
    return $y
    }

    exp -980*3+876%

    # eof
    --
    :wq
    Mike Sanders
    --- Synchronet 3.21a-Linux NewsLink 1.2