Как сохранить несколько семантических значений при разборе с Happy/Haskell

Я пытаюсь создать простой лексер / парсер с Alex/Happy в Haskell, и я хотел бы сохранить некоторую информацию о локализации из текстового файла в моем окончательном AST.

Мне удалось построить лексер, используя Alex, который строит список токенов с локализацией:

data Token = Token AlexPosn Foo Bar
lexer :: String -> [Token]

в моем файле Happy, когда я объявляю часть токена%, я могу объявить семантическую часть токена с символом $$

%token FOO  { Token _ $$ _ }

и в правиле разбора $ i будет ссылаться на этот $$.

foo_list: FOO  { [$1] }
        | foo_list FOO { $2 : $1 }

Есть ли способ сослаться на часть AlexPosn и часть Foo токена FOO? Прямо сейчас я знаю только, как относиться только к одному из них. Я могу найти информацию о том, как "добавить несколько $$", и обратиться к ним позже.

Есть ли способ сделать это?

V.

2 ответа

Решение

В итоге я нашел 2 решения:

  • упакуйте все значащие данные в кортеж, чтобы $$ указывал на этот кортеж, а затем извлекал данные по проекции:

    data Token = Token (AlexPosn,Foo) Bar
    %token FOO { Token $$ some_bar }
    rule : FOO  { Ast (fst $1) (snd $1) }
    
  • вообще не используйте $$: если вы не используете $$, happy предоставит вам полный токен во время синтаксического анализа, так что вы можете извлечь из этого токена то, что вам действительно нужно:

    data Token = Token AlexPosn Foo Bar
    %token FOO = { Token _ _ some_bar }
    rule : FOO  { Ast (get_pos $1) (get_foo $1) }
    
    get_pos :: Token -> AlexPosn
    get_foo :: Token -> Foo
    

    ...

Я думаю, что первый из них самый элегантный. Второй может быть довольно сложным с точки зрения строк кода, если вы несете много информации: вам придется создавать "проекции" вручную (сопоставление с образцом и т. Д.), И безопасное выполнение этого может быть сложным если ваш тип токена довольно большой.

Также возможно сохранить несколько значений следующим образом:

data Token = Token AlexPosn Foo Bar
%token FOO { Token pos foo some_bar }
rule : FOO { Ast pos foo }

Хотя я не уверен, что Happy действительно гарантирует, что это всегда будет работать. Причина того, почему это (возможно) работает, состоит в том, что happy сгенерирует код, которому соответствует шаблон Token pos foo some_bar, делая pos а также foo доступно в Ast pos foo,

Другие вопросы по тегам