1#! /bin/sed -nf 2# 3# dc.sed - an arbitrary precision RPN calculator 4# Created by Greg Ubben <gsu@romulus.ncsc.mil> early 1995, late 1996 5# 6# Dedicated to MAC's memory of the IBM 1620 ("CADET") computer. 7# @(#)GSU dc.sed 1.1 06-Mar-1999 [non-explanatory] 8# $OpenBSD: dc.sed,v 1.1 2008/10/13 13:22:10 millert Exp $ 9# 10# From http://sed.sourceforge.net/grabbag/scripts/ 11# Public Domain 12# 13# Examples: 14# sqrt(2) to 10 digits: echo "10k 2vp" | dc.sed 15# 20 factorial: echo "[d1-d1<!*]s! 20l!xp" | dc.sed 16# sin(ln(7)): echo "s(l(7))" | bc -c /usr/lib/lib.b | dc.sed 17# hex to base 60: echo "60o16i 6B407.CAFE p" | dc.sed 18# tests most of dc.sed: echo 16oAk2vp | dc.sed 19# 20# To debug or analyze, give the dc Y command as input or add it to 21# embedded dc routines, or add the sed p command to the beginning of 22# the main loop or at various points in the low-level sed routines. 23# If you need to allow [|~] characters in the input, filter this 24# script through "tr '|~' '\36\37'" first (or use dc.pl). 25# 26# Not implemented: ! \ 27# But implemented: K Y t # !< !> != fractional-bases 28# SunOS limits: 199/199 commands (though could pack in 10-20 more) 29# Limitations: scale <= 999; |obase| >= 1; input digits in [0..F] 30# Completed: 1am Feb 4, 1997 31 32s/^/|P|K0|I10|O10|?~/ 33 34:next 35s/|?./|?/ 36s/|?#[ -}]*/|?/ 37/|?!*[lLsS;:<>=]\{0,1\}$/N 38/|?!*[-+*/%^<>=]/b binop 39/^|.*|?[dpPfQXZvxkiosStT;:]/b binop 40/|?[_0-9A-F.]/b number 41/|?\[/b string 42/|?l/b load 43/|?L/b Load 44/|?[sS]/b save 45/|?c/ s/[^|]*// 46/|?d/ s/[^~]*~/&&/ 47/|?f/ s//&[pSbz0<aLb]dSaxsaLa/ 48/|?x/ s/\([^~]*~\)\(.*|?x\)~*/\2\1/ 49/|?[KIO]/ s/.*|\([KIO]\)\([^|]*\).*|?\1/\2~&/ 50/|?T/ s/\.*0*~/~/ 51# a slow, non-stackable array implementation in dc, just for completeness 52# A fast, stackable, associative array implementation could be done in sed 53# (format: {key}value{key}value...), but would be longer, like load & save. 54/|?;/ s/|?;\([^{}]\)/|?~[s}s{L{s}q]S}[S}l\1L}1-d0>}s\1L\1l{xS\1]dS{xL}/ 55/|?:/ s/|?:\([^{}]\)/|?~[s}L{s}L{s}L}s\1q]S}S}S{[L}1-d0>}S}l\1s\1L\1l{xS\1]dS{x/ 56/|?[ ~ cdfxKIOT]/b next 57/|?\n/b next 58/|?[pP]/b print 59/|?k/ s/^\([0-9]\{1,3\}\)\([.~].*|K\)[^|]*/\2\1/ 60/|?i/ s/^\(-\{0,1\}[0-9]*\.\{0,1\}[0-9]\{1,\}\)\(~.*|I\)[^|]*/\2\1/ 61/|?o/ s/^\(-\{0,1\}[1-9][0-9]*\.\{0,1\}[0-9]*\)\(~.*|O\)[^|]*/\2\1/ 62/|?[kio]/b pop 63/|?t/b trunc 64/|??/b input 65/|?Q/b break 66/|?q/b quit 67h 68/|?[XZz]/b count 69/|?v/b sqrt 70s/.*|?\([^Y]\).*/\1 is unimplemented/ 71s/\n/\\n/g 72l 73g 74b next 75 76:print 77/^-\{0,1\}[0-9]*\.\{0,1\}[0-9]\{1,\}~.*|?p/!b Print 78/|O10|/b Print 79 80# Print a number in a non-decimal output base. Uses registers a,b,c,d. 81# Handles fractional output bases (O<-1 or O>=1), unlike other dc's. 82# Converts the fraction correctly on negative output bases, unlike 83# UNIX dc. Also scales the fraction more accurately than UNIX dc. 84# 85s,|?p,&KSa0kd[[-]Psa0la-]Sad0>a[0P]sad0=a[A*2+]saOtd0>a1-ZSd[[[[ ]P]sclb1\ 86!=cSbLdlbtZ[[[-]P0lb-sb]sclb0>c1+]sclb0!<c[0P1+dld>c]scdld>cscSdLbP]q]Sb\ 87[t[1P1-d0<c]scd0<c]ScO_1>bO1!<cO[16]<bOX0<b[[q]sc[dSbdA>c[A]sbdA=c[B]sbd\ 88B=c[C]sbdC=c[D]sbdD=c[E]sbdE=c[F]sb]xscLbP]~Sd[dtdZOZ+k1O/Tdsb[.5]*[.1]O\ 89X^*dZkdXK-1+ktsc0kdSb-[Lbdlb*lc+tdSbO*-lb0!=aldx]dsaxLbsb]sad1!>a[[.]POX\ 90+sb1[SbO*dtdldx-LbO*dZlb!<a]dsax]sadXd0<asbsasaLasbLbscLcsdLdsdLdLak[]pP, 91b next 92 93:Print 94/|?p/s/[^~]*/&\ 95~&/ 96s/\(.*|P\)\([^|]*\)/\ 97\2\1/ 98s/\([^~]*\)\n\([^~]*\)\(.*|P\)/\1\3\2/ 99h 100s/~.*// 101/./{ s/.//; p; } 102# Just s/.//p would work if we knew we were running under the -n option. 103# Using l vs p would kind of do \ continuations, but would break strings. 104g 105 106:pop 107s/[^~]*~// 108b next 109 110:load 111s/\(.*|?.\)\(.\)/\20~\1/ 112s/^\(.\)0\(.*|r\1\([^~|]*\)~\)/\1\3\2/ 113s/.// 114b next 115 116:Load 117s/\(.*|?.\)\(.\)/\2\1/ 118s/^\(.\)\(.*|r\1\)\([^~|]*~\)/|\3\2/ 119/^|/!i\ 120register empty 121s/.// 122b next 123 124:save 125s/\(.*|?.\)\(.\)/\2\1/ 126/^\(.\).*|r\1/ !s/\(.\).*|/&r\1|/ 127/|?S/ s/\(.\).*|r\1/&~/ 128s/\(.\)\([^~]*~\)\(.*|r\1\)[^~|]*~\{0,1\}/\3\2/ 129b next 130 131:quit 132t quit 133s/|?[^~]*~[^~]*~/|?q/ 134t next 135# Really should be using the -n option to avoid printing a final newline. 136s/.*|P\([^|]*\).*/\1/ 137q 138 139:break 140s/[0-9]*/&;987654321009;/ 141:break1 142s/^\([^;]*\)\([1-9]\)\(0*\)\([^1]*\2\(.\)[^;]*\3\(9*\).*|?.\)[^~]*~/\1\5\6\4/ 143t break1 144b pop 145 146:input 147N 148s/|??\(.*\)\(\n.*\)/|?\2~\1/ 149b next 150 151:count 152/|?Z/ s/~.*// 153/^-\{0,1\}[0-9]*\.\{0,1\}[0-9]\{1,\}$/ s/[-.0]*\([^.]*\)\.*/\1/ 154/|?X/ s/-*[0-9A-F]*\.*\([0-9A-F]*\).*/\1/ 155s/|.*// 156/~/ s/[^~]//g 157 158s/./a/g 159:count1 160 s/a\{10\}/b/g 161 s/b*a*/&a9876543210;/ 162 s/a.\{9\}\(.\).*;/\1/ 163 y/b/a/ 164/a/b count1 165G 166/|?z/ s/\n/&~/ 167s/\n[^~]*// 168b next 169 170:trunc 171# for efficiency, doesn't pad with 0s, so 10k 2 5/ returns just .40 172# The X* here and in a couple other places works around a SunOS 4.x sed bug. 173s/\([^.~]*\.*\)\(.*|K\([^|]*\)\)/\3;9876543210009909:\1,\2/ 174:trunc1 175 s/^\([^;]*\)\([1-9]\)\(0*\)\([^1]*\2\(.\)[^:]*X*\3\(9*\)[^,]*\),\([0-9]\)/\1\5\6\4\7,/ 176t trunc1 177s/[^:]*:\([^,]*\)[^~]*/\1/ 178b normal 179 180:number 181s/\(.*|?\)\(_\{0,1\}[0-9A-F]*\.\{0,1\}[0-9A-F]*\)/\2~\1~/ 182s/^_/-/ 183/^[^A-F~]*~.*|I10|/b normal 184/^[-0.]*~/b normal 185s:\([^.~]*\)\.*\([^~]*\):[Ilb^lbk/,\1\2~0A1B2C3D4E5F1=11223344556677889900;.\2: 186:digit 187 s/^\([^,]*\),\(-*\)\([0-F]\)\([^;]*\(.\)\3[^1;]*\(1*\)\)/I*+\1\2\6\5~,\2\4/ 188t digit 189s:...\([^/]*.\)\([^,]*\)[^.]*\(.*|?.\):\2\3KSb[99]k\1]SaSaXSbLalb0<aLakLbktLbk: 190b next 191 192:string 193/|?[^]]*$/N 194s/\(|?[^]]*\)\[\([^]]*\)]/\1|{\2|}/ 195/|?\[/b string 196s/\(.*|?\)|{\(.*\)|}/\2~\1[/ 197s/|{/[/g 198s/|}/]/g 199b next 200 201:binop 202/^[^~|]*~[^|]/ !i\ 203stack empty 204//!b next 205/^-\{0,1\}[0-9]*\.\{0,1\}[0-9]\{1,\}~/ !s/[^~]*\(.*|?!*[^!=<>]\)/0\1/ 206/^[^~]*~-\{0,1\}[0-9]*\.\{0,1\}[0-9]\{1,\}~/ !s/~[^~]*\(.*|?!*[^!=<>]\)/~0\1/ 207h 208/|?\*/b mul 209/|?\//b div 210/|?%/b rem 211/|?^/b exp 212 213/|?[+-]/ s/^\(-*\)\([^~]*~\)\(-*\)\([^~]*~\).*|?\(-\{0,1\}\).*/\2\4s\3o\1\3\5/ 214s/\([^.~]*\)\([^~]*~[^.~]*\)\(.*\)/<\1,\2,\3|=-~.0,123456789<></ 215/^<\([^,]*,[^~]*\)\.*0*~\1\.*0*~/ s/</=/ 216:cmp1 217 s/^\(<[^,]*\)\([0-9]\),\([^,]*\)\([0-9]\),/\1,\2\3,\4/ 218t cmp1 219/^<\([^~]*\)\([^~]\)[^~]*~\1\(.\).*|=.*\3.*\2/ s/</>/ 220/|?/{ 221 s/^\([<>]\)\(-[^~]*~-.*\1\)\(.\)/\3\2/ 222 s/^\(.\)\(.*|?!*\)\1/\2!\1/ 223 s/|?![^!]\(.\)/&l\1x/ 224 s/[^~]*~[^~]*~\(.*|?\)!*.\(.*\)|=.*/\1\2/ 225 b next 226} 227s/\(-*\)\1|=.*/;9876543210;9876543210/ 228/o-/ s/;9876543210/;0123456789/ 229s/^>\([^~]*~\)\([^~]*~\)s\(-*\)\(-*o\3\(-*\)\)/>\2\1s\5\4/ 230 231s/,\([0-9]*\)\.*\([^,]*\),\([0-9]*\)\.*\([0-9]*\)/\1,\2\3.,\4;0/ 232:right1 233 s/,\([0-9]\)\([^,]*\),;*\([0-9]\)\([0-9]*\);*0*/\1,\2\3,\4;0/ 234t right1 235s/.\([^,]*\),~\(.*\);0~s\(-*\)o-*/\1~\30\2~/ 236 237:addsub1 238 s/\(.\{0,1\}\)\(~[^,]*\)\([0-9]\)\(\.*\),\([^;]*\)\(;\([^;]*\(\3[^;]*\)\).*X*\1\(.*\)\)/\2,\4\5\9\8\7\6/ 239 s/,\([^~]*~\).\{10\}\(.\)[^;]\{0,9\}\([^;]\{0,1\}\)[^;]*/,\2\1\3/ 240# could be done in one s/// if we could have >9 back-refs... 241/^~.*~;/!b addsub1 242 243:endbin 244s/.\([^,]*\),\([0-9.]*\).*/\1\2/ 245G 246s/\n[^~]*~[^~]*// 247 248:normal 249s/^\(-*\)0*\([0-9.]*[0-9]\)[^~]*/\1\2/ 250s/^[^1-9~]*~/0~/ 251b next 252 253:mul 254s/\(-*\)\([0-9]*\)\.*\([0-9]*\)~\(-*\)\([0-9]*\)\.*\([0-9]*\).*|K\([^|]*\).*/\1\4\2\5.!\3\6,|\2<\3~\5>\6:\7;9876543210009909/ 255 256:mul1 257 s/![0-9]\([^<]*\)<\([0-9]\{0,1\}\)\([^>]*\)>\([0-9]\{0,1\}\)/0!\1\2<\3\4>/ 258 /![0-9]/ s/\(:[^;]*\)\([1-9]\)\(0*\)\([^0]*\2\(.\).*X*\3\(9*\)\)/\1\5\6\4/ 259/<~[^>]*>:0*;/!t mul1 260 261s/\(-*\)\1\([^>]*\).*/;\2^>:9876543210aaaaaaaaa/ 262 263:mul2 264 s/\([0-9]~*\)^/^\1/ 265 s/<\([0-9]*\)\(.*[~^]\)\([0-9]*\)>/\1<\2>\3/ 266 267 :mul3 268 s/>\([0-9]\)\(.*\1.\{9\}\(a*\)\)/\1>\2;9\38\37\36\35\34\33\32\31\30/ 269 s/\(;[^<]*\)\([0-9]\)<\([^;]*\).*\2[0-9]*\(.*\)/\4\1<\2\3/ 270 s/a[0-9]/a/g 271 s/a\{10\}/b/g 272 s/b\{10\}/c/g 273 /|0*[1-9][^>]*>0*[1-9]/b mul3 274 275 s/;/a9876543210;/ 276 s/a.\{9\}\(.\)[^;]*\([^,]*\)[0-9]\([.!]*\),/\2,\1\3/ 277 y/cb/ba/ 278/|<^/!b mul2 279b endbin 280 281:div 282# CDDET 283/^[-.0]*[1-9]/ !i\ 284divide by 0 285//!b pop 286s/\(-*\)\([0-9]*\)\.*\([^~]*~-*\)\([0-9]*\)\.*\([^~]*\)/\2.\3\1;0\4.\5;0/ 287:div1 288 s/^\.0\([^.]*\)\.;*\([0-9]\)\([0-9]*\);*0*/.\1\2.\3;0/ 289 s/^\([^.]*\)\([0-9]\)\.\([^;]*;\)0*\([0-9]*\)\([0-9]\)\./\1.\2\30\4.\5/ 290t div1 291s/~\(-*\)\1\(-*\);0*\([^;]*[0-9]\)[^~]*/~123456789743222111~\2\3/ 292s/\(.\(.\)[^~]*\)[^9]*\2.\{8\}\(.\)[^~]*/\3~\1/ 293s,|?.,&SaSadSaKdlaZ+LaX-1+[sb1]Sbd1>bkLatsbLa[dSa2lbla*-*dLa!=a]dSaxsakLasbLb*t, 294b next 295 296:rem 297s,|?%,&Sadla/LaKSa[999]k*Lak-, 298b next 299 300:exp 301# This decimal method is just a little faster than the binary method done 302# totally in dc: 1LaKLb [kdSb*LbK]Sb [[.5]*d0ktdSa<bkd*KLad1<a]Sa d1<a kk* 303/^[^~]*\./i\ 304fraction in exponent ignored 305s,[^-0-9].*,;9d**dd*8*d*d7dd**d*6d**d5d*d*4*d3d*2lbd**1lb*0, 306:exp1 307 s/\([0-9]\);\(.*\1\([d*]*\)[^l]*\([^*]*\)\(\**\)\)/;dd*d**d*\4\3\5\2/ 308t exp1 309G 310s,-*.\{9\}\([^9]*\)[^0]*0.\(.*|?.\),\2~saSaKdsaLb0kLbkK*+k1\1LaktsbkLax, 311s,|?.,&SadSbdXSaZla-SbKLaLadSb[0Lb-d1lb-*d+K+0kkSb[1Lb/]q]Sa0>a[dk]sadK<a[Lb], 312b next 313 314:sqrt 315# first square root using sed: 8k2v at 1:30am Dec 17, 1996 316/^-/i\ 317square root of negative number 318/^[-0]/b next 319s/~.*// 320/^\./ s/0\([0-9]\)/\1/g 321/^\./ !s/[0-9][0-9]/7/g 322G 323s/\n/~/ 324s,|?.,&K1+k KSbSb[dk]SadXdK<asadlb/lb+[.5]*[sbdlb/lb+[.5]*dlb>a]dsaxsasaLbsaLatLbk K1-kt, 325b next 326 327# END OF GSU dc.sed 328