编写MiniScript脚本语言-1

原创,转载请注明出处: @author zfzheng http://blog.csdn.net/redvalley

MiniScript脚本语言

起因:应老大需要,编写一种脚本语言。之所以不用groovy/javascript...等,因为我们需要其它特殊的功能,自己开发一个语言,则可最大限度地进行“定制”。自告奋勇编写(貌似其它人不在行这个 :D),也练练手。

要求功能

  1. 表达式赋值/计算
  2. 控制语句if/for/while/switch
  3. 变量可从java执行环境传入
  4. 支持对象方法调用
  5. 与java交互

实现步骤

  1. 定义文法
  2. 编写词法/语法分析器(javacc)
  3. JTB产生语法树
  4. 使用访问者模式执行脚本

完成,测试

做个简单的UI (测试传入变量则需要调用代码中编写)界面:

 编写MiniScript脚本语言-1_第1张图片

测试脚本执行java代码功能:编写MiniScript脚本语言-1_第2张图片

TODO

  • 变量范围控制
  • 控制台环境可调试
  • 支持函数

恐怕没这么多精力来继续了,目前够用就好。附上测试例子及javacc的jj文件

     /**
     * 执行脚本
     * 
@param  script
     * 
@param  varMap
     
*/
    
public   void  exec(String script,Map varMap){
        
try  {
            ScriptResult res 
=  MiniScriptEngine.exec(script, varMap);
            res.dumpVar();
        } 
catch  (Exception e) {
            e.printStackTrace();
        }
    }
    
    
/**
     * 测试方法
     * 
@param  hello
     * 
@return
     
*/
    
public  String hello(String hello){
        System.out.println(
" Call method hello: " + hello);
        
return   " [ " + hello + " ] " ;
    }
    
    
/**
     * 测试赋值语句
     *
     
*/
    
public   void  testAssign(){
        Map map
= new  HashMap();
        map.put(
" a " , new  Integer( 100 ));
        String s
= " a/=12; b='bb'; b+=a; System.out.println('OUT:a='+(++a)); " ;
        exec(s,map);
    }
    
    
/**
     * 测试条件语句
     *
     
*/
    
public   void  testIf(){
        Map map
= new  HashMap();
        map.put(
" a " , new  Integer( 1 ));
        String s
= " if(a>10){ System.out.println(a+'<10'); } else { System.out.println(a+'>=10'); } " ;
        s
+= " a=20; " + s;
        exec(s,map);
    }
    
    
/**
     * 测试函数调用
     *
     
*/
    
public   void  testFunction(){
        Map map
= new  HashMap();
        map.put(
" a " , " Hello,world! " );
        map.put(
" s " , new  MiniScriptSample());
        String s
= " s.hello(a); " ;
        exec(s,map);
    }
    
    
/**
     * 测试函数调用2
     *
     
*/
    
public   void  testFunction2(){
        Map map
= new  HashMap();
        map.put(
" a " , " Hello,world! " );
        map.put(
" s " , new  MiniScriptSample());
        String s
= " b=s.hello(a); System.err.println(b.substring(1,6)); " ;
        exec(s,map);
    }
    
    
public   void  testLoop(){
        Map map
= new  HashMap();
        map.put(
" a " , new  Integer( 12 ));
        String s
= " while(a-->0) System.out.println('############'.substring(0,a)); " ;
        exec(s,map);
        s
= " for(a=0;a<12;a++){  "   +
                
" for(b=0;b<2;b++){ "   +
                
" System.out.print('------------'.substring(0,b)); "   +
                
" "   +
                
" System.out.println('############'.substring(0,a)); "   +
                
" } " ;
        exec(s,map);        
    }
    
    
public   static   void  main(String[] args) {
        MiniScriptSample ss
= new  MiniScriptSample();
        ss.testLoop();
        
    }

 

/**
 * JavaCC file
 * 
@author  zfzheng
 
*/
 
