Skip to content

词法规则 ​

CIN 的编译前端是手写词法分析器(codecin/cin.py 中的 tokenize()): 先把源码切成记号(token),再做续行过滤,最后交给递归下降解析器。 本页说明写代码时真正会碰到的词法约定。

注释 ​

形式写法说明
行注释// 说明文字到行尾结束;可用于语句尾部
块注释/* 说明文字 */可跨多行;块注释内不嵌套
cin
// 整行注释
int x = 1        // 行尾注释
/* 块注释
   可以跨行 */
int y = 2

块注释的边界

块注释以遇到的下一个 */ 结束,不支持嵌套。写成 /* a /* b */ c */ 时, 注释在第一个 */ 就结束了,剩下的 c */ 会被当成代码而产生语法错误。

标识符与关键字 ​

元素规则
标识符首字符为字母或 _,后续为字母、数字或 _;区分大小写
保留字struct enum function if else while for do switch case default break continue return true false unsigned
内嵌指令名set add subtract multiply divide increment decrement(语句首出现时按内嵌语句解析)
内建函数名println print strlen sqrt … 见 内建函数
cin
int Counter = 1      // 与 counter 是两个不同的变量
int _tmp = 2
int a1_b2 = 3

关键字不是硬保留

CIN 的关键字识别发生在语法层而不是词法层:function、if 等只是普通标识符, 在特定位置才被当作关键字解释。因此把变量命名为 set 之类在语法上可能通过, 但会与内嵌指令语句撞车 —— 别这么写。

字面量 ​

整数字面量 ​

cin
int dec = 42
int neg = -7              // 负号是一元运算符, 不是字面量的一部分
int hex = 0xFF            // 16 进制 (0x / 0X)
int bin = 0b1010          // 2 进制  (0b / 0B)
int oct = 0o17            // 8 进制  (0o / 0O)
int sep = 1_000_000       // 数字下划线可读性分隔
int hsep = 0x1_0          // 进制前缀字面量同样支持下划线
unsigned int big = 4000000000
规则说明
进制前缀0x/0X = 16,0b/0B = 2,0o/0O = 8
下划线允许出现在数字之间,任意位置(1_0 合法);解析时被剔除
后缀 u/U/l/L被忽略(值模型是 64 位槽,无宽度差异):0xFFu、100L、42u 都合法
后缀 f/F把该字面量标记为 float:100f 等价于 100.0
十进制上限不能超过 0x7FFFFFFFFFFFFFFF(有符号 64 位最大值)
十六进制上限不能超过 0xFFFFFFFFFFFFFFFF(无符号 64 位最大值)
非法写法只有前缀没有数字(0x)、纯下划线(0x_)会报 Malformed numeric literal
cin
int a = 0xFFu             // 255
int b = 0b1010U           // 10
int c = 0o17L             // 15
int d = 42u               // 42
float e = 1.5f            // 1.5
float f = 100f            // 100.0

超出范围会编译失败

int x = 9223372036854775808 直接报错(不是静默截断)。 同理 0xFFFFFFFFFFFFFFFF 是合法的(恰好 64 位无符号上限),再加一位就报错。

浮点字面量 ​

cin
float pi = 3.14
float tiny = 1e-5             // 科学计数法 (e / E, 指数可带 +/-)
float big = 2.5E+10
float one = 1.0
float dot = .5                // 以 . 开头也可
float forced = 1f             // 整数字面量 + f 后缀 -> float
float under = 1_000.5         // 下划线同样可读

整数值的 float 打印出来没有小数点

float_to_str(100.0) 输出 100(去掉多余的 .0),float_to_str(3.14) 输出 3.14。 写日志时若需要固定的 x.0 形式,请自行拼接字符串。

字符字面量 ​

字符字面量是整数字符编码(没有任何独立的 char 值语义),可用转义:

cin
char letter = 'A'             // 65
char newline = '\n'           // 10
char tab = '\t'               // 9
char quote = '\''             // 39
char backslash = '\\'         // 92
char nul = '\0'               // 0
char bell = '\a'              // 7  (报警)
char backspace = '\b'         // 8
char formfeed = '\f'          // 12
char vtab = '\v'              // 11
char dquote = '\"'            // 34

字符字面量只接受单个字符或单字符转义:\x / \u / \U 是字符串字面量专属(见下), 写进字符字面量会按「未知转义保留原字符」处理。'ab' 报 Unterminated char literal。

字符串字面量 ​

字符串用双引号,支持单字符转义与字节/码点转义;不支持 ' 包裹的字符串:

cin
string s = "hello"
string path = "C:\\temp\\file.txt"      // 反斜杠要转义
string multi = "line1\nline2"
string empty = ""
转义含义说明
\n \t \r \0 \" \\换行 / 制表 / 回车 / NUL / 双引号 / 反斜杠与 C 一致
\a \b \f \v报警 / 退格 / 换页 / 垂直制表与 C 一致
\xH / \xHH原始字节(1~2 位十六进制)"\xE4\xB8\xAD" 就是 "中" 的 UTF-8 三字节
\uHHHHUnicode 码点,必须正好 4 位十六进制,按 UTF-8 编码写入"\u4E2D" 与 "中" 等价
\UHHHHHHHHUnicode 码点,必须正好 8 位十六进制,按 UTF-8 编码写入"\U0001F600"
cin
string a = "\xE4\xB8\xAD"       // 原始字节: 中
string b = "\u4E2D"             // 码点: 同样是 中
println(int_to_str(strlen(a)) + " " + int_to_str(strlen(b)))   // 3 3
println("\u4F60\u597D")         // 你好
  • \x 是字节语义:只写一个字节,不按 UTF-8 重新编码;\u / \U 是码点语义:先得到 码点再按 UTF-8 编码,所以 \u4E2D 写出来也是 3 个字节;
  • 位数不足分别报 \x escape needs at least one hex digit、 \u escape needs exactly 4 hex digits、\U escape needs exactly 8 hex digits; 码点超过 0x10FFFF 报 \u escape out of Unicode range。

