Я реализовал красивый принтер, который хорошо работает на сложном синтаксическом дереве. Поскольку синтаксис сложный, иногда заданный statement
или expression
, он помогает распечатать конструкторы, чтобы понять их структуру. С этой целью я добавил параметр constructor_print
. Когда эта переменная ложна, обычно печатается statement
или expression
; в противном случае все связанные конструкторы печатаются в хорошем порядке. Вот очень небольшая часть коды (фактически существует множество функций pp_...
):Автоматизация отступов в симпатичном принтере
let tercs s0 s1 =
if !constructor_print then
format_of_string s0
else
format_of_string s1
let pp_e (chan: out_channel) (e: expression) =
match e with
| ADD_E_E (e0, e1) ->
Printf.fprintf chan (tercs "ADD_E_E (\n%a,\n%a)" "%a + %a") pp_e e0 pp_e e1
| UMINUS_E e ->
Printf.fprintf chan (tercs "UMINUS_E %a" "- %a") pp_e e
| PARENTHESIZED_E e ->
Printf.fprintf chan (tercs "PARENTHESIZED_E %a" "(%a)") pp_e e
...
let pp_s (chan: out_channel) (s: statement) =
...
...
Например, 3 + (-2)
является разобранным к выражению e
. Когда !constructor_print
является ложным. pp_e stdout e
3 + (-2)
; в противном случае возвращает pp_e stdout e
ADD_E_E (
Int 3,
PARENTHESIZED_E UMINUS_E INT 2)
Однако, проблема в том, я хотел бы напечатать отступ при необходимости, чтобы сделать его более удобным для чтения. Например, я хотел бы надеяться, что предыдущий выход может быть:
ADD_E_E (
INT 3,
PARENTHESIZED_E UMINUS_E INT 2)
Правила довольно просто: когда есть пара (или тройной или более) конструктор (например ADD_E_E
), он выводит новые строки для своих аргументов , каждая строка имеет еще 2 пробела отступов; когда есть унарный конструктор (например, UMINUS_E
), он не печатает новую строку.
Почти все линии имеют эту структуру Printf.fprintf chan (tercs ... ...) ...
, так как их много, мне действительно нужно автоматизировать отступ в умном ключе.
Один из способов, я думаю, состоит в том, чтобы иметь переменную ref i
, которая представляет количество пробелов текущего отступа. Мы включаем i := !i+2
и i := !i-2
до и после Printf.fprintf chan (tercs ... ...)
. Также нам нужно изменить формат, возвращаемый tercs
: после этого есть \n
, мы добавим i
пробелов после \n
.
Но я также слышал о box
, hint
и т. Д., Предоставляемый модулем Format
. Кто-нибудь знает их хорошо, и есть ли более прямое решение по моей просьбе?
Было также полезно узнать, как использовать модуль Format. http://caml.inria.fr/resources/doc/guides/format.en.html –