options {
  JDK_VERSION 
=   " 1.4 " ;
  JAVA_UNICODE_ESCAPE 
=   true ;  
  STATIC
= false ;
    
// DEBUG_LOOKAHEAD=true;
//     DEBUG_PARSER=true;
//     DEBUG_TOKEN_MANAGER=true; 
}
PARSER_BEGIN(MiniScriptParser)
package  com.xxx.miniscript.parser;
import  com.xxx.miniscript.parser.syntaxtree. * ;
import  java.io.ByteArrayInputStream;
import  java.util.ArrayList;
import  java.util.List;

public   class  MiniScriptParser {
    
  
public  MiniScript parse() throws  Exception{
    
return  MiniScript();
  }  
  
  
public  MiniScriptParser(String s) throws  Exception{
    
this ( new  ByteArrayInputStream(s.getBytes()));
  }

}

PARSER_END(MiniScriptParser)

SKIP :
{
   
"   "
   
|   " "
   
|   " "
   
|   " "
   
|   " "
}

SPECIAL_TOKEN :
{
   
< #SINGLE_LINE_COMMENT:  " // "  ( ~ [ " " " " ]) *  ( " "   |   " "   |   " " ) >
   
|   < #FORMAL_COMMENT:  " /** "  ( ~ [ " * " ]) *   " * "  ( " * "   |  ( ~ [ " * " " / " ] ( ~ [ " * " ]) *   " * " )) *   " / " >
   
|   < #MULTI_LINE_COMMENT:  " /* "  ( ~ [ " * " ]) *   " * "  ( " * "   |  ( ~ [ " * " " / " ] ( ~ [ " * " ]) *   " * " )) *   " / " >
   
|< COMMENT: ( < SINGLE_LINE_COMMENT > ) | ( < FORMAL_COMMENT > ) | ( < MULTI_LINE_COMMENT > >
}

TOKEN :
{
    
< TRUE:  " true " >
|      < FALSE:  " false " >
|      < IF:  " if " >
|      < ELSE:  " else " >
|      < FOR:  " for " >
|      < WHILE:  " while " >
|      < DO:  " do " >
|      < SWITCH:  " switch " >
|      < CASE:  " case " >
|      < DEFAULT_TOKEN:  " default " >
|      < BREAK:  " break " >
|      < CONTINUE:  " continue " >
|      < EXIT:  " exit " >
|      < NULL:  " null " >
}

TOKEN :
{
   
< LPAREN:  " ( " >
   
|   < RPAREN:  " ) " >
   
|   < LBRACE:  " { " >
   
|   < RBRACE:  " } " >
   
|   < LBRACKET:  " [ " >
   
|   < RBRACKET:  " ] " >
   
|   < SEMICOLON:  " ; " >
   
|   < COMMA:  " , " >
   
|   < DOT:  " . " >
}

TOKEN :
{
   
< ASSIGN:  " = " >
   
|   < GT:  " > " >
   
|   < LT:  " < " >
   
|   < BANG:  " ! " >
   
|   < TILDE:  " ~ " >
   
|   < HOOK:  " ? " >
   
|   < COLON:  " : " >
   
|   < EQ:  " == " >
   
|   < LE:  " <= " >
   
|   < GE:  " >= " >
   
|   < NE:  " != " >
   
|   < SC_OR:  " || " >
   
|   < SC_AND:  " && " >
   
|   < INCR:  " ++ " >
   
|   < DECR:  " -- " >
   
|   < PLUS:  " + " >
   
|   < MINUS:  " - " >
   
|   < STAR:  " * " >
   
|   < SLASH:  " / " >
   
|   < BIT_AND:  " & " >
   
|   < BIT_OR:  " | " >
   
|   < XOR:  " ^ " >
   
|   < REM:  " % " >
   
|   < LSHIFT:  " << " >
   
|   < RSIGNEDSHIFT:  " >> " >
   
|   < RUNSIGNEDSHIFT:  " >>> " >
   
|   < PLUSASSIGN:  " += " >
   
|   < MINUSASSIGN:  " -= " >
   
|   < STARASSIGN:  " *= " >
   
|   < SLASHASSIGN:  " /= " >
   
|   < ANDASSIGN:  " &= " >
   
|   < ORASSIGN:  " |= " >
   
|   < XORASSIGN:  " ^= " >
   
|   < REMASSIGN:  " %= " >
   
|   < LSHIFTASSIGN:  " <<= " >
   
|   < RSIGNEDSHIFTASSIGN:  " >>= " >
   
|   < RUNSIGNEDSHIFTASSIGN:  " >>>= " >
}

TOKEN :
{
   
< #LETTER: [ " $ " " A " - " Z " " _ " " a " - " z " " À " - " Ö " " Ø " - " ö " " ø " - " ÿ " " Ā " - " ῿ " " " - " " " " - " " " " - " " " " - " 鿿 " " " - " 﫿 " ] >
//    <#LETTER: ["A"-"Z", "_", "a"-"z", "À"-"Ö", "Ø"-"ö", "ø"-"ÿ", "Ā"-"῿", "぀"-"㆏", "㌀"-"㍿", "㐀"-"㴭", "一"-"鿿", "豈"-"﫿"]>
    |   < #DIGIT: [ " 0 " - " 9 " " ٠ " - " ٩ " " ۰ " - " ۹ " " " - " " " " - " " " " - " " " " - " " " " - " " " " - " " " " - " " " " - " " " " - " " " " - " " " " - " " " " - " " ] >
}


TOKEN :
{
   
< IDENTIFIER:  < LETTER >  ( < LETTER >   |   < DIGIT > ) *   >
}
        
TOKEN :
{
   
< INTEGER_LITERAL:  < DECIMAL_LITERAL >  ([ " l " " L " ]) ?   |   < HEX_LITERAL >  ([ " l " " L " ]) ?   |   < OCTAL_LITERAL >  ([ " l " " L " ]) ?>
   
|   < #DECIMAL_LITERAL: [ " 1 " - " 9 " ] ([ " 0 " - " 9 " ]) *>
   
|   < #HEX_LITERAL:  " 0 "  [ " x " " X " ] ([ " 0 " - " 9 " " a " - " f " " A " - " F " ]) +>
   
|   < #OCTAL_LITERAL:  " 0 "  ([ " 0 " - " 7 " ]) *>
   
|   < FLOATING_POINT_LITERAL: ([ " 0 " - " 9 " ]) +   " . "  ([ " 0 " - " 9 " ]) *  ( < EXPONENT > ) ?  ([ " f " " F " " d " " D " ]) ?   |   " . "  ([ " 0 " - " 9 " ]) +  ( < EXPONENT > ) ?  ([ " f " " F " " d " " D " ]) ?   |  ([ " 0 " - " 9 " ]) +   < EXPONENT >  ([ " f " " F " " d " " D " ]) ?   |  ([ " 0 " - " 9 " ]) +  ( < EXPONENT > ) ?  [ " f " " F " " d " " D " ] >
   
|   < #EXPONENT: [ " e " " E " ] ([ " + " " - " ]) ?  ([ " 0 " - " 9 " ]) +>
   
|   < CHARACTER_LITERAL:  " ' "  (( ~ [ " ' " " / " " " " " ])  |  ( " / "  ([ " n " " t " " b " " r " " f " " / " " ' " " " " |  [ " 0 " - " 7 " ] ([ " 0 " - " 7 " ]) ?   |  [ " 0 " - " 3 " ] [ " 0 " - " 7 " ] [ " 0 " - " 7 " ])))  " ' " >
   
|   < STRING_LITERAL1:  " " "  (( ~ [ " " " " / " " " " " ])  |  ( " / "  ([ " n " " t " " b " " r " " f " " / " " ' " " " " |  [ " 0 " - " 7 " ] ([ " 0 " - " 7 " ]) ?   |  [ " 0 " - " 3 " ] [ " 0 " - " 7 " ] [ " 0 " - " 7 " ]))) *   " " " >  
   
|   < STRING_LITERAL2:  " ' "  (( ~ [ " ' " " / " " " " " ])  |  ( " / "  ([ " n " " t " " b " " r " " f " " / " " ' " " " " |  [ " 0 " - " 7 " ] ([ " 0 " - " 7 " ]) ?   |  [ " 0 " - " 3 " ] [ " 0 " - " 7 " ] [ " 0 " - " 7 " ]))) *   " ' " >     
}
    


void  MiniScript():{}
{
    (Statement())
*
}

void  Statement() : {}
{
    Block()
    
|
    EmptyStatement()
    
|
    IfStatement()    
    
|
    ForStatement()
    
|
    WhileStatement1()
    
|
    WhileStatement2()
    
|
    SwitchStatement()    
    
|
    BreakStatement()
    
|
    ContinueStatement()
    
|
    ExitStatement()
    
|
    StatementExpression()
}

void  Block() : {}
{
    
" { "
    (Statement())
*
    
" } "
}

void  EmptyStatement() : {}
{
    
" ; "
}

void  IfStatement() : {}
{
    
" if "   " ( "  Expression()  " ) "
    Statement()(EmptyStatement())
?
    (
        
" else "  Statement()(EmptyStatement()) ?
    )
?
}

void  ForStatement():{}
{
    
" for "   " ( "  (Expression()) ?  EmptyStatement() Expression() EmptyStatement() (Expression()) ?   " ) "
    Statement()(EmptyStatement())
?
}

void  WhileStatement1() : {}
{
    
" while "   " ( "  Expression()  " ) "
    Statement()(EmptyStatement())
?
}

void  WhileStatement2() : {}
{
    
" do "
    Statement()(EmptyStatement())
?
    
" while "   " ( "  Expression()  " ) " EmptyStatement()
}

void  SwitchStatement():{}
{
    
" switch "   " ( "  Expression()  " ) "
    
" { "
        (
            SwitchLabel()
            (Statement()(EmptyStatement())
? ) *
        )
*
    
" } "
    
}

void  SwitchLabel():{}
{
    (
" case "  Expression()  " : " )
    
|
    (
" default "   " : " )
}

void  BreakStatement() : {}
{
    
" break " EmptyStatement()
}
void  ContinueStatement() : {}
{
    
" continue " EmptyStatement()
}

void  ExitStatement() : {}
{
    
" exit " EmptyStatement()
}

void  StatementExpression() : {}
{
    PreIncrementExpression()
    
|
    PreDecrementExpression()
    
|
    LOOKAHEAD(PrimaryExpression() AssignmentOperator())
    Assignment()
    
|
    PostfixExpression()

}

void  Assignment():{}{    
    PrimaryExpression()
    AssignmentOperator()
    Expression()
}

void  PreIncrementExpression() :{}
{
    
" ++ "  PrimaryExpression()
}

void  PreDecrementExpression() :{}
{
    
" -- "  PrimaryExpression()
}

void  PrimaryExpression() :{}
{
    PrimaryPrefix()
    (
        PrimarySuffix()
    )
*
}

void  PrimaryPrefix():{}
{
    
        Literal()
    
|
        PrimaryVariable()
//     |
//         PrimarySystemObject()
     |
        (
" ( " Expression() " ) " )
}

void  PrimaryVariable():{}{
//     "$"<IDENTIFIER>
     < IDENTIFIER >
}

// void PrimarySystemObject():{}{
//     "#"<IDENTIFIER>
// }

void  PrimarySuffix():{}{
        (
" . " < IDENTIFIER > )
    
|
        Arguments()
}


Literal Literal() :{}
{
        IntegerLiteral()
    
|     FloatLiteral()
    
|     CharacterLiteral()
    
|     StringLiteral()
    
|     BooleanLiteral()
    
|     NullLiteral()
}

void  IntegerLiteral():{}
{
    
< INTEGER_LITERAL >
}

void  FloatLiteral():{}
{
    
< FLOATING_POINT_LITERAL >  
}

void  CharacterLiteral():{}
{
    
< CHARACTER_LITERAL >  
}

void  StringLiteral():{}
{
    
< STRING_LITERAL1 >   |< STRING_LITERAL2 >
}

void  BooleanLiteral():{}{
    
" true " | " false "
}

void  NullLiteral():{}{
    
" null "
}

void  Arguments() :{}
{
    LOOKAHEAD(
" ( "" ) " )( " ( "" ) " )    
    
| ( " ( " ArgumentList() " ) " )

}

void  ArgumentList() :{}
{
    (
        Expression()(
" , " Expression()) *
    )
}

void  AssignmentOperator() :{}
{
    
" = " | " += " | " -= " | " *= " | " /= " | " %= " | " &= " | " |= " | " ^= " | " >>= " | " <<= " | " >>>= "
}

void  PostfixExpression() :{}
{
    PrimaryExpression() (
" ++ " | " -- " ) ?
}

void  Expression() : {}
{    
   (
      LOOKAHEAD(PrimaryExpression() AssignmentOperator())
        Assignment()    
   
|
        ConditionalExpression()
    )
}

void  ConditionalExpression() :{}
{
    ConditionalOrExpression()
   (
      
" ? "
      Expression()
      
" : "
      ConditionalExpression()
   )
?    
}

void  ConditionalOrExpression() :{}
{
    ConditionalAndExpression()
    (
    
" || "
    ConditionalAndExpression()   
    )
*
}


void  ConditionalAndExpression() :{}
{
    InclusiveOrExpression()
    (
    
" && "
    InclusiveOrExpression()   
    )
*
}

void  InclusiveOrExpression() :{}
{
    ExclusiveOrExpression()
    (
    
" | "
    ExclusiveOrExpression()   
    )
*
}


void  ExclusiveOrExpression() :{}
{
    AndExpression()
    (
    
" ^ "
    AndExpression()   
    )
*
}

void  AndExpression() :{}
{
    EqualityExpression()
    (
    
" & "
    EqualityExpression()   
    )
*
}


void  EqualityExpression() :{}
{
    RelationalExpression()
    (
    (
" == " | " != " )
    RelationalExpression()
    )
*
}


void  RelationalExpression() :{}
{
    ShiftExpression()
    (
    (
" > " | " < " | " >= " | " <= " )
    ShiftExpression()   
    )
*
}

void  ShiftExpression() :{}
{
    AdditiveExpression()
    (
    (
" >> " | " << " | " >>> " )
    AdditiveExpression()   
    )
*
}

void  AdditiveExpression() :{}
{
    MultiplicativeExpression()(
    (
" + " | " - " )
    MultiplicativeExpression()   
    )
*
}


void  MultiplicativeExpression() :{}
{
    UnaryExpression()
    (
    (
" * " | " / " | " % " )
    UnaryExpression() 
    )
*   
}


void  UnaryExpression() :{}
{
    ((
" + " | " - " )UnaryExpression())
    
|
        PreIncrementExpression()      
    
|
        PreDecrementExpression()
    
|
        UnaryExpressionNotPlusMinus()   
}

void  UnaryExpressionNotPlusMinus():{}
{
    ((
" ~ " | " ! " )UnaryExpression())
    
|
    PostfixExpression()
}






编写过程小记:

  • switch case处理起来比较麻烦
  • 写一个语言,除了脑力也是一种体力活动,基本的赋值、运算语句处理好了,加一些语法还是比较轻松一点。
  • 前后大概花了4个工作日,现在感觉很累很累,不过很高兴基本写好了,也很好用。

 

你可能感兴趣的:(HashMap,脚本,测试,Integer,语言,token)