编译器构造:显式解析树
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了编译器构造:显式解析树相关的知识,希望对你有一定的参考价值。
编译器如何在不构造显式解析树的情况下完成?显式解析树构造的好处和缺点是什么?
我知道编译器可以在没有显式解析树的情况下通过使用SDT并在解析期间运行与之关联的语义来构建。但我想知道显式解析树结构的好处和缺点。
答案
我有点像菜鸟所以请耐心等待...... thx ...
但是要回答你的问题,一个递归正常的编译(没有解析树)只能在最简单的情况下完成,其中没有前向引用和符号仅从其声明的点而不是它的整个范围有效。
显然它不会使用像java这样的语言。如果是前向引用,那么至少需要两次传递,如果在java之上重载函数,那么将需要三次传递(或者如果你知道如何在不到三个时间内执行它那么请指教我们) 。为此,我们构建了一个解析树。
最简单的解析树节点可能看起来像这样(免责声明:这不是真正的代码)。
package compiler;
import java.util.ArrayList;
import scanner.Token;
import scanner.TokenSet;
class Production
{
Token leading; // the first token in the production
int productionID; // a unique integer that identifies the production
ArrayList<Production> childNodes; // duh
Production mother; // mother node (may be null)
public Production (Token leading, int productionID)
{
this.leading = leading;
this.productionID = productionID;
childNodes = new ArrayList<Production>();
}
public void append (Production child) // add a new child node
{
child nodes.add(child);
child.mother = this;
}
public abstract void build1 (TokenSet follow, TokenSet anchor); // implements pass 1
public abstract void build2 ....
}
但更强大的方法是在每个生成中派生一个新的子类,并将子节点声明为字段变量。然后我们可以消除productionID并使用instanceof检查。您甚至可以在定义符号的给定子类上实现符号接口,并将该节点直接插入到符号表中;定义嵌套作用域的作品也可以有自己的符号表(我不会在这里做)。关键是这样,句法和语义分析都可以集成到解析树结构中,甚至也可以集成到最终翻译中。唯一的缺点是那些可怕的java接口:lol:
例如,我们可以将Modula-2头文件声明为:
// i wont bother with imports since this isnt real code
class DefinitionModule extends Production
{
Identifier name;
ArrayList<ImportClause> importClauses;
ArrayList<ExportClause> exportClauses;
ArrayList<Production> itemList; // CONST-,TYPE-, & VAR- declarators & function headers
public DefinitionModule() // no more productionID
{
super(lastTokenRead()); // always sits on DEFINITION
importClauses = new ArrayList<ImportClause>;
}
// build()
//
// DefinitionModule ::= DEFINITION MODULE Identifier ";" {ImportClause}{ExportClause}{HeaderItem} END Identifier
//
// where HeaderItem ::= ConstDeclarator | TypeDeclarator | VarDeclator | ProcedureHeader.
// Identifier, ImportClause, & ExportClause below are all derived from
// Production, above
public void build (TokenSet follow, TokenSet anchor)
{
Scanner.getToken(); // skip the DEFINITION
Scanner.expectToken(Token.ID_MODULE); // make sure MODULE is there & then skip it
name = name.build(new TokenSet(Token.ID_SEMICOLON));
expectToken(Token.ID_SEMICOLON);
while (lastTokenRead()==Token.ID_IMPORT || lastTokenRead()==Token.ID_FROM)
{
ImportClause IC = new ImportClause(lastTokenRead());
importClauses.add(IC.build(new TokenSet(Token.ID_SEMICOLON));
Scanner.expectToken(Token.ID_SEMICOLON);
}
while (lastTokenRead()==Token.ID_EXPORT)
{
ExportClause XC = new ExportClause(lastTokenRead());
exportClauses.add(XC.build(new TokenSet(Token.ID_SEMICOLON));
Scanner.expectToken(Token.ID_SEMICOLON);
}
// etc, etc, etc
}
}
如果你这样做,编译器将围绕语言的功能而不是编译器的传统通道构建自己。
祝好运...
以上是关于编译器构造:显式解析树的主要内容,如果未能解决你的问题,请参考以下文章