如何改写Java类型文法消除左递归,适配解析器组合子解析数组类型?
消除Java类型文法的左递归以支持数组类型解析
要解决数组类型带来的左递归问题,核心思路是将数组后缀从类型的递归定义中剥离,作为基础类型的可选重复后缀,从而彻底消除左递归。以下是改写后的文法规则:
javatype := base_type, array_suffix* base_type := identifier, subtypes subtypes := ('<', javatype, (',', javatype)*, '>') | ε // ε表示空 array_suffix := "[]"
文法改写说明
- 拆分递归结构:把原有的
javatype拆分为base_type和array_suffix两部分。base_type负责解析基础类型(包括泛型类型,如Tuple<Integer, List<Integer>>),array_suffix负责解析后续的数组标记[]。 - 消除左递归:新的
javatype规则先解析无左递归的base_type,再重复解析array_suffix——这是右递归/迭代式结构,完全兼容递归下降式的解析器组合子。 - 支持所有数组场景:无论是
int[]、List<Integer>[]还是int[][],都能被正确解析:int[]→base_type为int,后跟1个array_suffixint[][]→base_type为int,后跟2个array_suffixList<Integer>[]→base_type为List<Integer>,后跟1个array_suffix
Haskell解析器组合子实现示例
假设你使用自定义解析器组合子或Parsec,以下是对应的数据类型和解析器实现:
定义类型表示
调整Type结构,增加arrayDepth字段记录数组层数(替代嵌套的递归类型,更简洁):
data Type = Type { typeName :: String , subTypes :: [Type] , arrayDepth :: Int -- 0表示非数组,n表示n维数组 } deriving (Show, Eq)
实现解析器
-- 解析简化版Java标识符 identifier :: Parser String identifier = do first <- letter <|> char '_' rest <- many (alphaNum <|> char '_') return (first : rest) -- 解析基础类型(含泛型) baseType :: Parser Type baseType = do name <- identifier subTypes <- option [] parseSubtypes return $ Type name subTypes 0 where parseSubtypes = do char '<' types <- sepBy javatype (char ',') -- 递归解析泛型参数 char '>' return types -- 解析单个数组后缀 arraySuffix :: Parser Int arraySuffix = string "[]" >> return 1 -- 最终的Java类型解析器 javatype :: Parser Type javatype = do base <- baseType depths <- many arraySuffix let totalDepth = sum depths return base { arrayDepth = totalDepth }
解析逻辑验证
- 解析
int[]:baseType得到Type "int" [] 0,many arraySuffix得到[1],最终返回Type "int" [] 1。 - 解析
List<Integer>[]:baseType解析List后,通过parseSubtypes递归解析Integer,得到Type "List" [Type "Integer" [] 0] 0,再加上1层数组后缀,最终返回Type "List" [Type "Integer" [] 0] 1。 - 解析
int[][]:baseType得到Type "int" [] 0,many arraySuffix得到[1,1],最终返回Type "int" [] 2。
这种方案既消除了左递归,又完整支持Java的基础类型、泛型类型和任意维度的数组类型,完全适配解析器组合子的递归下降解析模式。
内容的提问来源于stack exchange,提问作者Lemma
相关产品推荐
相关产品推荐

