手把手开发一门程序语言JimLang (2)

news2024/11/17 19:47:27

根据爱因斯坦的相对论,物体的质量越大,时间过得越快,所以托更对于我的煎熬,远远比你们想象的还要痛苦…今天给大家来盘硬菜,也是前些时日预告过的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

在这里插入图片描述

执行结果

在这里插入图片描述

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/398612.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

轮毂要怎么选?选大还是选小?

随着改装车的越来越火爆&#xff0c;汽车轮毂可选择的款式也越来越多&#xff0c;90%的人换轮毂&#xff0c;首先选的就是外观。大轮毂的款式多&#xff0c;外形大气好看&#xff0c;运动感十足&#xff0c; 那是不是选大轮毂就可以呢&#xff1f;不是的&#xff0c;汽车轮毂要…

全面吃透Java Stream流操作,让代码更加的优雅

文章目录1 认识Stream流1.1 什么是流1.2 流与集合1.2.1 流只能遍历一次1.2.2 外部迭代和内部迭代1.3 流操作1.3.1 中间操作1.3.2 终端操作1.3.3 使用流2 学会使用Stream流2.1 筛选和切片2.1.1 用谓词筛选2.1.2 筛选各异的元素2.1.3 截短流2.1.4 跳过元素2.2 映射2.2.1 map方法2…

Java经典面试题——对比 Vector、ArrayList、LinkedList 有何区别?

典型回答 这三者都是实现集合框架中的 List &#xff0c;也就是所谓的有序集合&#xff0c;因此具体功能也比较近似&#xff0c;比如都提供按照位置进行定位、添加或者删除的操作&#xff0c;都提供迭代器以遍历其内容等。但因为具体的设计区别&#xff0c;在行为、性能、线程…

详解CRC原理以及C语言实现

CRC检验原理 CRC&#xff08;Cyclic Redundancy Check&#xff09;校验是一种常用的数据校验方法&#xff0c;它通过计算数据的校验码来检测数据在传输过程中是否出现了错误。 CRC校验的基本原理是将数据按照一定的规则进行计算&#xff0c;得到一个固定长度的校验码&#xf…

JavaScript内改变this指向

之前我们说的都是代码内 this 的默认指向 今天我们要来说一下如何能改变 this 指向 也就是说, 你指向哪我不管, 我让你指向哪, 你就得指向哪 开局 在函数的原型( Function.prototype ) 上有三个方法 call apply bind 既然是在函数的原型上, 那么只要是函数就可以调用这三个方…

React(七):Router基本使用、嵌套路由、编程式导航、路由传参、懒加载

React&#xff08;七&#xff09;一、React-Router的基本使用1.安装和介绍2.路由的配置和跳转3.Navigate的使用4.如果找不到对应的路由路径&#xff1f;二、嵌套路由的用法三、编程式路由导航1.类组件中使用useNavigate2.函数式组件中使用useNavigate四、路由跳转传参1.设置好路…

小白学Pytorch 系列--Torch API(1)

小白学Pytorch 系列–Torch API Torch version 1.13 Tensors TORCH.IS_TENSOR 如果obj是PyTorch张量&#xff0c;则返回True。 注意&#xff0c;这个函数只是简单地执行isinstance(obj, Tensor)。使用isinstance 更适合用mypy进行类型检查&#xff0c;而且更显式-所以建议使…

【计组】主存储器有关知识梳理

一、主存储器 主存储器可以直接和CPU进行通信&#xff0c;但是只能保存临时数据&#xff0c;在断电后数据就消失。还有一个特点是&#xff0c;主存储器的容量小&#xff0c;速度快&#xff0c;造价高。 1.构成 2.主存中存储体的构造 最小的存储单位是存储元&#xff0c;存储元…

近亿美元:人工心脏龙头永仁心医疗完成超大额A轮融资

近日&#xff0c;永仁心医疗器械有限公司&#xff08;以下简称“永仁心医疗”&#xff09;完成近一亿美元A轮融资&#xff0c;由北京科兴中维生物技术有限公司&#xff08;SINOVAC科兴&#xff09;领投&#xff0c;太平&#xff08;深圳&#xff09;医疗健康产业私募股权投资基…

腾讯IM h5版本,在安卓原生和IOS原生支持情况的调查以及踩坑、解决办法

