## Specific Python

### I. 程序结构

按照控制流逐行执行。

### II. 语法规则

#### 1. 字符集合

ASCII 编码，区分大小写，中文字符是**未定义**的，合法字符集如下：

- **标识符**（包括变量标识符、函数标识符）：26 个小写英语字母，26 个大写英语字母，数码 `0` 到 `9`，下划线 `_`
- **标准运算符**：加号 `+`，减号 `-`，乘号 `*`，浮点除 `/`，整除`//`，取模 `%`
- **关系运算符**：大于 `>`，小于 `<`，大于等于 `>=`，小于等于 `<=`，不等于 `!=`，等于 `==`
- **增量运算符**：加法 `+=`，减法 `-=`，乘法 `*=`，浮点除 `/=`，整除 `//=`，取模`%=`
- **赋值运算符**：赋值 `=`
- **下标运算符**：取下标对象 `[]`
- **优先级运算符**：括号 `()`
- **分隔符**：逗号 `,`
- **特殊符号**：空格 ` `，换行符 `\n`，制表符 `\t`，注释标识符 `#`，字符串标识符 `"` 或 `'`。

#### 2. 关键字

```python
None
True
False
def
return
break
continue
if
elif
else
while
or
and
not
```

关键字不可作为变量名或函数名。

#### 3. 空白字符

**空格**、**制表符**在源文件中可以区分词素 (Token)，同时在一行的开头可以表示缩进。

**换行符**表示新的语句的开始。

缩进在 Python 用于识别代码块，相关问题将在 Parser 中使用 Antlr4 解决，无需考虑相关的实现。

#### 4. 注释

从 `#` 开始到本行结束的内容都会被作为注释。

#### 5. 标识符

标识符的第一个字符必须是英文字母，第二个字符开始可以是英文字母、数字或者下划线。

标识符区分大小写。长度超过 $64$ 个字符的标识符是**未定义**的。

#### 6. 常量

- 逻辑常量：`True` 为真，`False` 为假

- 整数常量：

  - 整数常量以十进制表示，非十进制的表示为**未定义**行为
  - 整数常量不设负数，负数可以由正数取负号得到

  - Python 中，整数的范围是没有限制的，此处同理，这意味着你必须实现高精度整数

  - 首位为 $0$ 的整数常量是**未定义**的

- 浮点数常量：

  - 浮点数常量以十进制表示
  - 浮点数常量不设负数，负数可以由正数取负号得到
  - 拥有前导 $0$ 的浮点数为**未定义**的，如`0001.1`
  - 含有 e 的浮点数为**未定义**的，如 `1e5`
  - 以 . 开头的浮点数为**未定义**的，如 `.123`

- 字符串常量
  - 字符串常量是由双引号 `"` 或单引号 `'` 括起来的字符串
  - 可以由两个字符串拼接而形成新的字符串常量。如 `"123""456"` 相当于 `"123456"`
  - 字符串中的所有字符必须是可示字符 (printable character) 或空格中的一种
- 空值常量：`None` 用来表示变量没有指向任何值

### 7. 数据类型

- `bool`：只有 `True` 和 `False`

- `int`：高精度整数

- `float`: 与 C++ 中的 `double` 一致

- `str`：字符串，**不可修改!**

- 元组: 具体表现请参考 python (待完善)

### 8. 表达式

#### 8.1. 基础表达式

基础表达式包括单独出现的常量、变量、函数调用和数组访问。

#### 8.2. 算术表达式

合法的算术运算符包括：`+`, `-`, `*`, `/`, `//`, `%`，具体行为可以参照 C++，特殊行为有：

- 字符串运算符
  - `str + str` 表示字符串的拼接
  - `str * int` 表示字符串的重复
  - `str <= str` 表示字符串的比较，比较规则同 C++ `std::striing`，`>=`, `==`等同理
- 除法
  - `/` 表示浮点除，即计算结果为浮点数
  - `//` 表示整除，即计算结果为整数。注意无论正负皆**向下取整**，例如 `-5 // 3 = -2`
  - `%` 表示模运算，无论模数的正负，皆定义为：`a % b = a - (a // b) * b`
