写在所有的前面:
本文采用PYTHON实现代码
文章更新时间:2025.5.16,17:44
目录
实验说明
要求
设计并实现C++词法分析器,将 C++ 源代码分解为一个个有意义的词法单元。
设计
词法单元类型
- 预处理指令PREPROCESSOR:
#include
、#define
- 注释:
单行//
、多行/* */
- 关键字:
数据类型关键字:int
、long
、short
、double
、float
、char
、void
语句关键字:if
、else
、for
、while
、switch
、case
、break
、continue
、return
、printf
特殊关键字:(hrw老师自定义扩展类型)
main
、int36
非直接识别关键字:char*
- int36类型字面量:
0z(XX)
(包含字母a-z,不区分大小写) - 标识符:
任意单词
- 整数:支持十六进制、八进制、二进制和十进制
- 浮点数:支持小数、指数形式,如
3.14e10
- 字符字面量 转义字符字面量
'\a'
'\b'
'\f'
'\n'
'\r'
'\t'
'\v'
'\\'
'\''
'\"'
'3位\数字0-7'
(8进制数)'任意字符'
- 运算符: (不包括点,因为点在标识符中已经处理)
算术运算符:+
、-
、*
、/
、%
赋值运算符:=
、+=
、-=
、*=
、/=
比较运算符:==
、!=
、>
、<
、>=
、<=
逻辑运算符:&&
、||
、!
位运算符:&
、|
、^
、~
、<<
、>>
自增 / 自减:++
、--
- 分隔符:
括号:(
、)
、{
、}
、[
、]
标点符号:,
、;
、"
、'
、\
、.
- 格式说明符:
%d
、%s
、%f
等(用于printf/scanf
) - 转义字符:
\a
\b
\f
\n
\r
\t
\v
\\
\'
\"
- 字符串处理:
拆解处理,非转义,非格式说明符,则为普通字符串内容:如"Hello, world!"
中的Hello
和world!
代码设计
1. 模块导入与数据结构
- re 模块(正则表达式操作)
功能:提供正则表达式匹配功能,用于识别和提取特定模式的文本。 - sys 模块(系统相关功能)
功能:提供对 Python 解释器和系统环境的访问。
import re
import sys
2. 正则表达式(词法单元类型定义)
- 使用正则表达式精确匹配各种词法单元
- 特殊格式支持:36 进制整数、点分标识符、格式说明符等
- 优先级控制:长模式优先(如++先于+),关键字优先于标识符
# 定义 token 类型与对应的正则表达式
token_specification = [
# 预处理指令: #include <任意内容> 或 #define 单词1 单词2
('PREPROCESSOR', r'#(include\s+<[^>]+>|define\s+\w+\s+\w+)'),
# 多行注释: /* 尽可能少的字符 */
('COMMENT_MULTI', r'/\*.*?\*/'),
# 单行注释: // 任意字符至本行末尾
('COMMENT_SINGLE', r'//.*'),
# 关键字:数据类型: int|long|short|int36|double|float|char|void|struct
# 语句: if|else|for|while|switch|case|break|continue|return|printf
# 老师要求:增加更多的 C++ 关键字,包括 int36(36进制整数)
('KEYWORD', r'\b(int|long|short|int36|double|float|char|void|struct|if|else|for|while|switch|case|break|continue|return'
r'|printf)\b'),
# int36类型字面量: 0z(XX) (包含字母a-z,不区分大小写)
('INT36_LITERAL', r'0[zZ]\([0-9a-zA-Z]+\)'),
# 标识符(单词)
('IDENTIFIER', r'[a-zA-Z_]\w*'),
# 浮点数:支持小数、指数形式,如 3.14e10
('FLOAT_LITERAL', r'\d+\.\d+(e[+-]?\d+)?'),
# 整数:支持十六进制、八进制、二进制和十进制
('INT_LITERAL', r'0[xX][0-9a-fA-F]+|0[0-7]+|\d+'),
# 字符字面量 转义字符字面量 '\a' '\b' '\f' '\n' '\r' '\t' '\v' '\\' '\'' '\"' '3位\数字0-7'(8进制数) 或 '任意字符'
('CHAR_LITERAL', r"'(\\[abfnrtv\\\'\"?0-7]|[^\\'])'"),
# 运算符 (不包括点,因为点在标识符中已经处理)
('OPERATOR', r'\+\+|--|==|>=|<=|!=|&&|\|\||\+\-|\*/|<<|>>|&|\||\^|~|=|\+|\-|\*|\/|%|<|>'),
# 分隔符 ( ) { } , ; \ [ ] ' " .
('DELIMITER', r'[(){},;\[\]\'"\.]'),
# 转义字符 \a \b \f \n \r \t \v \\ \' \"
('ESCAPE_CHAR', r'\\[abfnrtv\\\'\"]'),
# 格式说明符 %数字.数字字符 如:%3.3d
('FORMAT_SPECIFIER', r'%[0-9]*\.?[0-9]*[diouxXfFeEgGaAcspn]'),
# 字符串内容 除了%、双引号、换行符之外任意字符
('STRING_CONTENT', r'[^%\\"\n]+'),
# 空白符
('WHITESPACE', r'\s+'),
]
3. 按行处理
# 按行处理,方便处理预处理指令或注释
lines = code.split('\n')
line_num = 1 # 当前行数
in_multi_comment = False # 标记是否已在多行注释里
# 逐行处理
for line in lines:
stripped_line = line.lstrip()
3.1 注释处理
# 处理多行注释的情况
if in_multi_comment:
end_pos = stripped_line.find('*/')
if end_pos != -1:
# 多行注释在此行结束,提取注释内容
comment_content = stripped_line[:end_pos + 2]
tokens.append(('COMMENT_MULTI', comment_content, line_num))
in_multi_comment = False
# 处理注释后的剩余部分
remaining = stripped_line[end_pos + 2:].lstrip()
if remaining:
# 递归处理剩余部分(简化版,实际可能需要更复杂逻辑)
tokens.extend(tokenize(remaining))
else:
# 多行注释继续到下一行
tokens.append(('COMMENT_MULTI', stripped_line, line_num))
line_num += 1
continue
# 检查是否开始新的多行注释
if stripped_line.startswith('/*'):
end_pos = stripped_line.find('*/')
if end_pos != -1:
# 单行内的多行注释 /* ... */
tokens.append(('COMMENT_MULTI', stripped_line[:end_pos + 2], line_num))
# 处理注释后的剩余部分
remaining = stripped_line[end_pos + 2:].lstrip()
if remaining:
tokens.extend(tokenize(remaining))
else:
# 多行注释开始但未结束
tokens.append(('COMMENT_MULTI', stripped_line, line_num))
in_multi_comment = True
line_num += 1
continue
# 检查是否为单行注释
comment_pos = line.find('//')
3.2 预处理指令处理
# 处理预处理指令
if line.startswith('#'):
tokens.extend(tokenize_preprocessor(line, line_num))
line_num += 1
continue
调用函数
def tokenize_preprocessor(line, line_num):
"""处理预处理指令"""
tokens = []
if line.startswith('#include'):
tokens.append(('PREPROCESSOR', line, line_num))
elif line.startswith('#define'):
tokens.append(('PREPROCESSOR', line, line_num))
return tokens
4. 按字处理
# 对非预处理指令的行应用常规的词法分析
pos = 0 # 本行已处理指针
# 逐字符判断
while pos < len(line):
# 跳过空白字符
if line[pos].isspace():
pos += 1
continue
4.1 单行注释
# 单行注释
if pos == comment_pos:
comment_text = line[comment_pos:]
tokens.append(('COMMENT_SINGLE', comment_text, line_num))
break
4.2 字符串处理
4.1 字符串内容处理
- 解析字符串中的格式说明符(如%d)
- 识别转义字符(如\n)
- 提取普通文本内容
# 检查是否是字符串字面量
if line[pos] == '"':
# 添加左引号
tokens.append(('DELIMITER', '"', line_num))
pos += 1
# 找到右引号(非转义)
end_pos = pos
while end_pos < len(line):
if line[end_pos] == '"':
# 检查是否为转义引号
backslash_count = 0
prev_pos = end_pos - 1
while prev_pos >= pos and line[prev_pos] == '\\':
backslash_count += 1
prev_pos -= 1
# 如果反斜杠数量为奇数,则是转义引号,继续寻找
if backslash_count % 2 != 0:
end_pos += 1
continue
# 否则找到真正的右引号
break
end_pos += 1
if end_pos < len(line):
# 提取字符串内容
string_content = line[pos:end_pos]
# 处理字符串内部的各种元素
string_tokens = tokenize_string(string_content)
tokens.extend([(token_type, token, line_num) for token_type, token in string_tokens])
# 添加右引号
tokens.append(('DELIMITER', '"', line_num))
pos = end_pos + 1
else:
# 未闭合的字符串,错误处理
tokens.append(('错误', '未闭合的字符串', line_num))
pos = end_pos
continue
调用函数
def tokenize_string(content):
"""
将字符串内容拆分为 STRING_CONTENT、FORMAT_SPECIFIER 和 ESCAPE_CHAR
"""
tokens = []
pos = 0
while pos < len(content):
# 处理转义字符
if content[pos] == '\\' and pos + 1 < len(content):
tokens.append(('ESCAPE_CHAR', content[pos:pos + 2]))
pos += 2
continue
# 处理格式说明符
if content[pos] == '%' and pos + 1 < len(content):
m = re.match(r'%[0-9]*\.?[0-9]*[diouxXfFeEgGaAcspn]', content[pos:])
if m:
tokens.append(('FORMAT_SPECIFIER', m.group(0)))
pos += len(m.group(0))
continue
# 处理普通字符串内容
next_p = content.find('%', pos)
next_b = content.find('\\', pos)
end = min(
next_p if next_p != -1 else len(content),
next_b if next_b != -1 else len(content)
)
if end > pos:
tokens.append(('STRING_CONTENT', content[pos:end]))
pos = end
else:
pos += 1
return tokens
4.3 界符
# 单字符的界符直接处理
elif line[pos] in "(){},;[]":
tokens.append(('DELIMITER', line[pos], line_num))
pos += 1
4.4 普通词法匹配
else:
# 使用正则模式进行普通词法分析
match = None
for token_type, pattern in token_specification:
# 不处理空白符和注释
if token_type in ('WHITESPACE', 'COMMENT_MULTI', 'COMMENT_SINGLE'):
continue
# 尝试匹配当前位置的模式
regex = re.compile(pattern)
m = regex.match(line[pos:])
if m and m.start() == 0: # 确保匹配从当前位置开始
lexeme = m.group(0)
if lexeme == 'char':
next_pos = pos + m.end() # 计算匹配结束后的位置
if next_pos < len(line): # 确保没有超出字符串范围
next_char = line[next_pos] # 获取下一个字符
if next_char == '*':
lexeme = 'char*'
tokens.append((token_type, lexeme, line_num))
pos += len(lexeme)
match = True
break
4.5 容错跳过(可删除)以及返回
容错跳过
if not match:
# 如果没有匹配任何模式,跳过当前字符
pos += 1
返回
line_num += 1
return tokens
5. 主程序入口
- 输入: C++ 源文件名称
- 调用词法分析器处理代码
- 输出:词法单元 (类型) 行号
- 词典将输出结果转中文
def main():
file_path = input("请输入测试文件名:") # example1.cpp
try:
with open(file_path, 'r', encoding='utf-8') as f:
code = f.read()
except FileNotFoundError:
print(f"错误: 文件 '{file_path}' 未找到.")
sys.exit(1)
tokens = tokenize(code)
# 输出结果,类型用中文表示
type_map = {
'PREPROCESSOR': '预处理器',
'COMMENT_MULTI': '多行注释',
'COMMENT_SINGLE': '单行注释',
'KEYWORD': '关键字',
'IDENTIFIER': '标识符',
'FLOAT_LITERAL': '浮点数',
'INT_LITERAL': '整数',
'INT36_LITERAL': '36进制整数',
'OPERATOR': '运算符',
'DELIMITER': '分隔符',
'CHAR_LITERAL': '字符字面量',
'FORMAT_SPECIFIER': '格式说明符',
'STRING_CONTENT': '字符串内容',
'ESCAPE_CHAR': '转义字符',
'WHITESPACE': '空白符',
}
# 类型 内容 行号
for ttype, lexeme, lineno in tokens:
print(f'{lexeme} ({type_map[ttype]}) {lineno}')
if __name__ == '__main__':
main()
6. 特别说明
36 进制整数 int36
r'0[zZ]\([0-9a-zA-Z]+\)'
格式:0z(XX)
(如0z(1A)表示十进制 46)
字符串边界判断
- 识别双引号边界
- 避免转义字符的影响
- 能正确处理连续多个反斜杠的情况(如 \\")
# 检查是否是字符串字面量
if line[pos] == '"':
# 添加左引号
tokens.append(('DELIMITER', '"', line_num))
pos += 1
# 找到右引号(非转义)
end_pos = pos
while end_pos < len(line):
if line[end_pos] == '"':
# 检查是否为转义引号
backslash_count = 0
prev_pos = end_pos - 1
while prev_pos >= pos and line[prev_pos] == '\\':
backslash_count += 1
prev_pos -= 1
# 如果反斜杠数量为奇数,则是转义引号,继续寻找
if backslash_count % 2 != 0:
end_pos += 1
continue
# 否则找到真正的右引号
break
end_pos += 1
char* 数据类型关键词
# 尝试匹配当前位置的模式
regex = re.compile(pattern)
m = regex.match(line[pos:])
if m and m.start() == 0: # 确保匹配从当前位置开始
lexeme = m.group(0)
if lexeme == 'char':
next_pos = pos + m.end() # 计算匹配结束后的位置
if next_pos < len(line): # 确保没有超出字符串范围
next_char = line[next_pos] # 获取下一个字符
if next_char == '*':
lexeme = 'char*'
词法分析器工作流程
- 按行扫描:逐行处理源代码
- 注释优先:先标注处理单行注释和多行注释
- 预处理优先:先处理#include和#define
- 字符串特殊处理:识别完整字符串并解析内部结构
- 正则匹配:按顺序使用正则表达式匹配各种词法单元
- 容错处理:无法匹配的字符直接跳过(简化处理)
完整代码 lexer1.py
import re
import sys
# 定义 token 类型与对应的正则表达式
token_specification = [
# 预处理指令: #include <任意内容> 或 #define 单词1 单词2
('PREPROCESSOR', r'#(include\s+<[^>]+>|define\s+\w+\s+\w+)'),
# 多行注释: /* 尽可能少的字符 */
('COMMENT_MULTI', r'/\*.*?\*/'),
# 单行注释: // 任意字符至本行末尾
('COMMENT_SINGLE', r'//.*'),
# 关键字:数据类型: int|long|short|int36|double|float|char|void|struct
# 语句: if|else|for|while|switch|case|break|continue|return|printf
# 老师要求:增加更多的 C++ 关键字,包括 int36(36进制整数)
('KEYWORD', r'\b(int|long|short|int36|double|float|char|void|struct|if|else|for|while|switch|case|break|continue|return'
r'|printf)\b'),
# int36类型字面量: 0z(XX) (包含字母a-z,不区分大小写)
('INT36_LITERAL', r'0[zZ]\([0-9a-zA-Z]+\)'),
# 标识符(单词)
('IDENTIFIER', r'[a-zA-Z_]\w*'),
# 浮点数:支持小数、指数形式,如 3.14e10
('FLOAT_LITERAL', r'\d+\.\d+(e[+-]?\d+)?'),
# 整数:支持十六进制、八进制、二进制和十进制
('INT_LITERAL', r'0[xX][0-9a-fA-F]+|0[0-7]+|\d+'),
# 字符字面量 转义字符字面量 '\a' '\b' '\f' '\n' '\r' '\t' '\v' '\\' '\'' '\"' '3位\数字0-7'(8进制数) 或 '任意字符'
('CHAR_LITERAL', r"'(\\[abfnrtv\\\'\"?0-7]|[^\\'])'"),
# 运算符 (不包括点,因为点在标识符中已经处理)
('OPERATOR', r'\+\+|--|==|>=|<=|!=|&&|\|\||\+\-|\*/|<<|>>|&|\||\^|~|=|\+|\-|\*|\/|%|<|>'),
# 分隔符 ( ) { } , ; \ [ ] ' " .
('DELIMITER', r'[(){},;\[\]\'"\.]'),
# 转义字符 \a \b \f \n \r \t \v \\ \' \"
('ESCAPE_CHAR', r'\\[abfnrtv\\\'\"]'),
# 格式说明符 %数字.数字字符 如:%3.3d
('FORMAT_SPECIFIER', r'%[0-9]*\.?[0-9]*[diouxXfFeEgGaAcspn]'),
# 字符串内容 除了%、双引号、换行符之外任意字符
('STRING_CONTENT', r'[^%\\"\n]+'),
# 空白符
('WHITESPACE', r'\s+'),
]
def tokenize(code):
"""
传入 C++ 代码字符串,返回一个 (token_type, lexeme) 的列表
"""
tokens = []
# 按行处理,方便处理预处理指令或注释
lines = code.split('\n')
line_num = 1 # 当前行数
in_multi_comment = False # 标记是否已在多行注释里
# 逐行处理
for line in lines:
stripped_line = line.lstrip()
# 处理多行注释的情况
if in_multi_comment:
end_pos = stripped_line.find('*/')
if end_pos != -1:
# 多行注释在此行结束,提取注释内容
comment_content = stripped_line[:end_pos + 2]
tokens.append(('COMMENT_MULTI', comment_content, line_num))
in_multi_comment = False
# 处理注释后的剩余部分
remaining = stripped_line[end_pos + 2:].lstrip()
if remaining:
# 递归处理剩余部分(简化版,实际可能需要更复杂逻辑)
tokens.extend(tokenize(remaining))
else:
# 多行注释继续到下一行
tokens.append(('COMMENT_MULTI', stripped_line, line_num))
line_num += 1
continue
# 检查是否开始新的多行注释
if stripped_line.startswith('/*'):
end_pos = stripped_line.find('*/')
if end_pos != -1:
# 单行内的多行注释 /* ... */
tokens.append(('COMMENT_MULTI', stripped_line[:end_pos + 2], line_num))
# 处理注释后的剩余部分
remaining = stripped_line[end_pos + 2:].lstrip()
if remaining:
tokens.extend(tokenize(remaining))
else:
# 多行注释开始但未结束
tokens.append(('COMMENT_MULTI', stripped_line, line_num))
in_multi_comment = True
line_num += 1
continue
# 检查是否为单行注释
comment_pos = line.find('//')
# 处理预处理指令
if line.startswith('#'):
tokens.extend(tokenize_preprocessor(line, line_num))
line_num += 1
continue
# 对非预处理指令的行应用常规的词法分析
pos = 0 # 本行已处理指针
# 逐字符判断
while pos < len(line):
# 跳过空白字符
if line[pos].isspace():
pos += 1
continue
# 单行注释
if pos == comment_pos:
comment_text = line[comment_pos:]
tokens.append(('COMMENT_SINGLE', comment_text, line_num))
break
# 检查是否是字符串字面量
if line[pos] == '"':
# 添加左引号
tokens.append(('DELIMITER', '"', line_num))
pos += 1
# 找到右引号(非转义)
end_pos = pos
while end_pos < len(line):
if line[end_pos] == '"':
# 检查是否为转义引号
backslash_count = 0
prev_pos = end_pos - 1
while prev_pos >= pos and line[prev_pos] == '\\':
backslash_count += 1
prev_pos -= 1
# 如果反斜杠数量为奇数,则是转义引号,继续寻找
if backslash_count % 2 != 0:
end_pos += 1
continue
# 否则找到真正的右引号
break
end_pos += 1
if end_pos < len(line):
# 提取字符串内容
string_content = line[pos:end_pos]
# 处理字符串内部的各种元素
string_tokens = tokenize_string(string_content)
tokens.extend([(token_type, token, line_num) for token_type, token in string_tokens])
# 添加右引号
tokens.append(('DELIMITER', '"', line_num))
pos = end_pos + 1
else:
# 未闭合的字符串,错误处理
tokens.append(('错误', '未闭合的字符串', line_num))
pos = end_pos
continue
# 单字符的界符直接处理
elif line[pos] in "(){},;[]":
tokens.append(('DELIMITER', line[pos], line_num))
pos += 1
else:
# 使用正则模式进行普通词法分析
match = None
for token_type, pattern in token_specification:
# 不处理空白符和注释
if token_type in ('WHITESPACE', 'COMMENT_MULTI', 'COMMENT_SINGLE'):
continue
# 尝试匹配当前位置的模式
regex = re.compile(pattern)
m = regex.match(line[pos:])
if m and m.start() == 0: # 确保匹配从当前位置开始
lexeme = m.group(0)
if lexeme == 'char':
next_pos = pos + m.end() # 计算匹配结束后的位置
if next_pos < len(line): # 确保没有超出字符串范围
next_char = line[next_pos] # 获取下一个字符
if next_char == '*':
lexeme = 'char*'
tokens.append((token_type, lexeme, line_num))
pos += len(lexeme)
match = True
break
if not match:
# 如果没有匹配任何模式,跳过当前字符
pos += 1
line_num += 1
return tokens
def tokenize_preprocessor(line, line_num):
"""处理预处理指令"""
tokens = []
if line.startswith('#include'):
tokens.append(('PREPROCESSOR', line, line_num))
elif line.startswith('#define'):
tokens.append(('PREPROCESSOR', line, line_num))
return tokens
def tokenize_string(content):
"""
将字符串内容拆分为 STRING_CONTENT、FORMAT_SPECIFIER 和 ESCAPE_CHAR
"""
tokens = []
pos = 0
while pos < len(content):
# 处理转义字符
if content[pos] == '\\' and pos + 1 < len(content):
tokens.append(('ESCAPE_CHAR', content[pos:pos + 2]))
pos += 2
continue
# 处理格式说明符
if content[pos] == '%' and pos + 1 < len(content):
m = re.match(r'%[0-9]*\.?[0-9]*[diouxXfFeEgGaAcspn]', content[pos:])
if m:
tokens.append(('FORMAT_SPECIFIER', m.group(0)))
pos += len(m.group(0))
continue
# 处理普通字符串内容
next_p = content.find('%', pos)
next_b = content.find('\\', pos)
end = min(
next_p if next_p != -1 else len(content),
next_b if next_b != -1 else len(content)
)
if end > pos:
tokens.append(('STRING_CONTENT', content[pos:end]))
pos = end
else:
pos += 1
return tokens
def main():
file_path = input("请输入测试文件名:") # example1.cpp
try:
with open(file_path, 'r', encoding='utf-8') as f:
code = f.read()
except FileNotFoundError:
print(f"错误: 文件 '{file_path}' 未找到.")
sys.exit(1)
tokens = tokenize(code)
# 输出结果,类型用中文表示
type_map = {
'PREPROCESSOR': '预处理器',
'COMMENT_MULTI': '多行注释',
'COMMENT_SINGLE': '单行注释',
'KEYWORD': '关键字',
'IDENTIFIER': '标识符',
'FLOAT_LITERAL': '浮点数',
'INT_LITERAL': '整数',
'INT36_LITERAL': '36进制整数',
'OPERATOR': '运算符',
'DELIMITER': '分隔符',
'CHAR_LITERAL': '字符字面量',
'FORMAT_SPECIFIER': '格式说明符',
'STRING_CONTENT': '字符串内容',
'ESCAPE_CHAR': '转义字符',
'WHITESPACE': '空白符',
}
# 类型 内容 行号
for ttype, lexeme, lineno in tokens:
print(f'{lexeme} ({type_map[ttype]}) {lineno}')
if __name__ == '__main__':
main()
实验样例
- 新建 example1.cpp 样例文件
- 输入样例代码(这里采用实验2老师给的样例)
struct student{
char* name; //姓名
int num; //学号
int age; //年龄
float score; //成绩
};
void main(){
int i, num_140 = 0;
float sum = 0;
student sts[2]={{"Li ping", 5, 18, 145.0},
{"Wang ming", 6, 18, 150.0}};
if(sts[1].score<140) flag=-1;
else flag=1;
printf("%d ", flag);
}
- 启动程序 lexer1.py 并输入 example1.cpp
- 输出结果
struct (关键字) 1
student (标识符) 1
{ (分隔符) 1
char* (关键字) 2
name (标识符) 2
; (分隔符) 2
//姓名 (单行注释) 2
int (关键字) 3
num (标识符) 3
; (分隔符) 3
//学号 (单行注释) 3
int (关键字) 4
age (标识符) 4
; (分隔符) 4
//年龄 (单行注释) 4
float (关键字) 5
score (标识符) 5
; (分隔符) 5
//成绩 (单行注释) 5
} (分隔符) 6
; (分隔符) 6
void (关键字) 7
main (标识符) 7
( (分隔符) 7
) (分隔符) 7
{ (分隔符) 7
int (关键字) 8
i (标识符) 8
, (分隔符) 8
num_140 (标识符) 8
= (运算符) 8
0 (整数) 8
; (分隔符) 8
float (关键字) 9
sum (标识符) 9
= (运算符) 9
0 (整数) 9
; (分隔符) 9
student (标识符) 10
sts (标识符) 10
[ (分隔符) 10
2 (整数) 10
] (分隔符) 10
= (运算符) 10
{ (分隔符) 10
{ (分隔符) 10
" (分隔符) 10
Li ping (字符串内容) 10
" (分隔符) 10
, (分隔符) 10
5 (整数) 10
, (分隔符) 10
18 (整数) 10
, (分隔符) 10
145.0 (浮点数) 10
} (分隔符) 10
, (分隔符) 10
{ (分隔符) 11
" (分隔符) 11
Wang ming (字符串内容) 11
" (分隔符) 11
, (分隔符) 11
6 (整数) 11
, (分隔符) 11
18 (整数) 11
, (分隔符) 11
150.0 (浮点数) 11
} (分隔符) 11
} (分隔符) 11
; (分隔符) 11
if (关键字) 12
( (分隔符) 12
sts (标识符) 12
[ (分隔符) 12
1 (整数) 12
] (分隔符) 12
. (分隔符) 12
score (标识符) 12
< (运算符) 12
140 (整数) 12
) (分隔符) 12
flag (标识符) 12
= (运算符) 12
- (运算符) 12
1 (整数) 12
; (分隔符) 12
else (关键字) 13
flag (标识符) 13
= (运算符) 13
1 (整数) 13
; (分隔符) 13
printf (关键字) 14
( (分隔符) 14
" (分隔符) 14
%d (格式说明符) 14
(字符串内容) 14
" (分隔符) 14
, (分隔符) 14
flag (标识符) 14
) (分隔符) 14
; (分隔符) 14
} (分隔符) 15
其他解释
本小组自用广西大学编译原理课程设计,指导教师 hrw
个别功能符号的识别未实现(面向结果的编程)