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

プロンプトで「happy」コマンドを実行すると、すべて問題ありません。

C:> happy "myParser.y"

しかし、結果の .hs ファイルを GHCI にロードすると、次のようになります。

Prelude> :l "myParser.hs"

VariablesListtype を typeに一致させることができないという広範なエラーが表示されます[(String,ArithmeticExpression)]。私が行ったさまざまなテストにより、問題は私のVariablesList文法規則の 2 番目のパターンにあることがわかっています。

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

特にその($2,ArithmeticInt 0):$4部分。私は Haskell の初心者で、4 番目の引数 ($4) は型VariablesListであり、型(String,ArithmeticExpression)をそれに連結 (:) できないことを理解できます。

どんな種類のヘルプやガイダンスも大歓迎です:)。

編集: 請願により、最小限の作業用 Happy ファイルを次に示します。

{  
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 ファイルが生成されますが、コンパイルはされません。したがって、挿入した haskell コードが有効かどうかはチェックhappyしません。これは、後でファイルをコンパイルするときに行われます。表示される動作は予期されたものです。

問題は、ルールが次のとおりであることです。

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

where$4は a を参照しますVariablesListが、: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 を使用すると、パラメータ化された productionsを定義できます。通常、リストはそのようなルールでより適切に処理されます。

たとえば、区切り記号付きのリストを表すプロダクションを定義できます。

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 に答える