2017-07-18 28 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

相关问题