使用Happy编写算术表达式解析器时遇token type错误求助
解决Happy算术表达式解析器的"no token type given"及相关错误
核心错误原因
- 缺少Token类型声明:Happy必须明确知晓token的类型定义,未添加声明会直接触发"no token type given"错误。
- Token定义与语法规则不匹配:语法中声明的
float { TokenNum $$ }与lexer生成的TokenFloat不一致,且Token类型同时存在TokenFloat和TokenNum,导致其中一个终结符未被使用(对应"unused terminals:1")。 - 辅助函数
isNum类型逻辑错误:isNum参数为[Token],但span需要的是Char -> Bool类型函数,用来判断字符是否属于数字/小数点,当前实现完全不符合需求。 - 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
相关产品推荐
相关产品推荐

