数据类型与 Haskell 解析器生成器不匹配 - 快乐
Data type mismatch with Haskell parser generator - Happy
我已经处理这个问题几天了,我没有想法,希望你能帮助我:
我的令牌列表如下:
%Token
var {TokenVariableDeclaration}
varId {TokenVar $$} -- Strings like "x", "n" or "m"
int {TokenInt $$}
我的语法规则如下:
VariablesList : var varId ';' {VariablesList [(,ArithmeticInt 0)]}
| var varId ',' VariablesList {VariablesList ((,ArithmeticInt 0):)}
ArithmeticExpression : int {ArithmeticInt }
它只是定义了一个变量列表,就像您在命令式编程语言中可能找到的任何变量一样(在这种给定的语言中,变量只能分配整数):
var n,m,x;
我的词法分析器(文件的 Haskell 部分)具有以下数据类型:
data VariablesList = VariablesList [(String,ArithmeticExpression)] deriving (Show, Eq)
data ArithExpression = ArithInt Int deriving (Show, Eq)
这样,在解析之后,我可以获得所有声明的变量列表,并使用数据 "ArithmeticInt 0":
VariablesList [("n",ArithmeticInt 0),("m",ArithmeticInt 0),("x",ArithmeticInt 0)]
当我在提示符下 运行 'happy' 命令时,一切正常:
C:> happy "myParser.y"
但是当我在我的 GHCI 上加载生成的 .hs 文件时:
Prelude> :l "myParser.hs"
我收到一个广泛的错误,指出类型 VariablesList
无法与类型 [(String,ArithmeticExpression)]
匹配。我知道,由于我进行了不同的测试,问题出在我的 VariablesList
语法规则的第二个模式上:
VariablesList : var varId ';' {VariablesList [(,ArithmeticInt 0)]}
| var varId ',' VariablesList {VariablesList ((,ArithmeticInt 0):)}
特别是 (,ArithmeticInt 0):
部分。我对 Haskell 很陌生,我能理解的是第四个参数 ($4) 是 VariablesList
类型,(String,ArithmeticExpression)
类型不能连接 (:) 到它。
非常欢迎任何形式的帮助或指导:)。
编辑:请愿,这是一个最小的工作快乐文件:
{
module HappyLambdaSyntax4 where
import Data.Char
import System.IO
}
%name parse VariablesList
%tokentype {Token}
%error {parseError}
%token
var {TokenVariableDeclaration}
varId {TokenVar $$} -- Strings like "x", "n" or "m"
int {TokenInt $$}
';' {TokenPuntoYComa}
',' {TokenComa}
%%
VariablesList : var varId ';' {VariablesList [(,ArithmeticInt 0)]} -- var n;
| var varId ',' varId ';' {VariablesList ((,ArithmeticInt 0):[(,ArithmeticInt 0)])} --var n,m;
| var varId ',' varId ',' varId ';' {VariablesList ((,ArithmeticInt 0):[(,ArithmeticInt 0),(,ArithmeticInt 0)])} --var n,m,x;
-- var varId ',' VariablesList {VariablesList ((,ArithmeticInt):)} Ideal solution. Recursive. Does not work.
ArithmeticExpression : int {ArithmeticInt }
{
parseError :: [Token] -> a
parseError _ = error ("Parse error.")
data ArithmeticExpression = ArithmeticInt Int deriving (Show, Eq)
data VariablesList = VariablesList [(String,ArithmeticExpression)] deriving (Show, Eq)
data Token = TokenVariableDeclaration
| TokenVar String
| TokenInt Int
| TokenPuntoYComa
| TokenComa
deriving (Show, Eq)
lexer :: String -> [Token]
lexer [] = []
lexer (c:cs)
| isSpace c = lexer cs
| isDigit c = lexNum (c:cs)
| isAlpha c = lexVar (c:cs)
| c == ';' = TokenPuntoYComa : (lexer cs)
| c == ',' = TokenComa : (lexer cs)
| otherwise = error ("Lexer error.")
lexNum cs = TokenInt (read num) : lexer rest
where (num,rest) = span isDigit cs
lexVar cs =
case span isAlpha cs of
("var",rest) -> TokenVariableDeclaration : lexer rest
(var,rest) -> TokenVar var : lexer rest
}
运行 与:
>happy "file.y"
然后,在 GHCI 中,加载:
Prelude> :l file.hs
最后,测试一下:
Prelude> parse (lexer "var n,m,x;")
或少于 3 个变量的任何列表。
首先:当您启动 happy
时,它会生成一个 Haskell 文件,但不会编译它。所以 happy
而不是 检查您插入的 haskell 代码是否有效。这是在您编译文件后完成的。
您看到的行为是预期的。
现在的问题是你的规则是:
var varId ',' VariablesList {VariablesList ((,ArithmeticInt 0):)}
其中 </code> 指的是 <code>VariablesList
但 :
的类型是 a -> [a] -> [a]
而不是 (String, ArithmeticExpression) -> VariablesList -> VariablesList
。
</code> <em> 而不是 </em> 引用包含在 <code>VariablesList
.
中的列表
您需要的是一种连接 VariablesList
的方法,例如:
x <:> (VariablesList xs) = VariablesList (x:xs)
并使用规则:
var varId ',' VariablesList {(,ArithmeticInt 0) <:> }
一个建议:happy可以让你自己定义parametrized productions。通常使用此类规则可以更好地处理列表。
例如,您可以定义一个表示带有分隔符的列表的产生式:
rev_list_sep(p, sep) : p {[]}
| rev_list_sep(p, sep) sep p { : }
并将其用作:
VarDecl : var varId
VariablesList : rev_list_sep(VarDecl, ',') ';' {VariablesList (reverse )}
(未测试,仅供参考)
请注意,您可以重复使用这样的产生式来定义其他列表:
SomeOtherList : rev_list_sep(SomethingElse, ';') {Whatever (reverse )}
我已经处理这个问题几天了,我没有想法,希望你能帮助我:
我的令牌列表如下:
%Token
var {TokenVariableDeclaration}
varId {TokenVar $$} -- Strings like "x", "n" or "m"
int {TokenInt $$}
我的语法规则如下:
VariablesList : var varId ';' {VariablesList [(,ArithmeticInt 0)]}
| var varId ',' VariablesList {VariablesList ((,ArithmeticInt 0):)}
ArithmeticExpression : int {ArithmeticInt }
它只是定义了一个变量列表,就像您在命令式编程语言中可能找到的任何变量一样(在这种给定的语言中,变量只能分配整数):
var n,m,x;
我的词法分析器(文件的 Haskell 部分)具有以下数据类型:
data VariablesList = VariablesList [(String,ArithmeticExpression)] deriving (Show, Eq)
data ArithExpression = ArithInt Int deriving (Show, Eq)
这样,在解析之后,我可以获得所有声明的变量列表,并使用数据 "ArithmeticInt 0":
VariablesList [("n",ArithmeticInt 0),("m",ArithmeticInt 0),("x",ArithmeticInt 0)]
当我在提示符下 运行 'happy' 命令时,一切正常:
C:> happy "myParser.y"
但是当我在我的 GHCI 上加载生成的 .hs 文件时:
Prelude> :l "myParser.hs"
我收到一个广泛的错误,指出类型 VariablesList
无法与类型 [(String,ArithmeticExpression)]
匹配。我知道,由于我进行了不同的测试,问题出在我的 VariablesList
语法规则的第二个模式上:
VariablesList : var varId ';' {VariablesList [(,ArithmeticInt 0)]}
| var varId ',' VariablesList {VariablesList ((,ArithmeticInt 0):)}
特别是 (,ArithmeticInt 0):
部分。我对 Haskell 很陌生,我能理解的是第四个参数 ($4) 是 VariablesList
类型,(String,ArithmeticExpression)
类型不能连接 (:) 到它。
非常欢迎任何形式的帮助或指导:)。
编辑:请愿,这是一个最小的工作快乐文件:
{
module HappyLambdaSyntax4 where
import Data.Char
import System.IO
}
%name parse VariablesList
%tokentype {Token}
%error {parseError}
%token
var {TokenVariableDeclaration}
varId {TokenVar $$} -- Strings like "x", "n" or "m"
int {TokenInt $$}
';' {TokenPuntoYComa}
',' {TokenComa}
%%
VariablesList : var varId ';' {VariablesList [(,ArithmeticInt 0)]} -- var n;
| var varId ',' varId ';' {VariablesList ((,ArithmeticInt 0):[(,ArithmeticInt 0)])} --var n,m;
| var varId ',' varId ',' varId ';' {VariablesList ((,ArithmeticInt 0):[(,ArithmeticInt 0),(,ArithmeticInt 0)])} --var n,m,x;
-- var varId ',' VariablesList {VariablesList ((,ArithmeticInt):)} Ideal solution. Recursive. Does not work.
ArithmeticExpression : int {ArithmeticInt }
{
parseError :: [Token] -> a
parseError _ = error ("Parse error.")
data ArithmeticExpression = ArithmeticInt Int deriving (Show, Eq)
data VariablesList = VariablesList [(String,ArithmeticExpression)] deriving (Show, Eq)
data Token = TokenVariableDeclaration
| TokenVar String
| TokenInt Int
| TokenPuntoYComa
| TokenComa
deriving (Show, Eq)
lexer :: String -> [Token]
lexer [] = []
lexer (c:cs)
| isSpace c = lexer cs
| isDigit c = lexNum (c:cs)
| isAlpha c = lexVar (c:cs)
| c == ';' = TokenPuntoYComa : (lexer cs)
| c == ',' = TokenComa : (lexer cs)
| otherwise = error ("Lexer error.")
lexNum cs = TokenInt (read num) : lexer rest
where (num,rest) = span isDigit cs
lexVar cs =
case span isAlpha cs of
("var",rest) -> TokenVariableDeclaration : lexer rest
(var,rest) -> TokenVar var : lexer rest
}
运行 与:
>happy "file.y"
然后,在 GHCI 中,加载:
Prelude> :l file.hs
最后,测试一下:
Prelude> parse (lexer "var n,m,x;")
或少于 3 个变量的任何列表。
首先:当您启动 happy
时,它会生成一个 Haskell 文件,但不会编译它。所以 happy
而不是 检查您插入的 haskell 代码是否有效。这是在您编译文件后完成的。
您看到的行为是预期的。
现在的问题是你的规则是:
var varId ',' VariablesList {VariablesList ((,ArithmeticInt 0):)}
其中 </code> 指的是 <code>VariablesList
但 :
的类型是 a -> [a] -> [a]
而不是 (String, ArithmeticExpression) -> VariablesList -> VariablesList
。
</code> <em> 而不是 </em> 引用包含在 <code>VariablesList
.
您需要的是一种连接 VariablesList
的方法,例如:
x <:> (VariablesList xs) = VariablesList (x:xs)
并使用规则:
var varId ',' VariablesList {(,ArithmeticInt 0) <:> }
一个建议:happy可以让你自己定义parametrized productions。通常使用此类规则可以更好地处理列表。
例如,您可以定义一个表示带有分隔符的列表的产生式:
rev_list_sep(p, sep) : p {[]}
| rev_list_sep(p, sep) sep p { : }
并将其用作:
VarDecl : var varId
VariablesList : rev_list_sep(VarDecl, ',') ';' {VariablesList (reverse )}
(未测试,仅供参考)
请注意,您可以重复使用这样的产生式来定义其他列表:
SomeOtherList : rev_list_sep(SomethingElse, ';') {Whatever (reverse )}