更新至版本1.1
此外,SRC源文件与命令文档结构类似,所以为命令编写的SRC测试源文件,可以直接作为命令解释文档使用。甚至SRC源文件拥有比一般命令文档更多、更准确的信息,例如采用的连接类型、字节序约定、加密协议、HTTP包装等等,因为这些都是SRC源代码里必须明确指定的信息。
SRC源代码结构
SRC的源代码主要包括:变量声明,函数调用,和命令结构。下面是一个简单的例子:
STR server_ip := "127.0.0.1" //变量声明
U16 server_port := 9527
TCP conn(server_ip,server_port)
NET_BYTE_ORDER //函数调用
COMMAND QueryCommand //命令结构
SEND(conn)
U16 ver := 100
U16 cmd_type := 161
U32 seq := 1234
U32 len
BEGIN(len)
STR file_hash := "http://www.google.com"
STR client_hash := UNHEX("1A2B3C4D5E6F")
STR peer_id := "ABCDEF1234567890"
END COMMAND
上面的SRC代码定义了一个名为“QueryCommand”的命令结构,并准备发送给本机的9531端口。
数据类型
SRC语言支持的基本数据类型有:
分类 | 关键字 | 字节数 | 意义 |
数值类型 | U8 | 1 | 无符号8位整数 |
S8 | 1 | 有符号8位整数 | |
U16 | 2 | 无符号16位整数 | |
S16 | 2 | 有符号16位整数 | |
U32 | 4 | 无符号32位整数 | |
S32 | 4 | 有符号32位整数 | |
U64 | 8 | 无符号64位整数 | |
S64 | 8 | 有符号64位整数 | |
字符串类型 | STR | 可变 | 字符串 |
RAW | 可变 | 字符串 | |
网络连接类型 | TCP | N/A | TCP连接 |
UDP | N/A | UDP连接 |
表 1 基本数据类型
数值类型的变量,编码和解码时直接写入和读取真正的数据。
STR类型的变量,编码时首先写入U32类型的长度字段,然后写入真正的数据;在解码时,STR类型的变量首先读取U32类型的长度,然后读取真正的数据;
RAW类型的变量,编码时直接写入真正的数据;在解码时,RAW类型的变量直接读取真正的数据,但是必须和其他条件配合才能确定读取的结束位置。
TCP和UDP属于网络连接类型,不能被编码或解码,
函数调用
在SRC语言里,函数调用的格式为:
FUNCTION ( arg_list )
FUNCTION
其中,FUNCTION可以是任意内置函数,或者是任意数据类型关键字。arg_list是用‘,’分隔的参数列表,可以为空。对于内置函数,当参数列表为空的时候,可以省略‘(’和‘)’。
内置函数
SRC语言提供了如下的内置函数:
l HBO或HOST_BYTE_ORDER
参数:无
意义:设置以本地字节序编码或解码
说明:由于HBO函数没有参数,调用时采用下面2种形式均可:
HBO
HBO()
HOST_BYTE_ORDER
HOST_BYTE_ORDER()
l NBO或NET_BYTE_ORDER
参数:无
意义:设置以网络字节序编码或解码
说明:由于NBO函数没有参数,调用时采用下面2种形式均可:
NBO
NBO()
NET_BYTE_ORDER
NET_BYTE_ORDER()
在默认情况下,SRC编译器采用网络字节序进行编码和解码。
l HEX
参数:字符串
意义:将参数字符串的每个字符以16进制表示生成新字符串,作为函数的返回值
说明:采用如下方式调用:
STR hex_1 = HEX(“abc”) // hex_1 = “616263”
l UNHEX
参数:字符串
意义:将参数字符串的每2个字符作为16进制数值,生成新字符串,作为函数的返回值
说明:要求参数字符串为连续的16进制字符(0-9,A-F,a-f),例如:
STR origin = UNHEX(“616263”) // origin = “abc”
l SEND
参数:若干连接变量(TCP或UDP)
意义:将命令发送给指定的连接
说明:如果SEND函数没有参数,那么编译器会选择整个源文件里定义的第一个连接变量作为参数。SEND函数的参数个数没有限制,如果参数里有重复的连接变量,那么同一个命令会多次发送给这个连接。调用示例:
SEND // 自动选择第一个连接变量作为参数
SEND()
SEND(conn1,conn2,…)
l RECV
参数:若干连接变量(TCP或UDP)
意义:从指定的连接接收命令
说明:如果RECV函数没有参数,那么编译器会选择整个源文件里定义的第一个连接变量作为参数。虽然从语法上,RECV函数的参数个数没有限制,但运行时只从RECV函数的第一个参数接收命令,这是目前编译器的实现限制。调用示例:
RECV // 自动选择第一个连接变量作为参数
RECV()
RECV(conn1,conn2,…) // 运行时只从conn1接收命令
l BEGIN
参数:1个或以上的变量名
意义:为计算数据段长度的变量指定起始偏移位置
说明:在命令里总有一些字段表示某个数据段的长度。在数据段开始的地方,调用BEGIN函数,并传入记录该数据段长度的变量的名字。
BEGIN函数的参数必须是变量名,并且这些变量必须是数值类型的(Uxx或Sxx)。调用示例:
U32 body_len
BEGIN(body_len)
l END
参数:1个或以上的变量名
意义:为计算数据段长度的变量指定结束偏移位置
说明:在数据段结束的地方,调用END函数,并传入记录该数据段长度的变量的名字。END函数应该与BEGIN函数成对出现,并且END函数的位置应在后面。在一个命令结构结束的时候,如果存在调用了BEGIN函数却没有调用END函数的变量,编译器会自动为其调用END函数,位置就是整个命令的结尾。
END函数的参数必须是变量名,并且这些变量必须是数值类型的(Uxx或Sxx)。调用示例:
U32 body_len
BEGIN(body_len)
…… // 任意字段
END(body_len)
l FUN或FUNCTION
参数:自定义函数名字 + 长度数值
意义:对命令数据调用指定的用户自定义函数
说明:有些命令除了写入所有字段,还需要进行一些特殊处理,比如加密、计算校验码等等;同样,有些命令除了读取所有字段,需要进行上述操作的逆处理。SRC语言没有从语法上支持这些复杂的操作,但是允许用户对命令数据进行自定义的操作,方式就是通过FUN函数调用。调用示例:
FUN(my_encrypt_fun)
FUN(my_decrypt_fun,30) //保证后续至少有30字节数据的前提下调用指定函数
l IP NBO
参数:1个字符串或1个数值
意义:把参数字符串表示的IPv4地址转化为网络字节序的U32数值;或者将网络字节序的U32数值转化成为IPv4字符串
说明:注意这里是2个关键字组合起来,表示一个函数。采用如下方式调用:
STR ip_str = IP NBO(0x505AA8C0) // ip_str = “192.168.90.80”
STR ip_val = IP NBO(“192.168.90.80”) // ip_val = 0x505AA8C0
l IP HBO
参数:1个字符串或1个数值
意义:把参数字符串表示的IPv4地址转化为本地字节序的U32数值;或者将本地字节序的U32数值转化成为IPv4字符串
说明:同上面一样,这里是2个关键字组合起来,表示一个函数。采用如下方式调用:
STR ip_str = IP HBO(0xC0A85A50) // ip_str = “192.168.90.80”
U32 ip_val = IP HBO(“192.168.90.80”) // ip_val = 0xC0A85A50
l PRINT
参数:1个或以上的可打印变量
意义:在标准输出打印指定的内容
说明:可用于在代码任何地方,打印出任何信息,包括调试信息,提示信息,等等。PRINT函数要求至少有一个参数,没有上限。目前,所有SRC语言的基本类型都是可打印的。调用示例:
U32 val = 100
STR str = “Hello”
TCP conn(“127.0.0.1”,9531)
PRINT(“val = “,val)
PRINT(“str = “,str)
PRINT(“conn = “,conn)
会在标准输出上打印:
val = 100
str = Hello
conn = (3,127.0.0.1:9531) //打印格式为 (fd , IP : Port)
l BEGIN ARRAY
参数:0个或1个的数值变量
意义:指定一个数组的起始位置,参数数值表示元素个数
说明:有些命令并非只是简单字段的组合,而是有内部的逻辑结构,甚至有一些复杂结构的数组。“BEGIN ARRAY”函数用于定义这种结构体数组的起始位置。
调用示例:
BEGIN ARRAY(3) //指定数组起始位置,并指定元素个数为3
U32 val = 100
STR str = “abc”
END ARRAY //数组结构结束,每个元素包含U32和STR两个字段
该函数只能出现在命令结构体内。
如果在发送命令里:
1. 如果函数没有参数,SRC编译器报告“数组长度未知”错误;
2. 如果函数有参数,SRC编译器把元素的每个字段依次编码,并重复参数指定的次数。
例如上面的代码,由于指定了元素个数为3,编译器会把:
编码U32变量val
编码STR变量str
重复做3次。这就相当于编码了3个结构体,每个结构体包括U32和STR两个字段。
如果在接收命令里:
1. 如果函数没有参数,SRC编译器会先读取U32元素个数字段,然后依次读取每个元素的每个字段;
2. 如果函数有参数,SRC编译器会假定元素个数为参数数值,直接依次读取每个元素的每个字段。
值得注意的是,“BEGIN ARRAY”函数可以嵌套调用,即在一个数组结构体内部,可以定义另一个数组结构体,这样就允许定义任意复杂的命令,例如:
BEGIN ARRAY //第一层数组结构体
U32 val_1
BEGIN ARRAY //第二层数组结构体
U8 val_2
BEGIN ARRAY //第三层数组结构体
STR str_3
STR id_3
END ARRAY //第三层数组结构体结束
U64 sz_2
END ARRAY //第二层数组结构体结束
STR str_1
END ARRAY //第一层数组结构体结束
实际中可能很难找到如此复杂的命令,但是有些命令的确会用到第二层数组结构体。
l END ARRAY
参数:无
意义:指定一个数组的结束位置
说明:“END ARRAY”函数必须与“BEGIN ARRAY”函数成对出现。函数的使用请见上面的介绍。
构造函数
在SRC语言里,每一种数据类型都对应有若干个构造函数,用于初始化相应的变量。下面是各种数据类型的构造函数的介绍:
l U8,S8,U16,S16,U32,S32,U64,S64
参数:0个或1个数值或变量名
意义:用参数值或0初始化对应类型的变量
说明:如果参数列表为空,则用0初始化变量。调用示例:
U32 v1 = U32(100)
U32 v2 = U32(v1)
U8 v3 = U8() //使用0初始化变量
数值类型的变量可以直接相互赋值,但是当出现溢出或者符号不匹配时,SRC编译器会报告一个运行时错误,此时用户应该确认转化的正确意义。
l STR,RAW
参数:0个或1个字符串或变量名
意义:用参数字符串初始化对应类型的变量
说明:如果参数列表为空,则用空字符串初始化变量。调用示例:
STR s1 = STR(“abc”)
RAW v2 = RAW(s1)
RAW v3 = RAW() //默认使用空字符串初始化变量
STR和RAW类型的变量,可以直接相互赋值。
l TCP,UDP
参数:以下几种组合都是可以的:
s 1个相同类型的连接对象
s 字符串(IP地址)+ 字符串(端口)+ 数值(超时,可省略)
s 字符串(IP地址)+ 数值(端口)+ 数值(超时,可省略)
意义:建立新连接,或指向一个已有的连接
说明:如果参数是另一个连接对象,那么只是复制了指向连接的指针,而没有建立新的连接;其他情况下会建立一个新的连接。“超时”参数暂时没有任何作用,并且可以省略,因为当前的SRC编译器采用阻塞模式发送和接收数据。
调用示例:
UDP(“127.0.0.1”,9527)
TCP tcp1 = TCP(“127.0.0.1”,”9527”)
TCP tcp2 = TCP(tcp1) //只是复制了连接指针,没有建立新的连接
TCP与UDP变量之间不能相互转化,并且也不能参与命令编码与解码,所以无论是构造函数,还是变量声明,都只能出现在命令结构之外,即全局空间里。
整个SRC源文件里,最先建立的连接(无论是通过变量声明,还是构造函数),会作为默认连接,如果调用SEND或RECV函数而没有传递参数,SRC编译器会选择默认连接作为参数。
变量声明
变量声明是SRC语言里最重要、最复杂的语句,也是使用最多的语句。SRC语言的变量声明分为普通声明和自由变量声明。首先介绍普通声明:
数组变量声明
数组变量的声明格式为:
TYPE [] name
TYPE [ expression ] name
其中,TYPE是数据类型关键字;expression是任意可求值的表达式,并且是数值类型。例如:
U32 [] u32_array;
STR [] str_array;
U8[12] char_array_size_12;
但是以下类型不能声明为数组:
s RAW
s TCP
s UDP
数组类型的变量不能被编码,因为数组声明无法给元素赋初值。在解码时,没有指定长度的数组变量,会先读取U32类型的元素个数字段,然后依次读取每个元素;指定了长度的数组变量,直接读取每个元素。
数组变量声明只允许出现在接收命令结构里。
上面第一种声明方式通过读取到的命令数据内容来决定元素的个数,第二种方式指定了数组的元素个数。其实这2种方式在某些情况下是等价的,例如:
STR[] str_array //先读取U32元素个数,再读取每个元素
等价于
U32 array_sz //先读取U32元素个数
STR[array_sz] str_array //再读取每个元素
常量声明
在SRC语言里,常量是指在声明的时候可以立刻求值,并且在以后都不会改变的对象,相当于C++里的const常量。常量的声明方式如下:
TYPE name := expression
TYPE name :( arg_list )
其中,expression表示任何可求值的表达式,而arg_list表示用‘,’分隔的参数列表,可以为空。例如:
U32 ver := 100 //定义值为100的U32常量
U32 ver:(100) //与上面等价
TCP conn := TCP(“127.0.0.1”,9527) //定义一个TCP常量,连接本机的9527端口
TCP conn:(“127.0.0.1”,9527) //与上面等价
TCP conn1 := conn //定义另一个TCP常量conn1,与conn表示同一个连接
TCP conn1:(conn) //与上面等价
常量声明只能出现在全局空间或发送命令结构里。
普通变量声明
在SRC语言里,普通变量是指在声明的时候无法求值,或者求出的不一定是最终值的对象。普通变量的声明方式如下:
TYPE name
TYPE name = expression
TYPE name ( arg_list )
其中expression和arg_list的意义与常量的相同。例如:
U32 body_len //定义初值为0的U32变量,可能在后面被改变
U32 body_len = 0 //与上面等价
U32 body_len(0) //与上面等价
普通变量声明可以出现在任何地方。
对于TCP和UDP连接类型,普通变量声明和常量声明是等价的,因为连接总是会在变量声明的地方开始建立,并且无法改变变量所代表的连接对象。
对于STR和RAW类型,因为除了在普通变量声明的时候赋值,没有其他方法改变值,所以普通变量和常量的声明也是等价的。
断言变量声明
断言变量声明是SRC语言引入的新语法,用于在读取命令字段的同时,检查字段值的有效性。在接收命令里,为了尽早发现错误的数据,可以为一些字段加上限制条件,例如版本号应该大于或等于100,数据包长度应该小于32K字节,等等。这些限制条件可以通过断言变量方便的实现。断言变量的声明方式如下:
TYPE name OP expression
其中,OP是下列判断操作符之一:
s <
s >
s <=
s >=
s ==
s !=
expression的意义与前面的相同。例如:
U32 ver >= 100 //变量ver的值必须大于或等于100
U32 body_len < 32K //变量body_len的值必须小于32×1024
RAW str == “HTTP header” //字符串str必须等于“HTTP header”
断言变量的声明只能出现在接收命令里,因为在其他地方进行断言,本身就是没有意义的。
如果断言返回值为真,SRC编译器继续进行后面的操作;如果断言返回值为假,SRC编译器会报告错误,并终止操作。
流操作变量声明
流操作变量是SRC语言的又一特色,用于字符串与数值类型变量之间的相互转化。流操作变量有2种:流输出变量,流输入变量。
l 流输出变量声明
流输出变量声明用于把其他类型的值,转化成字符串类型的变量,声明方式如下:
STRING name << expression
其中,STRING表示STR或RAW;expression是任意可求值的表达式,并且返回值能够转化成字符串。实际上,除了TCP和UDP连接类型,SRC语言支持的其他类型都可以转化成字符串。使用示例:
U32 value = 100
STR str << value //str = “100”
流输出变量声明只能出现在发送命令里。
l 流输入变量声明
流输入变量声明能把字符串转化成数值类型,声明方式如下:
STRING name >> expression
STRING name >> TYPE
其中,STRING表示STR或RAW;expression是任意可求值的表达式,并且返回值必须是数值类型;TYPE表示任意数值类型关键字(Uxx或Sxx)。使用示例:
DEF U32 value
STR str >> value //把str字符串转化成U32值,赋给value变量
STR str >> U32 //把str字符串转化成U32值
流输入变量声明只能出现在接收命令里。
自由变量声明
只要在普通声明的前面加上“DEF”或“DEFINE”关键字,就是自由变量的声明。
在命令结构体内,使用普通方式定义的任意变量,都会作为该命令的字段,并需要进行编码或解码。而自由变量则不作为命令的字段,也不参与编码或解码,但是仍像普通变量那样求值。自由变量在某些场合下有不可替代的作用,例如:
DEF U32 def_total_len // 使用自由变量计算整个数据包的长度
BEGIN(def_total_len)
…… //命令头的字段
U32 total_len = def_total_len // 实际编码的是total_len字段
…… //命令体的字段
END(def_total_len)
上例中,普通变量total_len需要计算整个数据包的长度,这就需要在声明total_len之前调用BEGIN(total_len),而在函数内使用未定义的变量是SRC语言所不允许的,所以需要使用自由变量def_total_len完成计算任务,最后将值赋给普通变量total_len,并最终编码进数据包。
断言表达式
断言表达式用于在接收命令里判断数据的合理性,它比断言变量声明更好的地方在于:可以随时随地进行判断,不一定非在变量定义的时候。
SRC语言的断言表达式格式如下:
OP1 expression
expression OP2 expression
其中,OP1代表一元判断操作符,目前支持的有:
s !
OP2代表二元判断操作符,目前支持:
s <
s >
s <=
s >=
s ==
s !=
expression的意义与前面的相同,不过要求返回值类型可以进行相应的判断操作。具体来说就是,对于一元操作符“!”,要求expression的返回值是数值类型;对于二元操作符,要求左右expression的返回值要么都是数值类型,要么都是字符串类型。例如:
U32 ver
ver >= 100 //二元判断操作符
!ver //一元判断操作
STR str
str == “abc”
命令结构
SRC语言主要是用来定义各种各样的命令结构,而SRC源文件一般就是若干个命令结构的集合。
命令结构的定义通过“CMD”或“COMMAND”关键字,格式如下:
CMD CmdName //命令结构开始,CmdName是命令的名字,可以为空
…… //任意字段
END CMD //命令结构结束
命令的名字CmdName可以为空,但是不允许与其他全局变量重名,不同的命令也不允许使用相同的名字。
命令结构有2种类型:发送命令和接收命令。
发送命令
发送命令的标志,是在所有命令字段声明之前,有SEND函数调用,例如:
CMD QueryCommand
SEND
…… //命令的其他字段
END CMD
SEND函数可以被多次调用,也可以传递任意个数的参数,SRC编译器会自动把命令数据发送给SEND函数的每个参数,无论是否有重复。
在发送命令里不允许出现的语句包括:
s TCP和UDP类型的变量声明和构造函数
s 数组变量声明
s 断言变量声明
s 流输入变量声明
s RECV函数调用
s 断言表达式
s 无参数的BEGIN ARRAY函数
下面是一个简单的发送命令的示例:
COMMAND QueryCommand //命令名字为“QueryCommand”
SEND //在所有字段声明之前调用SEND函数
U16 ver := 100 //对于可以立即求值的字段,请使用常量声明
U16 cmd_type := 161
U32 seq := 1234
U32 len //对于需要延后求值的字段,请使用普通变量声明
BEGIN(len) //调用BEGIN函数
STR file_hash := "http://www.google.com"
STR client_hash := UNHEX("1A2B3C4D5E6F")
STR peer_id := "ABCDEF1234567890"
END COMMAND //命令结束时,自动为len字段调用END函数
这个命令只是简单的把每个字段打包,最后发送出去。
有一些命令,还需要加上HTTP头,而HTTP头里有一个“Content-Length:”字段,表示HTTP数据体的长度,为了正确填写这个字段,需要使用自由变量和流输出变量:
CMD QueryCommand SEND //SEND函数还可以写在这个位置
RAW http1 := "POST http://127.0.0.1:12345/ HTTP/1.1/r/n/
Content-Length: " //使用转义字符‘/’,将较长的字符串分行表示
DEF U32 pack_len //使用自由变量记录命令包的总长度
RAW pack_len_str << pack_len //将pack_len流输出到字符串
RAW http2 := "/r/nContent-Type: application/octet-stream/r/n/
Connection:Close/r/n/r/n"
BEGIN(pack_len) //从此处开始计算数据包长度
…… //其他字段与上例相同
END CMD //QueryCommand //命令结束时,自动为pack_len调用END函数
现在,这个发送命令加入了HTTP头,通过SRC编译器的处理,最后发送出去的会是如下数据:
0000h: 50 4F 53 54 20 68 74 74 70 3A 2F 2F 31 32 37 2E ; POST http://127.
0010h: 30 2E 30 2E 31 3A 31 32 33 34 35 2F 20 48 54 54 ; 0.0.1:12345/ HTT
0020h: 50 2F 31 2E 31 0D 0A 43 6F 6E 74 65 6E 74 2D 4C ; P/1.1..Content-L
0030h: 65 6E 67 74 68 3A 20 35 36 0D 0A 43 6F 6E 74 65 ; ength: 56..Conte
0040h: 6E 74 2D 54 79 70 65 3A 20 61 70 70 6C 69 63 61 ; nt-Type: applica
0050h: 74 69 6F 6E 2F 6F 63 74 65 74 2D 73 74 72 65 61 ; tion/octet-strea
0060h: 6D 0D 0A 43 6F 6E 6E 65 63 74 69 6F 6E 3A 20 43 ; m..Connection: C
0070h: 6C 6F 73 65 0D 0A 0D 0A 00 64 00 A1 00 00 04 D2 ; lose.....d......
0080h: 00 00 00 2C 00 00 00 14 68 74 74 70 3A 2F 2F 77 ; ...,....http://w
0090h: 77 77 2E 62 61 69 64 75 2E 63 6F 6D 00 00 00 06 ; ww.baidu.com....
00a0h: 1A 2B 3C 4D 5E 6F 00 00 00 06 41 42 43 44 45 46 ; .+<M^o....ABCDEF
可以看到,HTTP数据体的长度为“56”,被正确的写入了HTTP头信息里。
除了加HTTP头信息,还可以对命令进行更加复杂的处理,例如加密解密,计算校验和等等,这些操作可以通过FUN函数来实现,具体请参考“Using SRC Language”。
接收命令
接收命令的标志,是在所有命令字段声明之前,有RECV函数调用,例如:
CMD RespCommand
RECV
…… //命令的其他字段
END CMD
RECV函数可以被多次调用,也可以传递任意个数的参数,但是由于实现限制,目前SRC编译器只会从第一个RECV调用的第一个参数接收数据。
在接收命令里不允许出现的语句包括:
s TCP和UDP类型的变量声明和构造函数
s 常量声明
s 流输出变量声明
s SEND函数调用
下面是一个简单的接收命令的示例:
CMD RespCommand RECV //RECV函数还可以写在这个位置
U16 ver >= 100
U16 cmd_type == 162
U32 seq
U32 len < 32K //32K = 32×1024 = 32768
U8 result
!result
STR fileHash_ == "http://www.baidu.com";
STR clientHash_;
STR[] peerId_; //array
END CMD
这个接收命令只需解码每个字段即可,但实际中有些命令会使用HTTP头回复,例如上面带HTTP头的发送命令的回复。为了正确的接收HTTP头信息,需要对RAW类型的变量使用断言声明和流输入声明,示例如下:
CMD RespCommand RECV
RAW http1 == "HTTP/1.1 200 OK/r/nContent-Length: "
//使用“==”断言声明,既判断内容的正确性,又提示RAW
//字符串的长度
RAW pack_len_str >> U32 //使用流输入声明,提示RAW字符串的内容
RAW http2 == "/r/nContent-Type: Application/octet-stream/
/r/nConnection: Close/r/n/r/n"
…… //其他字段与上例相同
END CMD
在接收命令里读取RAW字符串字段的最大问题,是无法知道读取操作的结束位置,因为RAW字符串没有长度字段。所以必须与其他条件配置,例如上面的“==”断言,限制字符串的内容,同时也限制了RAW字符串的长度;而“>>”流输入操作符,可以限制字符串的内容必须是数字字符“0-9”,当读取到其他字符的时候,SRC编译器就知道读取结束了。
其他语法
下面的内容介绍了SRC语言里比较基础的一些语法。
语法常量
SRC语言的语法常量包括数值常量和字符串常量。数值常量的表达方式遵循C++语法,例如:
S32 int_v := 10 //“10”表示整型常量10
S32 long_v := 100L //“100L”表示长整型常量100
S64 long_long_v := 1000LL //“1000LL”表示64位长整型常量1000
S64 i64_v := 1000i64 //同上
U32 uint_v := 10U //“10U”表示无符号整型常量10
U32 long_v := 100UL //“100UL”表示无符号长整型常量100
U64 long_long_v := 1000ULL //“1000ULL”表示64位无符号长整型常量1000
S8 char_v := ‘a’ //“’a’”表示字符‘a’的ASCII码值
关于数值常量表示语法的详细信息,请参考C++语言的语法说明。
字符串常量的表达方式同样遵循C++语法,例如:
STR str_v := “abc” //使用引号表示字符串常量“abc”
STR long_str_v := “this is a very long/
string that needs return new line” //使用转义字符‘/’使字符串换行
STR odd_str_v := “O/rD/aD/tS/032T/xaeR”
//这也是合法的字符串常量,不信用C++试试!
关于字符串常量表示语法的详细信息,请参考C++语言的语法说明。
目前SRC语言不支持宽字符和字符串,即以“L”前导表示的字符和字符串。在C++语言里宽字符的类型是wchar_t,在SRC语言里没有对应的类型。
注释
SRC语言的注释以“#”或“//”开始,到行尾结束,可以与有效代码同行,例如:
# This is shell style comments
//This is C++ style comments
STR str_v //comments after statement
在C++语言里,使用“//”的注释可以通过转义字符‘/’延伸到下一行,但是在SRC语言里,这是不允许的,即注释里的‘/’字符没有转行的意义。
语句分隔符
语句分隔符是指一条完整语句的结束标志,例如C++语言里的‘;’字符。在SRC语言里,‘;’字符和换行符都可以作为语句分隔符,例如下面的写法都是合法的:
U32 len ; BEGIN(len) //使用‘;’分隔语句
STR cid //使用换行符分割语句