Skip to content

one fully script Interpreter use flex and bison

Notifications You must be signed in to change notification settings

Clivebi/onescript

Repository files navigation

项目说明

这个是一个基于flex和bison实现的脚本解析执行引擎,实现了常见大部分的脚本语法规则。语法上满足基本的脚本实现的需求。有如下一些特点:

  1. 支持变量作用域和生命周期自动化管理。
  2. 支持资源的生命周期管理,例如文件句柄生命周期。
  3. 解析和执行分开,解析的中间结果可以方便序列化和反序列化。
  4. 较为通用的项目框架,可以基于这很方便实现自己的私有脚本引擎。

内建支持

字符串处理 tcp(tls) http(https)客户端实现 json 编码 解码(基于flex和bison实现)

基本语法

值类型
string - 字符串
integer- 整数
float - 双精度浮点
array - 数组(数组可存储所有值类型)
map - 字典
nil - nil值
bytes - 无符号字符串
function - 函数,函数作为第一类值,可以赋值给变量,传递给函数
resource - 系统资源,例如文件句柄

变量定义

var name1,name2,name3="1234";
这里name1,name2被初始化成NULL值

赋值时自动定义

name4 = 128;这种情况,只有上下文中中不存在name4变量的时候才会创建变量,如果存在就是赋值语句  

变量作用域
变量有3种作用域 文件作用域 函数作用域 局部作用域(for,for-in switch 语句) 离开作用域,变量自动销毁

var name5; #文件作用域
func do_something(a,b){
    var name5; #顶层的name5被屏蔽
    for(var i =0;i < 10;i++){
        var name5;#顶层的name5、函数内变量name5被屏蔽
    }
}

语法
支持大部分现代脚本的控制结构
赋值 = += -= *= /= |= &= ^= >>= <<=   基本算术运算 + - * / %(整数求余)
整数位运算 & | ^ ~ >> <<
逻辑运算 || && > >= < <= == !=   条件判断语句 if else 语法
循环语法 for
switch语法
数组/bytes和字典迭代 for ... in ...
数组/bytes切片 a=b[2:] ;a=b[1:4];a=b[:10];
支持自定义函数、内置函数

语法示例


#test help function

Println(VMEnv());
Println(GetAvaliableFunction());
var _is_test_passed = true;
func assertEqual(a,b){
    if(a != b){
        Println("error here a=",a,"b=",b);
        _is_test_passed = false;
    }
}

func assertNotEqual(a,b){
    if(a == b){
        Println("error here a=",a,"b=",b);
        _is_test_passed = false;
    } 
}

#basic arithmetic operation

assertEqual(1+1+2,4);
assertEqual(1+(1+2),4);
assertEqual(1+2*4,9);
assertEqual(4*(1+2),12);
assertEqual(4*5/5,4);
assertEqual(0-1000,-1000);
assertEqual(5*(-10),-50);
assertNotEqual(nil,false);
assertNotEqual(true,nil);
assertNotEqual(true,false);
func test_basic_convert(){
    var i = 100,f = 3.1415;
    var res = i+f;
    assertEqual(typeof(i),"integer");
    assertEqual(typeof(f),"float");

    #float + integer = float
    assertEqual(typeof(res),"float");

    #integer+=float  result as Integer
    i += 4.6;
    assertEqual(typeof(i),"integer");

    #convert string to bytes
    var buf = bytes("hello");
    var buf2 = bytes("world");

    assertEqual(typeof(buf),"bytes");
    assertEqual(typeof(buf2),"bytes");

    #convert Integer array to bytes
    var buf3 = bytes(0x68,0x65,0x6C,0x6C,0x6F);
    var buf4 = bytes([0x77,0x6F,0x72,0x6C,0x64]);

    assertEqual(typeof(buf3),"bytes");
    assertEqual(typeof(buf4),"bytes");
    assertEqual(buf,buf3);
    assertEqual(buf2,buf4);

    #convert hex string to bytes
    var buf5= HexDecodeString("68656C6C6F20776F726C64");
    var buf6= append(buf,0x20,buf4);

    assertEqual(buf5,buf6);
    Println(buf6);

    #convert bytes to string 
    var strTemp = string(buf5);
    assertEqual(typeof(strTemp),"string");

    var str1 = string(0x68,0x65,0x6C,0x6C,0x6F);
    assertEqual(typeof(str1),"string");
    var str2 = string([0x77,0x6F,0x72,0x6C,0x64]);
    assertEqual(typeof(str2),"string");
    var str3 = str1 + " " +str2;
    assertEqual(str3,string(buf5));
    assertEqual(str1[0],'h');
    
    #convert string to integer & float
    assertEqual(ToInteger("0xEEFFFF"),0xEEFFFF);
    assertEqual(ToInteger("8000"),8000);
    assertEqual(ToFloat("3.1415"),3.1415);
    assertEqual(ToFloat("3"),3.0);
    assertEqual(ToString(1000),"1000");
    assertEqual(ToString(3.14),ToString(ToFloat("3.14")));
    assertEqual(HexEncode(0xEEFFBB),"EEFFBB");
}

