手把手开发一门程序语言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<>();

    @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

在这里插入图片描述

执行结果

在这里插入图片描述

好了,今天的分享就倒这里。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

麒思妙想

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值