构建AST并将子代添加到树中时,两者之间有什么区别
void NonTerminal #Nonterminal: { Token t;}
{
t = <MULTIPLY> OtherNonTerminal() {jjtThis.value = t.image;} #Multiply
}
和:
void NonTerminal : { Token t;}
{
t = <MULTIPLY> OtherNonTerminal() {jjtThis.value = t.image;} #Multiply(2)
}
注意:
<MULTIPLY : "*">
有什么主要区别,并且两者都将以相同的方式工作吗?
也将为该生产规则构建树的另一种方法:
void NonTerminal() : { Token t; }
{
t = <MULTIPLY> OtherNonTerminal() { jjtThis.value = t.image; } #Mult(2)
| t = <DIVIDE> OtherNonTerminal() { jjtThis.value = t.image; } #Div(2)
| {}
}
像这样:
void NonTerminal() #Nonterminal(2) : { Token t; }
{
(t = <MULTIPLY> OtherNonTerminal() | t = <DIVIDE> OtherNonTerminal() | {}) {jjtThis.value = t.image;}
}
答案 0 :(得分:1)
这个问题的答案是肯定的。
JAVACC或JJTREE语法按照不同的步骤进行编译。
TOKEN
,SPECIAL_TOKEN
,MORE
和SKIP
部分中提供的正则表达式来构造标记。
在每次成功的词法分析之后,都会生成一个令牌。语法分析,其中这些标记将排列在名为Syntax tree的树中,该树具有提供的production rules
的终端节点和非终端节点。
语法分析收集从词法分析生成的每个令牌,然后尝试从中验证语法。
非终端节点:表示其他生产规则。
TERMINAL节点:表示令牌或数据节点。
这是区别,
按如下所示编辑评论
Multiply(2)仅表示两个子级,如果您的运算是A * B,则这是有意义的, 如果您正在执行A * B * C并使用#Multiply(2),则树将像
Multiply
/ \
Multiply C
/ \
A B
如果您执行A * B * C并使用#Multiply,则树将像
Multiply Multiply Multiply
| | |
A B C
基本上#Multiply和#Multiply(2)之间的区别是Multiply(2)将等待两个令牌生成,如果发现只有一个抛出异常,并且#Multiply会在生产规则发生时生成节点被匹配。
答案 1 :(得分:1)
在第一种情况下
void NonTerminal #Nonterminal: { Token t;}
{
t = <MULTIPLY>
OtherNonTerminal() {jjtThis.value = t.image;}
#Multiply
}
Multiply
节点将在其节点作用域内推送到堆栈上的所有节点作为子节点,但不包括在作用域末尾弹出的所有节点。在这种情况下,这意味着在解析OtherNonTerminal
期间所有节点被推送,而没有弹出。
在第二个示例中
void NonTerminal #void : { Token t;}
{
t = <MULTIPLY>
OtherNonTerminal() {jjtThis.value = t.image;}
#Multiply(2)
}
Multiply
节点将从堆栈中获得两个顶部节点作为其子节点。
所以可能有所不同。
另一个区别是第二个示例未指定与Nonterminal
关联的节点。
在第一种情况下,该树将被推送
Nonterminal
|
Multiply
|
All nodes pushed (but not popped) during the parsing of OtherNonterminal
在第二种情况下,OtherNonterminal
的解析将完成它的工作(弹出和推送节点),然后弹出两个节点,然后将这棵树推送
Multiply
| |
A child Another child
第二个问题。之间的区别
void NonTerminal() #void : { Token t; }
{
t = <MULTIPLY>
OtherNonTerminal()
{ jjtThis.value = t.image; }
#Mult(2)
|
t = <DIVIDE>
OtherNonTerminal()
{ jjtThis.value = t.image; }
#Div(2)
|
{}
}
和
void NonTerminal() #Nonterminal(2) : {
Token t; }
{
( t = <MULTIPLY> OtherNonTerminal()
| t = <DIVIDE> OtherNonTerminal()
| {}
)
{jjtThis.value = t.image;}
}
是当匹配空序列时,第一个不构建节点。
在下一个令牌不是*
或/
的情况下,请考虑第二种方法。您会得到
Nonterminal
/ \
Some node Some other node
don't want you don't want
第二个甚至超过Java编译器,实际上使我感到惊讶,因为对t
的引用是一个潜在的未初始化变量。