私はこの問題に数日間対処してきましたが、アイデアがありません。うまくいけば、私を助けてくれます:
私のトークンリストは次のとおりです。
%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"
VariablesList
type を 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 つ未満の任意のリスト。