在手写解析器中翻译语法文件
Translating a grammar file in a hand written parser
出于教育目的,我一直在尝试编写自己的编译器,但遇到了一个问题。我已经采用了递归下降方法以及一些关于 lex 和 yacc/bison.
的先前知识
到目前为止,我只是尝试处理解析方面的问题,而不考虑 AST 的生成或代码生成。
我正在尝试为这个特定的语法文件部分编写表达式解析
primary_expression
: IDENTIFIER
| CONSTANT
| STRING_LITERAL
| '(' expression ')'
;
postfix_expression
: primary_expression
| postfix_expression '[' expression ']'
| postfix_expression '(' ')'
| postfix_expression '(' argument_expression_list ')'
| postfix_expression '.' IDENTIFIER
| postfix_expression PTR_OP IDENTIFIER
| postfix_expression INC_OP
| postfix_expression DEC_OP
;
到目前为止我有这个代码
void Parser::primaryExpression()
{
if (accept(Token::eIdentifier))
{
}
else if (accept(Token::eIntNumber))
{
}
else if (accept('('))
{
expression();
expect(')');
}
}
void Parser::postfixExpression()
{
}
我在处理 postfix_expression
的递归性时遇到一些问题,我不知道如何继续使用 postfixExpression
函数。
我的印象是,对于递归下降解析器,我可能应该以不同的方式安排我的语法。
谁能给我指出正确的方向?
注意postfix_expression
总是先解析primary_expression
,所以业务的第一个顺序是primaryExpression()
。
那么,如果下一个字符是剩余7条规则中递归postfix_expression
之后的任意一个字符,那么你就是在解析postfix_expression
。这会给你另一个 posfix_expression
,所以你再重复一遍。
我不会为您编写 C++ 代码,而是使用伪代码:
postfixExpression()
{
primaryExpression();
while (next character is any of the characters that follow
postfix_expression in the remaining seven rules)
{
parse_the_appropriate_rule();
}
}
左递归很难在 LL(递归下降)解析器中处理——您需要识别 at 并将其更改为循环而不是递归调用。一般而言,您想将左递归重构为
A → α | β
然后你的递归下降例程变成
parseA() {
parseAlpha();
while (lookaheadMatchesBeta())
parseBeta();
}
注意,这需要足够的前瞻性来区分FIRST(β)和FOLLOW(A),以便找到所有可以匹配β的尾随事物的结尾
这与在 LL 文法中消除左递归的过程相同——您实际上是用
替换了上面的规则
A → α A'
A'→ ε | βA'
然后用循环替换 parseAPrime
中的尾递归调用并将其内联到 parseA
.
使用你的语法并使用你上面的代码使用的 accept/expect 技术,你会得到类似的东西:
void Parser::postfixExpression() {
primaryExpression();
while (true) {
if (accept('[')) {
expression();
expect(']');
} else if (accept('(')) {
if (accept(')')) {
} else {
argumentExpressionList();
expect(')'); }
} else if (accept('.')) {
⋮
} else if (accept(Token::DEC_OP)) {
} else {
break;
}
}
}
出于教育目的,我一直在尝试编写自己的编译器,但遇到了一个问题。我已经采用了递归下降方法以及一些关于 lex 和 yacc/bison.
的先前知识到目前为止,我只是尝试处理解析方面的问题,而不考虑 AST 的生成或代码生成。
我正在尝试为这个特定的语法文件部分编写表达式解析
primary_expression
: IDENTIFIER
| CONSTANT
| STRING_LITERAL
| '(' expression ')'
;
postfix_expression
: primary_expression
| postfix_expression '[' expression ']'
| postfix_expression '(' ')'
| postfix_expression '(' argument_expression_list ')'
| postfix_expression '.' IDENTIFIER
| postfix_expression PTR_OP IDENTIFIER
| postfix_expression INC_OP
| postfix_expression DEC_OP
;
到目前为止我有这个代码
void Parser::primaryExpression()
{
if (accept(Token::eIdentifier))
{
}
else if (accept(Token::eIntNumber))
{
}
else if (accept('('))
{
expression();
expect(')');
}
}
void Parser::postfixExpression()
{
}
我在处理 postfix_expression
的递归性时遇到一些问题,我不知道如何继续使用 postfixExpression
函数。
我的印象是,对于递归下降解析器,我可能应该以不同的方式安排我的语法。
谁能给我指出正确的方向?
注意postfix_expression
总是先解析primary_expression
,所以业务的第一个顺序是primaryExpression()
。
那么,如果下一个字符是剩余7条规则中递归postfix_expression
之后的任意一个字符,那么你就是在解析postfix_expression
。这会给你另一个 posfix_expression
,所以你再重复一遍。
我不会为您编写 C++ 代码,而是使用伪代码:
postfixExpression()
{
primaryExpression();
while (next character is any of the characters that follow
postfix_expression in the remaining seven rules)
{
parse_the_appropriate_rule();
}
}
左递归很难在 LL(递归下降)解析器中处理——您需要识别 at 并将其更改为循环而不是递归调用。一般而言,您想将左递归重构为
A → α | β
然后你的递归下降例程变成
parseA() {
parseAlpha();
while (lookaheadMatchesBeta())
parseBeta();
}
注意,这需要足够的前瞻性来区分FIRST(β)和FOLLOW(A),以便找到所有可以匹配β的尾随事物的结尾
这与在 LL 文法中消除左递归的过程相同——您实际上是用
替换了上面的规则A → α A'
A'→ ε | βA'
然后用循环替换 parseAPrime
中的尾递归调用并将其内联到 parseA
.
使用你的语法并使用你上面的代码使用的 accept/expect 技术,你会得到类似的东西:
void Parser::postfixExpression() {
primaryExpression();
while (true) {
if (accept('[')) {
expression();
expect(']');
} else if (accept('(')) {
if (accept(')')) {
} else {
argumentExpressionList();
expect(')'); }
} else if (accept('.')) {
⋮
} else if (accept(Token::DEC_OP)) {
} else {
break;
}
}
}