0

我正在为着色引擎编写一个编译器,并且每个编译器都运行良好,直到我到达语句解析部分。

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

.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(); }
;

问题是每个语句块应该只初始化一次该项目,但我不知道该怎么做。Usingif ($$ == null)是我尝试过的一种技巧,但它不起作用,因为它yylval可以包含到目前为止的任何内容。

使用 Bison 处理这种情况的正常/最佳方法是什么?

4

3 回答 3

1

有多种原因偏爱 yacc 的左递归规则,一方面,您可以在输入中尽早减少。

无论如何,当你这样做时,你可以使用这样的模式:

statements:                { $$ = new ... }
    | statements statement { /* now $1 and $2 do just what you want */ }
    ;
于 2009-11-05T02:05:54.167 回答
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); }

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

于 2009-11-05T21:29:04.283 回答
0

尝试如下的增强语法:

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

不确定这是否会有所帮助。

于 2009-11-01T16:31:08.977 回答