test_basic_convert();

func asciiCodeToChar(code){
    var test = bytes();
    test = append(test,code);
    return string(test);
}

assertEqual(asciiCodeToChar('A'),"A");

func test_bitwise_operation(){
    assertEqual(0xFFEE & 0xFF,0xEE);
    assertEqual(0xFF00 | 0xFF,0xFFFF);
    assertEqual(0xFF ^ 0x00,0xFF);
    assertEqual(0xFF54>>8,0xFF);
    assertEqual(0xFF54<<8,0xFF5400);
    assertEqual(true || false,true);
    assertEqual(false || true,true);
    assertEqual(false && true,false);
    assertEqual(true && false,false);
    assertEqual(true && true,true);
}

test_bitwise_operation();


func test_loop(){
    var j =0,k=0;
    for (var i = 0;i< 9;i++){
        j++;
        k++;
    }
    assertEqual(j,9);
    assertEqual(k,9);

    j=0;
    k=0;
    for (var i = 0;i< 9;i++){
        j++;
       if(!(i%2)){
           k++;
       }
    }
    assertEqual(k,5);
    assertEqual(j,9);
    j=0;
    k=0;
    for (var i = 0;i< 9;i++){
        j++;
        if(i > 5){
            continue;
        }
        k++;
    }
    assertEqual(k,6);
    assertEqual(j,9);

    j=0;
    k=0;
    for (var i = 0;i< 20;i++){
        j++;
        if(i >= 8){
            break;
        }
        k++;
    }
    assertEqual(k,8);
    assertEqual(j,9);

    j=0;
    k=0;
    for{
        j++;
        k++;
        if(j > 8){
            break;
        }
    }
    #empty body
    for(var i =0;i<3;i++){

    }
    assertEqual(k,9);
    assertEqual(j,9);
}

test_loop();

func test_shadow_name(name1){
    var name2 = name1;
    for(var name2 =0; name2< 3;name2++){
    }
    for(var i =0; i< 3;i++){
        name2++;
    }
    assertNotEqual(name1,name2);
}

test_shadow_name(100);

func test_array_map(){
    var list = ["hello"," ","world"];
    assertEqual(typeof(list),"array");
    assertEqual(len(list),3);
    assertEqual(list[0],"hello");
    list = append(list,"script");
    assertEqual(len(list),4);
    assertEqual(list[3],"script");
    list = append(list,100);
    assertEqual(len(list),5);
    assertEqual(typeof(list[4]),"integer");

    var sub = list[2:];
    assertEqual(sub[0],"world");
    assertEqual(len(sub),3);
    
    sub = list[2:4];
    assertEqual(len(sub),2);
    assertEqual(sub[0],"world");
    assertEqual(sub[1],"script");
    var _dirs = ["/bin/","/usr/bin/","/usr/local/bin/"];
    var _files = ["test1","test2","test3"];
    var _full_paths = [];
    var full;
    for v in _dirs{
        for v2 in _files{
         _full_paths = append(_full_paths, v+v2);
        }
    }
    assertEqual(len(_full_paths),len(_dirs)*len(_files));

    var dic = {"accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
     "accept-encoding":"gzip, deflate, br",
     "referer":"https://www.google.com/",
     "accpet-languare":"zh-CN,zh;q=0.9,en;q=0.8",
     "X":1000
    };
    
    dic[800]= "800";

    assertEqual(typeof(dic),"map");
    assertEqual(len(dic),6);
    assertEqual(dic["X"],1000);
    dic["800"]= "800";
    assertEqual(dic["800"],"800");
    assertEqual(dic["accept-encoding"],"gzip, deflate, br");

    var dic2 ={100:"100",200:"200",300:"300",400:"400",3.14:3.1415926};
    assertEqual(dic2[100],"100");
    assertEqual(dic2[3.14],3.1415926);
}

func map_test_ex(){
    var dic = {};
    var dic2 = {"name":"wawa","type":"aaaa",100:"459","100":"900"};
    dic["test"] = dic2;
    assertEqual(dic2[100],"459");
    assertEqual(dic2["100"],"900");
    dic2[3.1415926]= "pi";
    Println(dic2);
    Println(dic);
}
map_test_ex();

test_array_map();

# ByteOrder test

func reverse_bytes(blob){
    var result = bytes();
    for(var i = len(blob)-1;i>=0;i--){
        result += blob[i];
    }
    return result;
}

assertEqual(reverse_bytes(bytes(0x01,0x2,0x03,0x4)),bytes(0x04,0x03,0x02,0x1));

#0xFFAABBCC -> 0xCCBBAAFF
func Swap32(val){
    var a = (val&0xFF),b=(val>>8)&0xFF,c=(val>>16)&0xFF,d=(val>>24)&0xFF;
    return (a <<24)|(b<<16)|(c<<8)|d;
}

