手把手开发一门程序语言JimLang

Posted 麒思妙想

tags:

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

根据爱因斯坦的相对论,物体的质量越大,时间过得越快,所以托更对于我的煎熬,远远比你们想象的还要痛苦…今天给大家来盘硬菜,也是前些时日预告过的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肝了4.5万字,手把手带你玩转JavaScript(建议收藏)

肝了4.5万字,手把手带你玩转JavaScript(建议收藏)

10分钟学会Less开发环境搭建与初体验

Java开发四年的程序员想再学习一门语言,该选着C还是Python呢?

Python的基础教程,比PHPGO等前景好的一门开发语言!

用 C 语言开发一门编程语言 — Lispy 编程演示