使用bison来解析元素列表

时间:2009-10-31 18:22:19

标签: compiler-construction parsing yacc bison

我正在为着色引擎编写一个编译器,并且每个工作正常,直到我到达语句解析部分。

我使用了用类定义的抽象语法树来完成所有工作(简化类型检查和中间代码生成)..所以我有一个祖先类ASTNode和所有降序类例如ASTFloatASTExpressionASTIdentifier等等。

.y文件中,我能够以通用方式构建AST:

nexp:
T_LPAR nexp T_RPAR { $$ = $2; }
| nexp OP_PLUS nexp { $$ = new ASTBExpression('+', (ASTExpression*)$1, (ASTExpression*)$3); }
| nexp OP_MINUS nexp { $$ = new ASTBExpression('-', (ASTExpression*)$1, (ASTExpression*)$3); }
| nexp OP_TIMES nexp { $$ = new ASTBExpression('*', (ASTExpression*)$1, (ASTExpression*)$3); }

它工作得很好但后来我尝试以这种方式生成范围的语句(例如 if 语句的主体):我使用了一个类ASTStatements有一个ASTNode*列表,必须由解析器填充每个语句。

所以这种方法与此类似:

statements:
statement { if ($$ == null) $$ = new ASTStatements(); ((ASTStatements*)$$)->addStatement($1); } statements { $$->generateASM(); }
;

问题是该项应该在每个语句块中初始化一次,但我不知道该怎么做。使用if ($$ == null)是我尝试过的黑客攻击,但它不起作用,因为yylval可以包含任何内容。

使用Bison处理此类情况的正常/最佳方式是什么?

3 个答案:

答案 0 :(得分:1)

尝试增强语法,如下所示:

statements: statement { $$ = new ASTStatements();
                       ((ASTStatements*)$$)->addStatement($1); }      
 | statements statement { ((ASTStatements*)$$)->addStatement($2); }

不确定这是否有帮助。

答案 1 :(得分:1)

有很多理由喜欢yacc的左递归规则,但有一点你可以在输入中尽早减少。

在任何情况下,当你这样做时,你可以使用这样的模式:

statements:                { $$ = new ... }
    | statements statement { /* now $1 and $2 do just what you want */ }
    ;

答案 2 :(得分:1)

我通过生成一个语句列表而不是一个退化树来解决这个问题。所以涉及的类对象是:

ASTStatements
{
    ASTStatements *m_next;
    ASTStatement *m_statement;

    ....

    public:
        ASTStatements(ASTStatement *statement) // used for last one
        ASTStatements(ASTStatement *stat, ASTStatements *next) // used with a next one
}

以下列方式使用.y中的规则:

statements: /* empty */ { $$ = null; }
| statements statement { if ($1 == null) $$ = new ASTStatements($2); else $$ = new ASTStatements($2, (ASTStatements*)$1); }

实际上这是左递归的,允许语句尽快减少而不会使堆栈混乱。对于我的语言中涉及的任何其他类型的“符号列表”,我采用相同的方法。