You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 13:55:28