Alex와 Happy를 사용하여 작은 컴파일러를 작성하는 법을 배우고 있습니다. 나는 사용자에게 의미있는 오류 메시지를 제공 할 수 있도록 내 AST 노드에 대한 행 및 열 정보를 유지하려고합니다. 내가 어떻게 그 계획을 세우는지를 설명하기 위해 작은 예제 (아래 코드 참조)를 썼다. 나는 문제에 접근하는 방법을 알기를 원한다. (AlexPosn을 토큰에 붙이면 다형성 속성 필드를 AST 노드에 붙인다. , tkPos 및 astAttr 사용) 좋은 스타일 또는 위치 정보를 처리하는 더 나은 방법이 있다면.Alex와 Happy로 위치 정보 관리하기
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
가 공유 할 해결책을 찾았 당신이 모나드/monadstate 래퍼를 처리하는 파서를 고정 실제로 도움이 필요한 경우
, 나는 여기가 작업을 얻을 내가 관리하는 방법에 대한 응답을 썼다? 정확히 똑같은 것에 대해 궁금해하기 – mfaerevaag