实现类作用域
在上一章,我们已经实现了一个语言的原型,在整个开发过程中,一个jvm语言的形成方案已经很明了,我们需要将原始代码编译为class
字节码文件,后续的工作也随之清晰了,我们需要对Qing
的语法进行不断扩充,使它可以承担更多的功能
而第一个需要扩充的语法显然是类作用域的定义
在java的语法中,我们需要通过Class
关键字来定义,类似这种Class Dog { XXX }
,我们已经是一个新语言了,还用Class
未免没有新意,调整一下用Type
怎么样
type Dog{ var name = "小白" print name var age = 3 print age}
而在本章节结束后,我们要达成的目标则是让上述的代码可以在Qing
上运行
一、语法解析规则
标题为 一、语法解析规则语言解析规则修改:
compilationUnit : ( variable | print )* EOF;
已更改为:
compilationUnit : classDeclaration * EOF;classDeclaration : TYPE className '{' classBody '}';classBody : ( variable | print )* ;TYPE : 'type';className : ID ;
这个规则要求:
- 每个
qing
文件都必须要实现有且只有一个的类定义classDeclaration
- 每个类定义以
type 类名 { 主体代码 }
的格式声明 - 主体代码和之前的规则一样,仍旧是变量声明和打印
二、调整编译器
标题为 二、调整编译器我们引入了一个新的实体来维护解析过程的类定义信息
public class ClassDeclaration { private String className;
Queue<Instruction> instructionsQueue = new ArrayDeque<>();
public ClassDeclaration(String className) { this.className = className; }
}
将其加入到监听器中
public void exitClassDeclaration(QingParser.ClassDeclarationContext ctx) { super.exitClassDeclaration(ctx); String className = ctx.className().getText(); classDeclaration= new ClassDeclaration(className); classDeclaration.setInstructionsQueue(instructionsQueue); }
调整编译器,此处主要是两处调整:
- 解析树返回的是我们维护的
ClassDeclaration
- 修改生成的字节码文件名
public class QingCompiler {
public static void main(String[] args) throws Exception { new QingCompiler().compile(args); }
public void compile(String[] args) throws Exception { File qingFile = new File(args[0]); String fileAbsolutePath = qingFile.getAbsolutePath(); ClassDeclaration classDeclaration= new SyntaxTreeTraverser().getClassDeclaration(fileAbsolutePath); writeBytecodeToClassFile(fileAbsolutePath, classDeclaration); }
private static void writeBytecodeToClassFile(String fileName, ClassDeclaration classDeclaration) throws IOException { byte[] byteCode = new BytecodeGenerator().generateBytecode(classDeclaration); String classFile = fileName.substring(0,fileName.lastIndexOf(File.separatorChar)+1) + classDeclaration.getClassName()+".class"; Path path = Paths.get(classFile); OutputStream os = Files.newOutputStream(path); os.write(byteCode); os.close(); }
}
三、运行调试
标题为 三、运行调试值得注意的是生成的字节码文件不再是以文件名命名,变为了根据类定义中的类名命名