- 连续比较
  - 存在 `1<2>3` 这样连续的关系运算符，处理方法是将其拆为相邻的比较并用 `and` 连接但**每个值最多只计算一次**
  - 如 `a()<b()<c()`，等价于先翻译成 `a()<b() and b()<c()` 再进行计算， `a(),b(),c()` 最多只调用一次（因为短路运算符）
- 逻辑运算符
  - `and` 等价于 C++ 中的 `&&`，`or` 等价于 C++ 中的 `||`， `not` 等价于 C++ 中的 `!`
  - `and` 和 `or` 为**短路**运算符
- **隐式转化**
  - 运算时如果两个运算数类型不一致，需转化成相同类型之后再进行运算
  - 具体转化规则参考 C++

不包含在特殊行为和 C++ 标准中的行为均为**未定义**行为。

#### 8.3. 赋值表达式

- 给一个变量赋值的意义是将这个变量指向右值，右值不管类型
- 如 `a=1,a=”123”,a=1.1` 这三条语句依次执行，再输出 `a`，结果是 `1.1`，允许变量遮蔽
- 可以给多变量赋值，如 `a,b=1,2` 意思是 `a=1,b=2` 依次执行，此处或与标准 Python **不同**
- 增量赋值即为普通算术运算的简化表达，具体行为参考 C++

#### 8.4. 运算符优先级

从低到高依次为（其中处在相同行的运算符优先级相同）

```python
=
or
and
not
< > <= >= == !=
+ -
* / // %
()
```

### 9. 语句

#### 9.1. 变量定义/赋值语句

- 单变量赋值：`var = value`
- 连续赋值：`var_1 = var_2 = ... = value`

参考[赋值表达式](####8.3. 赋值表达式)。

#### 9.2. 表达式语句

参考[表达式](###8. 表达式)

#### 9.3. 条件语句

```python
if expression_1:
	# code block
elif expression_2:
	# code block
else expression_3:
	# code block
```

`elif` 相当于 `else if`，`else` 可以没有。

#### 9.4. 循环语句

```python
while expression:
	# code block
```

#### 9.5. 跳转语句

- 包括 `return`，`break`，和 `continue`
- 具体行为参考 C++

### 10. 函数

#### 10.1. 函数定义

```python
def func(parameters):
	# code block
```

- 参数列表如 `a, b, c`，变量名之间用逗号分隔，可以为空

- 有些变量可以有默认值，但是都必须出现在无默认值的变量后面
- 函数可以有返回值，也可以没有返回值，无需显示声明。返回值可以为多变量，如 `return a, b`

#### 10.2. 函数调用

```python
func(parameters)
```

- 函数调用必须出现在该函数定义后。

- 参数有两种形式：keyword 和 positional

  - Keyword argument 比如 `foo(a=1,b=2)` 表示传入参数 `a` 的值为 `1`，`b` 的值 `2`

  - Positional argument 是指 `foo(1,2)` 这样按照出现顺序指代参数

  - 若一个参数列表中同时有两种参数形式，那么 positional argument 必须出现在 keyword argument 之前。如 `foo(1,b=2)`

- 数据保证递归层数不超过 $2000$ 层

### 11. 内建函数

- `print`：输出，可以有任意个参数，逐个输出，中间用空格分隔。输出后换行。输出 `float` 保留 $6$ 位小数。输出字符串不要输出前后面的引号。如 `print("123",1.0)` 请输出 `123 1.000000`。

- `int`：将 `float` 或 `bool` 或 `str` 转成 `int`。

- `float`: 将 `int` 或 `bool` 或 `str` 转成 `float`。

- `str`： 将 `int` 或 `float` 或 `bool` 转成 `str`。

- `bool`： 将 `int` 或 `float` 或 `str` 转成 `bool`。对于 `str`，如果是 `""` 则为 `False`，否则为 `True`。

- 转型类函数都只有一个参数。

### 12. 作用域

作用域相关规则：
- **与标准 Python 不同，全局变量的生效范围是全部范围**（不用 global 关键字即可访问）
- **只有函数的调用会产生新的作用域**，作用域的产生请参考 Python
- 没有代码块级作用域，变量注销只发生在函数级作用域退出时
- 全局作用域无需global即可访问，因此，局部变量覆盖全局变量的唯一方式是通过函数参数列表覆盖。
