与 bc 交互使用 m4

与 bc 交互使用 m4

我想以m4交互方式使用作为bc.我的直接用例是添加一项include功能bc,但我可以预见将来的其他用途。但有一个问题。这是一个bc单独使用的示例:

$ bc
bc 1.07.1
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006, 2008, 2012-2017 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
3+7
10
sqrt(12345)
111
quit
$

这是交互式使用的相同示例m4

$ m4 -iP - | bc
3+7
10
sqrt(12345)
111
quit

$

有两点不同。首先,m4版本打压了横幅。其次,该m4版本不会quit立即执行,而是需要在执行quit.

为什么会出现这些事情呢?如何使m4版本与版本一样工作bc

答案1

这是我想到的,尽管我仍在尝试,但它似乎按我预期的方式工作。 shellbc脚本位于/usr/local/bin/bc以下$PATH位置/usr/bin/bc

#! /bin/sh

HELP="usage: /usr/local/bin/bc [options] [file ...]
  -h              print usage message and exit
  -s              synclines; same as m4 -s
  -v              print bc version information and exit
  -D name[=value] define macro name, optionally give it a value
  -I directory    location of m4 include directory
  -U name         undefine macro name
  NOTE: bc -ql are always active; bc -sw are unavailable;
        m4 -P is always active; m4 -i may be active"

USAGE="-[hsv] [-D name[=value]] [-I directory] [-U name]\n"

# file locations
BC=/usr/bin/bc
BCPRE=/usr/local/bin/bc.prelude
M4=/usr/bin/m4
M4PRE=/usr/local/bin/bc.m4.prelude
SCRIPT="./bc.script.$(date +%Y%m%d)"

# collect command options
M4OPTS=""
while getopts "hsvD:I:U:" flag
do  case $flag in
    h) echo "$HELP"; exit 0;;        # print help message and exit
    s) M4OPTS="$M4OPTS -s";;         # synclines
    v) $BC -v; exit 0;;              # print bc version and exit
    D) M4OPTS="$M4OPTS -D $OPTARG";; # define macro name[=value]
    I) M4OPTS="$M4OPTS -I $OPTARG";; # specify include directory
    U) M4OPTS="$M4OPTS -U $OPTARG";; # undefine macro name
    ?) echo "Usage: $0 $USAGE"; exit 2;;
    esac
done
shift $(($OPTIND - 1))

# initialize random number generator
SRAND=$(mktemp /tmp/bc.srand.XXXXXX)
echo "srand = $(od -vAn -N4 -tu4 < /dev/urandom)" > $SRAND
trap "rm -f $SRAND" 0 1 2 3 15

# execute bc
if   test -t 0
then script -qfa bc.script.$(date +%Y%m%d) -c \
     "rlwrap -aN sh -c \"$M4 -iP $M4PRE $SRAND $BCPRE $@ - | $BC -ql\""
else $M4 -P $M4PRE $SRAND $BCPRE $@ - | $BC -ql
fi

这是bc.prelude

scale = 0; ibase = obase = A

define int(x) { # truncate toward zero
    auto s; s = scale; scale = 0; x /= 1; scale = s; return x }
define frac(x) { return x - int(x) }
define abs(x) { if (x<0) return -x else return x }
define sgn(x) { if (x<0) return -1; if (x>0) return 1; return 0 }
define max(a,b) { if (a<b) return b else return a }
define min(a,b) { if (a<b) return a else return b }
define mod(n,m) {
    auto x, s; s = scale; scale = 0; x = n % m; scale = s
    if (x < 0) return x + m; return x }
define gcd(a,b) {
    auto x, s; s = scale; scale = 0
    while (b != 0) { x = mod(a,b); a = b; b = x }
    scale = s; return a }
define push(*stack[],value) { return(stack[++stack[0]]=value) }
define pop(*stack[]) {
    if (stack[0]<1) stack[-1] else return stack[stack[0]--] }

define srand(seed) { # seed on half-open range [0,2^32)
    auto i, old_scale; old_scale = scale; scale = 0; srand[0] = seed
    for (i=1; i<32; i++) # initialize shuffle box
        srand = srand[i] = (69069 * srand[i-1] + 1234567) % 4294967296
    scale = old_scale; return seed }
junk = srand(srand) # initial seed from /dev/urandom via bc shell script
define rand() { # pseudorandom integer on half-open range [0,2^32)
    auto j, n, old_scale; old_scale = scale; scale = 0
    srand = (69069 * srand + 1234567) % 4294967296
    n = srand[(j = 32 * srand / 4294967296)]
    srand[j] = srand; scale = old_scale; return n }
define randint(lo,hi) { # pseudorandom integer from lo to hi inclusive
    auto randint, old_scale; old_scale = scale; scale = 0
    randint = (hi - lo + 1) * rand() / 4294967296 + lo
    scale = old_scale; return randint }

这是bc.m4.prelude

m4_divert(-1)

m4_define(error, `{ print $1, "\n"; 0/0 }')

m4_define(with_scale,
    { junk = push(saved_scale[],scale); scale = $1;
    $2;
    scale = pop(saved_scale[]) })

m4_define(load, `m4_include($1)')

m4_define(quit, `m4_m4exit')

m4_divert`'m4_dnl

以下是与 的交互示例bc

$ bc
rand()
2525043732
with_scale(20,a(1)*4)
3.14159265358979323844
define fib(n) {
    auto f1, f2, f3
    f1 = 0; f2 = 1
    while (n-- > 0) {
        f3 = f1 + f2
        f1 = f2; f2 = f3 }
    return f2 }
fib(37)
39088169
quit
$

命令历史记录readline似乎工作正常,我希望自动收集记录(每天一个文件,bc同一文件中有多个会话)将非常有用(前几天我是如何定义该函数的?)。

所有这些无疑都会随着时间而改变,但至少我有一个开始。

相关内容