我也能写编程语言(一)

本文介绍了使用ANTLR构建的MyLang语言的函数解析过程,通过MLVistor和Symbol类实现了函数声明、调用和栈帧。作者以《操作系统》中的状态机概念为灵感,展示了如何优雅地设计函数调用的实现。测试示例展示了`foo`和`bar`函数的调用行为。
摘要由CSDN通过智能技术生成

在这里插入图片描述

在写函数的实现时候,一直很迷茫,感觉不够优雅,直到听了南大的《操作系统》,程序就是状态机,方法调研就是引用计数++,函数返回就是弹栈,才豁然开朗,也让我鉴定了开一个系列坑,这里我打算实现一门开发语言。

今天我们先来实现函数一个简单的函数调用

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);
    }
}

测试结果

在这里插入图片描述

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

  • 16
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 15
    评论
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

麒思妙想

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

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

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

打赏作者

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

抵扣说明:

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

余额充值