0

我已经处理这个问题几天了,我没有想法,希望你能帮助我:

我的令牌列表如下:

%Token
var       {TokenVariableDeclaration}
varId     {TokenVar $$} -- Strings like "x", "n" or "m"
int       {TokenInt $$}

我的语法规则如下:

VariablesList : var varId ';'                   {VariablesList [($2,ArithmeticInt 0)]}
              | var varId ',' VariablesList     {VariablesList (($2,ArithmeticInt 0):$4)}

ArithmeticExpression : int {ArithmeticInt $1}

它只是定义了一个变量列表,就像您在命令式编程语言中可能找到的任何变量一样(在这种给定的语言中,变量只能被分配整数):

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)]

当我在提示符下运行“快乐”命令时,一切都很好:

C:> happy "myParser.y"

但是当我在我的 GHCI 上加载生成的 .hs 文件时:

Prelude> :l "myParser.hs"

我收到一个广泛的错误,说 typeVariablesList无法与 type 匹配[(String,ArithmeticExpression)]。我知道,由于我进行了不同的测试,问题出在我的VariablesList语法规则的第二种模式上:

VariablesList : var varId ';'                   {VariablesList [($2,ArithmeticInt 0)]}
              | var varId ',' VariablesList     {VariablesList (($2,ArithmeticInt 0):$4)}

确切地说是($2,ArithmeticInt 0):$4部分。我对 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 [($2,ArithmeticInt 0)]} -- var n;
              | var varId ',' varId ';'               {VariablesList (($2,ArithmeticInt 0):[($4,ArithmeticInt 0)])} --var n,m;
              | var varId ',' varId ',' varId ';'     {VariablesList (($2,ArithmeticInt 0):[($4,ArithmeticInt 0),($6,ArithmeticInt 0)])} --var n,m,x;
              -- var varId ',' VariablesList          {VariablesList (($2,ArithmeticInt):$4)} Ideal solution. Recursive. Does not work.

ArithmeticExpression : int {ArithmeticInt $1}

{
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 个变量的列表。

4

1 回答 1

1

首先:当你启动happy它时,它会生成一个 Haskell 文件,但不会编译它。所以happy不检查插入的haskell代码是否有效。之后在编译文件时完成。您看到的行为是预期的。

现在的问题是您的规则是:

var varId ',' VariablesList     {VariablesList (($2,ArithmeticInt 0):$4)}

where$4指的是 aVariablesList:有类型a -> [a] -> [a]not (String, ArithmeticExpression) -> VariablesList -> VariablesList$4引用包含在VariablesList.

您需要的是一种连接VariablesLists 的方法,例如:

x <:> (VariablesList xs) = VariablesList (x:xs)

并使用规则:

var varId ',' VariablesList     {($2,ArithmeticInt 0) <:> $4}

一个建议:happy 允许您定义参数化产品。通常使用此类规则可以更好地处理列表。

例如,您可以定义一个表示带有分隔符的列表的产品:

rev_list_sep(p, sep) : p                           {[$1]}
                     | rev_list_sep(p, sep) sep p  {$3 : $1}

并将其用作:

VarDecl : var varId
VariablesList : rev_list_sep(VarDecl, ',') ';'   {VariablesList (reverse $1)}

(未经测试,只是提供一个想法)。

请注意,您可以重用这样的产生式来定义其他列表:

SomeOtherList : rev_list_sep(SomethingElse, ';')  {Whatever (reverse $1)}
于 2015-05-01T19:13:27.250 回答