任务
你将使用图转移算法手工实现一个小型的词法分析器。
- 分析器的输入:存储在文本文件中的字符序列,字符取自ASCII字符集。文件中可能包括下面几种记号:关键字if、符合C语言标准的标识符、无符号整型数字、空格符、回车符\n。
- 分析器的输出:打印出所识别的记号的种类、及记号开始行号、开始列号信息。
注意:1. 忽略空格及回车符;2. 对于标识符和数字,要输出符号的具体词法单元(见下面的示例)。
【示例】对于下面的文本文件:
ifx if iif if 234
iff if
你的输出应该是(注意,因为文本显示的原因,列号信息可能不一定准确):
ID(ifx) (1, 1)
IF (1, 4)
ID(iif) (1, 8)
IF (1, 13)
NUM(234) (1, 16)
ID(iff) (2, 1)
IF (2, 8)
程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE 1024 //每行做大的字节数
//词法的类型
enum Kind {
IF,
ID,
NUM
};
//存储每个词的信息的结构体
struct Token {
enum Kind kind;
char* value;
int row;
int col;
};
struct Token *Token_new(enum Kind kind, char *value, int row, int col) {
struct Token *token = (struct Token*)malloc(sizeof(*token));
token->value = (char*)malloc(sizeof(*value));
strncpy(token->value, value, strlen(value));
token->kind = kind;
token->row = row;
token->col = col;
return token;
}
//用于存放所有词的链表结构
struct List {
struct Token *token;
struct List *next;
};
struct List *all_word;
struct List* List_new(struct Token* t, struct List* list) {
struct List* p = (struct List*)malloc(sizeof(*p));
p->token = t;
p->next = list;
return p;
}
void List_print(struct List* list) {
if (!list) {
return;
}
List_print(list->next);
switch (list->token->kind) {
case IF: {
printf("IF (%d, %d)\n", list->token->row, list->token->col);
break;
}
case ID: {
printf("ID(%s) (%d, %d)\n", list->token->value, list->token->row, list->token->col);
break;
}
case NUM: {
printf("NUM(%s) (%d, %d)\n", list->token->value, list->token->row, list->token->col);
break;
}
default:
break;
}
}
//处理单词
void Process_word(char *word, int len, int row, int col) {
if (strcmp("if", word) == 0) {
struct Token *token = Token_new(IF, word, row, col);
all_word = List_new(token, all_word);
}else if (Is_num(word, len) == 1) {
struct Token *token = Token_new(NUM, word, row, col);
all_word = List_new(token, all_word);
} else {
struct Token *token = Token_new(ID, word, row, col);
all_word = List_new(token, all_word);
}
}
//判断是否为数字
int Is_num(char* word, int len) {
for (int i = 0; i < len; i++) {
if (word[i] < '0' || word[i] > '9'){
return 0;
}
}
return 1;
}
int main() {
FILE *file;
char strLine[MAX_LINE];
char str[MAX_LINE];
if ((file = fopen("/home/hz/a.txt", "r")) == NULL) {
printf("Open Failed!");
return -1;
}
int curr_row = 0; //当前的行数
while (!feof(file)) {
curr_row++;
if(fgets(strLine, MAX_LINE, file)){
printf("%s", strLine);
int len = strlen(strLine);
int str_save_len = 0;
for (int i = 0; i < len; i++) {
char c = strLine[i];
switch (c) {
case ' ': {
if (str_save_len > 0) {
str[str_save_len] = '\0';
Process_word(str, str_save_len, curr_row, i + 1);
str_save_len = 0;
}
break;
}
case '\n': {
if (str_save_len > 0) {
str[str_save_len] = '\0';
Process_word(str, str_save_len, curr_row, i + 1);
str_save_len = 0;
}
break;
}
default: {
str[str_save_len++] = c;
}
}
}
}
}
List_print(all_word);
fclose(file);
return 0;
}