p4 language learning :Part 2(學習筆記)
技術標籤:p4 language程式語言
p4 language learning :Part 2
2.1 String literals
字串文字(字串常量)被指定為任意的8位字元序列,並用雙引號引起來。P4不會對字串進行任何有效性檢查(即它不會檢查字串是否代表合法的UTF-8編碼)。
注:UTF-8(8位元,Universal Character Set/Unicode Transformation Format)是針對Unicode的一種可變長度字元編碼。它可以用來表示Unicode標準中的任何字元,而且其編碼中的第一個位元組仍與ASCII相容,使得原來處理ASCII字元的軟體無須或只進行少部份修改後,便可繼續使用。因此,它逐漸成為電子郵件、網頁及其他儲存或傳送文字的應用中,優先採用的編碼。
2.2 Naming conventions
P4提供了豐富的型別。
基本型別包括位字串(bit-strings),數字(numbers)和錯誤(errors)。
也有內建型別來表示結構,例如解析器(parsers),管道(pipelines),操作(actions)和表(tables)。
使用者可以基於這些構造新型別:結構(structures),列舉(enumerations),標頭(headers),標頭堆疊(header stacks),標頭聯合(header unions)等。
在其文件有以下約定:
1.內建型別使用小寫字母書寫,例如int <20>
2.使用者定義的型別使用大寫字母,例如IPv4Address
4.變數不大寫,例如ipv4header
5.常數以大寫字母寫成,例如CPU_PORT
6.錯誤和列舉以駝峰表示法編寫,例如PacketTooShort
注:3.是型別的變數,而4.是普通變數,兩者注意區別
2.3 P4 programs
p4program
: /* empty */
| p4program declaration
| p4program ';' /* empty declaration */
;
declaration
: constantDeclaration
| externDeclaration
| actionDeclaration
| parserDeclaration
| typeDeclaration
| controlDeclaration
| instantiation
| errorDeclaration
| matchKindDeclaration
;
空宣告用單個分號表示。允許空宣告符合C / C ++和Java程式設計師的習慣-例如,某些結構(例如struct不需要終止的分號)
2.4 Scopes
一些P4構造充當名稱空間,用於建立名稱的本地範圍
1.派生型別宣告(struct, header, header_union, enum),它們引入了欄位名稱的本地作用域
2.Block statements,它引入了局部詞法包圍的作用域
3.parser, table, action, 和 control blocks它們引入了局部作用域
4.具有型別變數的宣告,為這些變數引入了新的範圍。例如,在以下extern宣告中,型別變數H的範圍擴充套件到了宣告的末尾:
extern E<H>(...) { ... } // scope of H ends here.
注:這段程式碼的E和H分別代表什麼我有點弄不清楚,如果弄清楚了會回來補充說明
宣告的順序很重要;除解析器狀態外,符號的所有使用都必須遵循符號的宣告。(這與P4_14有所不同,後者允許以任何順序進行宣告。這項要求大大簡化了P4編譯器的實現,允許編譯器使用有關已宣告識別符號的其他資訊來解決歧義。)
2.5 Stateful elements
大多數P4構造都是無狀態的:給定一些輸入,它們產生的結果僅取決於這些輸入。只有兩個有狀態的構造可以跨資料包保留資訊:
1.tables:對於資料平面而言,表是隻讀的,但它們的條目可以由控制平面修改
2.extern objects:許多物件的狀態可以由控制平面和資料平面讀取和寫入。來自P4_14語言版本的所有封裝狀態的結構(例如counters, meters, registers)均使用P4_16中的extern物件表示
在P4中,必須在編譯時通過稱為“例項化”的過程顯式分配所有有狀態元素。
此外,parsers, control blocks, 和 packages可能包含有狀態的元素例項化。因此,即使它們看起來不包含任何狀態,它們也被視為有狀態元素,並且必須在使用它們之前進行例項化。但是,儘管它們是有狀態的,但無需顯式例項化table-宣告table也會建立該table的例項。此約定旨在支援常見情況,因為大多數表僅使用一次。要對table例項化的進行更細粒度的控制,程式設計師可以在control中宣告它。
2.6 L-values
L值是可以出現在賦值操作左側或作為與out和inout函式引數相對應的引數出現的表示式。 L值表示儲存參考。以下表達式是合法的L值:
prefixedNonTypeName
: nonTypeName
| dotPrefix nonTypeName
;
lvalue
: prefixedNonTypeName
| lvalue '.' member
| lvalue '[' expression ']'
| lvalue '[' expression ':' expression ']'
;
1.基本或派生型別的識別符號。
2.Structure, header, 和 header union field成員訪問操作(使用點表示法)
3.對header stacks中元素的引用:索引,以及對last和next的引用。
4. 位切片運算子[m:l]的結果
以下是合法的左值:headers.stack [4] .field。請注意,方法和函式呼叫不能返回L值
注:L值應為左值
2.7 Calling convention: call by copy in/copy out
P4提供了多種用於編寫模組化程式的構造:extern methods, parsers, controls, actions。所有這些構造的行為都類似於標準通用程式語言中的過程:
1.它們具有命名和鍵入的引數。
2.它們為引數和區域性變數引入了新的區域性範圍。
3.它們通過將實參繫結到形參來傳遞引數。(They allow arguments to be passed by binding them to their parameters)
呼叫他們要使用copy in/copy out。
每個引數都可以標有方向:
1.in形參是隻讀的。在分配的左側使用in形參或將其作為非in實參傳遞給被呼叫者是錯誤的。通過在執行呼叫時複製相應實參的值來初始化in形參。
2.out形參未初始化(型別header或header_union的形參設定為“無效”),並在方法或函式的主體內被視為L值。作為out實參傳遞的引數必須是l值;呼叫執行後,形參值將複製到該L值的相應儲存位置
3.inout形參都是in和out。作為inout實參傳遞的引數必須是L值。
在呼叫函式本身之前,先從左到右評估引數。當為自變數提供的表示式可能有副作用時,求值順序很重要。考慮以下示例:
extern void f(inout bit x, in bit y);
extern bit g(inout bit z);
bit a;
f(a, g(a));
請注意,對g的求值可能會使其自變數a發生變化,因此編譯器必須確保傳遞給f的第一個引數的值不會因對第二個自變數的求值而改變。評估演算法呼叫的語義由以下演算法給出(不同的實現都會有相同的結果)(implementations can be different as long as they provide the same result):
1.當引數出現在函式呼叫表示式中時,它們從左到右進行求值。
2.對於每個out和inout實參,將儲存對應的L值(因此,不能通過以下引數的求值來更改它)。如果自變數包含對標頭堆疊的索引操作,則這一點很重要。
3.每個實參的值都儲存到一個臨時檔案中。
4.該函式以臨時變數作為實參呼叫。我們保證,作為實參傳遞的臨時物件絕不會彼此混淆,因此,如果體系結構支援,則可以使用按引用呼叫來實現此“生成的”函式呼叫。
5.在函式返回時,將與out或inout引數相對應的臨時物件按從左到右的順序複製到步驟2中儲存的L值中。
根據此演算法,先前的函式呼叫等效於以下語句序列:
bit tmp1 = a; // evaluate a; save result
bit tmp2 = g(a); // evaluate g(a); save result; modifies a
f(tmp1, tmp2); // evaluate f; modifies tmp1
a = tmp1; // copy inout result back into a
要了解上述演算法中的步驟2為什麼很重要,請考慮以下示例:
header H { bit z; }
H[2] s;
f(s[a].z, g(a));
此呼叫的評估等效於以下語句序列:
bit tmp1 = a; // save the value of a
bit tmp2 = s[tmp1].z; // evaluate first argument
bit tmp3 = g(a); // evaluate second argument; modifies a
f(tmp2, tmp3); // evaluate f; modifies tmp2
s[tmp1].z = tmp2; // copy inout result back; dest is not s[a].z
當用作實參時,extern物件只能作為無方向引數傳遞。例如,在VSS示例中檢視資料包實參引數。
注:文中argument均翻譯為實參,parameter均翻譯為形參或引數
筆者注:
1.今天學的有點迷迷糊糊的,有很多東西弄不清楚:
extern E<H>(...) { ... } // scope of H ends here.
這個的E和H和E< H >的用法搞不清楚是什麼意思?
還有這句話:“當用作實參時,extern物件只能作為無方向引數傳遞。例如,在VSS示例中檢視資料包實參引數。”有點不太清楚他在表達什麼???
2.全文來自P4_16 Language Specification,僅作學習用途,大部分為google翻譯,有感覺不太準確的地方加了原文,若有不對,歡迎指出!
3.最後希望自己可以繼續堅持吧!加油!