递归地使用 Antlr4 解析器和监听器
Recursively working with Antlr4 parsers and listeners
我正在从事一个项目来解析类似布尔的 DSL 并将其转换为特定的 JSON 格式。我构建了一个 classes 的一般层次结构来完成此任务,但我不确定从哪里开始将解析树转换为我想要的数据结构。
这是我的语法:
grammar filter;
filter: category EOF;
category
: LPAREN category RPAREN # ParenCat
| category AND category # CatAndBlock
| label COLON expression # CategoryBlock
;
expression
: LPAREN expression RPAREN # ParenExp
| NOT expression # NotBlock
| expression AND expression # AndBlock
| expression OR expression # OrBlock
| atom # AtomExp
;
label
: ALPHANUM
;
atom
: ALPHANUM
;
这里是一个输入字符串的例子:
( cat1:( ( (1 OR 2 ) AND ( 3 ) ) ) ) AND cat2:( 4 )
使用以下解析树:
这是我希望实现的 class 层次结构的粗略草图(每个 class 都有自己的 'write' 方法):
CategoryContainer: LinkedList<Category>
Category: LinkedList<ItemBlock> list, String categoryName #CategoryBlock
ItemBlock: LinkedList<ItemBlock> list, String type
AndBlock extends ItemBlock
OrBlock extends ItemBlock
NotBlock extends ItemBlock
AtomBlock extends ItemBlock: list = null, String value = "atomValue"
我一直在为听众浏览一些教程,并且对正在发生的事情有一个非常扎实的了解。但是,我似乎找不到太多关于递归问题的信息,就像我正在处理的问题一样。您对我如何开始有任何建议吗?
编辑:澄清我希望实现的目标,
例如输入字符串:
cat1:(4 AND 5) AND cat2:( 4 )
我想递归生成以下 classes(括号列表符号代表各自的链表):
CategoryContainer:
[
Category: categoryName="cat1", # CategoryBlock Listener
[
AndBlock: [ AtomBlock: value="4", AtomBlock: value="5" ] # AndBlock Listener
],
Category: categoryName="cat2", # CategoryBlock Listener
[
AtomBlock: value="4" # AtomBlock Listener
]
]
既然您提到您已经回顾了监听器模式,那么我的建议如下:
- 创建监听器并将其连接到 TreeWalker
- Listener 支持覆盖 "Enter"(沿着树向下)和 "Exit"(回到树上)事件。为每个“可用的退出事件”创建一个简单的硬编码覆盖。
- 运行 应用程序。您将看到深度优先遍历和递归在起作用。
- 从那里,更新您的 "Exit" 事件覆盖以添加到您的链表结构,或者基于堆栈的结构也适用于展开递归。
- 无论哪种情况,完成后,您都会得到与您提议的结构非常相似的东西。
使用 Listener 和 Exit 事件,为您处理递归和遍历。你会发现它非常有用。
我正在从事一个项目来解析类似布尔的 DSL 并将其转换为特定的 JSON 格式。我构建了一个 classes 的一般层次结构来完成此任务,但我不确定从哪里开始将解析树转换为我想要的数据结构。
这是我的语法:
grammar filter;
filter: category EOF;
category
: LPAREN category RPAREN # ParenCat
| category AND category # CatAndBlock
| label COLON expression # CategoryBlock
;
expression
: LPAREN expression RPAREN # ParenExp
| NOT expression # NotBlock
| expression AND expression # AndBlock
| expression OR expression # OrBlock
| atom # AtomExp
;
label
: ALPHANUM
;
atom
: ALPHANUM
;
这里是一个输入字符串的例子:
( cat1:( ( (1 OR 2 ) AND ( 3 ) ) ) ) AND cat2:( 4 )
使用以下解析树:
这是我希望实现的 class 层次结构的粗略草图(每个 class 都有自己的 'write' 方法):
CategoryContainer: LinkedList<Category>
Category: LinkedList<ItemBlock> list, String categoryName #CategoryBlock
ItemBlock: LinkedList<ItemBlock> list, String type
AndBlock extends ItemBlock
OrBlock extends ItemBlock
NotBlock extends ItemBlock
AtomBlock extends ItemBlock: list = null, String value = "atomValue"
我一直在为听众浏览一些教程,并且对正在发生的事情有一个非常扎实的了解。但是,我似乎找不到太多关于递归问题的信息,就像我正在处理的问题一样。您对我如何开始有任何建议吗?
编辑:澄清我希望实现的目标,
例如输入字符串:
cat1:(4 AND 5) AND cat2:( 4 )
我想递归生成以下 classes(括号列表符号代表各自的链表):
CategoryContainer:
[
Category: categoryName="cat1", # CategoryBlock Listener
[
AndBlock: [ AtomBlock: value="4", AtomBlock: value="5" ] # AndBlock Listener
],
Category: categoryName="cat2", # CategoryBlock Listener
[
AtomBlock: value="4" # AtomBlock Listener
]
]
既然您提到您已经回顾了监听器模式,那么我的建议如下:
- 创建监听器并将其连接到 TreeWalker
- Listener 支持覆盖 "Enter"(沿着树向下)和 "Exit"(回到树上)事件。为每个“可用的退出事件”创建一个简单的硬编码覆盖。
- 运行 应用程序。您将看到深度优先遍历和递归在起作用。
- 从那里,更新您的 "Exit" 事件覆盖以添加到您的链表结构,或者基于堆栈的结构也适用于展开递归。
- 无论哪种情况,完成后,您都会得到与您提议的结构非常相似的东西。
使用 Listener 和 Exit 事件,为您处理递归和遍历。你会发现它非常有用。