熟悉并实现一个简单的扫描器,设计扫描器的自动机;设计翻译、生成Token的算法;编写代码并上机调试运行通过。 要求扫描器可识别的单词包括:关键字、界符、标识符和常整形数。 其中关键字表、界符表、标识符表、常整数表如下:(表中没有的关键字、界符等可以接着编号继续扩展)
时间: 2024-01-12 16:05:02 浏览: 187
为了实现一个简单的扫描器,需要设计一个有限状态自动机(Finite State Automaton, FSA),它可以将输入的字符流转换成一系列的 Token。在设计自动机之前,需要先定义好 Token 的类型以及它们的属性。
Token 类型:
- 关键字(KEYWORD):if、else、while、for、int等
- 界符(DELIMITER):括号、分号、逗号等
- 标识符(IDENTIFIER):由字母和数字组成的字符串,不能以数字开头
- 常整数(INTEGER):由数字组成的字符串
接下来,我们需要设计一个自动机来将字符流转换成 Token。这个自动机可以分为以下几个状态:
- 初始状态(INITIAL):读入一个字符,决定下一步进入哪个状态
- 关键字状态(KEYWORD):读入字符直到不再是字母或数字,输出一个关键字 Token
- 标识符状态(IDENTIFIER):读入字符直到不再是字母或数字,输出一个标识符 Token
- 常整数状态(INTEGER):读入字符直到不再是数字,输出一个常整数 Token
- 界符状态(DELIMITER):读入一个字符,输出一个界符 Token
下面是自动机的状态转移图:
```
+---------------------+
| ( |
v |
+-----------+ |
| INITIAL |------(------> | DELIMITER
+-----------+ | |
| | |
| letter|number
| | |
v | |
+-----------+ | |
| KEYWORD |<------( |
+-----------+ | |
| | |
| letter|number
| | |
v | |
+-------------+ | |
| IDENTIFIER |<-----( |
+-------------+ | |
| | |
| digit| |
| v |
v +--------+ |
+-----------+ | INTEGER|<--+
| | +--------+ |
| DELIMITER | | |
| | | |
+-----------+ | |
| | |
| digit|letter|
| v |
+----------- +-------+
```
根据状态转移图我们可以设计如下的 Tokenizer 类:
```python
class Tokenizer:
def __init__(self, keywords, delimiters):
self.keywords = keywords
self.delimiters = delimiters
def tokenize(self, input_str):
tokens = []
state = 'INITIAL'
buffer = ''
for c in input_str:
if state == 'INITIAL':
if c.isalpha():
buffer += c
state = 'KEYWORD'
elif c.isdigit():
buffer += c
state = 'INTEGER'
elif c in self.delimiters:
tokens.append((c, 'DELIMITER'))
elif c.isspace():
pass # skip whitespace
else:
raise ValueError(f'Invalid character: {c}')
elif state == 'KEYWORD':
if c.isalnum():
buffer += c
else:
if buffer in self.keywords:
tokens.append((buffer, 'KEYWORD'))
else:
tokens.append((buffer, 'IDENTIFIER'))
buffer = ''
state = 'INITIAL'
if c.isdigit():
buffer += c
state = 'INTEGER'
elif c in self.delimiters:
tokens.append((c, 'DELIMITER'))
elif not c.isspace():
raise ValueError(f'Invalid character: {c}')
elif state == 'IDENTIFIER':
if c.isalnum():
buffer += c
else:
tokens.append((buffer, 'IDENTIFIER'))
buffer = ''
state = 'INITIAL'
if c.isdigit():
buffer += c
state = 'INTEGER'
elif c in self.delimiters:
tokens.append((c, 'DELIMITER'))
elif not c.isspace():
raise ValueError(f'Invalid character: {c}')
elif state == 'INTEGER':
if c.isdigit():
buffer += c
else:
tokens.append((buffer, 'INTEGER'))
buffer = ''
state = 'INITIAL'
if c.isalpha():
buffer += c
state = 'KEYWORD'
elif c in self.delimiters:
tokens.append((c, 'DELIMITER'))
elif not c.isspace():
raise ValueError(f'Invalid character: {c}')
# Handle final buffer
if state == 'KEYWORD':
if buffer in self.keywords:
tokens.append((buffer, 'KEYWORD'))
else:
tokens.append((buffer, 'IDENTIFIER'))
elif state == 'IDENTIFIER':
tokens.append((buffer, 'IDENTIFIER'))
elif state == 'INTEGER':
tokens.append((buffer, 'INTEGER'))
return tokens
```
这个 Tokenizer 类接受一个关键字列表和一个界符列表作为参数,然后提供一个 tokenize 方法来将输入的字符串转换成 Token 的列表。
下面是一个使用 Tokenizer 的例子:
```python
keywords = ['if', 'else', 'while', 'for', 'int']
delimiters = ['(', ')', '{', '}', ',', ';']
tokenizer = Tokenizer(keywords, delimiters)
tokens = tokenizer.tokenize('for (i = 0; i < n; i++) { printf("%d\n", i); }')
print(tokens)
# Output: [('for', 'KEYWORD'), ('(', 'DELIMITER'), ('i', 'IDENTIFIER'),
# ('=', 'DELIMITER'), ('0', 'INTEGER'), (';', 'DELIMITER'),
# ('i', 'IDENTIFIER'), ('<', 'DELIMITER'), ('n', 'IDENTIFIER'),
# (';', 'DELIMITER'), ('i', 'IDENTIFIER'), ('+', 'DELIMITER'),
# ('+', 'DELIMITER'), (')', 'DELIMITER'), ('{', 'DELIMITER'),
# ('printf', 'IDENTIFIER'), ('(', 'DELIMITER'), ('"%d\\n"', 'STRING'),
# (',', 'DELIMITER'), ('i', 'IDENTIFIER'), (')', 'DELIMITER'),
# (';', 'DELIMITER'), ('}', 'DELIMITER')]
```
在这个例子中,我们创建了一个 Tokenizer 并使用它将一个 for 循环的字符串转换成 Token 列表。可以看到,我们得到了正确的 Token 列表,其中包括了关键字、标识符、常整数、界符等不同类型的 Token。
阅读全文