字符串里没有的转义

遇到未定义的转义(如 \q)时,词法分析器会退化为「保留该字符本身」而不是报错, "\q" 得到的就是 q。这类写法容易掩盖笔误,建议只用上表列出的转义。

布尔字面量 ​

cin
bool ok = true
bool no = false
println("ok = " + ok)          // ok = true

bool 打印为 true / false;参与数值运算时按 1 / 0 处理(见 类型系统)。

语句分隔与续行 ​

CIN 以换行作为语句终止符(; 可作显式分隔符)。词法层对换行的处理有三条规则:

场景换行是否被忽略说明
圆括号 (...) / 方括号 [...] 内忽略(自动连接)参数表、条件、下标可自由折行
行尾是运算符忽略(续行)长的表达式可以断在运算符后
花括号 {...} 块内保留(语句终止符)不能把一条语句折成两行

可触发续行的行尾运算符包括:

text
+  -  *  /  %              算术
&  |  ^  ~  <<  >>        位运算
=  +=  -=  *=  /=  %=  &=  |=  ^=  <<=  >>=
==  !=  <  >  <=  >=      比较
&&  ||                    逻辑
++  --                    自增自减
,  .  ..  ->              逗号 / 成员 / case 范围 / 箭头
cin
// 可行: 行尾运算符续行
int long_result = value1 + value2 +
                  value3

// 可行: 括号内续行 (无需行尾运算符)
float x = (a + b) *
          (c + d)
println("total = " +
        int_to_str(long_result))

// 可行: 多行参数表
int m = idiv(1000 +
             234,
             7)
cin
// 错误: 花括号内不能把语句折行
function bad() -> int {
    int x = 1 +
        2            // 这里的换行是语句终止符 -> 解析报错
    return x
}

最常见的语法错误来源

Expected RBRACE ... at line N

出现这个报错时,先回头看第 N 行附近:多数情况是块内语句折行、 花括号不配对,或者把表达式断在了行尾非运算符的位置。

语句终止符对照 ​

cin
int a = 1
int b = 2
println("sum = " + (a + b))

大小写与编码 ​

事项约定
大小写敏感:x 与 X 是不同标识符,if 与 If 不同
源文件编码UTF-8;字符串字面量可直接包含中文等多字节字符
BOM文件开头的 UTF-8 BOM(\ufeff)被自动忽略,含 BOM 的源文件与 import 均正常工作
行尾符\r 与 \t、空格一起被当作空白跳过,CRLF 源文件可用
制表符仅作空白,不参与语法
powershell
# Windows: 查看文件是否带 BOM (前 3 字节 EF BB BF)
Format-Hex -Path hello.cin | Select-Object -First 1
bash
# Linux / macOS: 同样的检查
head -c 3 hello.cin | xxd

BOM 与 import 的关系

早期版本中带 BOM 的文件里 import 会静默失效;现在 BOM 在词法层被丢弃, 带 BOM 的模块文件也能正常引用。参见 tests/test_literals_and_bom.py。

词法错误速查 ​

报错信息触发原因修正
Malformed numeric literal at ...0x 后无数字、只有下划线、非法进制数字补全数字或改进制前缀
Numeric literal out of 64-bit range at ...十进制 > 0x7FFF...FFFF、十六进制 > 0xFFFF...FFFF缩小字面量或用 unsigned int 接收合法范围内的值
Unexpected character 'x' at ...出现了词法层不认识的字符(如 @、#、全角符号)改用合法运算符,检查是否混入中文标点
Unterminated char literal at ...字符字面量缺右引号,或写了 'ab'字符字面量只能是一个字符或一个转义
\x escape needs at least one hex digit at ...\x 后面没有十六进制数字补 1~2 位十六进制
\u escape needs exactly 4 hex digits at ... / \U escape needs exactly 8 hex digits at ...\u / \U 位数不足分别写满 4 位 / 8 位
\u escape out of Unicode range at ...码点大于 0x10FFFF用合法码点
Expected RBRACE ... at line N块内语句折行 / 花括号不配对用行尾运算符或括号续行
一个完整的词法探针

下面这段程序用到了本页的全部字面量形式,可直接运行验证:

cin
function main() -> int {
    int hex = 0xFFu
    int bin = 0b1010U
    int oct = 0o17L
    int sep = 1_000_000
    float forced = 100f
    char letter = 'A'
    string s = "a\tb" + "\n"
    bool ok = true
    println("hex=" + int_to_str(hex) + " bin=" + int_to_str(bin)
            + " oct=" + int_to_str(oct) + " sep=" + int_to_str(sep))
    println("forced=" + float_to_str(forced) + " letter=" + int_to_str(letter))
    println("len=" + int_to_str(strlen(s)) + " ok=" + bool_to_str(ok))
    return 0
}
text
hex=255 bin=10 oct=15 sep=1000000
forced=100 letter=65
len=4 ok=true

相关页面 ​

文档由 VitePress 构建