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