介绍 公司准备基于腾讯IM进行开发即时通讯功能&#xff0c;想用H5来开发&#xff0c;这样方便以后移植&#xff0c;在原生app里直接加载&#xff0c;通过三天时间的调查&#xff0c;以及与腾讯客服&#xff0c;技术来回沟通&#xff0c;已经有一定的成果&#xff0c;现将调查成…

【Redis】Redis持久化(一)

目录 1.Redis持久化 1.1.RDB持久化 1.1.1.执行时机 1.1.2.RDB原理 1.1.3.小结 1.2.AOF持久化 1.2.1.AOF原理 1.2.2.AOF配置 1.2.3.AOF文件重写 1.3.RDB与AOF对比 1.Redis持久化 Redis有两种持久化方案&#xff1a; RDB持久化 AOF持久化 1.1.RDB持久化 RDB全称Red…

SpringBoot - 什么是跨域?如何解决跨域?

什么是跨域&#xff1f; 在浏览器上当前访问的网站&#xff0c;向另一个网站发送请求&#xff0c;用于获取数据的过程就是跨域请求。 跨域&#xff0c;是浏览器的同源策略决定的&#xff0c;是一个重要的浏览器安全策略&#xff0c;用于限制一个 origin 的文档或者它加载的脚本…

Doris集成其他系统——ODBC外部表

Doris集成其他系统——ODBC外部表 文章目录Doris集成其他系统——ODBC外部表0. 写在前面1. 正文1.1 ODBC外部表介绍1.2 使用方式2. 使用 ODBC 的 MySQL 外表2.1 前置芝士2.2 安装 unixODBC2.3 安装MySQL 对应版本的 ODBC2.3.1 安装方式2.3.2 检查安装结果2.3.3 其他节点的安装及…

prometheus 配置服务器监控、服务监控、容器中服务监控与告警

最近公司有几个服务遇到了瓶颈&#xff0c;也就是数据量增加了&#xff0c;没有人发现&#xff0c;这不是缺少一个监控服务和告警的系统吗&#xff1f; 主要需求是监控每个服务&#xff0c;顺带监控一下服务器和一些中间件&#xff0c;这里采集的2种&#xff0c;zabbix和prom…

Kafka 消费者组

Kafka 消费者组Consumer数位移重平衡消费者组 (Consumer Group) : 可扩展且容错性的消费者机制 一个组内可能有多个消费者 (Consumer Instance) : 共享一个公共 ID (Group ID)组内的所有消费者协调消费订阅主题 (Subscribed Topics) 的所有分区 (Partition)每个分区只能由同个…

【1】熟悉刷题平台操作

TestBench使用 与quartus中testbench的写法有些许。或者说这是平台特有的特性&#xff01;&#xff01; 1 平台使用谨记 &#xff08;1&#xff09;必须删除&#xff1a;若设计为组合逻辑&#xff0c;需将自动生成的clk删除 若不删除&#xff0c;会提示运行超时错误。 &#…

git推送指定的提交到远程分支详细方法

默认情况下&#xff0c;git push会推送暂存区所有提交&#xff08;也即HEAD及其之前的提交&#xff09;到远程库&#xff0c;实际开发中可能因为功能没有开发完成&#xff0c;但是又必须提交部分修改好的代码就需要用到推送指定commit到远程分支。第一种方式&#xff1a;即符合…

CSS流动布局-页面自适应

项目中经常会碰到页面自适应的问题&#xff0c;例如&#xff1a;商城的列表展示、分类列表展示等页面&#xff0c;如下&#xff1a; 该页面会随着页面的放大缩小而随之发生变化&#xff0c;这种自适应的页面布局在大屏幕、小屏幕、不同的浏览器设备上都应该呈现出与设计匹配的…

【STM32MP157应用编程】4.串口接收、发送数据

目录 串口文件 指令操作串口 程序操作串口 程序说明 程序代码 4_ChuanKou_2.c 启动交叉编译工具 编译 拷贝到开发板 测试 串口文件 在/dev目录下&#xff0c;存放了串口的文件。 文件名对应的串口ttySTM0CH340ttySTM1com2&#xff08;公头&#xff09;ttySTM2com1&a…

java版云HIS系统源码 微服务架构支持VUE

云his系统源码 一个好的HIS系统&#xff0c;要具有开放性&#xff0c;便于扩展升级&#xff0c;增加新的功能模块&#xff0c;支撑好医院的业务的拓展&#xff0c;而且可以反过来给医院赋能&#xff0c;最终向更多的患者提供更好地服务。 私信了解更多&#xff01; 本套基于…