Graphviz code: graphviz.pal
From PROSE Programming Language - Wiki
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % graphviz.pal % Author: Mark R. Bannister % Date: 20/Apr/2017 % % Creates some graphviz functions for producing a .gv dot file based on % nexus objects passed into gv_add_node() % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ~Module EQUS {[sys.tools]} ._init func/def [gv_open], &[.open], NULL, [psIndex], [data] func/def [gv_add_node], &[.add_node], NULL, [psPointer], [node] func/def [gv_close], &[.close] % For testing only %func/def [main], &[.main] local/rtn .open var/addr P0, [data] % 0=no data, 1=classes, 2=attributes % 3=add stat class to file objects % (and convert statMode to octal) attr/index P0, P0, [psIndex] reg/load P15, P0 var/global NULL, [psIndex], [data], P0 attr/mvadd ![.prose.sys.io], [psStreamOut], [digraph G {\n], [ concentrate=true;\n], [ ratio=compress;\n] % Use HTML tables if we need to display data too reg/jmpge &[.no_shape], P15, #1 func/rtn .no_shape attr/add ![.prose.sys.io], [psStreamOut], [ node [shape=none\]\n] func/rtn .close attr/add ![.prose.sys.io], [psStreamOut], [}\n] func/rtn .add_node var/addr P0, [node], P15, [data] attr/index P15, P15, [psIndex] attr/copy P1, P0, [psPointer] obj/addr P0, P1 reg/jmplt &[.no_add_stat], P15, #3 % Add the stat class if requested reg/clr SFLG class/test P0, [psFile], [psFileHook] reg/jmpeq &[.no_add_stat], SFLG, #0 class/add P0, [psStatUnix] attr/load P14, [statMode] .no_add_stat % Convert dots in node path to underscores local/jsr &[.replace_illegal_chars] reg/move P9, P1 reg/copy P11, P9 % Get parent node reg/load P8, NULL error/jmp &[.no_parent], ![.prose.error.sys.BadObject] obj/pa P5, P0 error/jmp var/local P5, [psPointer], [parent], P5 attr/copy P1, P5, [psPointer] local/jsr &[.replace_illegal_chars] reg/move P8, P1 % Add node label local/jsr &[.label_node] % Output node in graph attr/mvadd ![.prose.sys.io], [psStreamOut], [ ], P8, [ -> ], P9, [\n] func/rtn .no_parent % Output root node local/jsr &[.label_node] func/rtn .label_node attr/copy P12, P0, [pn] reg/jmpge &[.render_class], P15, #1 attr/mvadd ![.prose.sys.io], [psStreamOut], [ ], P11, [ [label="], P12, ["\]\n] local/rtn .render_class % Render HTML for the list of object classes and attributes attr/mvadd ![.prose.sys.io], [psStreamOut], [ ], P11, [ [label=<\n], [ <table border="0" cellborder="1" cellspacing="0" cellpadding="8">\n], [ <tr><td bgcolor="#3366ff"><font color="#ffffff"><b>], P12, [</b></font></td></tr>\n], [ <tr><td><table border="0" cellborder="0" cellspacing="0" cellpadding="2">\n] % Iterate through class list stack/push P1, P2, P3, P4, P5 class/load P1, (P0) .class_loop class/load P2, (P1) reg/jmpeq &[.class_break], P2, NULL reg/copy P3, P2 attr/mvadd ![.prose.sys.io], [psStreamOut], [ <tr><td align="left"><font color="#3366ff"><b>objectClass:</b></font></td><td align="left">], P3, [</td></tr>\n] local/jmp &[.class_loop] .class_break attr/mvadd ![.prose.sys.io], [psStreamOut], [ </table></td></tr>\n] reg/jmplt &[.label_rtn], P15, #2 % Iterate through attribute list attr/mvadd ![.prose.sys.io], [psStreamOut], [ <tr><td><table border="0" cellborder="0" cellspacing="0" cellpadding="2">\n] attr/load P1, (P0) error/jmp &[.attr_catch], ![.prose.error.sys.NoEntry], ![.prose.error.sys.NoSupport] .attr_loop attr/load P2, (P1) reg/jmpeq &[.attr_break], P2, NULL local/jsr &[.render_attr] local/jmp &[.attr_loop] .render_attr reg/copy P3, P2 % Iterate through attribute values attr/copy P4, (P0, P2) % ... except stdin, stdout, stderr reg/clr SFLG reg/cmp P3, [psStreamIn], P3, [psStreamOut], P3, [psStreamError], P3, [psStreamDebug], P3, [psByteStream] reg/jmpeq &[.atval_loop], SFLG, #0 attr/mvadd ![.prose.sys.io], [psStreamOut], [ <tr><td align="left"><font color="#3366ff"><b>], P3, [:</b></font></td><td align="left"> ], [</td></tr>\n] local/rtn .attr_catch error/clr error/jmp &[.attr_catch], ![.prose.error.sys.NoEntry], ![.prose.error.sys.NoSupport] local/rtn .atval_loop attr/copy P5, (P4) reg/jmpeq &[.atval_break], P5, NULL % % If data mode is 3 and this is the statMode class, convert to octal % reg/jmplt &[.atval_display], P15, #3 reg/jmpne &[.atval_display], P2, P14 reg/conv P5, P5, #10 reg/conv P5, P5, #8 reg/copy P5, [0], P5 .atval_display reg/copy P3, P2 attr/mvadd ![.prose.sys.io], [psStreamOut], [ <tr><td align="left"><font color="#3366ff"><b>], P3, [:</b></font></td><td align="left">], P5, [</td></tr>\n] local/jmp &[.atval_loop] .atval_break local/rtn .attr_break error/jmp attr/mvadd ![.prose.sys.io], [psStreamOut], [ </table></td></tr>\n] .label_rtn attr/mvadd ![.prose.sys.io], [psStreamOut], [ </table>\n >\]\n] stack/pull P5, P4, P3, P2, P1 local/rtn .replace_illegal_chars stack/push P0 .loop reg/xscan P0, P1, [.] reg/jmpeq &[.loop2], P0, NULL reg/save P1, (#0x5f000000, P0, #0xff000000) local/jmp &[.loop] .loop2 reg/xscan P0, P1, [#] reg/jmpeq &[.loop3], P0, NULL reg/save P1, (#0x5f000000, P0, #0xff000000) local/jmp &[.loop2] .loop3 reg/xscan P0, P1, [-] reg/jmpeq &[.loop4], P0, NULL reg/save P1, (#0x5f000000, P0, #0xff000000) local/jmp &[.loop3] .loop4 reg/xscan P0, P1, [/] reg/jmpeq &[.loop_end], P0, NULL reg/save P1, (#0x5f000000, P0, #0xff000000) local/jmp &[.loop4] .loop_end stack/pull P0 local/rtn %.main % For testing only %func/call NULL, [tools.gv_open], #0 %func/call NULL, [tools.gv_add_node], ![.prose] %func/call NULL, [tools.gv_add_node], ![.prose.sys] %func/call NULL, [tools.gv_add_node], ![.prose.sys.io] %func/call NULL, [tools.gv_add_node], ![.prose.code] %func/call NULL, [tools.gv_add_node], ![.prose.code.sys] %func/call NULL, [tools.gv_add_node], ![.prose.error] %func/call NULL, [tools.gv_add_node], ![.prose.error.sys] %func/call NULL, [tools.gv_add_node], ![.prose.error.sys.StackLocked] %func/call NULL, [tools.gv_add_node], ![.prose.error.sys.RegisterDuplication] %func/call NULL, [tools.gv_add_node], ![.prose.error.sys.OutOfBounds] %func/call NULL, [tools.gv_close] %func/rtn