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

使用Happy编写算术表达式解析器时遇token type错误求助

解决Happy算术表达式解析器的"no token type given"及相关错误

核心错误原因

  1. 缺少Token类型声明:Happy必须明确知晓token的类型定义,未添加声明会直接触发"no token type given"错误。
  2. Token定义与语法规则不匹配:语法中声明的float { TokenNum $$ }与lexer生成的TokenFloat不一致,且Token类型同时存在TokenFloat和TokenNum,导致其中一个终结符未被使用(对应"unused terminals:1")。
  3. 辅助函数isNum类型逻辑错误:isNum参数为[Token],但span需要的是Char -> Bool类型函数,用来判断字符是否属于数字/小数点,当前实现完全不符合需求。
  4. AST结构冗余:已移除变量相关规则,但AST中仍保留Let构造器,属于无用代码。

分步修正方案

1. 添加Token类型声明

在语法文件的%token块前添加:

%tokentype { Token }

此声明告知Happy所有token的类型为你定义的Token数据类型。

2. 统一Token定义与语法规则

删除Token类型中的TokenNum,并修改%token块:

%token
    int    { TokenInt $$ }
    float  { TokenFloat $$ }
    '+'    { TokenPlus }
    '-'    { TokenMinus }
    -- 按需补充其他运算符,如*、/等

3. 修复isNum与lexer逻辑

重新定义isNum为字符判断函数:

isNum :: Char -> Bool
isNum c = isDigit c || c == '.'

修改lexer的数字处理逻辑,自动区分整数与浮点数:

lexer (c:cs)
    | isSpace c = lexer cs
    | isNum c = lexNumOrFloat (c:cs)
    | c == '+' = TokenPlus : lexer cs
    | c == '-' = TokenMinus : lexer cs
    -- 补充其他运算符的处理逻辑
    | otherwise = error $ "Unexpected character: " ++ [c]

lexNumOrFloat cs =
    let (numStr, rest) = span isNum cs
    in case reads numStr of
        [(n, "")] | '.' `notElem` numStr -> TokenInt n : lexer rest
        [(n, "")] -> TokenFloat n : lexer rest
        _ -> error $ "Invalid number: " ++ numStr

4. 清理冗余AST代码

删除Exp中的Let构造器,简化结构:

data Exp
    = Expl Expl
    deriving Show

若需求允许,还可进一步合并Exp与Expl结构,减少冗余。

5. 校验语法与lexer的一致性

确保语法中所有终结符(如'+')都在lexer中有对应的生成逻辑,避免出现未识别的token。

编译验证

完成上述修改后,重新用Happy编译语法文件,即可解决"no token type given"和"unused terminals"错误。

内容的提问来源于stack exchange,提问作者nau5ea

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 00:25:30