使用Alex和Happy管理位置信息

19
我正在学习使用Alex和Happy编写一个小型编译器。我希望为我的AST节点维护行列信息,以便向用户提供有意义的错误消息。为了说明我计划如何做到这一点,我写了一个小例子(请参见下面的代码),我想知道我解决问题的方式(将AlexPosn附加到标记上,将多态属性字段附加到AST节点上,使用tkPos和astAttr)是否是良好的风格,或者是否有更好的处理位置信息的方法。
Lexer.x:
{
module Lexer where
}

%wrapper "posn"

$white = [\ \t\n]

tokens :-

$white+ ;
[xX] { \pos s -> MkToken pos X }
"+"  { \pos s -> MkToken pos Plus }
"*"  { \pos s -> MkToken pos Times }
"("  { \pos s -> MkToken pos LParen }
")"  { \pos s -> MkToken pos RParen }

{
data Token = MkToken AlexPosn TokenClass
           deriving (Show, Eq)

data TokenClass = X
                | Plus
                | Times
                | LParen
                | RParen
                  deriving (Show, Eq)

tkPos :: Token -> (Int, Int)
tkPos (MkToken (AlexPn _ line col) _) = (line, col)
}

Parser.y:

{
module Parser where

import Lexer
}

%name simple
%tokentype { Token }
%token
    '(' { MkToken _ LParen }
    ')' { MkToken _ RParen }
    '+' { MkToken _ Plus }
    '*' { MkToken _ Times }
    x   { MkToken _ X }

%%

Expr : Term '+' Expr     { NAdd $1 $3 (astAttr $1) }
     | Term              { $1 }

Term : Factor '*' Term   { NMul $1 $3 (astAttr $1) }
     | Factor            { $1 }

Factor : x               { NX (tkPos $1) }
       | '(' Expr ')'    { $2 }


{
data AST a = NX a
           | NMul (AST a) (AST a) a
           | NAdd (AST a) (AST a) a
             deriving (Show, Eq)

astAttr :: AST a -> a
astAttr (NX a)       = a
astAttr (NMul _ _ a) = a
astAttr (NAdd _ _ a) = a

happyError :: [Token] -> a
happyError _ = error "parse error"
}

Main.hs:

module Main where

import Lexer
import Parser

main :: IO ()
main = do
  s <- getContents
  let toks = alexScanTokens s
  print $ simple toks

1
找到一个想要分享的解决方案吗?是否有同样的疑问? - mfaerevaag
1个回答

3

我个人认为你描述的风格还不错。然而,这种方法非常手动化,我希望至少提供一种可能更容易管理的替代方案。

如果你查看alex wrappers的文档,你会注意到monad和monadstate包装器都包含位置信息。缺点是现在整个内容都被包装在一个monad中,这使得解析器稍微复杂了一些。然而,通过将其包装在monad中,解析的结果是一个Alex a,这意味着在创建ast节点时可以完全访问行和列信息。现在这只是从词法分析器中去除了一些样板代码,没有做更多的事情。

通过这样做,你也可以携带AlexState与你的token一起使用,但这可能是不必要的。

如果你需要帮助实际修复解析器以处理monad/monadstate包装器,我写了一个回答,介绍了我如何让它工作:如何在Happy中使用Alex单子词法分析器?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接