Fix 2015/burton (add missing file, apply patch)
On Dave Burton's web page he provided a patch with a bug fix in his entry. This patch has been applied to prog.c (not the alt code). Added the missing file spoilers.markdown (but changed the extension to .md). Format fixes in README.md. Didn't check the full file yet. That'll almost certainly come another time in another pull request.
This commit is contained in:
1 parent
d7cb97d1ad
commit
8f601361e1
3 files changed
+46
-12
No files matched your search
@@ -9,7 +9,7 @@
|
||||
make
|
||||
```
|
||||
|
||||
### To run:
|
||||
## To run:
|
||||
|
||||
```sh
|
||||
./prog "expression"
|
||||
@@ -23,7 +23,7 @@ or:
|
||||
|
||||
Type in expressions on standard input.
|
||||
|
||||
### Try:
|
||||
## Try:
|
||||
|
||||
```sh
|
||||
./prog '?0x3343<<2'
|
||||
@@ -49,7 +49,7 @@ grep '[0-9]' prog.c
|
||||
man ./calc.1
|
||||
```
|
||||
|
||||
## Alternate code
|
||||
## Alternate code:
|
||||
|
||||
An alternate version of this entry, `prog.alt.c`, is provided.
|
||||
This alternate code is discussed in the "prog.c vs prog.alt.c" section of the
|
||||
@@ -210,7 +210,7 @@ With -Wall -std=c99, both are quite noisy, and all can be ignored:
|
||||
* `value computed is not used [-Wunused-value]`
|
||||
* `operation on 'j' may be undefined [-Wsequence-point]`
|
||||
|
||||
### Test Suite
|
||||
### Test Suite:
|
||||
|
||||
If the program name begins with an "e", it echoes stdin to stdout.
|
||||
This allows for a convenient test suite:
|
||||
@@ -220,9 +220,9 @@ ln -s prog eprog
|
||||
PATH=. eprog < test.in | diff - test.out
|
||||
```
|
||||
|
||||
### Spoilers
|
||||
### Spoilers:
|
||||
|
||||
If you do not want to puzzle out how it works, see `spoilers.markdown`.
|
||||
If you do not want to puzzle out how it works, see [spoilers.md](spoilers.md).
|
||||
|
||||
## Copyright and CC BY-SA 4.0 License:
|
||||
|
||||
|
||||
+6
-6
@@ -14,8 +14,8 @@ I H char O;
|
||||
I H short Y;
|
||||
I H long long Z;
|
||||
|
||||
O S[]="syntax_error!"
|
||||
"M@K~|JOEF\\^~_NHI]"; L*N,*K,*
|
||||
O S[]="syntax_error="
|
||||
"M@K~|JOEF\\^~_NHIA"; L*N,*K,*
|
||||
B,*E,*T,*A,*x,D; Q(*k)(),v; V z(P),j,_,*
|
||||
o,b,f,u,s,c,a,t,e,d; J l; Q _k(P){ R*K?*K++:
|
||||
~-d; } V r(L a){ R a&&putchar(a); } L n(){ R*T=j=
|
||||
@@ -90,21 +90,21 @@ I H long long Z;
|
||||
,L**K){ V*A; q(K); W(w())**
|
||||
K-c*c-b||p(B),_i(!setjmp(l)?T=B
|
||||
,M(((A=(*o=m()==c-~s&&(j=a|T[-b])&&
|
||||
s-m()==~s)?&o[j-a*u]:(T=B,&_)),*A=F())
|
||||
c-m()==-c)?&o[j-a*u]:(T=B,&_)),*A=F())
|
||||
),B:(L*)S); } V z(P){ V
|
||||
s; W(m() &&v<=f*c
|
||||
s; W(m() &&v< f*c
|
||||
)R v<t ?(v-f)*
|
||||
z():( v-=u<<
|
||||
f)<f ?v?--v
|
||||
?G() : i(z(
|
||||
)):~ z( ):
|
||||
(v-= f) <u
|
||||
(v-= f) <f
|
||||
?v?s = F()
|
||||
,m() ==a>>
|
||||
b?s :G ():
|
||||
_:! (v-=
|
||||
t)? --T,_f
|
||||
(): v-f?o[
|
||||
(): v==b?o[
|
||||
(T[ -b]|a)-
|
||||
a*u]: !z();
|
||||
G(); }
|
||||
@@ -0,0 +1,34 @@
|
||||
### Spoilers
|
||||
|
||||
|
||||
Calc is a recursive-descent parser. It allocates from the stack deep enough
|
||||
that all expressions are exhausted before the recursion stack depth reaches the
|
||||
allocations. The memory map and source is documented in src.doc.rot13. Tokens
|
||||
are encoded using values 0-20, where 0 is an invalid token, 1 is minus, 2 is
|
||||
space, 3 is plus, etc. The necessary constants are derived at the start of the program,
|
||||
using the guarantee that globals are initialized to zero; so a correct null pointer
|
||||
is obtained from an uninitialized global pointer variable, and the integers from
|
||||
uninitialized global int variables. If x is a global int, then !x is 1, and the
|
||||
derivation proceeds from there, using some identities that are confusingly similar
|
||||
and interestingly combined (increasing obfuscation):
|
||||
|
||||
obc clr
|
||||
--- ---
|
||||
-~x x+1
|
||||
~-x x-1
|
||||
y-~x y+x+1
|
||||
|
||||
The derived constants are a compromise between simple expressions, maximum utility,
|
||||
and minimum number of variables used.
|
||||
|
||||
Command line arguments are copied into the upper half of the input buffer,
|
||||
separated by a space. This allows the code to have a single input parser by using
|
||||
a pointer-to-func to either getchar() if live, or a getchar() simulator.
|
||||
|
||||
A small amount of obfuscation comes from void functions declared int, but missing return.
|
||||
This is necessary to allow these functions in ternary ?: expressions and paired with && and ||;
|
||||
but the requisite returns would add symbol count at no benefit to obscurity or functionality.
|
||||
Function decomposition was mostly chosen to avoid curly braces:
|
||||
if a for-loop required multiple statements, the body became a new function.
|
||||
Last, but not least: sharing state via global variables is an ancient and honored
|
||||
form of obfuscation, and remarkably effective.
|
||||
Reference in new issue
Block a user