p4 language learning :Part 2(学习笔记)

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.最后希望自己可以继续坚持吧!加油!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值