我试图创建一个递归下降解析器。到目前为止,我已经完成了所有基础设置,我只需要正确实现一些函数来强制执行语法。我认为一切都是正确的,它看起来如此,但我想我的Aop
,Expr
或Term
函数做错了。有时输入流会被切断,事情也无法识别。我不知道怎么回事。
是否有任何网站或来源可以更深入地解释这一点,并提供代码示例?我所看到的一切都非常通用,这很好,但我仍然坚持实施。
注意:编辑2016年4月17日:我的功能非常好,结构合理,适用于我的程序。我遇到的问题并没有意识到,在某些情况下,当我打电话给getToken时,我会吃掉"吃掉"输入流中的字符。有时这很好,有时候它不是,输入流需要重置。所以我只需添加一个小循环,我需要将字符串char放回char。 E.G:
if(t.getType() !=Token::EQOP)
{
//cout<<"You know it" << endl;
int size = t.getLexeme().size();
while(size>0)
{
br->putback(t.getLexeme().at(size-1));
size--;
}
return ex;
}
所以说到这一点,我几乎能够相应地编辑我的程序,一旦我看到吃掉角色的东西,一切都很顺利。
这是语法:
Program::= StmtList
StmtList::= Stmt | StmtList
Stmt::= PRINTKW Aop SC | INTKW VAR SC | STRKW VAR SC | Aop SC
Expr::= Expr PLUSOP Term | Expr MINUSOP Term | Term
Term::= Term STAROP Primary | Primary
Primary::= SCONST | ICONST | VAR | LPAREN Aop RPAREN
这是包含所有功能的主程序:http://pastebin.com/qMB8h8vE
我似乎最麻烦的功能是AssignmentOperator(Aop)
,Expression(Expr)
和Term
。我会在这里列出它们。
ParseTree* Aop(istream *br)
{
ParseTree * element = Expr(br);
if(element!=0)
{
if(element->isVariable())
{
Token t= getToken(br);
if(t==Token::EQOP)
{
cout<<"No" << endl;
ParseTree * rhs = Aop(br);
if(rhs==0)
return 0;
else
{
return new AssignOp(element, rhs);
}
}
else
{
return element;
}
}
}
return 0;
}
ParseTree* Expr(istream *br)
{
ParseTree * element = Term(br);
if(element!=0)
{
Token t=getToken(br);
if(t==Token::MINUSOP || t==Token::PLUSOP)
{
if(t==Token::PLUSOP)
{
ParseTree* rhs = Expr(br);
if(rhs==0)
return 0;
else
{
return new AddOp(element, rhs);
}
}
if(t==Token::MINUSOP)
{
ParseTree* rhs = Expr(br);
if(rhs==0)
return 0;
else
{
return new SubtractOp(element, rhs); //or switch the inputs idk
}
}
}
else
{
return element;
}
}
return 0;
}
ParseTree* Term(istream *br)
{
ParseTree *element = Primary(br);
if(element!=0)
{
Token t=getToken(br);
if(t==Token::STAROP)
{
ParseTree* rhs =Term(br);
if(rhs==0)
return 0;
else
{
return new MultiplyOp(element, rhs);
}
}
else
{
return element;
}
}
return 0;
}
答案 0 :(得分:1)
为了编写recusrive下降解析器,您需要将语法转换为LL形式,摆脱left recursion。对于规则
Term::= Term STAROP Primary | Primary
你会得到类似的东西:
Term ::= Primary Term'
Term' ::= epsilon | STAROP Primary Term'
然后变成一个类似的函数:
ParseTree *Term(istream *br) {
ParseTree *element = Primary(br);
while (element && peekToken(br) == Token::STAROP) {
Token t = getToken(br);
ParseTree *rhs = Primary(br);
if (!rhs) return 0;
element = new MulOp(element, rhs); }
return element;
}
请注意,您需要peekToken
功能才能在不消耗它的情况下展望下一个令牌。也可以使用getToken
+ ungetToken
来做同样的事情。