表达式

expr -> 
      operator_expr
    | negate_expr
    | assign_expr
    | as_expr
    | call_expr
    | literal_expr
    | ident_expr
    | group_expr

表达式是代码中运算的最小单位。在语法解析的时候,一个表达式会被展开成一棵树,称作表达式树。

提示:对于 运算符表达式 operator_expr、取反表达式 negate_expr 和类型转换表达式 as_expr 可以使用局部的算符优先文法进行分析。

表达式中运算符的优先级从高到低为:

运算符结合性
括号表达式-
函数调用-
前置 --
as-
* /左到右
+ -左到右
> < >= <= == !=左到右
=右到左

运算符表达式

binary_operator -> '+' | '-' | '*' | '/' | '==' | '!=' | '<' | '>' | '<=' | '>='
operator_expr -> expr binary_operator expr

运算符表达式是中间由一个运算符分隔、两边是子表达式的表达式。r0 一共有 10 种双目运算符。它们分别是:

  • 算数运算符 + - * /
  • 比较运算符 > < >= <= == !=

每个运算符的两侧必须是相同类型的数据。各运算符含义如下:

运算符含义参数类型结果类型结合性
+将左右两侧相加数值与参数相同左到右
-左侧减去右侧数值与参数相同左到右
*将左右两侧相乘数值与参数相同左到右
/左侧除以右侧数值与参数相同左到右
>如果左侧大于右侧则为真数值布尔*左到右
<如果左侧小于右侧则为真数值布尔*左到右
>=如果左侧大于等于右侧则为真数值布尔*左到右
<=如果左侧小于等于右侧则为真数值布尔*左到右
==如果左侧等于右侧则为真数值布尔*左到右
!=如果左侧不等于右侧则为真数值布尔*左到右

* 关于布尔类型

布尔类型的表达式只能出现在 ifwhile 语句的条件表达式中。因此,我们不强制规定布尔类型的值的表现形式。所有非 0 值都会被视为 true,0 会被视为 false。

取反表达式

negate_expr -> '-' expr

取反表达式是在表达式前添加负号组成的表达式。取反表达式的语义是将表达式转换成它的相反数。

赋值表达式

l_expr -> IDENT
assign_expr -> l_expr '=' expr

赋值表达式是由 左值表达式等号 =表达式 组成的表达式。赋值表达式的值类型永远是 void(即不能被使用)。

左值表达式是一个局部或全局的变量名。

赋值表达式的语义是将右侧表达式的计算结果赋给左侧表示的值。

类型转换表达式

as_expr -> expr 'as' ty

类型转换表达式是由 表达式关键字 as类型 组成的表达式。类型转换表达式的语义是将左侧表达式表示的值转换成右侧类型表示的值。

在 c0 实验中只会涉及到整数 int 和浮点数 double 之间的互相转换。

函数调用表达式

call_param_list -> expr (',' expr)*
call_expr -> IDENT '(' call_param_list? ')'

函数调用表达式是由 函数名调用参数列表 组成的表达式。函数调用表达式的语义是使用给出的参数调用函数名代表的函数。函数必须在调用前声明过(也就是说不存在先出现调用后出现声明的函数)。

特殊情况

标准库中的函数在调用前不需要声明,见 标准库文档

字面量表达式

literal_expr -> UINT_LITERAL | DOUBLE_LITERAL | STRING_LITERAL

digit -> [0-9]
UINT_LITERAL -> digit+
DOUBLE_LITERAL -> digit+ '.' digit+ ([eE] [+-]? digit+)?

escape_sequence -> '\' [\\"'nrt]
string_regular_char -> [^"\\]
STRING_LITERAL -> '"' (string_regular_char | escape_sequence)* '"'

字面量表达式可以是一个无符号整数、浮点数或者字符串的字面量。整数浮点数字面量 的语义就是用对应类型表示的字面量的值(64 位);字符串字面量 只会在 putstr 调用中出现,语义是对应的全局常量的编号。

标识符表达式

ident_expr -> IDENT

标识符表达式是由标识符组成的表达式。其语义是标识符对应的局部或全局变量。标识符表达式的类型与标识符的类型相同。

括号表达式

group_expr -> '(' expr ')'

括号表达式内部的表达式的值将被优先计算。