如何为下面的语法创建一个递归下降LL(1)解析器(我使用C++
):
S -> SS
S -> (S)
S -> epsilon
我尝试使用递归函数,但我认为这是完全错误的。我知道规则需要按顺序实现,但是如何在不进行无限循环的情况下获得第一条规则来检查第一条规则的其他实例?在我的代码中,我只检查后续规则。
我的代码:
bool rule1(tokenizer * tp){ // S -> SS
return rule2(tp) && rule2(tp);
}
bool rule2(tokenizer * tp){ // S -> (S)
bool returnVal = false;
if(tp-> lookahead. front( ). type == tkn_LPAR){
tokenizer tmpTknzr = &tp;
tp-> lookahead. pop_front( );
if(tp-> lookahead. front( ). type == tkn_RPAR){ // S -> epsilon
tp-> lookahead. pop_front( );
returnVal = true;
} else {
if(evalS(tp) && tp-> lookahead. front( ). type == tkn_RPAR){
tp-> lookahead. pop_front( );
returnVal = true;
}
}
}
return returnVal;
}
bool evalS(tokenizer * tp){ // evaluate S
return rule1(tp) || rule2(tp);
}
答案 0 :(得分:2)
问题是你的语法不是LL(1) - 事实上它是模棱两可的,这使得解析更加困难。尝试将LL(1)语法用于括号,例如
S -> (S)S
S -> ε
答案 1 :(得分:1)
LL(1)中的1表示您必须能够通过向前看不超过1个令牌来选择要扩展的当前规则。
使用您编写的语法,在查看第一个令牌时无法确定要扩展的规则。如果它是'('
,那么您就不知道它是第2条规则还是第1规则,其中第一个S扩展为epsilon。这就是为什么你会陷入无限递归的原因。
诀窍是将您的语法转换为一种形式,其中可应用于非终端X的每个规则都以不同的终端开头。克里斯多德的答案显示了一种方法来为你的语法做到这一点。