#0xFFAA -> 0xAAFF
func Swap16(val){
    var a = (val&0xFF),b=(val>>8)&0xFF;
    return (a<<8)|b;
}

#0xFFEEDDCCBBAA9988->0x8899AABBCCDDEEFF
func Swap64(val){
    var a = (val&0xFF),b=(val>>8)&0xFF,c=(val>>16)&0xFF,d=(val>>24)&0xFF;
    var e =(val>>32)&0xFF,f =(val>>40)&0xFF,g =(val>>48)&0xFF,h =(val>>56)&0xFF;
    return (a <<56)|(b<<48)|(c<<40)|(d<<32)|(e<<24)|(f<<16)|(g<<8)|h; 
}

func IsBigEndianOS(){
    var env = VMEnv();
    return env["ByteOrder"] == "BigEndian";
}

func AppendUInt32ToBuffer(buf,val,isBigEndian){
    if(isBigEndian){
        return append(buf,(val>>24)&0xFF,(val>>16)&0xFF,(val>>8)&0xFF,val&0xFF);
    }
    return append(buf,(val)&0xFF,(val>>8)&0xFF,(val>>16)&0xFF,(val>>24)&0xFF);
}

func ReadUInt32FromBuffer(buf,isBigEndian){
    var val ;
    if(isBigEndian){
        val = ((buf[0]&0xFF)<<24)|((buf[1]&0xFF)<<16) |((buf[2]&0xFF)<<8) |buf[3]&0xFF;
    }else{
        val = ((buf[3]&0xFF)<<24)|((buf[2]&0xFF)<<16) |((buf[1]&0xFF)<<8) |buf[0]&0xFF;
    }
    return val &0xFFFFFFFF;
}

func AppendUInt16ToBuffer(buf,val,isBigEndian){
    if(isBigEndian){
        return append(buf,(val>>8)&0xFF,val&0xFF);
    }
    return append(buf,(val)&0xFF,(val>>8)&0xFF);
}

func ReadUInt16FromBuffer(buf,isBigEndian){
    var val ;
    if(isBigEndian){
        val = ((buf[0]&0xFF)<<8) |buf[1]&0xFF;
    }else{
        val = ((buf[1]&0xFF)<<8) |buf[0]&0xFF;
    }
    return val&0xFFFF;
}

func test_bin_pack(){
    var val32 = 0xFFEECCDD,val16 = 0xFFEE;
    buf = bytes();
    buf = AppendUInt32ToBuffer(buf,val32,true);
    assertEqual(buf[0]&0xFF,0xFF);
    assertEqual(buf[1]&0xFF,0xEE);
    assertEqual(ReadUInt32FromBuffer(buf,true),val32);
    buf = bytes();
    buf = AppendUInt16ToBuffer(buf,val16,true);
    assertEqual(buf[0]&0xFF,0xFF);
    assertEqual(buf[1]&0xFF,0xEE);
    assertEqual(ReadUInt16FromBuffer(buf,true),val16);
    assertEqual(Swap32(val32),0xDDCCEEFF);
}

test_bin_pack();

func byteslib_test(){
    var str = "!!! hello world !!!!!";
    result = TrimString(str,"! ");
    assertEqual(result,"hello world");
    result = TrimLeftString(str,"! ");
    assertEqual(result,"hello world !!!!!");
    result = TrimRightString(str,"! ");
    assertEqual(result,"!!! hello world");
    assertEqual(ContainsString(str,"hello"),true);
    assertEqual(IndexString(str,"hello"),4);
    assertEqual(IndexString(str,"helloW"),-1);
    assertEqual(LastIndexString(str,"o"),11);
    assertEqual(ReplaceAllString(str,"!!! ",""),"hello world !!!!!");
    assertEqual(ReplaceString(str,"!","",3)," hello world !!!!!");
    assertEqual(ReplaceString(str,"!","",-1),ReplaceAllString(str,"!",""));
    var list = RepeatString("hello ",5);
    var list_array = SplitString(TrimString(list," ")," ");
    assertEqual(len(list_array),5);
    for v in list_array{
        assertEqual(v,"hello");
    }
    assertEqual(ToLowerString("heLLo"),"hello");
    assertEqual(ToUpperString("heLLo"),"HELLO");
    assertEqual(HasPrefixString(str,"!!! X"),false);
    assertEqual(HasSuffixString(str," !!!!!"),true);
    assertEqual(HasPrefixString(str,"!!! "),true);
    assertEqual(HasSuffixString(str," X!!!!!"),false);
}

byteslib_test();

if(_is_test_passed){
    Println("all test passed");
}else{
    Println("some test not passed");
}

var log =Println;

log("hello"," world!");

var func2 = func(a,b){
    Println(a,b);
};

func2("text1","text2");


参考

https://github.com/stdpain/compiler-interpreter

About

one fully script Interpreter use flex and bison

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published