2013-12-15 4 views
20

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 
+1

가 공유 할 해결책을 찾았 당신이 모나드/monadstate 래퍼를 처리하는 파서를 고정 실제로 도움이 필요한 경우

, 나는 여기가 작업을 얻을 내가 관리하는 방법에 대한 응답을 썼다? 정확히 똑같은 것에 대해 궁금해하기 – mfaerevaag

답변

1

나는 개인적으로 당신이 설명한 스타일 꽤 괜찮을 것 . 그러나 이것은 매우 수동적이며 적어도 관리하기 쉬운 대안을 제공하기를 희망했습니다.

documentation for alex wrappers을 약간 더 살펴보면 모나드 및 모나드테 포장이 둘 다 위치 정보를 포함하고 있음을 알 수 있습니다. 단점은 모나드에 싸인 전체 내용을 가지고 파서를 약간 복잡하게 만드는 것입니다. 그러나 모나드로 감싸는 것으로 구문 분석의 결과는 Alex a입니다. 이는 ast 노드를 만들 때 줄 정보와 열 정보에 대한 전체 액세스 권한이 있음을 의미합니다. 이제 이것은 렉서 (lexer)에서 보일러 플레이트의 일부를 제거하고 훨씬 더 많은 일을하지 않습니다.

이렇게하면 AlexState를 토큰과 함께 가지고 다닐 수도 있지만 불필요 할 수 있습니다. How to use an Alex monadic lexer with Happy?