Post Reply 
RPL stackrobatics decoder
07-10-2018, 04:42 PM
Post: #5
RE: RPL stackrobatics decoder
(07-10-2018 07:17 AM)Thomas Klemm Wrote:  Not a suggestion but looking at Thomas Okken's program here:
Code:
<< DUP 1 - -> n n1
   << 1 n FOR i i INV NEXT
      n 1 + n n1 + FOR i n1 DUPN i INV NEXT
      n DUP 2 ->LIST ->ARRY
   >>
>>

I wonder how you would ever end up with something like this:
Code:
double[][] hilbert(int n) {
    double[][] h = new double[n][n];
    for (int j = 0; j < n; j++)
        h[0][j] = 1.0 / (j + 1);
    for (int i = 1; i < n; i++) {
        for (int j = 0; j < n - 1; j++)
            h[i][j] = h [i - 1][j + 1];
        h[i][n - 1] = 1.0 / (i  + j + 1);
    }
    return h;
}

Commands like DUPN, ->LIST or ->ARRY consume or produce an arbitrary number of parameters. We know their exact numbers only at runtime.
Thus using local variables like in case of + or MOD wouldn't work.

Yes, those commands are trouble, one way to handle them could be for this decoder to explicitly output those "push/drop" that I was doing in the background, then have special rules to cancel them out and remove them in the cleanup phase. The stack would then be used as a vector, and whatever is not removed would look like the user storing elements in a vector.

Now the C code you show is not the target of this decoder, I wasn't thinking of specifically targetting constructs of a different language, but mostly to help the reader understand the algorithm by turning it into code in a language he's more familiar with. The decoder cannot rewrite an algorithm, merely try to present it in a way the programmer would be able to understand and "recode" properly in a language of choice.

Back to the example you presented, with explicit stack being output for example with a vector called 'stk' and an index called 'stkidx':

Code:

<< ----> output 'function fcn1() {'
DUP ----> Empty stack! The decoder will need to detect this and push 'arg1', while adding the argument to the function declaration above 'function fcn1(arg1)'. Now we make the pushes explicit: output 'stk[stkidx++]=arg1'. After that bit, output 'l1=arg1', 'stk[stkidx++]=l1'
1 -----> 'l2=1', 'stk[stkidx++]=l2'
- -----> output 'stkidx--', 'stkidx--' (drop 2 arguments explicitly), 'l1=l1-l2', 'stk[stkidx++]=l1'
-> n n1 << -----> output 'stkidx--','stkidx--', 'n=arg1', 'n1=l1'
1 -----> 'l3=1', 'stk[stkidx++]=l3'
n -----> 'l4=n', 'stk[stkidx++]=l4'
FOR i -----> 'stkidx--', 'stkidx--', 'for i= l3 to l4 {'
i -----> 'l5=i', 'stk[stkidx++]=l5'
INV -----> 'stkidx--', 'l5=1/l5', 'stk[stkidx++]=l5'
NEXT -----> output ' } '
n -----> 'l6=n', 'stk[stkidx++]=l6'
1 -----> 'l7=1', 'stk[stkidx++]=l7'
+ -----> 'stkidx--', 'stkidx--', 'l6=l6+l7', 'stk[stkidx++]=l6'
n -----> 'l8=n', 'stk[stkidx++]=l8
n1 -----> 'l9=n1', 'stk[stkidx++]=l9'
+ -----> 'stkidx--', 'stkidx--', 'l8=l8+l9', 'stk[stkidx++]=l8'
FOR i -----> 'stkidx--' 'stkidx--' 'for i= l6 to l8 {'
n1 -----> 'l10=n1', 'stk[stkidx++]=l10'
DUPN -----> 'stkidx--', here output NDUPN as a loop 'for tmp1=1 to l10 { stk[stkidx++]=stk[stkidx-l10] }'
i -----> 'l11=i', 'stk[stkidx++]=l11'
INV -----> 'stkidx--', l11=1/l11', 'stk[stkidx++]=l11'
NEXT -----> ' } '
n -----> 'l12=n', 'stk[stkidx++]=l12'
DUP -----> 'l13=l12', 'stk[stkidx++]=l13'
2 -----> 'l14=2', 'stk[stkidx++]=l14
->LIST -----> 'stkidx--', and implement it as a loop as well: ' l15={ }', 'for tmp2=0 to l14-1 { l15[tmp2+1]=stk[stkidx-l14+tmp2] } 'stkidx=stkidx-l14' 'stk[stkidx++]=l15'
->ARRY -----> 'stkidx--', and implement as a loop as well: 'l16=[][]', 'for tmp3=1 to l15[1] { for tmp4=1 to l15[2] { l16[tmp3][tmp4]=stk[stkidx-(l15[1]*l15[2])+l15[2]*(tmp3-1)+(tmp4-1)] } } stkidx=stkidx-l15[1]*l15[2] stk[stkidx++]=l16'
>> -----> ' } '
>> -----> ' } '

