根据爱因斯坦的相对论,物体的质量越大,时间过得越快,所以托更对于我的煎熬,远远比你们想象的还要痛苦…今天给大家来盘硬菜,也是前些时日预告过的JimLang
的开发过程… Let’s go !!!
语法及解析
JimLang.g4
这里我们还是借用ANTLR来做解析器,构建基础的函数语法
grammar JimLang;
prog: statementList? EOF;
statementList : ( variableDecl | functionDecl | functionCall | expressionStatement )* ;
assignment: '=' singleExpression ;
returnStatement: RETURN expressionStatement;
variableDecl : VAR identifier typeAnnotation? ( assignment )* ';';
typeAnnotation : ':' typeName;
functionDecl: FUNCTION identifier '(' parameterList? ')' functionBody ';'? ;
functionBody: '{' statementList? returnStatement? '}';
functionCall: (sysfunction | identifier) '(' parameterList? ')';
expressionStatement: singleExpression | singleExpression ';';
singleExpression: primary (binOP primary)* ;
primary: ID | NUMBER_LITERAL| STRING_LITERAL | BOOLEAN_LITERAL | functionCall | '(' singleExpression ')' ;
binOP : '+'
| '-'
| '*'
| '/'
| '='
| '<='
| '>='
;
parameterList: singleExpression (',' singleExpression)*;
identifier: ID;
sysfunction : 'print'
| 'println'
;
typeName : 'string'
| 'number'
| 'boolean'
;
VAR: 'var';
FUNCTION: 'function';
RETURN: 'return';
BOOLEAN_LITERAL: 'true' | 'false' ;
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 ;
WS: [ \t\r\n\u000C]+ -> channel(HIDDEN);
COMMENT: '/*' .*? '*/' -> channel(HIDDEN);
LINE_COMMENT: '//' ~[\r\n]* -> channel(HIDDEN);
JimLangVistor.java
构建vistor
package com.dafei1288.jimlang;
import com.dafei1288.jimlang.metadata.StackFrane;
import com.dafei1288.jimlang.metadata.Symbol;
import com.dafei1288.jimlang.metadata.SymbolFunction;
import com.dafei1288.jimlang.metadata.SymbolType;
import com.dafei1288.jimlang.metadata.SymbolVar;
import com.dafei1288.jimlang.parser.JimLangBaseVisitor;
import com.dafei1288.jimlang.parser.JimLangParser.AssignmentContext;
import com.dafei1288.jimlang.parser.JimLangParser.FunctionCallContext;
import com.dafei1288.jimlang.parser.JimLangParser.FunctionDeclContext;
import com.dafei1288.jimlang.parser.JimLangParser.PrimaryContext;
import com.dafei1288.jimlang.parser.JimLangParser.ReturnStatementContext;
import com.dafei1288.jimlang.parser.JimLangParser.SingleExpressionContext;
import com.dafei1288.jimlang.parser.JimLangParser.SysfunctionContext;
import com.dafei1288.jimlang.parser.JimLangParser.VariableDeclContext;
import com.dafei1288.jimlang.sys.Funcall;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Hashtable;
import org.antlr.v4.runtime.TokenStream;
public class JimLangVistor extends JimLangBaseVisitor {
Hashtable<String, Symbol> _sympoltable = new Hashtable<>();
@Override
public Object visitVariableDecl(VariableDeclContext ctx) {
String varName = ctx.identifier().getText();
if(_sympoltable.get(varName) == null){
SymbolVar symbol = new SymbolVar();
symbol.setName(varName);
symbol.setParseTree(ctx);
if(ctx.typeAnnotation()!=null && ctx.typeAnnotation().typeName()!=null){
symbol.setTypeName(ctx.typeAnnotation().typeName().getText());
}
for(AssignmentContext assignmentContext : ctx.assignment()){
if(assignmentContext.singleExpression() != null && assignmentContext.singleExpression().primary() != null && assignmentContext.singleExpression().primary().size() > 0){
SingleExpressionContext singleExpressionContext = assignmentContext.singleExpression();
PrimaryContext primaryContext = singleExpressionContext.primary(0);
if(primaryContext.NUMBER_LITERAL() != null){
symbol.setValue(Integer.parseInt(primaryContext.NUMBER_LITERAL().getText().trim()));
}else if(primaryContext.STRING_LITERAL() != null){
symbol.setValue(primaryContext.STRING_LITERAL().getText());
}else{
}
}
}
_sympoltable.put(varName,symbol);
}
return super.visitVariableDecl(ctx);
}
@Override
public Object visitSingleExpression(SingleExpressionContext ctx) {
PrimaryContext primaryContext = ctx.primary(0);
if(_sympoltable.get(primaryContext.getText())!=null){
return _sympoltable.get(primaryContext.getText().trim()).getValue();
}
if(primaryContext.NUMBER_LITERAL() != null){
return Integer.parseInt(primaryContext.NUMBER_LITERAL().getText().trim());
}else if(primaryContext.STRING_LITERAL() != null){
String text = primaryContext.STRING_LITERAL().getText();
if(text.startsWith("\"")){
text = text.substring(1,text.length()-1);
}
return text;
}else if(primaryContext.BOOLEAN_LITERAL() != null){
return Boolean.valueOf(primaryContext.BOOLEAN_LITERAL().getText());
// return this.visitBooleanType(primaryContext.booleanType());
}
return super.visitSingleExpression(ctx);
}
@Override
public Object visitFunctionDecl(FunctionDeclContext ctx) {
String functionName = ctx.identifier().getText();
if(_sympoltable.get(functionName) == null){
// System.out.println("define function ==> "+functionName);
// sympoltable.put(ctx.identifier().getText(),ctx);
SymbolFunction symbol = new SymbolFunction();
symbol.setName(functionName);
symbol.setParseTree(ctx);
if(Funcall.isSysFunction(functionName)){
symbol.setType(SymbolType.SYSFUNCTION);
}else{
symbol.setType(SymbolType.FUNCTION);
}
if(ctx.parameterList()!=null && ctx.parameterList().singleExpression()!=null){
List<String> pl = ctx.parameterList().singleExpression().stream().map(it->it.getText().trim()).collect(Collectors.toList());
symbol.setParameterList(pl);
}
if(ctx.functionBody() != null){
symbol.setFunctionBody(ctx.functionBody().getText());
if(ctx.functionBody().returnStatement() != null){
Object o = this.visitReturnStatement(ctx.functionBody().returnStatement());
symbol.setValue(o);
}
}
// if(ctx.functionBody().)
_sympoltable.put(functionName,symbol);
// return null;
}
//return null;
return super.visitFunctionDecl(ctx);
}
@Override
public Object visitReturnStatement(ReturnStatementContext ctx) {
if(ctx.expressionStatement().singleExpression()!=null){
return this.visitSingleExpression(ctx.expressionStatement().singleExpression());
}
return super.visitReturnStatement(ctx);
}
@Override
public Object visitFunctionCall(FunctionCallContext ctx) {
String functionName = null;
if(ctx.parameterList() != null){
this.visitParameterList(ctx.parameterList());
}
if(ctx.sysfunction() != null){
functionName = ctx.sysfunction().getText();
// System.out.println(functionName);
List<Object> all = ctx.parameterList().singleExpression().stream().map(it->{
return this.visitSingleExpression(it);
}).collect(Collectors.toList());
return Funcall.exec(functionName,all);
}
if(ctx.identifier() != null){
functionName = ctx.identifier().getText();
}
SymbolFunction currentSymbol = (SymbolFunction) _sympoltable.get(functionName);
if(currentSymbol != null){
// System.out.println("call function ==> "+currentSymbol.getName());
StackFrane stackFrane = new StackFrane(currentSymbol,functionName);
return currentSymbol.getValue();
}
return super.visitFunctionCall(ctx);
}
@Override
public Object visitSysfunction(SysfunctionContext ctx) {
String functionName = ctx.getText();
return super.visitSysfunction(ctx);
}
}
Funcall.java
系统函数执行器
package com.dafei1288.jimlang.sys;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
public class Funcall {
public static Set<String> SYS_FUNCTION_NAMES = new HashSet<>();
static{
SYS_FUNCTION_NAMES.add("PRINTLN");
SYS_FUNCTION_NAMES.add("PRINT");
}
public static boolean isSysFunction(String functionName){
boolean tag = false;
if(SYS_FUNCTION_NAMES.contains(functionName.toUpperCase(Locale.ROOT))){
tag = true;
}
return tag;
}
public static Object exec(String functionName, List<Object> params){
Funcall f = new Funcall();
Method method = Arrays.stream(f.getClass().getMethods()).filter(it->it.getName().equals(functionName)).findFirst().get();
try {
return method.invoke(f,params.toArray());
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
public void println(Object obj){
System.out.println(obj);
}
public void print(Object obj){
System.out.print(obj);
}
}
符号表
构建符号表系统
Symbol.java
package com.dafei1288.jimlang.metadata;
import org.antlr.v4.runtime.tree.ParseTree;
public interface Symbol {
String getName();
void setName(String name);
SymbolType getType();
void setType(SymbolType type);
ParseTree getParseTree();
void setParseTree(ParseTree parseTree);
String getTypeName() ;
void setTypeName(String typeName) ;
Object getValue() ;
void setValue(Object value);
Scope getScope();
void setScope(Scope scope);
}
AbstractSymbol.java
package com.dafei1288.jimlang.metadata;
import org.antlr.v4.runtime.tree.ParseTree;
public class AbstractSymbol implements Symbol {
private String name ;
private SymbolType type;
private ParseTree parseTree;
private String typeName;
private Object value;
private Scope scope;
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;
}
public String getTypeName() {
return typeName;
}
public void setTypeName(String typeName) {
this.typeName = typeName;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
public Scope getScope() {
return scope;
}
public void setScope(Scope scope) {
this.scope = scope;
}
@Override
public String toString() {
return "AbstractSymbol{" +
"name='" + name + '\'' +
", type=" + type +
", parseTree=" + parseTree +
", dataType='" + typeName + '\'' +
", value=" + value +
'}';
}
}
SymbolFunction.java
package com.dafei1288.jimlang.metadata;
import java.util.List;
public class SymbolFunction extends AbstractSymbol {
private List<String> parameterList;
private String functionBody;
public List<String> getParameterList() {
return parameterList;
}
public void setParameterList(List<String> parameterList) {
this.parameterList = parameterList;
}
public String getFunctionBody() {
return functionBody;
}
public void setFunctionBody(String functionBody) {
this.functionBody = functionBody;
}
}
SymbolVar.java
package com.dafei1288.jimlang.metadata;
public class SymbolVar extends AbstractSymbol {
}
测试
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 T2() throws IOException {
String script = """
var i = 11 ;
function aa(i){
return i;
}
print(aa(i))
""";
System.out.println(script);
System.out.println("--------------------");
CharStream stream= CharStreams.fromString(script);
JimLangLexer lexer=new JimLangLexer(stream);
JimLangParser parser = new JimLangParser(new CommonTokenStream(lexer));
ParseTree parseTree = parser.prog();
JimLangVistor mlvistor = new JimLangVistor();
Object o = mlvistor.visit(parseTree);
// System.out.println(o);
}
}
测试结果:
AST
执行结果
好了,今天的分享就倒这里。