如何将函数作为参数传递给生成的快乐解析器?
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是一种功能性语言,我有强烈的怀疑,我错过了一些微不足道的东西,但我没有看到它...... 任何人都可以请提供一个函数传递给开心生成的解析器的例子吗? 在此先感谢!
皮埃尔
happy
可以让你在单子工作。它可以消耗lexer
功能与接下来的两个签名之一:
[Token] -> a
Monad m => (Token -> m a) -> m a
第一个选项是上下文和第二个是环境感知。如果你需要额外的参数传递给lexer
功能,你可以做两件事情之一:
-
部分适用
lexer
您在.y
文件中像这样的功能:%lexer { lexer fixedFunction }
和你
lexer
功能将具有类型T -> [Token] -> a
,其中T
是fixedFunction
的类型。 在某些情况下传递函数,如
Reader
monad。我使用State
monad来跟踪令牌位置。你可以在这里看到我的例子:my monad和my lexer。
使用任何解决方案,您可以添加额外的参数和一些额外的上下文到您的lexer
。
本示例基于标准快乐示例( 请参阅,例如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"))))
这部分回答了自己的问题:我想传递给函数周围使用属性和没有明确地在这个例子中...
好吧,现在我明白你的问题了。是的,对于'快乐'需要'显示'实例的AST。你可以为所有类型的函数添加虚假的'Show'实例,并对它感到满意。但是,使用_parser combinators_而不是_parser generators_可能会更简单。 – Shersh
在你的单子解析器你不使用属性就文法我可以看到。你知道在Happy中是否可以混合使用monadic解析器和属性语法? –
@DamianNadales好像有可能。只有条件规则中的一些语法差异:https://www.haskell.org/happy/doc/html/sec-AtrributeGrammarsInHappy.html我无法想象为什么它不应该可能混合monadic分析器和属性。 – Shersh
我问过,因为使用monadic解析器需要一个特殊的语法'{%...}',我不知道这是否可以完成。 –