Question

I am currently writing a Logo to Postscript compiler. My PS output code doesn't seem to be valid. Any ideas what could be the problem? Or what the actual PostScript version for the LOGO should look like?

The LOGO input code

PROC LDRAGON ( LEVEL )
    IF LEVEL == 0 THEN
    FORWARD 5 
    ELSE
    LDRAGON ( LEVEL - 1 )
    LEFT 90
    RDRAGON ( LEVEL - 1 )
    ENDIF 


PROC RDRAGON ( LEVEL )
    IF LEVEL == 0 THEN
    FORWARD 5 
    ELSE
    LDRAGON ( LEVEL - 1 ) 
    RIGHT 90
    RDRAGON ( LEVEL - 1 )
    ENDIF 

PROC MAIN (VOID)
   LDRAGON ( 11 )

The code from my compiler.

%!PS-Adobe-3.0
/Xpos { 300 } def showpage
/Ypos { 500 } def
/Heading { 0 } def
/Arg { 0 } def
/Right {
Heading exch add Trueheading
/Heading exch def
} def
/Left {
Heading exch sub Trueheading
/Heading exch def
} defп
/Trueheading {
360 mod dup
0 lt { 360 add } if
} def
/Forward {
dup Heading sin mul
exch Heading cos mul
2 copy Newposition
rlineto
} def
/Newposition {
Heading 180 gt Heading 360 lt
and { neg } if exch
Heading 90 gt Heading 270 lt
and { neg } if exch
Ypos add /Ypos exch def
Xpos add /Xpos exch def
} def
/LEVEL { 11 } def
/LDRAGON{
LEVEL
0
eq
{
5 FORWARD }{
LEVEL
1
1
sub
LDRAGON
90
LEFT
LEVEL
1
sub
RDRAGON
} ifelse
} def
/MAIN {
11
LDRAGON
} def
Xpos Ypos moveto
MAIN
stroke
showpage
Was it helpful?

Solution

First problem is the opening comment line. The Adobe-3.0 part is not the Postscript version that the code uses, but the Document Structuring Conventions version that the file conforms to. Since you're not using any DSC comments at all, this first line should be %!PS or just %!.

Next, there are gibberish characters in left column of most lines. I'm guessing this is a an encoding for a TAB character, but it's not an ASCII tab. Safest policy is to always uses spaces for indentation.

The showpage operator emits the output of the current page. It almost certainly should be at the end, not the beginning. ... Oh, I see it's at the bottom, too. The one at the top should be removed.

Next thing I see (although not technically a problem) is that addition is commutative. So exch add can always be simplified to add.

There's a typo at the end of the definition of Left: defn should be def.

Heading 180 gt Heading 360 lt and is always false. Perhaps you intended or? ... Actually I think this part isn't necessary at all. Postscript's trig functions yield the appropriate signed-values for all quadrants.

This part looks like it has too many 1s:

LEVEL
1
1
sub
LDRAGON

And RDRAGON is not defined. Although since the functions are identical, you can reuse the same function body. /RDRAGON /LDRAGON load def


If the name LEVEL in the LDRAGON function should refer to the function's argument, then it must be explicitly defined. And it needs to define a local namespace, so it doesn't overwrite other instances of the same variable.

/LDRAGON{
    1 dict begin
    /LEVEL exch def
    %...
    end

And now that we have local dictionaries, re-defining a "global" variable (like Heading, Xpos, and Ypos) should use store instead of def.


Postscript is case sensitive, so FORWARD and Forward are 2 distinct names.


Corrected Postscript program:

%!
%(debug.ps/db5.ps)run traceon stepon currentfile cvx debug
/Xpos { 300 } def
/Ypos { 500 } def
/Heading { 0 } def
/Arg { 0 } def
/Right {
    Heading add Trueheading
    /Heading exch store
} def
/Left {
    Heading exch sub Trueheading
    /Heading exch store
} def
/Trueheading {
    360 mod dup
    0 lt { 360 add } if
} def
/Forward {
    dup Heading sin mul
    exch Heading cos mul
    2 copy Newposition
    rlineto
} def
/Newposition {
    Heading 180 gt Heading 360 lt
    and { neg } if
    exch
    Heading 90 gt Heading 270 lt
    and { neg } if exch
    Ypos add /Ypos exch store
    Xpos add /Xpos exch store
} def
/LEVEL { 11 } def
/LDRAGON{
    1 dict begin
    /LEVEL exch def
    LEVEL
    0
    eq
    {
        5 Forward }{
        LEVEL
        1
        sub
        LDRAGON
        90
        Left
        LEVEL
        1
        sub
        RDRAGON
    } ifelse
    end
} def
/RDRAGON{
    1 dict begin
    /LEVEL exch def
    LEVEL
    0
    eq
    {
        5 Forward }{
        LEVEL
        1
        sub
        LDRAGON
        90
        Right
        LEVEL
        1
        sub
        RDRAGON
    } ifelse
    end
} def
/MAIN {
    11
    LDRAGON
} def
Xpos Ypos moveto
MAIN
stroke
showpage
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top