Graphviz code: graphviz.pal

From PROSE Programming Language - Wiki
Revision as of 09:50, 22 June 2018 by Cambridge (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% 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