我也能写编程语言

Posted 麒思妙想

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我也能写编程语言相关的知识,希望对你有一定的参考价值。

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

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

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


测试结果

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

以上是关于我也能写编程语言的主要内容,如果未能解决你的问题,请参考以下文章

我也能写编程语言

我也能写编程语言

转载不会编程也能写爬虫?可视化爬虫工具是什么东东

没有基础也能写个小程序

没有基础也能写个小程序

我作了首诗,保你闭着眼睛也能写对二分查找