更新至版本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 //使用換行符分割語句