在写函数的实现时候,一直很迷茫,感觉不够优雅,直到听了南大的《操作系统》,程序就是状态机,方法调研就是引用计数++,函数返回就是弹栈,才豁然开朗,也让我鉴定了开一个系列坑,这里我打算实现一门开发语言。
今天我们先来实现函数一个简单的函数调用
MyLang.g4
这里我们还是借用ANTLR来做解析器,构建基础的函数语法
grammar MyLang;
prog: statementList? EOF;
statementList : ( variableDecl | functionDecl | expressionStatement )* ;
variableDecl : VAR identifier typeAnnotation? ( '=' singleExpression)? ';';
typeAnnotation : ':' typeName;
functionDecl: FUNCTION identifier '(' parameterList ')' functionBody;
functionBody: '{' statementList? '}';
functionCall: identifier '(' parameterList? ')';
expressionStatement: singleExpression ';';
singleExpression: primary (binOP primary)* ;
primary: ID | NUMBER_LITERAL | functionCall | '(' singleExpression ')' ;
binOP : '+'
| '-'
| '*'
| '/'
| '='
| '<='
| '>='
;
parameterList: singleExpression(',' singleExpression)*;
identifier: ID;
typeName : 'String'
| 'Number'
| 'Boolean'
;
VAR: 'var';
FUNCTION: 'function';
STRING_LITERAL: '"'[a-zA-Z0-9!@#$% "]*'"';
NUMBER_LITERAL: [0-9]+(.)?[0-9]?;
ID : [a-zA-Z_][a-zA-Z0-9_]*;
WS : [ \t\r\n]+ -> skip ;
MLVistor.java
构建vistor
package wang.datahub.mylang;
import wang.datahub.mylang.parser.MyLangBaseVisitor;
import wang.datahub.mylang.parser.MyLangParser;
import java.util.Hashtable;
public class MLVistor extends MyLangBaseVisitor {
// Hashtable<String, MyLangParser.FunctionDeclContext> sympoltable = new Hashtable<>();
Hashtable<String,Symbol> _sympoltable = new Hashtable<>();
@Override
public Object visitFunctionDecl(MyLangParser.FunctionDeclContext ctx) {
String functionName = ctx.identifier().getText();
if(_sympoltable.get(functionName) == null){
System.out.println("define function ==> "+functionName);
// sympoltable.put(ctx.identifier().getText(),ctx);
Symbol symbol = new Symbol();
symbol.setName(functionName);
symbol.setParseTree(ctx);
symbol.setType(Symbol.SymbolType.FUNCTION);
_sympoltable.put(functionName,symbol);
return null;
}
//return null;
return super.visitFunctionDecl(ctx);
}
@Override
public Object visitFunctionCall(MyLangParser.FunctionCallContext ctx) {
String functionName = ctx.identifier().getText();
if("print".equals(functionName)){
String parStr = ctx.parameterList().getText();
if(parStr.startsWith("\"")){
parStr = parStr.substring(1,parStr.length()-1);
}
System.out.println(parStr);
return null;
}else{
System.out.println("run function ==>"+functionName);
MyLangParser.FunctionDeclContext fdc = (MyLangParser.FunctionDeclContext) _sympoltable.get(functionName).getParseTree();
//sympoltable.get(functionName);
if(fdc==null){
throw new RuntimeException("undefine function ...." + functionName);
}
super.visitFunctionDecl(fdc);
}
return super.visitFunctionCall(ctx);
}
}
Symbol.java
做一个简单的栈帧实现
package wang.datahub.mylang;
import org.antlr.v4.runtime.tree.ParseTree;
public class Symbol {
public static enum SymbolType {
FUNCTION,VAR,
}
private String name ;
private SymbolType type;
private ParseTree parseTree;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public SymbolType getType() {
return type;
}
public void setType(SymbolType type) {
this.type = type;
}
public ParseTree getParseTree() {
return parseTree;
}
public void setParseTree(ParseTree parseTree) {
this.parseTree = parseTree;
}
@Override
public String toString() {
return "Symbol{" +
"name='" + name + '\'' +
", type=" + type +
", parseTree=" + parseTree +
'}';
}
}
测试
Test01.mylang
function foo(){
print("in foo")
bar()
}
function bar(){
print("in bar")
}
foo()
Test01.java
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import org.junit.Test;
import wang.datahub.mylang.MLVistor;
import wang.datahub.mylang.parser.MyLangLexer;
import wang.datahub.mylang.parser.MyLangParser;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
public class Test01 {
@Test
public void T1() throws IOException {
List<String> lines = Files.readAllLines(Paths.get("src/test/java/Test01.mylang"));
String expr = lines.stream().collect(Collectors.joining("\n"));
System.out.println(expr);
System.out.println("--------------------");
CharStream stream= CharStreams.fromString(expr);
MyLangLexer lexer=new MyLangLexer(stream);
MyLangParser parser = new MyLangParser(new CommonTokenStream(lexer));
ParseTree parseTree = parser.prog();
MLVistor mlvistor = new MLVistor();
mlvistor.visit(parseTree);
}
}
测试结果
好了,今天的分享就倒这里。