%% %% Copyright (C) 1989, Digital Equipment Corporation %% All rights reserved. %% See the file COPYRIGHT for a full description. %% %%Title: railroad.h %%Creator: Bill Kalsow %%CreationDate: Fri Oct 23 13:21:27 1987 by kalsow %%EditDate: Last modified on Fri Nov 3 16:32:12 1989 by muller %%EditDate: modified on Thu Oct 12 08:19:31 1989 by kalsow %% %% experimental Postscript operators for railroad diagrams %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % misc. operators to make Postscript programming more tolerable /min { 2 copy gt { exch } if pop } def /max { 2 copy lt { exch } if pop } def /stringlen { stringwidth pop } def /defEnumeration { 0 exch { 1 index def 1 add } forall pop } def /inches { 72 mul } def %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Sizing & font parameters for the picture /DASHLen SCALE 0.4 mul def /DDASHLen DASHLen dup add def /HDASHLen DASHLen 2 div def /BOXHgt SCALE 1.2 mul def /BOXStep BOXHgt 2 div def /TERMFont /Helvetica-Bold findfont SCALE scalefont def % TERMFont /NONTERMFont /Times-Italic findfont SCALE scalefont def % NONTERMFont %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % drawing primitives /Hook1 { currentpoint % x y DASHLen sub % x y-D DASHLen 90 0 arcn % x y-D D 90 0 arcn } def % Hook1 /Hook2 { currentpoint % x y exch DASHLen add exch % x+D y DASHLen 180 270 arc % x+D y D 180 270 arc } def % Hook2 /Hook3 { currentpoint % x y DASHLen add % x y+D DASHLen 270 0 arc % x y+D D 270 0 arc } def % Hook3 /Hook4 { currentpoint % x y exch DASHLen add exch % x+D y DASHLen 180 90 arcn % x+D y D 180 90 arcn } def % Hook4 /Hook5 { currentpoint % x y DASHLen add % x y+D DASHLen 270 180 arcn % x y+D D 270 180 arcn } def % Hook6 /Hook6 { currentpoint % x y exch DASHLen sub exch % x-D y DASHLen 0 270 arcn % x-D y D 0 270 arcn } def % Hook6 /Arrow { gsave currentpoint newpath moveto 0.86602 DASHLen mul neg HDASHLen rlineto 0 DASHLen neg rlineto closepath fill grestore } def % Arrow /BackArrow { gsave currentpoint newpath moveto 0.86602 DASHLen mul HDASHLen rlineto 0 DASHLen neg rlineto closepath fill grestore } def % BackArrow /DASH { newpath moveto DASHLen 0 rlineto stroke } def % DASH %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % frames - a record of values with access functions /CurrentFrame [ 0 0 0 0 0 0 0 0 0 0 0 ] def [ /METHODS /INFO /BODY /INITIALX /INITIALY /FINALX /FINALY /NORTH /SOUTH /EAST /WEST ] defEnumeration /methods { CurrentFrame METHODS get } def /methods! { CurrentFrame exch METHODS exch put } def /info { CurrentFrame INFO get } def /info! { CurrentFrame exch INFO exch put } def /body { CurrentFrame BODY get } def /body! { CurrentFrame exch BODY exch put } def /initialX { CurrentFrame INITIALX get } def /initialX! { CurrentFrame exch INITIALX exch put } def /initialY { CurrentFrame INITIALY get } def /initialY! { CurrentFrame exch INITIALY exch put } def /finalX { CurrentFrame FINALX get } def /finalX! { CurrentFrame exch FINALX exch put } def /finalY { CurrentFrame FINALY get } def /finalY! { CurrentFrame exch FINALY exch put } def /north { CurrentFrame NORTH get } def /north! { CurrentFrame exch NORTH exch put } def /south { CurrentFrame SOUTH get } def /south! { CurrentFrame exch SOUTH exch put } def /east { CurrentFrame EAST get } def /east! { CurrentFrame exch EAST exch put } def /west { CurrentFrame WEST get } def /west! { CurrentFrame exch WEST exch put } def /ENTER: { % exchange top-of-stack and CurrentFrame CurrentFrame exch /CurrentFrame exch def } def % ENTER: /:EXIT { % exchange top-of-stack and CurrentFrame CurrentFrame exch /CurrentFrame exch def } def % :EXIT %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % object methods: each object type must provide these methods [ /TOPVIEW /SIZE /DRAW ] defEnumeration % TopView: returns the label and body associated with an object /TopView { % self ENTER: % parent-frame methods TOPVIEW get % parent-frame topview-method cvx exec % parent-frame :EXIT % self } def % TopView % Compute-Size: computes the bounding box and final (x,y) of the frame % on the stack assuming the frame's initial position is (0,0). /Compute-Size { % self ENTER: % parent-frame methods SIZE get % parent-frame size-method cvx exec % parent-frame :EXIT % self } def % Compute-Size % Draw: given (x, y, frame), draw frame at (x,y). /Draw { % x y self ENTER: % x y parent-frame 3 1 roll % parent-frame x y initialY! % parent-frame x initialX! % parent-frame methods DRAW get % parent-frame draw-method cvx exec % parent-frame :EXIT % self pop % } def % Draw %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Sequences /SEQ-View { } def % SEQ-View /SEQ-Size { 0 finalX! 0 finalY! body { Compute-Size dup NORTH get finalY add north max north! dup SOUTH get finalY add south min south! dup WEST get finalX add west max west! dup EAST get finalX add east min east! dup FINALX get finalX add finalX! FINALY get finalY add finalY! } forall } def % SEQ-Size /SEQ-Draw { initialX initialY % make save copies body { % f dup % f f initialX initialY 3 -1 roll % f x y f Draw % f dup FINALX get initialX add % f f.finalX+initialX initialX! % f FINALY get initialY add % f.finalY+initialY initialY! % } forall initialY! initialX! % restore the initial copies } def % SEQ-Draw % method list /SEQ-Methods [ /SEQ-View /SEQ-Size /SEQ-Draw ] def % SEQ: body body ... :SEQ /SEQ: { [ SEQ-Methods 0 [ } def /:SEQ { ] 0 0 0 0 0 0 0 0 ] } def %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Terminal symbols /TERM-View { TERMFont setfont info show } def % TERM-View /TERM-Size { TERMFont setfont DDASHLen BOXHgt add info stringlen add west! 0 east! BOXStep neg south! BOXStep north! 0 finalY! west finalX! } def % TERM-Size /TERM-Draw { TERMFont setfont /len info stringlen def initialX initialY DASH initialX DASHLen add BOXStep add newpath dup initialY BOXStep 90 270 arc len 0 rlineto currentpoint BOXStep add BOXStep 270 90 arc closepath stroke dup initialY SCALE 0.34 mul sub moveto info show len add BOXStep add initialY DASH } def % TERM-Draw % method list /TERM-Methods [ /TERM-View /TERM-Size /TERM-Draw ] def % (name) :TERM constructs a terminal node /:TERM { [ TERM-Methods 3 -1 roll 0 0 0 0 0 0 0 0 0 ] } def %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Non-terminal symbols /NONTERM-View { NONTERMFont setfont info show /CurrentFrame SEQ: body exec :SEQ def } def % NONTERM-View /NONTERM-Size { NONTERMFont setfont DDASHLen BOXHgt add info stringlen add west! 0 east! BOXStep neg south! BOXStep north! 0 finalY! west finalX! } def % NONTERM-Size /NONTERM-Draw { NONTERMFont setfont /len info stringlen def initialX initialY DASH initialX DASHLen add newpath dup initialY BOXStep sub moveto 0 BOXHgt rlineto BOXHgt len add 0 rlineto 0 BOXHgt neg rlineto closepath stroke dup BOXStep add initialY SCALE 0.34 mul sub moveto info show len add BOXHgt add initialY DASH } def % NONTERM-Draw % method list /NONTERM-Methods [ /NONTERM-View /NONTERM-Size /NONTERM-Draw ] def % (name) {body} :NONTERM /:NONTERM { [ NONTERM-Methods 4 -2 roll 0 0 0 0 0 0 0 0 ] } def %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Macros /:MACRO { % (name) {body} exch pop % {body} SEQ: % {body} [ SEQ-Methods 0 [ 5 -1 roll % [ SEQ-Methods 0 [ {body} exec % [ SEQ-Methods 0 [ body :SEQ % sequence } def %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Options /OPT-View { } def % OPT-View /OPT-Size { body Compute-Size 0 east! dup WEST get DDASHLen add west! dup SOUTH get DDASHLen sub south! dup NORTH get north! dup FINALX get DDASHLen add finalX! FINALY get finalY! } def % OPT-Size /OPT-Draw { initialX DASHLen add initialY body Draw initialX initialY DASH newpath initialX initialY moveto Hook1 0 body SOUTH get rlineto Hook2 body WEST get DDASHLen sub 0.5 mul dup 0 rlineto Arrow 0 rlineto Hook3 0 body FINALY get body SOUTH get sub rlineto Hook4 DASHLen neg 0 rlineto stroke } def % OPT-Draw % method list /OPT-Methods [ /OPT-View /OPT-Size /OPT-Draw ] def % OPT: body :OPT /OPT: { [ OPT-Methods 0 SEQ: } def /:OPT { :SEQ 0 0 0 0 0 0 0 0 ] } def %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % separated lists /LIST-View { } def % LIST-View /LIST-Size { body Compute-Size % body 0 east! % body dup WEST get west! % body dup SOUTH get south! % body dup NORTH get north! % body FINALY get finalY! % info Compute-Size % info dup NORTH get % info info.north 1 index SOUTH get sub % info info.north-info.south north add BOXStep add % info info.north-info.south+north+B north! % info WEST get west max west! % west DDASHLen add west! % west finalX! % } def % LIST-Size /LIST-Draw { % draw the body west body WEST get sub % west-body.west 2 div dup dup % (w-b.w)/2 (w-b.w)/2 (w-b.w)/2 newpath % (w-b.w)/2 (w-b.w)/2 (w-b.w)/2 initialX initialY moveto % (w-b.w)/2 (w-b.w)/2 (w-b.w)/2 0 rlineto % (w-b.w)/2 (w-b.w)/2 finalX initialX add % (w-b.w)/2 (w-b.w)/2 finX+initX finalY initialY add moveto % (w-b.w)/2 (w-b.w)/2 neg 0 rlineto % (w-b.w)/2 stroke % (w-b.w)/2 initialX add % (w-b.w)/2+initX initialY body Draw % % draw the separator & vertical lines west info WEST get sub % (w-i.w) DDASHLen sub % (w-i.w-2*D) 2 div dup % (w-i.w)/2 (w-i.w)/2 newpath % (w-i.w)/2 (w-i.w)/2 initialX DASHLen add % (w-i.w)/2 (w-i.w)/2 initX+D initialY moveto % (w-i.w)/2 (w-i.w)/2 Hook5 % (w-i.w)/2 (w-i.w)/2 initialX initialY % (w-i.w)/2 (w-i.w)/2 initX initY north add % (w-i.w)/2 (w-i.w)/2 iX iY+n info NORTH get sub % (w-i.w)/2 (w-i.w)/2 iX iY+n-i.n DASHLen sub lineto % (w-i.w)/2 (w-i.w)/2 Hook4 % (w-i.w)/2 (w-i.w)/2 0 rlineto currentpoint % (w-i.w)/2 x' y' stroke % (w-i.w)/2 x' y' 2 copy info Draw % (w-i.w)/2 x' y' newpath % (w-i.w)/2 x' y' info FINALY get add exch % (w-i.w)/2 y'+i.finY x' info FINALX get add exch % (w-i.w)/2 x'+i.finX y'+i.finY moveto % (w-i.w)/2 BackArrow % 0 rlineto % Hook1 % initialX west add % initX+w initialY finalY add % intiX+w initY+finY DASHLen add lineto % Hook6 % stroke % } def % LIST-Draw % method list /LIST-Methods [ /LIST-View /LIST-Size /LIST-Draw ] def % LIST: body :SEP: separator :LIST /LIST: { [ LIST-Methods SEQ: } def /:SEP: { :SEQ SEQ: } def /:LIST { :SEQ exch 0 0 0 0 0 0 0 0 ] } def %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % optional separated lists /OLIST: { OPT: LIST: } def /:OLIST { :LIST :OPT } def %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Loops /LOOP-View { } def % LOOP-View /LOOP-Size { body Compute-Size 0 east! dup WEST get DDASHLen add west! dup SOUTH get south! dup NORTH get DDASHLen add north! dup FINALX get DDASHLen add finalX! FINALY get finalY! } def % LOOP-Size /LOOP-Draw { initialX DASHLen add initialY body Draw initialX initialY DASH newpath initialX DASHLen add initialY moveto Hook5 0 body NORTH get rlineto Hook4 body WEST get 0.5 mul dup 0 rlineto BackArrow 0 rlineto Hook1 0 body FINALY get body NORTH get sub rlineto Hook6 DASHLen 0 rlineto stroke } def % LOOP-Draw % method list /LOOP-Methods [ /LOOP-View /LOOP-Size /LOOP-Draw ] def % LOOP: body :LOOP /LOOP: { [ LOOP-Methods 0 SEQ: } def /:LOOP { :SEQ 0 0 0 0 0 0 0 0 ] } def %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Optional loops /OLOOP: { OPT: LOOP: } def /:OLOOP { :LOOP :OPT } def %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Vertical list of choices /CHOICE-View { } def % CHOICE-View /CHOICE-Size { 0 % total body { % total f Compute-Size % total f dup WEST get % total f f.west west max west! % total f dup NORTH get % total f f.north exch SOUTH get % total f.north f.south sub add % total+(f.north-f.south) } forall % total body length 1 sub % total N-1 BOXStep mul add % total+(N-1)*B/2 body 0 get NORTH get % total f[0].north dup north! % total f[0].north sub neg south! % 0 east! % west DDASHLen dup add % MAX(body[i].west) 4*D add west! % body 0 get FINALY get % f[0].finalY finalY! % west finalX! % } def % CHOICE-Size /CHOICE-Draw { % % draw the first body % newpath initialX initialY moveto DDASHLen 0 rlineto stroke initialX DDASHLen add initialY body 0 get Draw body 0 get newpath dup FINALX get initialX add DDASHLen add exch FINALY get initialY add dup 3 -1 roll exch moveto west initialX add exch lineto stroke initialY body 0 get SOUTH get add info! % % draw the middle bodies % 1 1 body length 2 sub { body exch get dup NORTH get BOXStep add info exch sub info! newpath initialX DDASHLen add info moveto Hook5 initialX DDASHLen add 1 index FINALX get add 1 index FINALY get info add moveto west initialX add DDASHLen sub 1 index FINALY get info add lineto Hook3 stroke dup initialX DDASHLen add info 4 -1 roll Draw SOUTH get info add info! } for % % draw the final body % body dup length 1 sub get % f[N-1] dup NORTH get BOXStep add % fn fn.north+B/2 info exch sub info! % fn newpath % fn initialX initialY moveto % fn Hook1 % fn initialX DASHLen add % fn initX+D info DASHLen add lineto % fn Hook2 % fn initialX DDASHLen add % fn initX+2*D 1 index FINALX get add % fn initX+2*D+fn.finalX 1 index FINALY get info add % fn initX+2*D+fn.finX fn.finY+info moveto % fn west initialX add DDASHLen sub % fn west+initX-2*D 1 index FINALY get info add % fn west+initX-2*D fn.finY+info lineto % fn Hook3 % fn west initialX add DASHLen sub % fn west+initX-2*D initialY body 0 get FINALY get % fn west+initX-2*D initY+f[0].finalY add DASHLen sub lineto % fn Hook4 % fn stroke % fn initialX DDASHLen add info % fn initX+2*D info 3 -1 roll % initX+2*D info fn Draw % } def % CHOICE-Draw % method list /CHOICE-Methods [ /CHOICE-View /CHOICE-Size /CHOICE-Draw ] def % CHOICE: body0 body1 body2 ... bodyN :CHOICE /CHOICE: { [ CHOICE-Methods 0 [ } def /:CHOICE { ] 0 0 0 0 0 0 0 0 ] } def %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Horizontal list of choices /HCHOICE-View { } def % HCHOICE-View /HCHOICE-Size { 0 % total body { % total f Compute-Size % total f dup NORTH get % total f f.north north max north! % total f dup SOUTH get % total f f.south south min south! % total f WEST get add % total + f.west } forall % total body length % total N 3 mul 1 add % total 3N+1 DASHLen mul add % total + (3N+1)*D west! % west finalX! % 0 east! % 0 finalY! % south DASHLen sub south! north DASHLen add north! } def % CHOICE-Size /HCHOICE-Draw { % % draw the first body % newpath initialX initialY moveto DDASHLen 0 rlineto stroke initialX DDASHLen add initialY body 0 get Draw body 0 get newpath dup FINALX get initialX add DDASHLen add info! info exch FINALY get initialY add moveto Hook1 info DASHLen add info! info initialY south add DASHLen add lineto Hook2 initialX finalX add DDASHLen sub initialY south add lineto Hook3 0 south neg DDASHLen sub rlineto Hook4 stroke % % draw the middle bodies % 1 1 body length 2 sub { body exch get newpath info initialY north add moveto Hook1 info DASHLen add info! info initialY DASHLen add lineto Hook2 info DASHLen add info! currentpoint stroke 2 index Draw newpath dup FINALX get info add info! FINALY get initialY add info exch moveto Hook1 info DASHLen add info! info initialY south add DASHLen add lineto Hook2 stroke } for % % draw the final body % newpath initialX initialY moveto Hook3 0 north DDASHLen sub rlineto Hook4 info initialY north add lineto Hook1 info DASHLen add info! info initialY DASHLen add lineto Hook2 info DASHLen add info! stroke body dup length 1 sub get % f[N-1] dup dup % fn fn fn info initialY 3 -1 roll Draw % fn fn FINALX get info add % fn fn.finX+info exch FINALY get initialY add % fn.finX+info fn.finY newpath moveto initialX finalX add initialY finalY add lineto stroke } def % HCHOICE-Draw % method list /HCHOICE-Methods [ /HCHOICE-View /HCHOICE-Size /HCHOICE-Draw ] def % HCHOICE: body0 body1 body2 ... bodyN :HCHOICE /HCHOICE: { [ HCHOICE-Methods 0 [ } def /:HCHOICE { ] 0 0 0 0 0 0 0 0 ] } def %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Epsilon /EPSILON-View { } def /EPSILON-Size { 0 east! 0 west! 0 north! 0 south! 0 finalX! 0 finalY! } def % EPSILON-Size /EPSILON-Draw { } def % method list /EPSILON-Methods [ /EPSILON-View /EPSILON-Size /EPSILON-Draw ] def % :EPSILON: /:EPSILON: { [ EPSILON-Methods 0 0 0 0 0 0 0 0 0 0 ] } def %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % top-level drawing function /DrawProduction { % x y f 3 copy pop moveto % x y f TopView % x y f Compute-Size % x y f dup NORTH get % x y f f.north 2 index sub neg % x y f (y-f.north) BOXStep sub % x y f (y-f.north-B) 4 -1 roll BOXStep add % y f (y-f.north-B) (x+B) 4 -1 roll pop exch % f (x+B) (y-f.north-B) newpath % f (x+B) (y-f.north-B) 2 copy moveto % f (x+B) (y-f.north-B) DDASHLen 0 rlineto % f (x+B) (y-f.north-B) Arrow % f (x+B) (y-f.north-B) stroke % f (x+B) (y-f.north-B) exch DDASHLen add exch % f (x+B+2D) (y-f.north-B) 2 copy % f (x+B+2D) (y-f.north-B) (x+B+2D) (y-f.n-B) 4 index % f (x+B+2D) (y-f.north-B) (x+B+2D) (y-f.n-B) f Draw % f (x+B+2D) (y-f.north-B) newpath % f (x+B+2D) (y-f.north-B) moveto % f dup FINALX get % f f.finalX 1 index FINALY get % f f.finalX f.finalY rmoveto % f DDASHLen 0 rlineto % f Arrow % f stroke % f dup NORTH get % f f.north exch SOUTH get % f.north f.south sub SCALE add % f.north-f.south+SCALE BOXStep add % f.north-f.south+SCALE+B } def % DrawProduction