2013-12-15 7 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

は、あなたが共有したいソリューションを発見されましたか?正確に同じことを思い出す – mfaerevaag

答えて

1

私は個人的にあなたが説明してきたスタイルとはかなりOKだろう。しかし、それは非常に手作業であり、少なくとも管理しやすい方法を提供することを望んでいました。

documentation for alex wrappersをもう少し見ると、モナドラッパーとモナドステートラッパーの両方に位置情報が含まれていることがわかります。欠点は、あなたが今モナドに包まれた全体を持っていることです。そしてそれは少しパーサーを複雑にします。ただし、モナドにラップすると、解析の結果はAlex aになります。これは、astノードを作成するときに行と列の情報に完全にアクセスできることを意味します。これで、ボイラープレートの一部がレクサーから削除され、はるかに機能しなくなります。

このようにすると、あなたのトークンでAlexStateを持ち歩くこともできますが、それは不要かもしれません。

あなたが実際にモナド/ monadstateラッパーを処理するためのパーサを固定するヘルプが必要な場合、私はそれがここで働いて得ることができた方法についての応答を書いた:How to use an Alex monadic lexer with Happy?

関連する問題