% This file is part of the Attempto Parsing Engine (APE). % Copyright 2008-2013, Attempto Group, University of Zurich (see http://attempto.ifi.uzh.ch). % % The Attempto Parsing Engine (APE) is free software: you can redistribute it and/or modify it % under the terms of the GNU Lesser General Public License as published by the Free Software % Foundation, either version 3 of the License, or (at your option) any later version. % % The Attempto Parsing Engine (APE) is distributed in the hope that it will be useful, but WITHOUT % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR % PURPOSE. See the GNU Lesser General Public License for more details. % % You should have received a copy of the GNU Lesser General Public License along with the Attempto % Parsing Engine (APE). If not, see http://www.gnu.org/licenses/. :- module(trees_to_ascii, [ trees_to_ascii/2 % +SyntaxLists, -Ascii ]). /** ASCII trees This module creates ASCII graphics for syntax trees. @author Tobias Kuhn @version 2008-03-17 */ %% trees_to_ascii(+SyntaxLists, -Ascii) % % Returns the trees described by the syntax list as an atom (ASCII graphics). trees_to_ascii([], ''). trees_to_ascii([FirstAndOnly], Ascii) :- tree_to_ascii(FirstAndOnly, Ascii), !. trees_to_ascii([First | Rest], Ascii) :- tree_to_ascii(First, AsciiFirst), trees_to_ascii(Rest, AsciiRest), format(atom(Ascii), '~w~n~w', [AsciiFirst, AsciiRest]). %% tree_to_ascii(+SyntaxList, -Ascii) tree_to_ascii(Tree, Ascii) :- retractall(char(_,_,_)), retractall(final_line(_)), depth(Tree, Depth), FinalLine is Depth * 2, assert(final_line(FinalLine)), draw_tree(Tree, 0, 0, _, _), get_ascii(0, Ascii). %% char(+Line, +Pos, -Char) :- dynamic(char/3). %% final_line(-FinalLine) :- dynamic(final_line/1). %% get_ascii(+Line, -Ascii) get_ascii(Line, Ascii) :- setof(P, C^char(Line,P,C), Ps), !, last(Ps, MaxPos), get_line(Line, 0, MaxPos, Atom), NewLine is Line + 1, get_ascii(NewLine, AsciiRest), atom_concat(Atom, '\n', AtomT), atom_concat(AtomT, AsciiRest, Ascii). get_ascii(_, ''). %% get_line(+Line, +Pos, +End, -Ascii) get_line(_, Pos, End, '') :- Pos > End, !. get_line(Line, Pos, End, Ascii) :- ( char(Line, Pos, Char) ; Char = ' ' ), !, NewPos is Pos + 1, get_line(Line, NewPos, End, AsciiRest), atom_concat(Char, AsciiRest, Ascii). %% draw_tree(+Tree, +Line, +Start, -Head, -End) draw_tree(Tree, Line, Start, Start, End) :- (Tree = [Atom] ; Tree = Atom), atomic(Atom), !, atom_chars(Atom, AtomChars), final_line(FinalLine), draw_vertical_line(Start, Line, FinalLine-1), draw_chars(FinalLine, Start, AtomChars), length(AtomChars, Length), End is Start + Length. draw_tree([Parent|Children], Line, Start, Head, End) :- draw_children(Children, Line + 2, Start, ChildrenEnd, [FirstHead|HeadList]), last([FirstHead|HeadList], LastHead), draw_horizontal_line(Line + 1, FirstHead, LastHead), Head is (FirstHead + LastHead) // 2, atom_chars(Parent, ParentChars), draw_chars(Line, Head, ParentChars), draw_char(Line + 1, Head, '|'), length(ParentChars, Length), (ChildrenEnd > Head + Length -> End = ChildrenEnd ; End is Head + Length). %% draw_children(+Children, +Line, +Start, -End, -HeadList) draw_children([Child], Line, Start, End, [Head]) :- !, draw_tree(Child, Line, Start, Head, End). draw_children([Child|Rest], Line, Start, End, [Head|HeadList]) :- draw_tree(Child, Line, Start, Head, TempPos), draw_children(Rest, Line, TempPos + 1, End, HeadList). %% draw_chars(+Line, +Pos, -CharList) draw_chars(_, _, []). draw_chars(Line, Pos, [Char|Rest]) :- draw_char(Line, Pos, Char), NewPos is Pos + 1, draw_chars(Line, NewPos, Rest). %% draw_horizontal_line(+Line, +Start, +End) draw_horizontal_line(_, Start, End) :- Start > End, !. draw_horizontal_line(Line, Start, End) :- draw_char(Line, Start, '_'), draw_horizontal_line(Line, Start + 1, End). %% draw_vertical_line(+Pos, +LineStart, +LineEnd) draw_vertical_line(_, LineStart, LineEnd) :- LineStart > LineEnd, !. draw_vertical_line(Pos, LineStart, LineEnd) :- draw_char(LineStart, Pos, '|'), draw_vertical_line(Pos, LineStart + 1, LineEnd). %% draw_char(+Line, +Pos, +Char) draw_char(Line, Pos, Char) :- LineE is Line, PosE is Pos, asserta(char(LineE, PosE, Char)). %% depth(+List, -Depth) depth(Atom, 0) :- atomic(Atom). depth([Atom], 0) :- atomic(Atom), !. depth([H|T], D) :- depth(H, HD), depth(T, TD), (HD + 1 > TD -> D is HD + 1 ; D = TD).