Which results in:
Code:

/*function fcn1() {*/
function fcn1(arg1) {
stk[stkidx++]=arg1
l1=arg1
stk[stkidx++]=l1
l2=1
stk[stkidx++]=l2
stkidx--
stkidx--
l1=l1-l2
stk[stkidx++]=l1
stkidx--
stkidx--
n=arg1
n1=l1
l3=1
stk[stkidx++]=l3
l4=n
stk[stkidx++]=l4
stkidx--
stkidx--
for i= l3 to l4 {
l5=i
stk[stkidx++]=l5
stkidx--
l5=1/l5
stk[stkidx++]=l5
}
l6=n
stk[stkidx++]=l6
l7=1
stk[stkidx++]=l7
stkidx--
stkidx--
l6=l6+l7
stk[stkidx++]=l6
l8=n
stk[stkidx++]=l8
l9=n1
stk[stkidx++]=l9
stkidx--
stkidx--
l8=l8+l9
stk[stkidx++]=l8
stkidx--
stkidx--
for i= l6 to l8 {
l10=n1
stk[stkidx++]=l10
stkidx--
for tmp1=1 to l10 { stk[stkidx++]=stk[stkidx-l10] }
l11=i
stk[stkidx++]=l11
stkidx--
l11=1/l11
stk[stkidx++]=l11
}
l12=n
stk[stkidx++]=l12
l13=l12
stk[stkidx++]=l13
l14=2
stk[stkidx++]=l14
stkidx--
l15={ }
for tmp2=0 to l14-1 { l15[tmp2+1]=stk[stkidx-l14+tmp2] }
stkidx=stkidx-l14
stk[stkidx++]=l15
stkidx--
l16=[][]
for tmp3=1 to l15[1] { for tmp4=1 to l15[2] { l16[tmp3][tmp4]=stk[stkidx-(l15[1]*l15[2])+l15[2]*(tmp3-1)+(tmp4-1)] } }
stkidx=stkidx-l15[1]*l15[2]
stk[stkidx++]=l16
 } 
 }

Now applying the same 3 previous rules + the new "stack" rule for cleanup.
* Whenever stkidx-- is found, search for a previous stk[stkidx++]=... statement, but do not cross { } boundaries. If found, remove both statements.
For clarity, let's apply the new rule first:

Code:

function fcn1(arg1) {
/*stk[stkidx++]=arg1*/ // CANCELED OUT
l1=arg1
/*stk[stkidx++]=l1*/ CANCELED OUT
l2=1
/*stk[stkidx++]=l2
stkidx--*/ // BOTH CANCEL OUT TOGETHER
/*stkidx--*/ // cancels out with the l1
l1=l1-l2
/*stk[stkidx++]=l1
stkidx--*/  // CANCELED OUT
/*stkidx--*/ // CANCELS OUT THE arg1 PUSH
n=arg1
n1=l1
l3=1
/*stk[stkidx++]=l3*/
l4=n
/*stk[stkidx++]=l4
stkidx--*/
/*stkidx--*/ // CANCELS OUT THE l3 PUSH
for i= l3 to l4 {
l5=i
/*stk[stkidx++]=l5
stkidx--*/  // CANCEL OUT TOGETHER
l5=1/l5
stk[stkidx++]=l5
}
l6=n
/*stk[stkidx++]=l6*/
l7=1
/*stk[stkidx++]=l7
stkidx--*/
/*stkidx--*/  // CANCELS OUT THE l6 PUSH
l6=l6+l7
/*stk[stkidx++]=l6*/
l8=n
/*stk[stkidx++]=l8*/
l9=n1
/*stk[stkidx++]=l9
stkidx--*/
/*stkidx--*/ // CANCELS OUT THE l8 PUSH
l8=l8+l9
/*stk[stkidx++]=l8
stkidx--*/
/*stkidx--*/ // CANCELS OUT THE l6 PUSH
for i= l6 to l8 {
l10=n1
/*stk[stkidx++]=l10
stkidx--*/
for tmp1=1 to l10 { stk[stkidx++]=stk[stkidx-l10] }
l11=i
/*stk[stkidx++]=l11
stkidx--*/
l11=1/l11
stk[stkidx++]=l11
}
l12=n
stk[stkidx++]=l12
l13=l12
stk[stkidx++]=l13
l14=2
/*stk[stkidx++]=l14
stkidx--*/
l15={ }
for tmp2=0 to l14-1 { l15[tmp2+1]=stk[stkidx-l14+tmp2] }
stkidx=stkidx-l14
/*stk[stkidx++]=l15
stkidx--*/
l16=[][]
for tmp3=1 to l15[1] { for tmp4=1 to l15[2] { l16[tmp3][tmp4]=stk[stkidx-(l15[1]*l15[2])+l15[2]*(tmp3-1)+(tmp4-1)] } }
stkidx=stkidx-l15[1]*l15[2]
stk[stkidx++]=l16
 } 
 }

Now let's do the other rules with the cleaner output:

Code:

// CODE BEFORE THE FIRST PASS, AFTER THE STACK CLEANUP RULE ABOVE:
function fcn1(arg1) {
l1=arg1
l2=1
l1=l1-l2
n=arg1
n1=l1
l3=1
l4=n
for i= l3 to l4 {
l5=i
l5=1/l5
stk[stkidx++]=l5
}
l6=n
l7=1
l6=l6+l7
l8=n
l9=n1
l8=l8+l9
for i= l6 to l8 {
l10=n1
for tmp1=1 to l10 { stk[stkidx++]=stk[stkidx-l10] }
l11=i
l11=1/l11
stk[stkidx++]=l11
}
l12=n
stk[stkidx++]=l12
l13=l12
stk[stkidx++]=l13
l14=2
l15={ }
for tmp2=0 to l14-1 { l15[tmp2+1]=stk[stkidx-l14+tmp2] }
stkidx=stkidx-l14
l16=[][]
for tmp3=1 to l15[1] { for tmp4=1 to l15[2] { l16[tmp3][tmp4]=stk[stkidx-(l15[1]*l15[2])+l15[2]*(tmp3-1)+(tmp4-1)] } }
stkidx=stkidx-l15[1]*l15[2]
stk[stkidx++]=l16
 } 
 }

// FIRST PASS OTHER RULES
function fcn1(arg1) {
l1=arg1
l2=1
l1=l1-1 // l2 never used, replace
n=arg1
n1=arg1-1 // l1 never used after this, recursively replace by value since first replacement included l1 again
l3=1
l4=n
for i= 1 to n { // l3 and l4 never used after this, replace by value
/*l5=i*/
l5=1/i // CONSECUTIVE ASSIGNMENT, MERGE
stk[stkidx++]=1/i // l5 never used after
}
l6=n
l7=1
l6=l6+1  // l6 is still used, only l7 can be replaced
l8=n
l9=n1
l8=l8+n1 // l8 still used, only replace l19
for i= n+1 to n+n1 { // recursively replace l6 and l8, never used after here
l10=n1
for tmp1=1 to l10 { stk[stkidx++]=stk[stkidx-n1] } // replace l10, never used
/*l11=i*/
l11=1/i // CONSECUTIVE ASSIGNMENT, MERGE
stk[stkidx++]=1/i // l11 replaced, never used after here
}
l12=n
stk[stkidx++]=l12
l13=n // l12 replaced, never used
stk[stkidx++]=l13
l14=2
l15={ }
for tmp2=0 to l14-1 { l15[tmp2+1]=stk[stkidx-l14+tmp2] }
stkidx=stkidx-2 // l14 replaced
l16=[][]
for tmp3=1 to l15[1] { for tmp4=1 to l15[2] { l16[tmp3][tmp4]=stk[stkidx-(l15[1]*l15[2])+l15[2]*(tmp3-1)+(tmp4-1)] } }
stkidx=stkidx-l15[1]*l15[2]
stk[stkidx++]=l16
 } 
 }


// SECOND PASS OTHER RULES
function fcn1(arg1) {
l1=arg1
/*l2=1*/ // never used, remove
/*l1=l1-1*/ // never used, remove
n=arg1
n1=arg1-1
/*l3=1*/ // never used, remove
/*l4=n*/ // never used, remove
for i= 1 to n {
/*l5=1/i*/ // never used, remove
stk[stkidx++]=1/i
}
l6=n
/*l7=1*/ // never used, remove
/*l6=l6+1 */ // never used, remove (after replacing l6 with n but doesn't matter)
l8=n
/*l9=n1*/ // never used, remove
/*l8=l8+n1*/ // never used, remove
for i= n+1 to n+n1 {
l10=n1
for tmp1=1 to n1 { stk[stkidx++]=stk[stkidx-n1] } // replace other l10, never used
/*l11=1/i*/ // never used, remove
stk[stkidx++]=1/i
}
l12=n
stk[stkidx++]=n // l12 replaced, never used after
l13=n
stk[stkidx++]=n // l13 never used after this, replace
l14=2
l15={ }
for tmp2=0 to l14-1 { l15[tmp2+1]=stk[stkidx-2+tmp2] } // l14 replaced, never used after
stkidx=stkidx-2 
l16=[][]
for tmp3=1 to l15[1] { for tmp4=1 to l15[2] { l16[tmp3][tmp4]=stk[stkidx-(l15[1]*l15[2])+l15[2]*(tmp3-1)+(tmp4-1)] } }
stkidx=stkidx-l15[1]*l15[2]
stk[stkidx++]=l16
 } 
 }

