`

See代码阅读

 
阅读更多

 

See代码阅读

 

一、概述:

See是github上用ANTLR实现的开源脚本语言,网址在

https://github.com/MihaiB/mihaib的forge/antlr-ex/old-see下

https://github.com/MihaiB/see(已失效)

https://github.com/MihaiB/antlr-ex(失效)

它的语法像C,或者说像JavaScript。

例如:

void main()

{

int i = 0;

while(i < 10)

{

print(i);

i = i + 1;

}

}

输出:

0123456789

 

二、符号信息:

表示符号信息的类集中在see.symbol包中

1. Symbol(接口类,代表符号)

getName : 名称(String)

setType / getType : 类型(Type)

getScope : 作用域(Scope)

getDefNode : 定义ID的节点,用于数组类型(SeeAST)

getDefLocation : 定义的位置(String)

2. Type(接口类,继承自Symbol接口,代表类型符号)

getTypeIndex : 类型索引

3. Scope(代表可向上查找的符号表信息,是作用域树的一个节点)

name : 作用域名称(String)

parent : 父级(Scope)

members : 符号表(私有),String->Symbol(Map)

Scope : 受保护,确保Scope只能用于继承。

define : 在作用域中创建符号

getOrderedMembers : 把符号表转为Set

resolve : 把符号名转为Symbol对象(可能需要向上查找父级Scope)。

resolveMember : 把符号名转为Symbol对象(不向上查找)

4. NamedSymbol(包内可见的类,继承自Symbol,表示没有嵌套符号的符号)

NamedSymbol内部不能有其它Symbol。

例如ArrayType是NamedSymbol,但FunctionSymbol不是。

构造函数封装名称(非空)、作用域(非空)、SeeAST节点(可以为空),

如果SeeAST节点为空,则判断它是否为内置类型或内置类型的数组。

5. SymbolTable(符号表,单实例)

全局的符号信息,包含内置符号和脚本中的符号。

还包含语法信息。

作为单实例,用在语法解析器和运行解析器。

6. TypeTables(类型表)

一些语法信息,用于SymbolTable。

7. ArrayType(继承NamedSymbol,实现Type,单实例)

作为单实例用于构造指定Type和维数的数组。

同时它代表了带[]的数组类型节点.

它的SeeAST节点由参数的Type决定

8. BuiltInType(继承NamedSymbol,实现Type)

在SymbolTable中构造实例。

用于加入内置类型,例如boolean。

它不需要SeeAST节点.

9. FunctionSymbol(继承Scope,实现Symbol)

代表函数定义。

NamedSymbol是成员变量(相当于多继承)

它是Scope,所以可以嵌套其它Symbol。

10. StructType(继承Scope,实现Symbol)

代表结构体定义。

NamedSymbol是成员变量(相当于多继承)

它是Scope,所以可以嵌套其它Symbol。

11. VariableSymbol(继承NamedSymbol)

代表变量定义

它不能嵌套Symbol

 

三、运行时解析器

与运行时解析器相关的类定义在see.interp包中

1. FunctionReturnException(继承RuntimeException)

当return执行完后抛出(见Interpreter.java:returnStat)

2. UserArrayIndexOutOfBoundsException(继承ArrayIndexOutOfBoundsException)

当数组元素赋值或索引时下标超出范围时抛出。

(见Interpreter.java:arrayElemAssign和Interpreter.java:index)

3. UserNullPointerException(继承RuntimeException)

当操作数出现null时抛出(null通常来自用户类型实例的默认值或null关键词)

(见Interpreter.java中的arrayElemAssign,fieldAssign,index,lenOp,loadField)

4. MemorySpace

变量实例表(?)

5. Interpreter

运行时解析器(相当于虚拟机)。

运行SeeAST根节点。

入口点在run(),

Interpreter内部根据SeeAST节点的类型进行跳转和递归调用。

 

四、AST生成

1. Def(继承TreeFilter)

由Def.g生成

2. Ref(继承TreeFilter)

由Ref.g生成

3. Types(继承TreeFilter)

由Trees.g生成

4. SeeLexer(继承Lexer)

由See.g生成

5. SeeParser(继承Parser)

由See.g生成

6. SeeAST(继承CommonTree)

7. ErrorNode(继承SeeAST)

8. Listener

错误输出(包括位置和消息)

9. Main

程序主入口

 

五、关键代码:

1. see.symbol.SymbolTable.java:makeSingleton

  & see.symbol.SymbolTable.java:SymbolTable

创建global作用域,

构造内置类型。

SymbolTable的作用是处理SeeLexer产生的Token流,

在SeeParser启动前完成符号表的构建。

2. Interpreter.java:exec

AST语法成分判断分支

3. Main.java:main

主入口

 

六、技术细节:

1. 使用SeeParser.setTreeAdaptor()更改默认的树适配器

由于默认生成的SeeParser的适配器是CommonTreeAdaptor。

需要用这种方法把Token封转为SeeAST(CommonTree的子类),

携带更多信息。

CommonTreeAdaptor的代码注释中是这样说明的:

To get your parser to build nodes of a different type, override

create(Token), errorNode(), and to be safe, YourTreeClass.dupNode().

dupNode is called to duplicate nodes during rewrite operations.

【翻译】为了使你的解析器构建不同类型的节点,请覆盖create(Token)和errorNode(),

还有出于安全起见,覆盖<你的树类>.dupNode()。

调用dupNode是为了在重写操作期间复制节点。

更多信息见官网介绍:

Using custom AST node types

http://www.antlr.org/wiki/display/ANTLR3/Tree+construction

2. Main类中获取流的情况:

CommonTokenStream tokens = new CommonTokenStream(lexer);

从SeeLexer中获取CommonTokenStream

CommonTree t = parser.program().tree;

CommonTreeNodeStream nodes = new CommonTreeNodeStream(t);

nodes.setTokenStream(tokens);

从SeeParser中获取CommonTree,再获取CommonTreeNodeStream。

然后把CommonTokenStream放进CommonTreeNodeStream中

3. 树解析器(tree grammar)的使用。

(1) Def:符号定义。

(2) Ref:解析引用,把它们指向SymbolTable的Symbol(不能向前引用)。

(3) Types:计算引用类型(向前引用?)和表达式。

共通之处:

1. nodes.reset(); 在执行树解析器前重置CommonTreeNodeStream

2. TreeFilter.downup(t); 让每个树解析器运行(自下而上,深度遍历)

3. 逐个用downup写入CommonTree,最后把CommonTree传给Interpreter运行虚拟机。

4. 树模式匹配

官方介绍:

Tree pattern matching

http://www.antlr.org/wiki/display/ANTLR3/Tree+pattern+matching

它的明显特征是使用在.g文件中使用filter=true;的options选项:

这样,生成代码的树解析器类不是继承自TreeParser,而是继承自TreeFilter

TreeFilter实际上是TreeParser的子类,拥有执行downup的能力。

 

(TODO)

 
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics