Parsing 与Alex和Happy一起管理职位信息
我正在学习使用Alex,并乐于编写一个小编译器。我希望维护AST节点的行和列信息,以便向用户提供有意义的错误消息。为了说明我打算怎么做,我写了一个小例子(见下面的代码),我想知道我处理问题的方式(将AlexPosn连接到令牌,将多态属性字段连接到AST节点,使用tkPos和astAttr)是否是一种好的方式,或者是否有更好的方法来处理位置信息 Lexer.x:Parsing 与Alex和Happy一起管理职位信息,parsing,haskell,lexical-analysis,happy,alex,Parsing,Haskell,Lexical Analysis,Happy,Alex,我正在学习使用Alex,并乐于编写一个小编译器。我希望维护AST节点的行和列信息,以便向用户提供有意义的错误消息。为了说明我打算怎么做,我写了一个小例子(见下面的代码),我想知道我处理问题的方式(将AlexPosn连接到令牌,将多态属性字段连接到AST节点,使用tkPos和astAttr)是否是一种好的方式,或者是否有更好的方法来处理位置信息 Lexer.x: { module Lexer where } %wrapper "posn" $white = [\ \t\n] tokens :
{
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
modulemain其中
进口Lexer
导入解析器
main::IO()
main=do
我个人认为你所描述的风格还可以。然而,它是非常手动的,我希望至少能提供一个更容易管理的替代方案
如果再往下看一点,您会注意到monad和monadstate包装器都包含位置信息。缺点是您现在将整个内容包装在一个monad中,这会使解析器稍微复杂化。但是,通过将其包装在monad中,解析的结果是Alex a
,这意味着您在创建ast节点时可以完全访问行和列信息。现在,这只是从lexer上移除了一些锅炉板,并没有做更多的事情
通过这样做,您还可以携带您的代币在亚历克赛州四处走动,但这可能是不必要的
如果您确实需要帮助修复解析器以处理monad/monadstate包装器,我在这里写了一篇关于如何使其工作的回复:找到了您想要共享的解决方案?完全一样