手把手开发一门程序语言JimLang (2)
根据爱因斯坦的相对论,物体的质量越大,时间过得越快,所以托更对于我的煎熬,远远比你们想象的还要痛苦…今天给大家来盘硬菜,也是前些时日预告过的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<>();@Overridepublic 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);}@Overridepublic 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);}@Overridepublic 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);}@Overridepublic Object visitReturnStatement(ReturnStatementContext ctx) {if(ctx.expressionStatement().singleExpression()!=null){return this.visitSingleExpression(ctx.expressionStatement().singleExpression());}return super.visitReturnStatement(ctx);}@Overridepublic 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);}@Overridepublic 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;}@Overridepublic 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 {@Testpublic 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
执行结果
好了,今天的分享就倒这里。