Skip to content

Instantly share code, notes, and snippets.

@tksmiura
Last active January 6, 2018 08:43
Show Gist options
  • Save tksmiura/761e1b21452bed37d77ac54c201f46e4 to your computer and use it in GitHub Desktop.
Save tksmiura/761e1b21452bed37d77ac54c201f46e4 to your computer and use it in GitHub Desktop.
Create flowchart from comment

Create flowchart from comment

#!/usr/bin/perl
#flow chart
use utf8;
#use Encode;
use Class::Struct;
use Data::Dumper;
# syntax
# use "///" prefix for read flow
#
# start
# ///* function
#
# sequence
# /// a = b
#
# function call
# /// [submodule]
#
# loop
# ///{ cond > 0
#
# branch
# ///|> cond1 == false
#
# /// a = 1
# ///>
# /// a = 2
# ///>|
#
# loop end
# ///}
#
# end
# ///**
#形状パラメータ
$FontWidth = 5; # font幅(半角)
$FontWidthJ = 10; # 全角
$FontHeight = 10;
$FontSizeS = 8; # font(small)
$SeqWidth = 150; # ボックスの幅
$BoxPadding = 4; # パディング(内側の隙間)
$SeqMargin = 8; # シーケンス間のマージン
$DiaHeight = 32; # 分岐(菱側の高さ)
$SideMargin = 40; # 分岐間の横方向のマージン
$ArrowLength = 5; # 矢印の長さ
$ArrowWidth = 2; # 矢印の幅
$FuncPadding = 5; # 関数の2重線の隙間
$PageMargin = 10;
struct Node => {
type => '$', x => '$', y => '$', mid_x => '$', width => '$', height => '$',
text => '$', style => '$', blocks => '@', selectors => '@',
};
$While = 1;
$EndLoop =2;
$If = 3;
$Else = 4;
$EndIf = 5;
$Func = 6;
$Seq = 7;
$Begin = 8;
$End = 9;
$Eof = 10;
$Branch = 11;
$Loop = 12;
$DoWhile = 13;
$Debug = 0;
foreach $infile (@ARGV) {
print "flow chart input $infile \n";
open(FILE, "<$infile") || die "Can't open to $infile";
$Line = 0;
&Readline();
while ($Line == $Begin) {
# parse function block
my ($begin) = &CreateSequence($Text, $Begin);
$Outfile = $Text . ".svg";
print "create $Outfile\n";
&Readline();
my ($block) = &ParseBlock();
if ($Line != $End) {
die "syntax error $LineNum near $Line $Text in main\n";
};
&Readline();
my ($end) = &CreateSequence("", $End);
my (@work) = ( $begin, @$block, $end );
$ref_block_all = \@work;
$Debug && print Dumper($ref_block_all);
# fix position
my($width, $height) =
&Position($PageMargin,$PageMargin,$ref_block_all);
$width += $PageMargin*2;
$height += $PageMargin*2;
@block0 = @$ref_block_all;
$Debug && print Dumper(@block0);
# draw svg flow chart
&DrawFlow($Outfile, $width, $height, $ref_block_all);
}
if ($Line != $Eof) {
#$ref_block_all = &ParseBlock();
die "syntax error $LineNum near $Line $Text in main\n";
}
close(FILE);
print "complete\n";
}
exit 0;
sub ParseBlock {
$Debug && print "ParseBlock\n";
my (@block) = ();
while ($Line == $Seq || $Line == $Func ||
$Line == $If || $Line == $While) {
if ($Line == $Seq) { # 通常文
my($seq) = &CreateSequence($Text);
push(@block, $seq);
&Readline();
} elsif ($Line == $Func) {
my($seq) = &CreateSequence($Text, $Func);
push(@block, $seq);
&Readline();
} elsif ($Line eq $If) {
my($seq) = &ParseIf();
push(@block, $seq);
} elsif ($Line == $While) {
my($seq) = &ParseWhile();
push(@block, $seq);
}
}
return \@block;
}
sub ParseIf {
$Debug && print "ParseIf $Text\n";
my ($condition) = $Text;
my @ref_blocks;
my $ref_block;
my @Selectors;
push(@Selectors, $Selector);
&Readline();
$ref_block = &ParseBlock();
push(@ref_blocks, $ref_block);
while ($Line == $Else) {
push(@Selectors, $Selector);
&Readline();
$ref_block = &ParseBlock();
push(@ref_blocks, $ref_block);
}
if ($Line == $EndIf) {
&Readline();
} else {
die "syntax error $LineNum near $Line $Text in if\n";
}
return &CreateBranch($condition, \@ref_blocks, \@Selectors);
}
sub ParseWhile {
$Debug && print "ParseWhile $Text\n";
my $condition = $Text;
my $do_while = 0;
&Readline();
my ($ref_block) = &ParseBlock();
if ($Line == $EndLoop) {
if (!$condition) {
$condition = $Text;
$do_while = 1;
}
&Readline();
} else {
die "syntax error $LineNum near $Line $Text in loop\n";
}
return &CreateLoop($condition,$ref_block, $do_while);
}
#構造作成
sub CreateSequence {
my ($text,$style) = @_;
my $seq = Node->new();
my $w = 0;
my $h = 0;
my ($ch, $l, $w_max);
$w_max = $SeqWidth;
foreach $l (split /\n/, $text) {
foreach $ch (split //, $l) {
if ($ch =~ /[\x20-\x7f]/) {
$w += $FontWidth;
} elsif ($ch =~ /\n/) {
$h += $FontHeight;
} else {
$w += $FontWidthJ;
}
}
if ($w_max < $w) {
$w_max = $w;
}
$h += $FontHeight;
}
if ($h == 0) {
$h = $FontHeight;
}
$seq->type($Seq);
$seq->x(0);
$seq->y(0);
$seq->mid_x($w_max / 2);
$seq->width($w_max);
if ($style eq $Begin) {
$seq->height($h + $BoxPadding * 2 + $SeqMargin);
} elsif ($style eq $End) {
$seq->height($h + $BoxPadding * 2);
} else {
$seq->height($h + $BoxPadding * 2 + $SeqMargin * 2);
}
$seq->text($text);
$seq->style($style);
return $seq; # 参照を返す
}
sub CreateBranch {
my ($text,$ref_blocks) = @_;
my (@ref_blocks) = @$ref_blocks;
my @width, @height, @mid_x;
my $i = 0;
my $w = 0;
my $h = 0;
my $seq = Node->new();
foreach $ref_block (@ref_blocks) {
($width[$i], $height[$i], $mid_x[$i]) = &SizeOfBlock($ref_block);
$w += $width[$i];
if ($h < $height[$i]) {
$h = $height[$i];
}
$seq->blocks($i, $ref_block);
$i ++;
}
$w += $SideMargin * ($i - 1);
if ($i == 1) {
$w += $SideMargin;
}
$seq->type($Branch);
$seq->x(0);
$seq->y(0);
$seq->mid_x($mid_x[0]);
$seq->width($w);
$seq->height($h + $DiaHeight + $SeqMargin * 3);
$seq->text($text);
return $seq; # 参照を返す
}
sub CreateLoop {
my ($text, $ref_block, $do_while) = @_;
my ($width, $height, $mid_x) = &SizeOfBlock($ref_block);
my $seq = Node->new();
$seq->x(0);
$seq->y(0);
$seq->text($text);
$seq->blocks(0, $ref_block);
if (!$do_while) {
$seq->type($Loop);
$seq->mid_x($mid_x + $SideMargin);
$seq->width($width + $SideMargin * 2);
$seq->height($height + $DiaHeight + $SeqMargin * 5);
} else {
$seq->type($DoWhile);
$seq->mid_x($mid_x + $SideMargin);
$seq->width($width + $SideMargin);
$seq->height($height + $DiaHeight + $SeqMargin * 2);
}
return $seq; # 参照を返す
}
# Size
sub SizeOfBlock {
my ($ref_block) = @_;
my ($width) = $SeqWidth;
my ($height) = 0;
my ($left) = $width / 2;
my ($right) = $width / 2;
my ($ref_seq);
foreach $ref_seq (@$ref_block) {
if ($left < $ref_seq->mid_x) {
$left = $ref_seq->mid_x;
}
if ($right < $ref_seq->width - $ref_seq->mid_x) {
$right = $ref_seq->width - $ref_seq->mid_x;
}
$height += $ref_seq->height;
}
$width = $left + $right;
return ($width, $height, $left);
}
#位置を決定する
sub Position {
my ($x0,$y0,$ref_block) = @_;
my ($width, $height, $mid_x) = &SizeOfBlock($ref_block);
my ($cur_y) = $y0;
$Debug && print "Position $width, $height, $mid_x\n";
foreach $ref_seq (@$ref_block) {
$ref_seq->x($x0 + $mid_x - $ref_seq->mid_x);
$ref_seq->y($cur_y);
$cur_y += $ref_seq->height;
if ($ref_seq->type == $Loop) {
&Position($ref_seq->x + $SideMargin,
$ref_seq->y + $DiaHeight + $SeqMargin * 3,
$ref_seq->blocks(0));
} elsif ($ref_seq->type == $DoWhile) {
&Position($ref_seq->x + $SideMargin,
$ref_seq->y,
$ref_seq->blocks(0));
} elsif ($ref_seq->type == $Branch) {
my $offset_x = 0;
my $ref_block;
my $w1, $h1;
my $count = 0;
while ($ref_block = $ref_seq->blocks($count++)) {
($w1, $h1) = &Position($ref_seq->x + $offset_x,
$ref_seq->y + $DiaHeight +$SeqMargin * 2,
$ref_block); # ???
$offset_x += $w1 + $SideMargin;
}
}
}
return ($width,$height);
}
#字句解析部(行単位)
sub Readline {
my($l, $no_match);
# my $Debug = 1;
$Line = 0;
$Text = "";
$Selector = "";
$no_match = 0;
while ($Line == 0 || ($Line !=0 && $no_match == 0)) {
if (eof(FILE)) {
$Line = $Eof;
$Debug && print "Read(EOF)\n";
return;
}
$l = <FILE>;
$LineNum = $.;
if ($l =~ /\/\/\/\{\s*(.*)\s*$/) { # ///{
$Line = $While;
$Text = $1;
$Debug && print "Read($Line):$Text\n";
return;
} elsif ($l =~ /\/\/\/\}\s*(.*)\s*$/) { # ///}
$Line = $EndLoop;
$Text = $1;
$Debug && print "Read($Line):$Text\n";
return;
} elsif ($l =~ /\/\/\/\|>\s*([^\:]*)(\:(.*)|)\s*$/) { # ///|>
$Line = $If;
$Text = $1;
$Selector = $3;
$Debug && print "Read($Line):$Text\n";
return;
} elsif ($l =~ /\/\/\/>(\s+(.*)\s*|)$/) { # ///>
$Line = $Else;
$Text = "";
$Selector = $2;
$Debug && print "Read($Line): $Text\n";
return;
} elsif ($l =~ /\/\/\/>\|$/) { # ///>|
$Line = $EndIf;
$Debug && print "Read($Line)\n";
return;
} elsif ($l =~ /\/\/\/\s+\[([^\]]*)\]$/) { # /// [func]
$Line = $Func;
$Text = $1;
$Debug && print "Read($Line):$Text\n";
return;
} elsif ($l =~ /\/\/\/\*\s+([^\s]*)/) { # ///* name
$Line = $Begin;
$Text = $1;
$Debug && print "Read($Line):'$Text'\n";
return;
} elsif ($l =~ /\/\/\/\*\*/) { # ///**
$Line = $End;
$Text = $1;
$Debug && print "Read($Line):$Text\n";
return;
} elsif ($l =~ /\/\/\/\s+([^\s].*)$/) { # /// sequence
if ($Line != $Seq) {
$Line = $Seq;
$Text = $1;
} else {
$Text .= "\n$1";
}
$no_match = 0;
} else {
$no_match = 1;
}
}
$Debug && print "Read($Line):$Text\n";
return;
}
##################################################################
#SVG
sub DrawFlow {
my ($out_file, $width, $height, $ref_block) =@_;
open(OUT, ">:utf8", $out_file) || die "Can't open to $out_file\n"; # FILEを開く(utf8)
&StartPage($width, $height);
&DrawBlock($ref_block);
&EndPage();
close(OUT);
}
sub DrawBlock {
my ($ref_block) = @_;
foreach $ref_seq (@$ref_block) {
my($type) = $ref_seq->type;
if ($type == $Seq) {
$Debug && &TestBox($ref_seq->x,$ref_seq->y,
$ref_seq->width,$ref_seq->height);
&DrawSequence($ref_seq);
} elsif ($type == $Branch) {
$Debug && &TestBox($ref_seq->x,$ref_seq->y,
$ref_seq->width,$ref_seq->height);
&DrawBranch($ref_seq);
my $block;
my $count = 0;
while ($block = $ref_seq->blocks($count++)) {
&DrawBlock($block); # ???
}
} elsif ($type == $Loop) {
$Debug && &TestBox($ref_seq->x,$ref_seq->y,
$ref_seq->width,$ref_seq->height);
&DrawLoop($ref_seq);
&DrawBlock($ref_seq->blocks(0));
} elsif ($type == $DoWhile) {
$Debug && &TestBox($ref_seq->x,$ref_seq->y,
$ref_seq->width,$ref_seq->height);
&DrawDoWhile($ref_seq);
&DrawBlock($ref_seq->blocks(0));
}
}
}
sub DrawLoop {
my ($ref_seq) = @_;
my ($x,$y,$mid_x,$width,$height) = ($ref_seq->x,$ref_seq->y,
$ref_seq->mid_x,
$ref_seq->width,$ref_seq->height);
$Debug && print "DrawLoop $x, $y, $width, $height, $mid_x\n";
my ($text) = sprintf("%16.16s", $ref_seq->text);
my ($cx) = $x + $mid_x;
my ($cy) = $y + $SeqMargin * 2 + $DiaHeight / 2;
my ($ty) = $cy + $FontHeight / 2;
my ($x_out) = $x + $width;
my ($bottom_y) = $y + $height;
&Polyline($cx,$y,$cx,$y + $DiaHeight + $SeqMargin * 3);
&Diamond($cx, $y + $SeqMargin*2, $SeqWidth, $DiaHeight);
&Text($cx,$ty, $text);
&TextSmall($cx - $FontSizeS*2 ,$cy + $DiaHeight/2 + $FontSizeS, "YES");
&TextSmall($cx + $SeqWidth/2 + $FontSizeS*2 ,$cy - 2, "NO");
&Polyline($cx + $SeqWidth/2, $cy,
$x_out, $cy,
$x_out, $bottom_y - $SeqMargin,
$cx, $bottom_y - $SeqMargin,
$cx, $bottom_y);
&PolylineA($cx, $bottom_y - $SeqMargin*2,
$x, $bottom_y - $SeqMargin*2,
$x, $y + $SeqMargin,
$cx, $y + $SeqMargin);
}
sub DrawDoWhile {
my ($ref_seq) = @_;
my ($x,$y,$mid_x,$width,$height) = ($ref_seq->x,$ref_seq->y,
$ref_seq->mid_x,
$ref_seq->width,$ref_seq->height);
$Debug && print "DrawDoWhile $x, $y, $width, $height, $mid_x\n";
my ($text) = sprintf("%16.16s", $ref_seq->text);
my ($cx) = $x + $mid_x;
my ($cy) = $y + $height - $SeqMargin - $DiaHeight / 2;
my ($ty) = $cy + $FontHeight / 2;
my ($bottom_y) = $y + $height;
&Polyline($cx,$cy - $DiaHeight / 2 - $SeqMargin, $cx, $bottom_y);
&Diamond($cx, $cy - $DiaHeight / 2, $SeqWidth, $DiaHeight);
&Text($cx,$ty, $text);
&TextSmall($cx - $FontSizeS*2 ,$cy + $DiaHeight/2 + $FontSizeS, "NO");
&TextSmall($cx - $SeqWidth/2 - $FontSizeS*3 ,$cy - 2, "YES");
&PolylineA($cx - $SeqWidth/2 , $cy,
$x, $cy,
$x, $y,
$cx, $y);
}
# branch loop width{0|1}の処理が必要
sub DrawBranch {
my ($ref_seq) = @_;
my ($x,$y,$mid_x,$width,$height) = ($ref_seq->x,$ref_seq->y,
$ref_seq->mid_x,
$ref_seq->width,$ref_seq->height);
my ($text) = sprintf("%16.16s", $ref_seq->text);
my $cx = $x + $mid_x; # 中央x位置
my $cy = $y + $SeqMargin + $DiaHeight / 2; # 分岐の中央Y位置
my $ty = $cy + $FontHeight / 2; # テキスト表示位置
my $ref_block;
my $last_x;
&Polyline($cx, $y, $cx, $y + $SeqMargin); # 矩形直上の線
&Diamond($cx, $y + $SeqMargin, $SeqWidth, $DiaHeight); # 矩形
&Text($cx,$ty, $text);
&Polyline($cx, $cy + $DiaHeight/2,
$cx, $cy + $DiaHeight/2 + $SeqMargin); # 矩形直下の線
my $count = 0;
while ($ref_block = $ref_seq->blocks($count++)) {
my ($bw, $bh, $bmid_x) = &SizeOfBlock($ref_block); # ???
my $top = $$ref_block[0];
my $y;
$last_x = $top->x + $top->mid_x;
if ($count > 1) {
&Polyline($last_x, $cy, # 分岐直上の線
$last_x, $top->y);
&Polyline($last_x, $top->y + $bh, # 分岐直下の線
$last_x, $ref_seq->y + $ref_seq->height - $SeqMargin);
} else {
&Polyline($last_x, $top->y + $bh,
$last_x, $ref_seq->y + $ref_seq->height);
}
# &TextSmall($cx - $FontSizeS * 2 ,
# $cy + $SeqMargin + $DiaHeight / 2 , "YES");
# &TextSmall($cx + $SeqWidth/2 + $FontSizeS*2 ,$cy - 2, "NO");
}
$count --;
if ($count == 1) {
&TextSmall($cx - $FontSizeS*2 ,$cy + $DiaHeight/2 + $FontSizeS, "YES");
&TextSmall($cx + $SeqWidth/2 + $FontSizeS*2 ,$cy - 2, "NO");
$Debug && print "DrawBranch $x $y $width $height\n";
&PolylineA($cx + $SeqWidth/2, $cy,
$x + $width, $cy,
$x + $width, $y + $height - $SeqMargin,
$cx, $y + $height - $SeqMargin);
} else {
&Polyline($cx + $SeqWidth/2, $cy,
$last_x, $cy);
&PolylineA($last_x, $y + $height - $SeqMargin,
$cx , $y + $height - $SeqMargin);
}
}
sub Diamond {
my($cx,$y,$w,$h) = @_; # 始点は中央上
my($x2,$y2,$x3,$y3) = ($cx + $w/2, $y + $h/2, $cx - $w/2, $y + $h);
print OUT <<END_OF_DATA;
<polygon points="$cx $y, $x2 $y2, $cx $y3, $x3 $y2" fill="orangered" stroke="black" />
END_OF_DATA
}
sub DrawSequence {
my ($ref_seq) = @_;
my ($x, $y, $width, $height, $mid_x, $text, $style) =
($ref_seq->x, $ref_seq->y,
$ref_seq->width, $ref_seq->height,
$ref_seq->mid_x, $ref_seq->text,
$ref_seq->style);
my ($cx) = $x + $mid_x;
my $t;
$Debug && print "DrawSequence $x, $y, $width, $height, $mid_x, $text, $style\n";
if ($style eq $Begin) {
&Polyline($cx, $y + $height - $SeqMargin, $cx, $y + $height);
&RoundBox($x, $y, $width, $FontHeight * 1 + $BoxPadding * 2);
} elsif ($style == $End) {
&Polyline($cx, $y, $cx, $y + $SeqMargin);
$y += $SeqMargin;
&RoundBox($x, $y, $width, $FontHeight * 1 + $BoxPadding * 2);
$text = "END";
} else {
&Polyline($cx, $y, $cx, $y + $height);
$y += $SeqMargin;
if ($style == $Func) {
&BoxF($x, $y, $width, $height - $SeqMargin * 2);
} else {
&Box($x, $y, $width, $height - $SeqMargin * 2);
}
}
foreach $t (split /\n/, $text) {
&Text($cx, $y + $FontHeight * 1 + $BoxPadding, $t);
$y += $FontHeight;
}
}
#Pageの始め
sub StartPage {
my ($width, $height) = @_;
print OUT <<END_OF_DATA;
<?xml version="1.0" standalone="no"?>
<svg width="$width" height="$height" version="1.1" xmlns="http://www.w3.org/2000/svg">
<g transform="scale(1.0)">
END_OF_DATA
}
#Pageの終わり
sub EndPage {
print OUT <<END_OF_DATA;
</g>
</svg>
END_OF_DATA
}
#描画プリミティブ
#ボックス(処理内容)
sub Box {
my($x,$y,$w,$h) = @_;
print OUT <<END_OF_DATA;
<rect x="$x" y="$y" width="$w" height="$h" fill="white" stroke="black" />
END_OF_DATA
}
#ボックス(関数呼び出し)
sub BoxF {
my($x,$y,$w,$h) = @_;
my($x1,$w1) = ($x + $FuncPadding,$w - $FuncPadding*2);
print OUT <<END_OF_DATA;
<rect x="$x" y="$y" width="$w" height="$h" fill="slateblue" stroke="black" />
<rect x="$x1" y="$y" width="$w1" height="$h" fill="slateblue" stroke="black" />
END_OF_DATA
}
#角丸のボックス(開始・終了ノード)
sub RoundBox {
my($x,$y,$w,$h) = @_;
my ($r) = $h/2;
print OUT <<END_OF_DATA;
<rect x="$x" y="$y" width="$w" height="$h" rx="$r" fill="white" stroke="black" />
END_OF_DATA
}
#文字列表示(通常サイズ)
sub Text {
my ($x, $y, $text) = @_;
my ($text2) = &XMLText($text);
print OUT <<END_OF_DATA;
<text text-anchor="middle" x="$x" y="$y" font-size="$FontSize" >
$text2
</text>
END_OF_DATA
}
#文字列表示(小サイズ)=分岐先
sub TextSmall {
my ($x, $y, $text) = @_;
my ($text2) = &XMLText($text);
print OUT <<END_OF_DATA;
<text text-anchor="middle" x="$x" y="$y" font-size="$FontSizeS" >
$text2
</text>
END_OF_DATA
}
#ライン
sub Polyline {
my(@lines) = @_;
my ($x,$y);
$x = shift(@lines);
$y = shift(@lines);
my ($points) = "$x $y";
while (@lines) {
$x = shift(@lines);
$y = shift(@lines);
$points = $points . ", $x $y";
}
print OUT <<END_OF_DATA;
<polyline points="$points" fill="none" stroke="black" />
END_OF_DATA
}
#ライン(矢印付き)
sub PolylineA {
my(@lines) = @_;
my ($x,$y,$x2,$y2,$x3,$y3);
my($num) = $#lines;
my ($dx) = $lines[$num-1] - $lines[$num-3];
my ($dy) = $lines[$num] - $lines[$num-2];
if (abs($dx) > abs($dy)) {
$x2 = ($dx > 0) ? $lines[$num-1] - $ArrowLength : $lines[$num-1] + $ArrowLength;
$y2 = $lines[$num] + $ArrowWidth;
$x3 = $x2;
$y3 = $lines[$num] - $ArrowWidth;
} else {
$x2 = $lines[$num-1] + $ArrowWidth;
$y2 = ($dy > 0) ? $lines[$num] - $ArrowLength : $lines[$num-1] + $ArrowLength;
$x3 = $lines[$num-1] - $ArrowWidth;
$y3 = $y2;
}
$x = shift(@lines);
$y = shift(@lines);
my ($points) = "$x $y";
while (@lines) {
$x = shift(@lines);
$y = shift(@lines);
$points = $points . ", $x $y";
}
print OUT <<END_OF_DATA;
<polyline points="$points" fill="none" stroke="black" />
<polygon points="$x $y, $x2, $y2, $x3 $y3" fill="black" stroke="black" />
END_OF_DATA
}
sub PolylineDebug {
my(@lines) = @_;
my ($x,$y);
$x = shift(@lines);
$y = shift(@lines);
my ($points) = "$x $y";
while (@lines) {
$x = shift(@lines);
$y = shift(@lines);
$points = $points . ", $x $y";
}
print OUT <<END_OF_DATA;
<polyline points="$points" fill="none" stroke="red" />
END_OF_DATA
print <<END_OF_DATA;
debug: <polyline points="$points" fill="none" stroke="red" />
END_OF_DATA
}
#テスト用BOX
sub TestBox {
my($x, $y, $width, $height) = @_;
print OUT <<END_OF_DATA;
<rect x="$x" y="$y" width="$width" height="$height" fill="none" stroke="red"/>
END_OF_DATA
}
#XMLの特殊文字変換
sub XMLText {
local($text) =@_;
$text =~ s/\&/\&amp\;/g; # '&' → '&amp'
$text =~ s/\</\&lt\;/g; # '<' → '&lt'
$text =~ s/\>/\&gt\;/g; # '>' → '&gt'
return ($text);
}
Display the source blob
Display the rendered blob
Raw
<?xml version="1.0" standalone="no"?>
<svg width="630" height="518" version="1.1" xmlns="http://www.w3.org/2000/svg">
<g transform="scale(1.0)">
<polyline points="125 28, 125 36" fill="none" stroke="black" />
<rect x="50" y="10" width="150" height="18" rx="9" fill="white" stroke="black" />
<text text-anchor="middle" x="125" y="24" font-size="" >
function
</text>
<polyline points="125 36, 125 70" fill="none" stroke="black" />
<rect x="50" y="44" width="150" height="18" fill="white" stroke="black" />
<text text-anchor="middle" x="125" y="58" font-size="" >
a = b
</text>
<polyline points="125 70, 125 114" fill="none" stroke="black" />
<rect x="50" y="78" width="150" height="28" fill="white" stroke="black" />
<text text-anchor="middle" x="125" y="92" font-size="" >
this is a test
</text>
<text text-anchor="middle" x="125" y="102" font-size="" >
this is a test
</text>
<polyline points="125 114, 125 148" fill="none" stroke="black" />
<rect x="50" y="122" width="150" height="18" fill="slateblue" stroke="black" />
<rect x="55" y="122" width="140" height="18" fill="slateblue" stroke="black" />
<text text-anchor="middle" x="125" y="136" font-size="" >
submodule
</text>
<polyline points="125 148, 125 204" fill="none" stroke="black" />
<polygon points="125 164, 200 180, 125 196, 50 180" fill="orangered" stroke="black" />
<text text-anchor="middle" x="125" y="185" font-size="" >
cond &gt; 0
</text>
<text text-anchor="middle" x="109" y="204" font-size="8" >
YES
</text>
<text text-anchor="middle" x="216" y="178" font-size="8" >
NO
</text>
<polyline points="200 180, 620 180, 620 482, 125 482, 125 490" fill="none" stroke="black" />
<polyline points="125 474, 10 474, 10 156, 125 156" fill="none" stroke="black" />
<polygon points="125 156, 120, 158, 120 154" fill="black" stroke="black" />
<polyline points="125 204, 125 212" fill="none" stroke="black" />
<polygon points="125 212, 200 228, 125 244, 50 228" fill="orangered" stroke="black" />
<text text-anchor="middle" x="125" y="233" font-size="" >
cond1
</text>
<polyline points="125 244, 125 252" fill="none" stroke="black" />
<polyline points="125 286, 125 294" fill="none" stroke="black" />
<text text-anchor="middle" x="109" y="252" font-size="8" >
YES
</text>
<text text-anchor="middle" x="216" y="226" font-size="8" >
NO
</text>
<polyline points="200 228, 240 228, 240 286, 125 286" fill="none" stroke="black" />
<polygon points="125 286, 130, 288, 130 284" fill="black" stroke="black" />
<polyline points="125 252, 125 286" fill="none" stroke="black" />
<rect x="50" y="260" width="150" height="18" fill="white" stroke="black" />
<text text-anchor="middle" x="125" y="274" font-size="" >
a = 1
</text>
<polyline points="125 294, 125 302" fill="none" stroke="black" />
<polygon points="125 302, 200 318, 125 334, 50 318" fill="orangered" stroke="black" />
<text text-anchor="middle" x="125" y="323" font-size="" >
cond2 == false
</text>
<polyline points="125 334, 125 342" fill="none" stroke="black" />
<polyline points="125 376, 125 384" fill="none" stroke="black" />
<polyline points="315 318, 315 342" fill="none" stroke="black" />
<polyline points="200 318, 315 318" fill="none" stroke="black" />
<polyline points="315 376, 125 376" fill="none" stroke="black" />
<polygon points="125 376, 130, 378, 130 374" fill="black" stroke="black" />
<polyline points="125 342, 125 376" fill="none" stroke="black" />
<rect x="50" y="350" width="150" height="18" fill="white" stroke="black" />
<text text-anchor="middle" x="125" y="364" font-size="" >
b = 1
</text>
<polyline points="315 342, 315 376" fill="none" stroke="black" />
<rect x="240" y="350" width="150" height="18" fill="white" stroke="black" />
<text text-anchor="middle" x="315" y="364" font-size="" >
b = 2
</text>
<polyline points="125 384, 125 392" fill="none" stroke="black" />
<polygon points="125 392, 200 408, 125 424, 50 408" fill="orangered" stroke="black" />
<text text-anchor="middle" x="125" y="413" font-size="" >
cond3
</text>
<polyline points="125 424, 125 432" fill="none" stroke="black" />
<polyline points="125 466, 125 474" fill="none" stroke="black" />
<polyline points="315 408, 315 432" fill="none" stroke="black" />
<polyline points="505 408, 505 432" fill="none" stroke="black" />
<polyline points="200 408, 505 408" fill="none" stroke="black" />
<polyline points="505 466, 125 466" fill="none" stroke="black" />
<polygon points="125 466, 130, 468, 130 464" fill="black" stroke="black" />
<polyline points="125 432, 125 466" fill="none" stroke="black" />
<rect x="50" y="440" width="150" height="18" fill="white" stroke="black" />
<text text-anchor="middle" x="125" y="454" font-size="" >
c = A
</text>
<polyline points="315 432, 315 466" fill="none" stroke="black" />
<rect x="240" y="440" width="150" height="18" fill="white" stroke="black" />
<text text-anchor="middle" x="315" y="454" font-size="" >
c = B
</text>
<polyline points="505 432, 505 466" fill="none" stroke="black" />
<rect x="430" y="440" width="150" height="18" fill="white" stroke="black" />
<text text-anchor="middle" x="505" y="454" font-size="" >
c = C
</text>
<polyline points="125 490, 125 498" fill="none" stroke="black" />
<rect x="50" y="498" width="150" height="18" rx="9" fill="white" stroke="black" />
<text text-anchor="middle" x="125" y="512" font-size="" >
END
</text>
</g>
</svg>
start
///* function
sequence
/// a = b
sequence multi line
/// this is a test
/// this is a test
function call
/// [submodule]
loop
///{ cond > 0
branch
///
///|> cond1
/// a = 1
///>|
branch 2
///|> cond2 == false
/// b = 1
///>
/// b = 2
///>|
branch n
///|> cond3 : 'A'
/// c = A
///> 'B'
/// c = B
///> 'C'
/// c = C
///>|
loop end
///}
end
///**
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment