1. 程式人生 > 其它 >p4 language learning :Part 2(學習筆記)

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

3.型別變數始終是大寫字母,例如parser P <H,IH>(…)
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.最後希望自己可以繼續堅持吧!加油!