// THIRD PASS OTHER RULES
function fcn1(arg1) {
/*l1=arg1*/ // never used, remove
n=arg1
n1=arg1-1
for i= 1 to n {
stk[stkidx++]=1/i
}
/*l6=n*/ // never used, remove
/*l8=n*/ // never used, remove
for i= n+1 to n+n1 {
/*l10=n1*/ // never used, remove
for tmp1=1 to n1 { stk[stkidx++]=stk[stkidx-n1] }
stk[stkidx++]=1/i
}
/*l12=n*/ // never used, remove
stk[stkidx++]=n
/*l13=n*/ // never used, remove
stk[stkidx++]=n
l14=2
l15={ }
for tmp2=0 to 2-1 { l15[tmp2+1]=stk[stkidx-2+tmp2] } // l14 replaced, never used after
stkidx=stkidx-2 
l16=[][]
for tmp3=1 to l15[1] { for tmp4=1 to l15[2] { l16[tmp3][tmp4]=stk[stkidx-(l15[1]*l15[2])+l15[2]*(tmp3-1)+(tmp4-1)] } }
stkidx=stkidx-l15[1]*l15[2]
stk[stkidx++]=l16
 } 
 }

// FOURTH PASS OTHER RULES
function fcn1(arg1) {
n=arg1
n1=arg1-1
for i= 1 to n {
stk[stkidx++]=1/i
}
for i= n+1 to n+n1 {
for tmp1=1 to n1 { stk[stkidx++]=stk[stkidx-n1] }
stk[stkidx++]=1/i
}
stk[stkidx++]=n
stk[stkidx++]=n
/*l14=2*/ // never used, remove
l15={ }
for tmp2=0 to 2-1 { l15[tmp2+1]=stk[stkidx-2+tmp2] }
stkidx=stkidx-2 
l16=[][]
for tmp3=1 to l15[1] { for tmp4=1 to l15[2] { l16[tmp3][tmp4]=stk[stkidx-(l15[1]*l15[2])+l15[2]*(tmp3-1)+(tmp4-1)] } }
stkidx=stkidx-l15[1]*l15[2]
stk[stkidx++]=l16
 } 
 }

And this leads to the following final code:

Code:

// FINAL OUTPUT OTHER RULES
function fcn1(arg1)
{
    n=arg1
    n1=arg1-1
    for i= 1 to n {
        stk[stkidx++]=1/i
    }
    for i= n+1 to n+n1 {
        for tmp1=1 to n1 { stk[stkidx++]=stk[stkidx-n1] }
        stk[stkidx++]=1/i
    }
    stk[stkidx++]=n
    stk[stkidx++]=n
    l15={ }
    for tmp2=0 to 2-1 { l15[tmp2+1]=stk[stkidx-2+tmp2] }
    stkidx=stkidx-2 
    l16=[][]
    for tmp3=1 to l15[1] {
        for tmp4=1 to l15[2] {
            l16[tmp3][tmp4]=stk[stkidx-(l15[1]*l15[2])+l15[2]*(tmp3-1)+(tmp4-1)]
        }
    }
    stkidx=stkidx-l15[1]*l15[2]
    stk[stkidx++]=l16
}

It's a bit convoluted at the end, not sure if it helps as it is. To make it more like the actual code you would write, a more advanced decoder should detect that the loop 'for tmp2=0 to 1 ...' is determined at compile time, and should try to unroll the loop and simplify further, showing that l15[1]=l15[2]=n, replacing and removing it all. It would help a lot with readability in the last part, which is merely trying to fill up a matrix, the first couple of loops where the actual math is done came out pretty nice.
Anyway, this was a nice experiment as a proof of concept, perhaps one day I'll actually code it for newRPL giving it the power to decompile RPL into something like Lua or Python.
Find all posts by this user
Quote this message in a reply
Post Reply 


Messages In This Thread
RPL stackrobatics decoder - Claudio L. - 07-09-2018, 04:14 PM
RE: RPL stackrobatics decoder - Claudio L. - 07-09-2018, 06:12 PM
RE: RPL stackrobatics decoder - Claudio L. - 07-10-2018 04:42 PM
RE: RPL stackrobatics decoder - pier4r - 07-11-2018, 11:24 AM



User(s) browsing this thread: 1 Guest(s)