2017-07-18 44 views
1

Happy生成帶簽名的解析器:: [Token] -> a如何將函數作爲參數傳遞給生成的快樂解析器?

我想生成一個參數化的解析器,即需要函數作爲參數來傳遞解析器的函數。 所以我想簽名:(x->y) -> [Token] -> a。 但是,我也可以使用簽名:: [Token] -> (x->y) -> a

當功能固定後,我可以通過導入和分配函數來解決它 。

import Functions (fixedFunction) 

Root : Production Rule 
     { $$.argument = fixedFunction 
     } 

當參數爲顯示的一個實例,我可以如下解決它

Alex: 
    data Token = ... 
       | Carg   ArgType 
Happy: 
    %token 
     ... 
     Argument { Carg $$ } 

    Root : Argument Production Rule 
      { $$.argument = $1 
      } 

參見例如我的項目TorXakis的更多細節,特別是文件夾https://github.com/TorXakis/TorXakis/tree/develop/sys/front/src

但是,我無法傳遞一個函數的變量參數,因爲函數不是從Show!派生的! 由於Haskell是一種功能性語言,我有強烈的懷疑,我錯過了一些微不足道的東西,但我沒有看到它...... 任何人都可以請提供一個函數傳遞給開心生成的解析器的例子嗎? 在此先感謝!

皮埃爾

回答

2

happy可以讓你在單子工作。它可以消耗lexer功能與接下來的兩個簽名之一:

  1. [Token] -> a
  2. Monad m => (Token -> m a) -> m a

第一個選項是上下文和第二個是環境感知。如果你需要額外的參數傳遞給lexer功能,你可以做兩件事情之一:

  1. 部分適用lexer您在.y文件中像這樣的功能:

    %lexer { lexer fixedFunction }

    和你lexer功能將具有類型T -> [Token] -> a,其中TfixedFunction的類型。

  2. 在某些情況下傳遞函數,如Reader monad。我使用State monad來跟蹤令牌位置。你可以在這裏看到我的例子:my monadmy lexer

使用任何解決方案,您可以添加額外的參數和一些額外的上下文到您的lexer

+0

在你的單子解析器你不使用屬性就文法我可以看到。你知道在Happy中是否可以混合使用monadic解析器和屬性語法? –

+1

@DamianNadales好像有可能。只有條件規則中的一些語法差異:https://www.haskell.org/happy/doc/html/sec-AtrributeGrammarsInHappy.html我無法想象爲什麼它不應該可能混合monadic分析器和屬性。 – Shersh

+0

我問過,因爲使用monadic解析器需要一個特殊的語法'{%...}',我不知道這是否可以完成。 –

0

本示例基於標準快樂示例( 請參閱,例如https://www.haskell.org/happy/doc/html/sec-using.html) 本示例不使用monads,也不使用任何屬性。

表達式解析器需要一個函數來「標準化」變量名稱。例如,使它們不區分大小寫,或者像舊編程語言一樣,只考慮前8個字符。

解析器是:

{ 
module Calc 
(calc 
, lexer 
) 
where 
import Data.Char 
} 
%name calc 
%tokentype { Token } 
%error { parseError } 

%token 
     let    { TokenLet } 
     in    { TokenIn } 
     int    { TokenInt $$ } 
     var    { TokenVar $$ } 
     '='    { TokenEq } 
     '+'    { TokenPlus } 
     '-'    { TokenMinus } 
     '*'    { TokenTimes } 
     '/'    { TokenDiv } 
     '('    { TokenOB } 
     ')'    { TokenCB } 

%% 

Exp :: { (String -> String) -> Exp } 
     : let var '=' Exp in Exp { \p -> Let (p $2) ($4 p) ($6 p) } 
     | Exp1     { \p -> Exp1 ($1 p) } 

Exp1 :: { (String -> String) -> Exp1 } 
     : Exp1 '+' Term   { \p -> Plus ($1 p) ($3 p) } 
     | Exp1 '-' Term   { \p -> Minus ($1 p) ($3 p) } 
     | Term     { \p -> Term ($1 p) } 

Term :: { (String -> String) -> Term } 
     : Term '*' Factor   { \p -> Times ($1 p) ($3 p) } 
     | Term '/' Factor   { \p -> Div ($1 p) ($3 p) } 
     | Factor     { \p -> Factor ($1 p) } 

Factor:: { (String -> String) -> Factor } 
     : int      { \p -> Int $1 } 
     | var      { \p -> Var (p $1) } 
     | '(' Exp ')'    { \p -> Brack ($2 p) } 

{ 
parseError :: [Token] -> a 
parseError _ = error "Parse error" 

data Exp 
     = Let String Exp Exp 
     | Exp1 Exp1 
     deriving Show 

data Exp1 
     = Plus Exp1 Term 
     | Minus Exp1 Term 
     | Term Term 
     deriving Show 

data Term 
     = Times Term Factor 
     | Div Term Factor 
     | Factor Factor 
     deriving Show 

data Factor 
     = Int Int 
     | Var String 
     | Brack Exp 
     deriving Show 

data Token 
     = TokenLet 
     | TokenIn 
     | TokenInt Int 
     | TokenVar String 
     | TokenEq 
     | TokenPlus 
     | TokenMinus 
     | TokenTimes 
     | TokenDiv 
     | TokenOB 
     | TokenCB 
deriving Show 


lexer :: String -> [Token] 
lexer [] = [] 
lexer (c:cs) 
     | isSpace c = lexer cs 
     | isAlpha c = lexVar (c:cs) 
     | isDigit c = lexNum (c:cs) 
lexer ('=':cs) = TokenEq : lexer cs 
lexer ('+':cs) = TokenPlus : lexer cs 
lexer ('-':cs) = TokenMinus : lexer cs 
lexer ('*':cs) = TokenTimes : lexer cs 
lexer ('/':cs) = TokenDiv : lexer cs 
lexer ('(':cs) = TokenOB : lexer cs 
lexer (')':cs) = TokenCB : lexer cs 

lexNum cs = TokenInt (read num) : lexer rest 
     where (num,rest) = span isDigit cs 

lexVar cs = 
    case span isAlpha cs of 
     ("let",rest) -> TokenLet : lexer rest 
     ("in",rest) -> TokenIn : lexer rest 
     (var,rest) -> TokenVar var : lexer rest 

} 

和使用該分析器的主要是

module Main 

where 
import Data.Char 
import Calc 

caseSensitive :: String -> String 
caseSensitive = id 

caseInsensitive :: String -> String 
caseInsensitive = map toUpper 

firstEight :: String -> String 
firstEight = take 8 

main :: IO() 
main = getContents >>= (\a -> print (calc (lexer a) caseInsensitive)) 

使用將CASEINSENSITIVE函數的表達式分析器和輸入

let aap = 7 in Aap + AAP 

結果在輸出

Let "AAP" (Exp1 (Term (Factor (Int 7)))) (Exp1 (Plus (Term (Factor (Var "AAP"))) (Factor (Var "AAP")))) 

這部分回答了自己的問題:我想傳遞給函數週圍使用屬性和沒有明確地在這個例子中...

+0

好吧,現在我明白你的問題了。是的,對於'快樂'需要'顯示'實例的AST。你可以爲所有類型的函數添加虛假的'Show'實例,並對它感到滿意。但是,使用_parser combinators_而不是_parser generators_可能會更簡單。 – Shersh

相關問題