Consider a simple prefix arithmetic notation; a few examples:
+ 1 2 i.e. 1+2
+ * 4 4 * 6 6 i.e. (4*4) + (6*6)
/ 8 * 2 2 i.e. (8/(2*2))
The above grammar can be represented in Prolog as:
operator(plus).
operator(minus).
operator(multiply).
operator(divide).
arithmetic(Op, num, num) :- operator(Op).
arithmetic(Op, A, num) :-
operator(Op),
A = arithmetic(_,_,_).
arithmetic(Op, num, A) :-
operator(Op),
A = arithmetic(_,_,_).
arithmetic(Op, A, B) :-
operator(Op),
A = arithmetic(_,_,_),
B = arithmetic(_,_,_).So ‘parsing’ the prior examples would produce ASTs of the form (actual digits excluded)
arithmetic(plus, num, num). % + 1 2
arithmetic(plus, arithmetic(multiply, num, num), arithmetic(multiply, num, num)). % + * 4 4 * 6 6
arithmetic(divide, num, arithmetic(multiply, num, num)). % / 8 * 2 2 Given this AST, the objective is to spit out a sequence of HTML
<span> for coloring the various nodes. Prolog is no
stranger to tree rewriting; here’s one approach:
stringify_op(Op, Str) :-
(Op = plus, Str = '+')
; (Op = minus, Str = '-')
; (Op = multiply, Str = '*')
; (Op = divide, Str = '/').
highlight_num(num, Str) :-
format(atom(Str), '<span class="number">~a</span>', [num]).
highlight_op(Op, Str) :-
stringify_op(Op, S1),
format(atom(Str), '<span class="operator">~a</span>', [S1]).
highlight_arithmetic(Op, num, num, Highlight) :-
highlight_op(Op, OpHL),
highlight_num(num, N1HL),
highlight_num(num, N2HL),
format(atom(Highlight), '~a ~a ~a', [OpHL, N1HL, N2HL]).
highlight_arithmetic(Op, num, A, Highlight) :-
highlight_op(Op, OpHL),
highlight_num(num, N1HL),
A = arithmetic(SubOp, SubA, SubB),
highlight_arithmetic(SubOp, SubA, SubB, SubHL),
format(atom(Highlight), '~a ~a ~a', [OpHL, N1HL, SubHL]).
highlight_arithmetic(Op, A, num, Highlight) :-
highlight_op(Op, OpHL),
A = arithmetic(SubOp, SubA, SubB),
highlight_arithmetic(SubOp, SubA, SubB, SubHL),
highlight_num(num, N1HL),
format(atom(Highlight), '~a ~a ~a', [OpHL, SubHL, N1HL]).
highlight_arithmetic(Op, A, B, Highlight) :-
highlight_op(Op, OpHL),
A = arithmetic(AOp, AA, AB),
B = arithmetic(BOp, BB, BA),
highlight_arithmetic(AOp, AA, AB, AHL),
highlight_arithmetic(BOp, BA, BB, BHL),
format(atom(Highlight), '~a ~a ~a', [OpHL, AHL, BHL]).For syntax highlighting, the following CSS styling is used:
.operator {
color: red;
}
.number {
color: blue;
}Now for generating the HTML. Each node is converted to its equivalent span and concatenated. Again, using the initial examples:
?- highlight_arithmetic(plus,num,num,HL).
HL = '<span class="operator">+</span> <span class="number">num</span> <span class="number">num</span>' .+ num num
?- highlight_arithmetic(plus, arithmetic(multiply, num, num), arithmetic(multiply, num, num), HL).
HL = '<span class="operator">+</span> <span class="operator">*</span> <span class="number">num</span> <span class="number">num</span> <span class="operator">*</span> <span class="number">num</span> <span class="number">num</span>' .+ * num num * num num
?- highlight_arithmetic(divide, num, arithmetic(multiply, num, num), HL).
HL = '<span class="operator">/</span> <span class="number">num</span> <span class="operator">*</span> <span class="number">num</span> <span class="number">num</span>' ./ num * num num