使用Happy解析case of语句与函数应用的问题求助
Happy解析器问题解决
问题1:函数应用左结合修复
Haskell函数应用是左结合的,当前解析器将f x y解析为Application (Id "f") (Application (Id "x") (Id "y")),不符合预期的左结合结构。原因是%nonassoc application的设置导致解析器按右结合处理函数应用。
修复步骤:
- 将
%nonassoc application改为%left application,明确指定函数应用为左结合 - 保留
Exp Exp %prec application规则,Happy会自动按左结合解析,生成Application (Application (Id "f") (Id "x")) (Id "y")的正确结构
问题2:Case-of多分支解析
1. 扩展数据类型
首先需要修改Exp类型,添加分支结构:
data CaseBranch = CaseBranch Exp Exp -- 对应 pattern -> expr data Exp = Let String Exp Exp | Case String [CaseBranch] -- Case 变量 + 分支列表 | Plus Exp Exp | Minus Exp Exp | Times Exp Exp | Div Exp Exp | Equal Exp Exp | RoundBrack Exp | SquaredBrack Exp | CurlyBrack Exp | Int Int | Id String | Application Exp Exp deriving (Show)
2. 调整语法规则
在语法规则中添加分支相关定义,同时需要确保Lexer能识别->和|(需在Lexer中添加对应Token定义):
3. 更新Token定义
在%token部分添加:
'->' { TokenArrow } '|' { TokenPipe }
完整修改后代码
{ module Main where import Lexer } %name parse %tokentype {Token} %error {parseError} %token let { TokenLet } in { TokenIn } case { TokenCase } of { TokenOf } '->' { TokenArrow } '|' { TokenPipe } '+' { TokenPlus } '-' { TokenMinus } '*' { TokenTimes } '/' { TokenDiv } '=' { TokenEqual } '(' { TokenOpenRoundPar } ')' { TokenCloseRoundPar } '[' { TokenOpenSquaredPar } ']' { TokenCloseSquaredPar } '{' { TokenOpenCurlyBrace } '}' { TokenCloseCurlyBrace } int { TokenInt $$ } var { TokenId $$ } %left '+' '-' %left '*' '/' %left application -- 修改为左结合 %% Exp : let var '=' Exp in Exp { Let $2 $4 $6 } | case var of Branches { Case $2 $4 } | Exp '+' Exp { Plus $1 $3 } | Exp '-' Exp { Minus $1 $3 } | Exp '*' Exp { Times $1 $3 } | Exp '/' Exp { Div $1 $3 } | Exp '=' Exp { Equal $1 $3} | '(' Exp ')' { RoundBrack $2 } | '[' Exp ']' { SquaredBrack $2 } | '{' Exp '}' { CurlyBrack $2 } | int { Int $1 } | var { Id $1 } | Exp Exp %prec application { Application $1 $2} Branches : Branch { [$1] } | Branch '|' Branches { $1 : $3 } Branch : Exp '->' Exp { CaseBranch $1 $3 } { parseError :: [Token] -> a parseError _ = error "ParseError" data CaseBranch = CaseBranch Exp Exp data Exp = Let String Exp Exp | Case String [CaseBranch] | Plus Exp Exp | Minus Exp Exp | Times Exp Exp | Div Exp Exp | Equal Exp Exp | RoundBrack Exp | SquaredBrack Exp | CurlyBrack Exp | Int Int | Id String | Application Exp Exp deriving (Show) main = do s <- getLine print(parse (lexer s)) }
注意:需要同步更新Lexer代码,添加TokenArrow和TokenPipe的识别逻辑,确保能正确解析->和|符号。
内容的提问来源于stack exchange,提问作者Daniel Gattesco
相关产品推荐
相关产品推荐

