From 4e508cfc294adab766622d91178be308355a0880 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Tue, 1 May 2018 22:08:06 -0700 Subject: [PATCH] SCP: Add C style expression support for IF conditions and SET ENV -A Expression evaluation code provided by Gabriel Pizzolato. --- README.md | 2 + doc/simh_doc.doc | Bin 286720 -> 328192 bytes scp.c | 741 +++++++++++++++++++++++++++++++++++++++++++---- sim_defs.h | 11 +- 4 files changed, 696 insertions(+), 58 deletions(-) diff --git a/README.md b/README.md index 468074e9..0f3d5286 100644 --- a/README.md +++ b/README.md @@ -328,6 +328,7 @@ Device simulator authors can easily schedule their device polling activities to SCREENSHOT filename.bmp Save video window to the specified file SET ENV Name=Value Set Environment variable SET ENV -p "Prompt" Name=Default Gather User input into an Environment Variable + SET ENV -a Name=Expression Evaluate an expression and store result in an Environment Variable SET ASYNCH Enable Asynchronous I/O SET NOASYNCH Disable Asynchronous I/O SET VERIFY Enable command display while processing DO command files @@ -358,6 +359,7 @@ Device simulator authors can easily schedule their device polling activities to NOOP A no-op command ON Establish or cancel an ON condition dispatch IF Test some simulator state and conditionally execute commands + IF (C-style-expression) Test some simulator state and conditionally execute commands CD Change working directory SET DEFAULT Change working directory PWD Show working directory diff --git a/doc/simh_doc.doc b/doc/simh_doc.doc index ca44e4459e9e84431271affb1da00f61c16151ac..5a1a0ff38ef1a97f69753f6b69ec8809b178d053 100644 GIT binary patch delta 53431 zcmeI533wDm`naoS1_FTqfp7;H!hPpHxFh!+P6fFF1QHAhB;iI!@mg0rXSG!nQBe^^ zRFI&8A|R`-B8VcQDC;evawwn({NJy8dM*=4R>J=G`H?*DOjUh#e)Uy#O?P$owVT7Q zy&>Yx=;#GDW&TxD>T28?zB6afo|VAa_~*b}mJ5Xk@$Sy|GZM1@r9L?x`u$)$e^ZssI5k*)%K5*@YZrk$?|7?f1G6ct#3)_|7Rt)zO5En zam4=#o)1VzV^mg}DGC0T{Hs(^ao#?$G78RERN()Ym8NUEw8ZvS1^+Df6D1!QWN`g2R1&cVx)2SgYE;;J{-494^i6T5L6COm?lT zRQY;q2Ub`cQZ6YWE6vvggd5Dq!B0CeO-8GLy{aMNpXK4o@7W;0woF2?t#@~B{i;pS2t>s5aV9u z35$_1NtX~CMM<$0-4741>0V#EhLIvxq}4?lC(^izJ#uHvNY9z#P7RMRBE-1|M3`B| zyVul6G{WM&VF~W=hy)`n!5fz7&WmVkgeAJG)HKs3x!;cHW`re4SeO);Y!ui&p`v@j z^ho#Unr4NP-Lq;MYE4LS-(S;gR*HM48I~CBK3UVK11>8p#(ib2&XRXxjQhb_M%u(! z_qJLwMp&#jEY2NO+o(fgoHs1qeS7UrM!b0Uj@oA01o!dUEsd}QZ&;#xK%MqRSfYeg zmeP{U`lq-*Z`{xjCAoLjF|$Z^pR5yYgeAM%)iuLX+#|iNt4&u@wEJlvT@;@bZ`w~xiaR~LzSJ@)!M&t@8;@&aeKU_l_gD2>8}Sp(_^~nG_(|?g zk*y4w$9`jDy|QHYU6FA{Udis524-F=mv&Lae3k;$GF!uNRqU; ztgu*jorXzLR&uPT9`ROL$#L#Q4HFDm+@ECe?#~+bk&a6Cv^UnBTEiG*$qDXZjXD^` zB)AVWGOC!I=zg|QJ0mR7ogQU|CAlj&4eL%$@`fe5r#lVnNTzF>n(p6{HL;hd72li{43RgmeN zOuX!jf(&O5XTFh%1k5f-H)A_9d|5i@W@b&!bY^GF$;eBemf^0Q{l&Q32NL0-nR zto(wEy!`e~Z~J^La%McYj^a669G@sljXXoZ;4xW=4)P%@-OH(ki3}$uj~2+l36DJ*glseX{5_B&1D9>Xa!IDel%GgJx$J zWX;UZnrzf3B&0(~Ï(w8A2%|Zs{PMMuOJ3l0(dGnBgxzmW1?MxlqGbCiuqL6_u zPr#62$U`p6Dwvx^(Wcnz?MH)V=V#5ya7wiC-tb=Y{KLC;^$Lb%P0K8B4$sV*S`ZS_ zxwAKXV8&E$aF;G2y=KjJrDtaq%nu1^+$E%6PR6X+9&hI^Ap@~S=}XKn&q>VmY_jr& zhJ#z1A)&OG>}-4zzrJIfdo zVgX`pBQo*}Jb@YWtUwtWG9DNKc{2>tl2OqyEX?Wmw{Y-~5m!5VUD0p&2xnC1sbrf! zGh=essN!RFp6aqY-nHgz_#Z6#K1nt?NGs$p$X00WOI zVqZohq;=+C_G^VXt~1l=Qj9Un93CiuaH6{~$0^1T4{A)io@T**Es5zGo@-L=Q9V)bN_hwAK@)qwoGjun~>P5YuBV!UAjcKT6@Eh zd9__(sd;qajEsV;$pJH>f4C^rGs(%oFUX~9MtSBCU#|}DHNx3z@Th*nh72CmYw!qX zyHsZmP3hvRjv2R?camhTbLCj`lrg_Cr^!?yQ)PB~&a~Mwb24W#W#;DP(={zaF7WK( zGNz1DOdl6`_HdcgPsyi`3p{(cj9I1>(?`(kVT^qG#ONU>2h_cq0UHc9tYbxi#V1U$5h|Z&+p*Z-q|}h z&&6m-mw^*B?#ZdE(__(M$*EnE+QfRMIYZW~N8cfYHcM^h2~F*i;x7+Ko7yhMU*?y# zqB(JwlYRgN5( zT|ui~Gt(PKMfb1kFKcR_F28;KVi>s;R>{|1wc91rN7iXItN%`%@)fk;XdO#eSc{sO zhX?0-Dx3477O791t5pnYfPP?sR$gB+SF3Ck-{?iHzTrrnuhopCLjJW^jr?m=Z6S-+ zGjp{SzIy+}$)h6b-SFJ?*3Zn-qDoNupW0LT&-HnBesBw$_%-;@eC;DYuXLcazj{My z=*SA1UoQq{?VpXLE0ex>XQ8JXMEjzV!ea}yk8LHWUcKs{mMc>CWl_)2i0}&6nRc&l zUZ~YE`tDyYt+CxwXm#U(I_>jSd6cqXAA zyI%XaL>BQX=OBwv{l&A08!d~t(cdCokW+Vmp4`qmN!(Os7IAYxS01{#2#fez2`u84 zfNUn+o+S$!3|_R3<_p1A44)OPbGf2%J%v`JfU^VNP?N|Cj%96YQd^$M^5NA;;! zeMNGSMf~N93x$VX*UD?>wePL|%{MMc{AEKb>Po|(ey0{5+p5)Fpt<#mU2RQVH+-km z58ty-_XnjGz^W%szq5VQTHLGo-_zl-J@>nBS-dD~V%9B-CuVU4rdrL+DgD-R{X{;~`rDOi z>KCFv7i+6GFw{>PX1WtATqluh_{CM8Fk=65`735#)oW$GHF2LB(%)wIhxWJW%evX3 zdXY|kX4cB=-8arkM@=#oUS(d%F;kP1#4>6{ilIFZd!%Mb`kF0T%^C=vZ?`odD}8r2 zTU)K!z1?ljnxgQ7C|s2OBbu3jzG7Oz*k+!m%kSci{SEAugE03Y*{tdDlh z?Th8wSl*zDO4Vwr^_waiVW&-zOHPU%w9}?Y1(l__Czb& z-HzDMw7RPNa!L;RE8mbBnSYX8{z41be(Q47ASHG5gqG+#;y785Ic{&$opifaPRpnYkS_|_#QD$5c@aUCEAx|c?YbGlu!L`#XHxK!u?152aC zCfzS7(Ndx)ZV(KC%S)rgotKp89nPY-E8t3)RvINl}3rT_PS(=mL-bfzJ~AMNNJRq-20LeEhUQLj>4~? zI89gLvp8R0QlfV_i{dnJK<&~f@$NpCEYY$=QCuCU2Te<(#BO~rv=SK#0e}BHr@};W z&7dW8EsYXCyQD<#a2CaNgH#w?8YN!c?~)~2!&wwJ1ct(-(kL;q|0N|_N)*LSh73_) zX_WZN{|zO&N^*@w6z6|s@_ziAK(0{A70D2|f-91vVG7LipZjO}dvg3e*?8D0?D-R) z_b*%T@V-{Jeqfkaio=M|!d1j|wF>1_XmeGG#g*qOoN>u)%z&~O6E6QM8OOMbd&$i8 zr)y><=*~*gMKi$#cfdoi8s31<;AgP?q*Mb)fsWvRvDtT_xv5eUxUzf$+z2bdy7KJ1 z>a1&nYiIv$w34f?Ry;IrTwj&T(&qJ5(n&cJ-TT(0yUNKbBpeIPxWOK(cAuJh~J z2zt@#U8`rc-}U9PBjk=m>d$77dU}ICe0R{jd_Af<3VHj8fYm^sG{qUT7crZtiOf(exkt z*{bVn``Mbinu)QmfX6*`{)q4Trx-x+7<>aQsP|e0(Pd>?~mc1=xyhv9o@#BPtF za6J^lFVMW4re=Y@u8|^Vs){RMj{N8m=|bmY0KK3pq0SKBP5_fC07$ zSES_kI#e#Nsey1md<}6SnsUMO@Fmo&K>c6^{04*R&j&#I^|DY+-2xxN9ykO)!mvu3 z8Vi7Sqf{%liHTt%Y{b7^TKBnS-rtWiqxjp>$3EY>=(7tG*N} zg;|+?TUk@z!BIE{XW%TTFipAPAFvXls%q*}I0!$$Avg)Ap-MGPML=C>4eg*kq(B;s zgo!Yuby&)?TKlg@+ zyH=(*gdDtXHq@P*aIduqj@@i#U97OG?6M=ec#Z7!?L%xSeVx*SkHK5;HvA5!!0G@? z=`B%qD;NPI!Rmy2aX%TR=|>J}WA&?h(&N_LovP~(YxVS3A7&Oeo(fTImsYn=;0`sZ zym=V+xun|WLd|f|=PH~MjP72=_eMC+DN`deV-^2fnXKZ)-Wk2d-~YmiD%lRH?4r0$ z@EZK9G)jD8;D!DvWGT;7;s3_QH&cnCxOZR&d{i1G4j*($iSr9gC5qzq!an%EG)h#1 zFDcPdqA2bl9D-jnqD2nR? z{a}1)l=#XeC3=UmC~g8wf;pv8V&?EmmS|a`C~ht+fZIx=#F`^6DbZ4*DDHN+3mzzq z61QAZqIWop;+DcPc&ao?%pG~j5-m#<#jS$Xu(>o!j2v}IiIx&Yaj(Nxc(*i4eCvWM z(K-cYegE&APZY)NfL-uyX_T0G`GvMbOL^A!|Bezxao@o~I8hoUhFoz;iPmry#hrxT zp%PbqN_=_XiAzfK9-T#TmF2P-G%k%2dyW1-VTq&9y;I6OpD2oxYm!YM10DnGx};o> zYzlG>vOmbRN4e}cPj`K%b=R-?P78D8STmS>XBF!Sh*rFZ^u~p4^OBnEpONd0eiz(~ zYh+*f`p-30u4-Mlr$bl`DCtf&mm~;yYQzP6Iz$QjuXknXkOi<1Ho@!gIh=;7;hf)u zaA*T@ygVD^z3zO3w&26q;xhO%u8S7+F=(T0p#IY^ zTXTKca9g^IE9K>ROiNRh+*I{#Dtj}4hh9{Zno2D{fW5FEK7)gB7*4?-5L|1kwo=pP z&;~ldTu862sn9y41xH;?m8WoQ$LZNrW5H`otH zp>qRGb%WWk55gL$c%xO*Gkkm#~J)ub~6#y5!oTRB&U}UnUM!}8n`wyRb{(pbp@Bd$xyPM_s zmq+ZCSc0H$wkY^NjmCJkjQ;l_w$Az=eQlMJ(=4^OK;3gd)P6r~f$yPh4NYaiDmVl` zLRf^RH>ze!&^I5{GW7?m8@q(UOe1+L%i1`LbY9oDonyr;SBaN*M#eQ5f)YHOy+t`-5j9Sa)7B;&y zu&jJ1R=%qUYai!l+}HXUcnv=zf6vd*f5zC?HKX649tJOl9}9!P><7J8s;#lUdKs$j zBK0!%!{TaTZi>ZKPrv$VQ(BZOUXn>4RH$FhW^IjTLy>2bv@$xTs=j};t)Z))6f5H{ z0}@(jDiMysFEFMR101X|d5hn;?8Vsps2wvGH15Db6UIan9~Q^pkM)h+F1W7&8N;i< z&)ohvq+O+7En7_3JV;|auEpjYyXl11Q9nGv7V7df#ORes$>w=@9d^N2a00^OI7UM! z7z9&cA>0Kk;U#zn4#2;mdOTA;w1N~E2oqp7EP==1#dxiP+JWQCc&+fRLhbXE_3YWsb2{9>}UUjclUvFPv z+oWHWfrX!$Vmn$}IgqGfFdU}9^{_@ia+Ddd(@(Ys^l_QQU6R2pnf9oyoIc^0RzaUU z&30ckhs1mWK7b$0{0A2j{V}a3Ue&lGt%o=m3LEqe4qM&A_S0?eYgHv+F6gkMqfs}~ zW|OumUKQGjw6L&~CCZU(@v0}_N!S3t$hRlknUbvpbnnb83^#YS(&mvi9Ix68XF+vg z6{3efYHLu4KHk^D!U<>#gJG5kTI*rEw1)cU4qJu7adRa7EJU}$WAFxSmuLeE$ITPr zb^`W7m9AJFEYQPO*!t?@7NNUq_G&Xs7aI4ty!x!>SU~jUupLfxwW_>`T&v<$^}AsM zklW1?T_YmA>R#9gpLs>siU_az9g@1EhwfIY#UjG1Zi7v*%PYD;M0mMe7n~u?v%>kCzTq3C>LhJb#OOWm3lxbB?0T; zBe3_jN`6pE#;aPx0Lb@>mWc?jS^|&3I<{7_S-!*T6Eb=vfirRWHJq5HY|?^&FxacvTXNgYhua z6xT0o{{jsO#j9?C-2)0k*V&G1p}X;D1DQ7l7KW~ufG9jYAcKGn5|DxCCU}T|mkFrx z5T5tp7x)!I25EYw!x}|w6kXv}&7nWcMZ^TkB=xG)8?Sl<3So~|v{^)W)nRBhn2|f! zO0`8qc-4*YEPUh@ZIjmGRcD~(5XK)29%7`VU$;xY;#Cu15!?ZH4jR zPC@5k9Px))Wxp@Y!mAd;N_Zc3n_`;v0nMs{SA7k&hBI#tFRZf1c2o=Phi5*l8(tW? zSNd%op8XIqqA+xy1cZ#>0149x_*4R><9PtK6Y!Y?Y{zp78jmatJs<&%M{24g3?twR z2^faw26&QyuO#3}JRibg0=|)e!+5HWVwjC84E;_5TH_f5c?2AkfIK{I*g(J`0%~r+ z^C9ekZ=u`e*1@!pgXtSum;~g&4e){<9%&Dl6^*0KVd=9Mkben>q3IQtN{=F{iC6W3 zzAzf@0Bg?qMNB~gUWHGf&S)#`amg01iiJ#A>J^=oZ1Jl1U?+S5zk-$R?~<(q)E=X$ zXc#%h%JvV^*1)T7fi>_Zyk&~%4{a_{bD9gv(1xyy|CYFb*qbrDhJ{3Z$%xSIvN1 zV3k)CDw*O{@4;y}169WxDao|5WQtccf;Nz5ikKIwNTztz)vy|Ndqvemgjf9vRVSds z3076AiwLh83Nzp)uP8#Qf>*7EH{l03WQtL3Ejy~ktIj~3iJV}7e6Z$)I#O2&co^P* zPgpve3aBSp<5jIxVQSzwgUa9B-=SORJ+!SfQl3p?Pm4D09-PnkpUD%(^J`%n{V!H@70 zRGG%K0z+UXJO%%RlTbgCM!-UN2|fcymNY2lO|5R>^hEo;S`9h(Vr3jPk4>0|kL!(_ z+iy2-6)^4>;MYK^e&9>3k;^X0d%_HO7Cwa5(>ch%9q>A+s|bSuum~Q3eQ*XEWpla} zZiL6-Q)oDYs>4#)4yT}34poQQ@D!N8Gz;%Lt})jH{b&>UM^G!5pMEeJ7Q%bbU?ztH z$bzNtF+|T|I~6R4EpPS%nLi>$HW3!V zbMOKD0?D%pgZJSWG?~M&fcdZjc0swhEXW`PW_} zTw_!lBjr>V`y5-vB$c4zRJ@AUkEGfQg1jLfslKbXeNKSK8!<63o$2*P4WH_lPCVXp z$${xiuQy%lc)xVwDQDC~pP6c(=jZgqPta$L^2Rqko=E@h;f*g&Z~R9F`^6WJr(Owx zda%5n+}`W$%}t!%GyytDPysqf(EW5^dOW#x@8``;oZhYEwZ*JoBrU|fvM2|YWW%=1bqG1%C+^P-r<|a;We809Q8jA45 zzizlUzBs+{{o0;rwA~{~(tl3%_L%AMfAk{o0-6-|nGTdgF`J8{e-s<9^~<}`((oq zJUKl#(VLSvy*c@{JK4Y8jVF8Ki_;t5uieQ;yFKkl_857P*He1csovbg>5UZ7_GC}n zy=D3JeX_sZUz_R8O`M+iDgJhEdOW2cneL4*PH%j_wx<|v_tYyTaLij?Z#q96r1v^8|rqhTYucCeJw>(CB@c7%l&+AR+ z)q|uHk2js)*q3zig?B8pAJAM+%VY4p52V-bJ>zIRN7*v9CUcawyc`E9Tf?dyM^!Q| zMwayQp{wZk4)CC$budNcaDuMEm#<1ct^T@F?(R{7Sq zb+Pl$)upx)-)P(gsjaIlm0N<^a;5hyk6$pJ$$!C>TLRs>{A{5F)xF@gmG&1^O{R#~Lx-QDm_n~4Jxy-+1zREqvtK8gK>S;1A7$}NFzT}6-nU=y(X7reISogV+aa{yxh=U5(;xheRMzYDHhE|9bP z`<$n=U1e}iyQp#I8(cn@3^P}077Kr2oE4{A*MIfs%cHD|9)HDE_k!2fRkoKm&T9(t z``>r;z4)tem*3I%{PVztub=<;7fr~|!Qwi`N+Y-3#x$+5V2*HC;WR)~YYH z>8diN$pcbn+CtR`m98eKY?Yy$s*lR!j?*bflT^o14b^{Opgc6XA?ecw*c}nvwJ5Lh zZmholtm6f}V@&>eaLn;_Lref|UXZ(Z^h zb$JQ6yu(^v!7OhOmKWg4`&;Gpqw@AldHJKfyHH-eCvT3E7oW*{yX3V~^427I>5sg# zMqasMylRDSc}s#cNgksv4<47NU(3U!<$=udm|b~@Eze+e84q8TM_|em9OVIo^87q` z{F^+zOdh@^&yJEuAIXz@DS>xJB7AvaUVT@!M9gxvZdw>8L}3v!Es+>0PL9mrh;a^rx#w{d5H+yWr` z{Ef~0lU#j`-T6xP+snp!*+DN`p#6%|5m}s;&{v5Jm^`IZ{&%XF(Cn!&| zi)eKM3NNNwdfL<8+9wv@NX5Rs;<7+iY^(Ln{@EAXNU|utvlB6v;%XoLjJC* zHq9BoWi3HpX-y&7ewUa_^C_^el>?8YlD z8j@m-6iM+zGo`pz(R(SD)fT1El;XQr@4m)6DpJnTo9xCbwmmY(6=MbZbN<;E*KFAw zS6s72R@{sfuREXf^r1v6ZfqKR@AU7Uvp;_2R(V|$Z#9`-fg>b@v;L|Z%2Am`$}_Ah z2C$}(r$_9MU@cLbxxWtU5wO=~ZB~y1TYc6hQQX|tgx%z=IWk9c%;Espbf%`C>gPDE zfBk}e#rQ*%QiD?FQ-aW%Qkqdp<;onNDPqT!S!$xeAQm5Lr~CxS201GXr*GIT#Ql` zp$GJZ{xAk+#j)&z*I*m8iB~Ebo`x6T6ZirO5|mm9e@{~Ct|U$(yn|ymEJ@*2H!!s$ zYK2W*$q3q|DisHzJy;9E*q%yFgq`pKyvoakx569nHZe z34{6}gB^o8Di3y%fCrMbgv+2G^cc%x79N8qVGFzg2jEMXG>#i3;CfgB-@{SJyb2A# zlduZhJXPi%*a)ve?_4wn{a_IMZ6;c9@v&hRk>CWJg3I%$IXn(e!6)!J{K{J$PC$)C zte~Mew1nHi4J+U&=ykPHeV`ud3XUD-A5OI`vI&B3gIP4Sw`jH-w(6$f+3I6 z|Cc|i)GI469QYjm4XsyWjL_qGS^$G!B#eQHaJrCIY(NG>;S_5-+g5(Y>{hBSd<6U9 zo&8F^2W>thKj`&2T>zU|1HKOPzja|8ECiRq6L6XzHV%HITmchd2FQ<@y+2Sn7;y*# zge=H|2u5gqSO!nPTG$9tKVi5KcbFeJ&>hlXILv@|L0*P-qw5Gp0{6iS5Y4Z$cvx_p zSG>VkJ9p~ANrt?Zg9)JMyfQ(n*dpHcgwcys;mOQei6-#h8hEQd$nQFsgrVFSDbo7=d!Z4k#Buopgteeel1Zp&{6XaY?k4&tFV z^nuYZ24+DXEQJT*Ay@`$;5m2`-h%z`88mLkExynlQeAvp20dUgTn{h8diWQ-1Jm21 za&W;-@Bw@Xr{E88b|6!TgLs$*nXnWdg&ooS;(~|cu@U$fzJTuhsCD(>BMpW_KFk9h zmVrEkA_4N@26zj0!gVP;AqY0Y+i(gT9nloDhOhY{{3BH7M{s=@#LuN+FdRn1B*=u_ z-RS>Ma2$Z|;5V@I3%LvQf-x`=_VGLG3#inCCw0I^*aDq;yQ;2<1v9sG&m<}ss#+<$Lt8WUhb$|0{h?#s62^8 z&<%RSKVb)ypG?7UE!+xEz-sssz6bjh(n3>c0~28?d;#A>;|vOh-Y^8_!qwnf%Eu${ zC_D*o!%jF0a(Cf4m;wvndZ<5*Q30c2JWPNLsFsQ5peeM0AutN$*2OR3?JVw}gA;HX z`b{U!bS+yYUd1d0U%)}Ao{h?2FC2j1K%2o$c+eesL4UXrZiSCwKl}!#L2fAgH+%tK z!W+4aB#@=mHS6r%^xM|iqtE|Qhlemp^m36ZM48U>Cn`a{5uq%-)IJC29~_1MTxXBc zT$`q|8Ub|`M>VJe&0!RbhTq^6G|46$hQcUl%A%q<^n*b#3`WCjmaUM;W5|)AHy$j0+REU z>I65yt?&%2hEwx7^9bfbhC}csRxPjltz7C~t5ieyhSkbOzNw^!9LG5ShTNwEqix^n_qEc(% z7%Qefpc1R4aEOCMX#NuY-|8hYhZ*qN%Txv$Zo=T;mDgw)?1B&B(=EKP7NWPJN_ZMx zfC}4qjVnaFg}uNO$b>K7#?qn5E*7hB{Rc|j0yRFw5MkhlE?SAB&!=<)ys@ADgW$E> zbe2`wu=^(r4X*lGsT}BVSg9Cz3;qR*j?g9GJjyZ*CjQEj9hSjzsC2H3$BA3p_gX~Hj(eCFr*eoJGdS0f(mswaKYkM z9KK-{tDooKEBFCiC;0dS!rJiD4Vpqr=mgzi5DbH;ph#Q!#K!+Jh&U~ftBzqY=yVrC-@ak zgRKMSkf8=dL32oej?e@8!WA$UvLFW*!gX*v+&!3&Rj?Xff!ASqB8CC=Ic7J6ZXC0F zLwgRz@z9qeVH$itomDP;pTjrELFUYh_FMI^_4Y-@e$gAa3YVM3-ikG0O0h6YxFY>aK>=V1WPo9z+^5l`G@1)^s@@*3O?7O!Q_0g%=Ulc| zy)|*4ToThWYdad$k{2-kvEZ;;-~V@`_Hxat=}cX(?MNvn?hS<>)^>bu>oexL-ba$LRd)8I>O{Alq-96D(VZGBaTI0o`V;VbJ zIHK+gdtASHPk*NTrXaabf2RD}Ah}O}rhGw=+^0WNUJxYr>Ccqs1j&8+Gv%2R@2FZQ;Gv!@_Se1j&8+ zGvyV6@Y{Pt0}H#&>UJoOK1hHp$)W!cF-O=Ks3ZaEW|-PBtRl0K{BL3N9Y8dp$l|{ zZqOZ4;WFr9<7Z+|9KE17^nt$65BkFZ7zl%4Fbsh-7z)E+IE;XiFbXb*D_}H?fh%Dw zjDzto0YowBd{2VOwm$r(#E}70VH!w;EWW41RgeucAO~_`Cd`67$cF+rqu({mQA1xo z%;BiH5dR_xBOk$K$WIS<rOgw@a!G`ht-T zm$p*>eWYW7Hc_8F3SXxF>nKNVubIw~M%w6)t~9R)Py`UDcxaCMpbNR8x* zV=r}u>aX^xVJx^dtAXlG)k}Zsa!04IfUF9ST<*vy*YvWK%lM0rZI>L=JHB0fV$YuK dlH(J4v`gug5|fk~9os88Cc1FJILA%4{|9l4fc5|Y delta 22865 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 Bitwise Right Shift\n" + "++ << Bitwise Left Shift\n" + "++ == Equality\n" + "++ != Inequality\n" + "++ <= Less than or Equal\n" + "++ < Less than\n" + "++ >= Greater than or Equal\n" + "++ > Greater than\n" + "++ ! Logical Negation\n" + "++ ~ Bitwise Compliment\n\n" + " Operator precedence is consistent with C language precedence.\n\n" + " Expression can contain arbitrary combinations of constant\n" + " values, simulator registers and environment variables \n" + "5Examples:\n" + "++SET ENV -A A=7+2\n" + "++SET ENV -A A=A-1\n" + "++ECHO A=%%A%%\n" + "++A=8\n" "4Gathering Input From A User\n" " Input from a user can be obtained by:\n\n" "+set environment -P \"Prompt String\" name=default\n\n" @@ -1975,8 +2010,42 @@ static const char simh_help[] = " failed\" message. Otherwise, the command file will continue to bring up\n" " the operating system.\n" "4Conditional Expressions\n" - " The IF and ASSERT commands evaluate three different forms of conditional\n" + " The IF and ASSERT commands evaluate five different forms of conditional\n" " expressions.:\n\n" + "5C Style Simulator State Expressions\n" + + " Comparisons can optionally be done with complete C style computational\n" + " expressions which leverage the C operations in the below table and can\n" + " optionally reference any combination of values that are constants or\n" + " contained in environment variables or simulator registers. C style\n" + " expression evaluation is initiated by enclosing the expression in\n" + " parenthesis.\n\n" + " Expression can contain any of these C language operators:\n\n" + "++ ( Open Parenthesis\n" + "++ ) Close Parenthesis\n" + "++ - Subtraction\n" + "++ + Addition\n" + "++ * Multiplication\n" + "++ / Division\n" + "++ %% Modulus\n" + "++ && Logical AND\n" + "++ || Logical OR\n" + "++ & Bitwise AND\n" + "++ | Bitwise Inclusive OR\n" + "++ ^ Bitwise Exclusive OR\n" + "++ >> Bitwise Right Shift\n" + "++ << Bitwise Left Shift\n" + "++ == Equality\n" + "++ != Inequality\n" + "++ <= Less than or Equal\n" + "++ < Less than\n" + "++ >= Greater than or Equal\n" + "++ > Greater than\n" + "++ ! Logical Negation\n" + "++ ~ Bitwise Compliment\n\n" + " Operator precedence is consistent with C language precedence.\n\n" + " Expression can contain arbitrary combinations of constant\n" + " values, simulator registers and environment variables \n" "5Simulator State Expressions\n" " The values of simulator registers can be evaluated with:\n\n" "++{NOT} {} |{}\n\n" @@ -3961,59 +4030,69 @@ if (Exist || (*gbuf == '"') || (*gbuf == '\'')) { /* quoted string compari } } else { - cptr = get_glyph (cptr, gbuf, 0); /* get register */ - rptr = find_reg (gbuf, &gptr, sim_dfdev); /* parse register */ - if (rptr) { /* got register? */ - if (*gptr == '[') { /* subscript? */ - if (rptr->depth <= 1) /* array register? */ - return SCPE_ARG; - idx = (uint32) strtotv (++gptr, &tptr, 10); /* convert index */ - if ((gptr == tptr) || (*tptr++ != ']')) - return SCPE_ARG; - gptr = tptr; /* update */ + while (sim_isspace (*cptr)) /* skip spaces */ + ++cptr; + if (*cptr == '(') { + t_svalue value; + + cptr = sim_eval_expression (cptr, &value, TRUE, &r); + result = (value != 0); + } + else { + cptr = get_glyph (cptr, gbuf, 0); /* get register */ + rptr = find_reg (gbuf, &gptr, sim_dfdev); /* parse register */ + if (rptr) { /* got register? */ + if (*gptr == '[') { /* subscript? */ + if (rptr->depth <= 1) /* array register? */ + return SCPE_ARG; + idx = (uint32) strtotv (++gptr, &tptr, 10); /* convert index */ + if ((gptr == tptr) || (*tptr++ != ']')) + return SCPE_ARG; + gptr = tptr; /* update */ + } + else idx = 0; /* not array */ + if (idx >= rptr->depth) /* validate subscript */ + return SCPE_SUB; + } + else { /* not reg, check for memory */ + if (sim_dfdev && sim_vm_parse_addr) /* get addr */ + addr = sim_vm_parse_addr (sim_dfdev, gbuf, &gptr); + else + addr = (t_addr) strtotv (gbuf, &gptr, sim_dfdev ? sim_dfdev->dradix : sim_dflt_dev->dradix); + if (gbuf == gptr) /* not register? */ + return SCPE_NXREG; + } + if (*gptr != 0) /* more? must be search */ + get_glyph (gptr, gbuf, 0); + else { + if (*cptr == 0) /* must be more */ + return SCPE_2FARG; + cptr = get_glyph (cptr, gbuf, 0); /* get search cond */ + } + if (*cptr) { /* more? */ + if (flag) /* ASSERT has no more args */ + return SCPE_2MARG; + } + else { + if (!flag) + return SCPE_2FARG; /* IF needs actions! */ + } + if (rptr) { /* Handle register case */ + if (!get_rsearch (gbuf, rptr->radix, &sim_stabr) || /* parse condition */ + (sim_stabr.boolop == -1)) /* relational op reqd */ + return SCPE_MISVAL; + sim_eval[0] = get_rval (rptr, idx); /* get register value */ + result = test_search (sim_eval, &sim_stabr); /* test condition */ + } + else { /* Handle memory case */ + if (!get_asearch (gbuf, sim_dfdev ? sim_dfdev->dradix : sim_dflt_dev->dradix, &sim_staba) || /* parse condition */ + (sim_staba.boolop == -1)) /* relational op reqd */ + return SCPE_MISVAL; + reason = get_aval (addr, sim_dfdev, sim_dfunit);/* get data */ + if (reason != SCPE_OK) /* return if error */ + return reason; + result = test_search (sim_eval, &sim_staba); /* test condition */ } - else idx = 0; /* not array */ - if (idx >= rptr->depth) /* validate subscript */ - return SCPE_SUB; - } - else { /* not reg, check for memory */ - if (sim_dfdev && sim_vm_parse_addr) /* get addr */ - addr = sim_vm_parse_addr (sim_dfdev, gbuf, &gptr); - else - addr = (t_addr) strtotv (gbuf, &gptr, sim_dfdev ? sim_dfdev->dradix : sim_dflt_dev->dradix); - if (gbuf == gptr) /* not register? */ - return SCPE_NXREG; - } - if (*gptr != 0) /* more? must be search */ - get_glyph (gptr, gbuf, 0); - else { - if (*cptr == 0) /* must be more */ - return SCPE_2FARG; - cptr = get_glyph (cptr, gbuf, 0); /* get search cond */ - } - if (*cptr) { /* more? */ - if (flag) /* ASSERT has no more args */ - return SCPE_2MARG; - } - else { - if (!flag) - return SCPE_2FARG; /* IF needs actions! */ - } - if (rptr) { /* Handle register case */ - if (!get_rsearch (gbuf, rptr->radix, &sim_stabr) || /* parse condition */ - (sim_stabr.boolop == -1)) /* relational op reqd */ - return SCPE_MISVAL; - sim_eval[0] = get_rval (rptr, idx); /* get register value */ - result = test_search (sim_eval, &sim_stabr); /* test condition */ - } - else { /* Handle memory case */ - if (!get_asearch (gbuf, sim_dfdev ? sim_dfdev->dradix : sim_dflt_dev->dradix, &sim_staba) || /* parse condition */ - (sim_staba.boolop == -1)) /* relational op reqd */ - return SCPE_MISVAL; - reason = get_aval (addr, sim_dfdev, sim_dfunit);/* get data */ - if (reason != SCPE_OK) /* return if error */ - return reason; - result = test_search (sim_eval, &sim_staba); /* test condition */ } } if (Not ^ result) { @@ -4605,6 +4684,20 @@ else { return sim_messagef (SCPE_ARG, "Invalid quoted string: %s\n", cbuf); cbuf[str_size] = '\0'; } + else { + if (sim_switches & SWMASK ('A')) { /* Arithmentic Expression Evaluation argument? */ + t_svalue val; + t_stat stat; + + cptr = sim_eval_expression (cptr, &val, FALSE, &stat); + if (stat == SCPE_OK) { + sprintf (cbuf, "%ld", (long)val); + cptr = cbuf; + } + else + return stat; + } + } } setenv(varname, cptr, 1); return SCPE_OK; @@ -13122,3 +13215,543 @@ va_end (ap); return r; } #endif + +/* + * Expression evaluation package + * + * Derived from code provided by Gabriel Pizzolato + */ + + +typedef t_svalue (*Operator_Function)(t_svalue, t_svalue); + +typedef struct Operator { + const char *string; + int precedence; + int unary; + Operator_Function + function; + const char *description; + } Operator; + +typedef struct Stack_Element { + Operator *op; + char data[72]; + } Stack_Element; + +typedef struct Stack { + int size; + int pointer; + int id; + Stack_Element *elements; + } Stack; + +#define STACK_GROW_AMOUNT 5 /* Number of elements to add to stack when needed */ + +/* static variable allocation */ +static int stack_counter = 0; /* number of stacks current allocated */ + +/* start of true stack code */ +/*----------------------------------------------------------------------------- + * Delete the given stack and free all memory associated with it. + -----------------------------------------------------------------------------*/ +void delete_Stack (Stack *sp) +{ +if (sp == NULL) + return; + +sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d has been deallocated]\n", sp->id); + +/* Free the data that the stack was pointing at */ +free (sp->elements); +free (sp); +stack_counter--; +} + +/*----------------------------------------------------------------------------- + * Check to see if a stack is empty + -----------------------------------------------------------------------------*/ +static t_bool isempty_Stack (Stack *this_Stack) +{ +return (this_Stack->pointer == 0); +} + +/*----------------------------------------------------------------------------- + * Create a new stack. + -----------------------------------------------------------------------------*/ +static Stack *new_Stack (void) +{ +/* Stack variable to return */ +Stack *this_Stack = (Stack *)calloc(1, sizeof(*this_Stack)); + +this_Stack->id = ++stack_counter; +sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d has been allocated]\n", this_Stack->id); + +return this_Stack; /* Returns created stack */ +} + +/*----------------------------------------------------------------------------- + * Remove the top element from the specified stack + -----------------------------------------------------------------------------*/ +static t_bool pop_Stack (Stack * this_Stack, char *data, Operator **op) +{ +*op = NULL; +*data = '\0'; + +if (isempty_Stack(this_Stack)) + return FALSE; + +strcpy (data, this_Stack->elements[this_Stack->pointer-1].data); +*op = this_Stack->elements[this_Stack->pointer-1].op; +--this_Stack->pointer; + +if (*op) + sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d - Popping %s(%d)]\n", + this_Stack->id, (*op)->string, (*op)->precedence); +else + sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d - Popping %s]\n", + this_Stack->id, data); + +return TRUE; /* Success */ +} + +/*----------------------------------------------------------------------------- + * Add an element to the specified stack. + -----------------------------------------------------------------------------*/ +static t_bool push_Stack (Stack * this_Stack, char *data, Operator *op) +{ +if (this_Stack == NULL) + return FALSE; + +if (this_Stack->pointer == this_Stack->size) { /* If necessary, grow stack */ + this_Stack->size += STACK_GROW_AMOUNT; + this_Stack->elements = (Stack_Element *)realloc (this_Stack->elements, this_Stack->size * sizeof(*this_Stack->elements)); + memset (&this_Stack->elements[this_Stack->size - STACK_GROW_AMOUNT], 0, STACK_GROW_AMOUNT * sizeof(*this_Stack->elements)); + } + +this_Stack->elements[this_Stack->pointer].op = op; +strlcpy (this_Stack->elements[this_Stack->pointer].data, data, sizeof (this_Stack->elements[this_Stack->pointer].data)); +++this_Stack->pointer; + +if (op) + sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d - Popping %s(%d)]\n", + this_Stack->id, op->string, op->precedence); +else + sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d - Popping %s]\n", + this_Stack->id, data); + +return TRUE; /* Success */ +} + +/*----------------------------------------------------------------------------- + * Return the element at the top of the stack. + -----------------------------------------------------------------------------*/ +static t_bool top_Stack (Stack * this_Stack, char *data, Operator **op) +{ +if (isempty_Stack(this_Stack)) + return FALSE; + +strcpy (data, this_Stack->elements[this_Stack->pointer-1].data); +*op = this_Stack->elements[this_Stack->pointer-1].op; + +if (*op) + sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d - Topping %s(%d)]\n", + this_Stack->id, (*op)->string, (*op)->precedence); +else + sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d - Topping %s]\n", + this_Stack->id, data); + +return TRUE; /* Success */ +} + +/* All Functions implementing operations */ + +static t_svalue _op_add (t_svalue augend, t_svalue addend) +{ +return augend + addend; +} + +static t_svalue _op_sub (t_svalue subtrahend, t_svalue minuend) +{ +return minuend - subtrahend; +} + +static t_svalue _op_mult (t_svalue factorx, t_svalue factory) +{ +return factorx * factory; +} + +static t_svalue _op_div (t_svalue divisor, t_svalue dividend) +{ +return dividend / divisor; +} + +static t_svalue _op_mod (t_svalue divisor, t_svalue dividend) +{ +return dividend % divisor; +} + +static t_svalue _op_comp (t_svalue data, t_svalue unused) +{ +return ~data; +} + +static t_svalue _op_log_not (t_svalue data, t_svalue unused) +{ +return !data; +} + +static t_svalue _op_log_and (t_svalue data1, t_svalue data2) +{ +return data1 && data2; +} + +static t_svalue _op_log_or (t_svalue data1, t_svalue data2) +{ +return data1 || data2; +} + +static t_svalue _op_bit_and (t_svalue data1, t_svalue data2) +{ +return data1 & data2; +} + +static t_svalue _op_bit_rsh (t_svalue shift, t_svalue data) +{ +return data >> shift; +} + +static t_svalue _op_bit_lsh (t_svalue shift, t_svalue data) +{ +return data << shift; +} + +static t_svalue _op_bit_or (t_svalue data1, t_svalue data2) +{ +return data1 | data2; +} + +static t_svalue _op_bit_xor (t_svalue data1, t_svalue data2) +{ +return data1 ^ data2; +} + +static t_svalue _op_eq (t_svalue data1, t_svalue data2) +{ +return data1 == data2; +} + +static t_svalue _op_ne (t_svalue data1, t_svalue data2) +{ +return data1 != data2; +} + +static t_svalue _op_le (t_svalue data1, t_svalue data2) +{ +return data1 <= data2; +} + +static t_svalue _op_lt (t_svalue data1, t_svalue data2) +{ +return data1 < data2; +} + +static t_svalue _op_ge (t_svalue data1, t_svalue data2) +{ +return data1 >= data2; +} + +static t_svalue _op_gt (t_svalue data1, t_svalue data2) +{ +return data1 > data2; +} + +/* + * The order of elements in this array is significant. + * Care must be taken so that longer strings which have + * shorter strings contained in them must come first. + * For example "!=" must come before "!". + * + * These operators implement C language operator precedence + * as described in: + * http://en.cppreference.com/w/c/language/operator_precedence + */ +static Operator operators[] = { + {"(", 1, 0, NULL, "Open Parenthesis"}, + {")", 1, 0, NULL, "Close Parenthesis"}, + {"+", 4, 0, _op_add, "Addition"}, + {"-", 4, 0, _op_sub, "Subtraction"}, + {"*", 3, 0, _op_mult, "Multiplication"}, + {"/", 3, 0, _op_div, "Division"}, + {"%", 3, 0, _op_mod, "Modulus"}, + {"&&", 11, 0, _op_log_and, "Logical AND"}, + {"||", 12, 0, _op_log_or, "Logical OR"}, + {"&", 8, 0, _op_bit_and, "Bitwise AND"}, + {">>", 5, 0, _op_bit_rsh, "Bitwise Right Shift"}, + {"<<", 5, 0, _op_bit_lsh, "Bitwise Left Shift"}, + {"|", 10, 0, _op_bit_or, "Bitwise Inclusive OR"}, + {"^", 9, 0, _op_bit_xor, "Bitwise Exclusive OR"}, + {"==", 7, 0, _op_eq, "Equality"}, + {"!=", 7, 0, _op_ne, "Inequality"}, + {"<=", 6, 0, _op_le, "Less than or Equal"}, + {"<", 6, 0, _op_lt, "Less than"}, + {">=", 6, 0, _op_ge, "Greater than or Equal"}, + {">", 6, 0, _op_gt, "Greater than"}, + {"!", 2, 1, _op_log_not, "Logical Negation"}, + {"~", 2, 1, _op_comp, "Bitwise Compliment"}, + {NULL}}; + +static const char *get_glyph_exp (const char *cptr, char *buf, Operator **oper, t_stat *stat) +{ +static const char HexDigits[] = "0123456789abcdefABCDEF"; +static const char OctalDigits[] = "01234567"; +static const char BinaryDigits[] = "01"; + +*stat = SCPE_OK; /* Assume Success */ +*buf = '\0'; +*oper = NULL; +while (isspace (*cptr)) + ++cptr; +if (isalpha (*cptr)) { + while (isalnum (*cptr)) + *buf++ = *cptr++; + *buf = '\0'; + } +else { + if (isdigit (*cptr)) { + if ((!memcmp (cptr, "0x", 2)) || /* Hex Number */ + (!memcmp (cptr, "0X", 2))) { + memcpy (buf, cptr, 2); + cptr += 2; + buf += 2; + while (strchr (HexDigits, *cptr)) + *buf++ = *cptr++; + *buf = '\0'; + } + else { + if ((!memcmp (cptr, "0b", 2)) ||/* Binary Number */ + (!memcmp (cptr, "0B", 2))) { + memcpy (buf, cptr, 2); + cptr += 2; + buf += 2; + while (strchr (BinaryDigits, *cptr)) + *buf++ = *cptr++; + *buf = '\0'; + } + else { + if (*cptr == '0') { /* Octal Number */ + while (strchr (OctalDigits, *cptr)) + *buf++ = *cptr++; + *buf = '\0'; + } + else { /* Decimal Number */ + while (isdigit (*cptr)) + *buf++ = *cptr++; + *buf = '\0'; + } + } + } + if (isalpha (*cptr)) { /* Numbers can't be followed by alpha character */ + *stat = SCPE_INVEXPR; + return cptr; + } + } + else { + if (((cptr[0] == '-') || (cptr[0] == '+')) && + (isdigit (cptr[1]))) { /* Signed Decimal Number */ + *buf++ = *cptr++; + while (isdigit (*cptr)) + *buf++ = *cptr++; + *buf = '\0'; + if (isalpha (*cptr)) { /* Numbers can't be followed by alpha character */ + *stat = SCPE_INVEXPR; + return cptr; + } + } + else + { /* Special Characters (operators) */ + Operator *op; + + for (op = operators; op->string; op++) { + if (!memcmp (cptr, op->string, strlen (op->string))) { + strcpy (buf, op->string); + cptr += strlen (op->string); + *oper = op; + break; + } + } + if (!op->string) { + *stat = SCPE_INVEXPR; + return cptr; + } + } + } + } +while (isspace (*cptr)) + ++cptr; +return cptr; +} + +/* + * Translate a string containing an infix ordered expression + * into a stack containing that expression in postfix order + */ +static const char *sim_into_postfix (Stack *stack1, const char *cptr, t_stat *stat, t_bool parens_required) +{ +const char *start = cptr; +const char *last_cptr; +int parens = 0; +Operator *op = NULL, *last_op; +Stack *stack2 = new_Stack(); /* working stack */ +char gbuf[CBUFSIZE]; + +while (isspace(*cptr)) /* skip leading whitespace */ + ++cptr; +if (parens_required && (*cptr != '(')) { + delete_Stack (stack2); + *stat = SCPE_INVEXPR; + return cptr; + } +while (*cptr) { + last_cptr = cptr; + last_op = op; + cptr = get_glyph_exp (cptr, gbuf, &op, stat); + if (*stat != SCPE_OK) { + delete_Stack (stack2); + return cptr; + } + if (!last_op && !op && ((gbuf[0] == '-') || (gbuf[0] == '+'))) { + for (op = operators; gbuf[0] != op->string[0]; op++); + gbuf[0] = '0'; + cptr = last_cptr + 1; + } + if (!op) { + push_Stack (stack1, gbuf, op); + continue; + } + if (!strcmp (op->string, "(")) { + ++parens; + push_Stack (stack2, gbuf, op); + continue; + } + if (!strcmp (op->string, ")")) { + char temp_buf[CBUFSIZE]; + Operator *temp_op; + + --parens; + pop_Stack (stack2, temp_buf, &temp_op); + while (!temp_op || strcmp (temp_op->string, "(")) { + push_Stack (stack1, temp_buf, temp_op); + pop_Stack (stack2, temp_buf, &temp_op); + } + if (parens_required && (parens == 0)) { + delete_Stack (stack2); + return cptr; + } + continue; + } + while (!isempty_Stack(stack2)) { + char top_buf[CBUFSIZE]; + Operator *top_op; + + top_Stack (stack2, top_buf, &top_op); + if (op->precedence > top_op->precedence) + break; + pop_Stack (stack2, top_buf, &top_op); + push_Stack (stack1, top_buf, top_op); + } + push_Stack (stack2, gbuf, op); + } +/* migrate the rest of stack2 onto stack1 */ +while (!isempty_Stack (stack2)) { + pop_Stack (stack2, gbuf, &op); + push_Stack (stack1, gbuf, op); + } + +delete_Stack (stack2); /* deletes the working stack */ +return cptr; /* return any unprocessed input */ +} + +static t_svalue sim_value_of(const char *data) +{ +if (isalpha (*data)) { + CONST char *gptr; + REG *rptr = find_reg (data, &gptr, sim_dfdev); + + if (rptr) + return get_rval (rptr, 0); + gptr = getenv (data); + data = gptr; + } +return strtotsv(data, NULL, 0); +} + +/* + * Evaluate a given stack1 containing a postfix expression + */ +static t_svalue sim_eval_postfix (Stack *stack1, t_stat *stat) { +Stack *stack2 = new_Stack(); /* local working stack2 which is holds the numbers operators */ +char temp_data[CBUFSIZE]; /* Holds the items popped from the stack2 */ +Operator *temp_op; + +*stat = SCPE_OK; +/* Reverse stack1 onto stack2 leaving stack1 empty */ +while (!isempty_Stack(stack1)) { + pop_Stack (stack1, temp_data, &temp_op); + push_Stack (stack2, temp_data, temp_op); + } + +/* Loop through the postfix expression in stack2 evaluating until stack2 is empty */ +while (!isempty_Stack(stack2)) { + pop_Stack (stack2, temp_data, &temp_op); + if (temp_op) { /* operator? */ + char item1[CBUFSIZE]; + Operator *op1; + char item2[CBUFSIZE]; + Operator *op2; + + if (!pop_Stack (stack1, item1, &op1)) { + *stat = SCPE_INVEXPR; + return 0; + } + if (temp_op->unary) + strlcpy (item2, "0", sizeof (item2)); + else { + if ((!pop_Stack (stack1, item2, &op2)) && + (temp_op->string[0] != '-') && + (temp_op->string[0] != '+')) { + *stat = SCPE_INVEXPR; + return 0; + } + } + sprint_val (temp_data, (t_value)temp_op->function (sim_value_of (item1), sim_value_of (item2)), 10, sizeof(temp_data) - 1, PV_LEFTSIGN); + push_Stack (stack1, temp_data, NULL); + } + else + push_Stack (stack1, temp_data, temp_op); + } +if (!pop_Stack (stack1, temp_data, &temp_op)) { + *stat = SCPE_INVEXPR; + return 0; + } +delete_Stack (stack2); +return sim_value_of (temp_data); +} + +const char *sim_eval_expression (const char *cptr, t_svalue *value, t_bool parens_required, t_stat *stat) +{ +const char *iptr = cptr; +Stack *postfix = new_Stack (); /* for the postfix expression */ + +*value = 0; +cptr = sim_into_postfix (postfix, cptr, stat, parens_required); +if (*stat != SCPE_OK) { + delete_Stack (postfix); + *stat = sim_messagef (SCPE_ARG, "Invalid Expression Element:\n%s\n%*s^\n", iptr, (int)(cptr-iptr), ""); + return cptr; + } + +*value = sim_eval_postfix (postfix, stat); +delete_Stack (postfix); +return cptr; +} diff --git a/sim_defs.h b/sim_defs.h index e8061edf..b65f9753 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -405,8 +405,9 @@ typedef uint32 t_addr; #define SCPE_EXPECT (SCPE_BASE + 45) /* expect matched */ #define SCPE_AMBREG (SCPE_BASE + 46) /* ambiguous register */ #define SCPE_REMOTE (SCPE_BASE + 47) /* remote console command */ +#define SCPE_INVEXPR (SCPE_BASE + 48) /* invalid expression */ -#define SCPE_MAX_ERR (SCPE_BASE + 47) /* Maximum SCPE Error Value */ +#define SCPE_MAX_ERR (SCPE_BASE + 48) /* Maximum SCPE Error Value */ #define SCPE_KFLAG 0x10000000 /* tti data flag */ #define SCPE_BREAK 0x20000000 /* tti break flag */ #define SCPE_NOMESSAGE 0x40000000 /* message display supression flag */ @@ -843,9 +844,11 @@ struct DEBTAB { #define DEBUG_PRI(d,m) (sim_deb && (d.dctrl & (m))) #define DEBUG_PRJ(d,m) (sim_deb && ((d)->dctrl & (m))) -#define SIM_DBG_EVENT 0x10000 -#define SIM_DBG_ACTIVATE 0x20000 -#define SIM_DBG_AIO_QUEUE 0x40000 +#define SIM_DBG_EVENT 0x010000 +#define SIM_DBG_ACTIVATE 0x020000 +#define SIM_DBG_AIO_QUEUE 0x040000 +#define SIM_DBG_EXP_STACK 0x080000 +#define SIM_DBG_EXP_EVAL 0x100000 /* Open File Reference */ struct FILEREF {