从 PL/0 编译程序源码中抽出词法分析部分,构建 PL/0 独立词法分析程序。功能:输入为 PL/0 源程序, 输出为单词符号的序列;对于标识符和无符号整数,显示单词种别和单词自身的值两项内容;对于其他单词符号,仅显示其单词种别。
时间: 2024-05-06 07:16:12 浏览: 94
以下是一个简单的 PL/0 独立词法分析程序的示例代码:
```C++
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
// 单词种类
enum TokenType {
IDENTIFIER, // 标识符
NUMBER, // 无符号整数
RESERVED, // 保留字
SYMBOL, // 符号
ERROR // 错误
};
// 保留字列表
string reservedWords[] = { "const", "var", "procedure", "begin", "end", "if", "then", "while", "do", "call", "read", "write", "odd" };
// 单词符号
struct Token {
TokenType type; // 单词种类
string value; // 单词值
int line; // 行号
};
// 判断是否为字母
bool isLetter(char c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
// 判断是否为数字
bool isDigit(char c) {
return c >= '0' && c <= '9';
}
// 判断是否为空白符号
bool isWhitespace(char c) {
return c == ' ' || c == '\t' || c == '\r';
}
// 词法分析函数
Token getNextToken(ifstream& file, int& line) {
Token token;
char c;
string buffer = "";
// 跳过空白符号
do {
c = file.get();
if (c == '\n') {
line++;
}
} while (isWhitespace(c));
// 判断单词符号类型
if (isLetter(c)) { // 标识符或保留字
while (isLetter(c) || isDigit(c)) {
buffer += c;
c = file.get();
}
file.unget();
for (int i = 0; i < sizeof(reservedWords) / sizeof(reservedWords[0]); i++) {
if (buffer == reservedWords[i]) {
token.type = RESERVED;
token.value = buffer;
token.line = line;
return token;
}
}
token.type = IDENTIFIER;
token.value = buffer;
token.line = line;
return token;
}
else if (isDigit(c)) { // 无符号整数
while (isDigit(c)) {
buffer += c;
c = file.get();
}
file.unget();
token.type = NUMBER;
token.value = buffer;
token.line = line;
return token;
}
else { // 符号
switch (c) {
case '+':
case '-':
case '*':
case '/':
case '(':
case ')':
case ',':
case ';':
case '.':
case ':':
token.type = SYMBOL;
token.value = c;
token.line = line;
return token;
case '<':
c = file.get();
if (c == '=') {
token.type = SYMBOL;
token.value = "<=";
token.line = line;
}
else if (c == '>') {
token.type = SYMBOL;
token.value = "<>";
token.line = line;
}
else {
file.unget();
token.type = SYMBOL;
token.value = "<";
token.line = line;
}
return token;
case '>':
c = file.get();
if (c == '=') {
token.type = SYMBOL;
token.value = ">=";
token.line = line;
}
else {
file.unget();
token.type = SYMBOL;
token.value = ">";
token.line = line;
}
return token;
case ':':
c = file.get();
if (c == '=') {
token.type = SYMBOL;
token.value = ":=";
token.line = line;
return token;
}
else {
file.unget();
token.type = ERROR;
token.value = ":";
token.line = line;
return token;
}
default:
token.type = ERROR;
token.value = c;
token.line = line;
return token;
}
}
}
int main() {
ifstream file("program.pl0");
int line = 1;
Token token;
while (file.peek() != EOF) {
token = getNextToken(file, line);
cout << token.value << "\t" << token.type;
if (token.type == IDENTIFIER || token.type == NUMBER) {
cout << "\t" << token.value;
}
cout << endl;
}
file.close();
return 0;
}
```
在该程序中,我们定义了 `TokenType` 枚举类型,用来表示单词符号的种类。我们还定义了一个 `Token` 结构体,用来表示单词符号的值、种类和行号。对于保留字,我们使用一个字符串数组来存储,用于后续判断是否为保留字。
在 `getNextToken` 函数中,我们使用一个 `do-while` 循环来跳过源代码中的空白符号。接着,我们根据当前字符的类型来判断单词符号的类型。对于标识符和数字,我们使用 `while` 循环来读取整个单词,直到遇到不属于该单词的字符为止。对于符号,我们使用 `switch` 语句来判断具体的符号类型,并返回相应的 `Token` 结构体。
在 `main` 函数中,我们打开 PL/0 源程序文件,逐个读取单词符号,并输出其类型和值。对于标识符和数字,我们还输出其值。最后,我们关闭文件并退出程序。
需要注意的是,该程序只能识别 PL/0 的语法规则中定义的单词符号,如果源程序中存在语法错误,该程序可能无法正确识别单词符号。
阅读全文