Значение 'pos' в синтаксическом дереве

Я только начал изучать SML, и меня смущает следующий код:

type pos = int
datatype prog= Prog of statement option
    and statement =... some code..
    and expression =
         VarExp of symbol * pos
         | IntExp of int * pos
         | BoolExp of bool * pos
         | BopExp of exp * oper * exp * pos
         | UopExp of oper * exp * pos

Чего я не могу понять, так это использования pos. Разве подпись не должна быть похожа на BopExp of exp * oper * exp вместо BopExp of exp * oper * exp * pos?


person n0unc3    schedule 22.02.2018    source источник
comment
Дикое предположение состоит в том, что pos представляет собой какую-то позицию (номер строки или смещение символа или что-то в этом роде), возможно, для того, чтобы иметь возможность создавать разумные сообщения об ошибках. Скорее всего, это станет ясно, если вы прочитаете объяснение и использование шрифта.   -  person molbdnilo    schedule 22.02.2018
comment
Это может быть код для ML-YACC. pos передается для сообщения об ошибке.   -  person Tai    schedule 22.02.2018
comment
Когда синтаксический анализатор обнаруживает ошибку синтаксического анализа, он должен сообщить программисту, где возникла ошибка. Думаю, поэтому нам нужен pos.   -  person Tai    schedule 22.02.2018


Ответы (1)


Поскольку Джон, molbdnilo и Tai уже ответили вам в комментариях, сказав, что pos, вероятно, является своего рода позицией, предполагая, что текстовое представление синтаксического элемента находится в pos ' -й символ в файле, вот еще несколько мыслей:

Синтаксическое дерево может быть аннотировано всеми видами информации. Парсер обычно сохраняет позицию для сообщения об ошибках. То же самое и со статической проверкой типов, но она также может сохранять информацию о предполагаемом типе, которую она может передать себе или последующей фазе генерации кода.

Что вы можете сделать, так это параметризовать свое синтаксическое дерево:

datatype 'a prog = Prog of 'a stmt list
and 'a stmt = AssignStmt of symbol * 'a exp * 'a
            | PrintStmt of 'a exp * 'a
and 'a exp = VarExp of symbol * 'a
           | IntExp of int * 'a
           | BoolExp of bool * 'a
           | BopExp of 'a exp * oper * 'a exp * 'a
           | UopExp of oper * 'a exp * 'a

Затем программа типа x: = 2 + true; может быть сначала проанализирована и аннотирована как pos prog:

type pos = int
val hello = Prog [AssignStmt ("x", BopExp (IntExp (2, 6), "+",
                                           BoolExp (true, 10),
                                           6),
                              0)
                 ]

который говорит, что присвоение находится в позиции 0, выражение 2 + true находится в позиции 6, целое число 2 в позиции 6 и логическое значение true в позиции 10. Когда вы дойдете до проверки типов, вам может потребоваться программа (pos × typ):

type typ = Int | Bool | None | Conflict of typ list * typ
val hello = Prog [AssignStmt ("x", BopExp (IntExp (2, (6, Int)), "+",
                                           BoolExp (true, (10, Bool)),
                                           (6, Conflict ([Int, Bool], Int)),
                              (0, None)
                 ]

который сохраняет информацию о положении для достойного сообщения об ошибках (это все еще необходимо, если есть ошибка типа), но также сохраняет информацию о том, где есть конфликтующие типы, например Conflict ([Int, Bool], Int) должен был предположить, что, хотя он ожидает Int, он не может получить это из-за конфликтующих типов Int и Bool.

Тогда вам понадобится только одно определение синтаксического дерева для позиций, типов, регистров, всего, что вы можете придумать, чтобы аннотировать свои синтаксические элементы.

person Simon Shine    schedule 23.02.2018