-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy patherror.c
228 lines (201 loc) · 6.38 KB
/
error.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <assert.h>
#include "MEM.h"
#include "DBG.h"
#include "sicpy.h"
extern char *yytext;
/* 编译报错信息 */
char* scp_compile_error_message_format[] = {
"在($(token))附近发生语法错误",
"不正确的字符($(bad_char))",
"函数名重复($(name))",
};
/* 运行时报错信息 */
char* scp_runtime_error_message_format[] = {
"找不到变量($(name))。",
"找不到函数($(name))。",
"传入的参数数量多于函数定义。",
"传入的参数数量少于函数定义。",
"条件表达式的值必须是boolean型。",
"减法运算的操作数必须是数值类型。",
"双目操作符$(operator)的操作数类型不正确。",
"$(operator)操作符不能用于boolean型。",
"找不到对应文件,请为fopen()函数传入文件的路径和打开方式(两者都是字符串类型的)。",
"请为fclose()函数传入文件指针。",
"请为fread()函数传入文件指针。",
"请为fwrite()函数传入文件指针和字符串。",
"null只能用于运算符 == 和 !=(不能进行$(operator)操作)。",
"除0错误,请检查",
"全局变量$(name)不存在。",
"不能在函数外使用global语句。",
"运算符$(operator)不能用于字符串类型。",
};
/* 字符数组指针定义为字串 */
typedef struct {
char *string;
} VString;
/* 统计字串长度 */
int my_strlen(char *str)
{
/* 如果不慎传入空指针,则改变为0(strlen遇到空指针不能处理) */
if (str == NULL) {
return 0;
}
return strlen(str);
}
/* 添加字串 */
static void add_string(VString *message, char *str)
{
int old_len = my_strlen(message->string);
int new_size = old_len + strlen(str) + 1;
message->string = MEM_realloc(message->string, new_size);
strcpy(&message->string[old_len], str);
}
/* 添加字符 */
static void add_character(VString *message, int ch)
{
int current_len = my_strlen(message->string);
message->string = MEM_realloc(message->string, current_len + 2);
message->string[current_len] = ch;
message->string[current_len+1] = '\0';
}
/* 处理变长实参,全部存入args数组中 */
static void create_message_args(MessageArgument *arg_list, va_list ap)
{
int index = 0;
MessageArgumentType type;
/* 遍历参数列表,直到设定的参数末尾MESSAGE_ARGUMENT_END,va_arg获取指定类型的当前参数 */
while ((type = va_arg(ap, MessageArgumentType)) != MESSAGE_ARGUMENT_END) {
arg_list[index].type = type;
arg_list[index].name = va_arg(ap, char*);
switch (type) {
case INT_MESSAGE_ARGUMENT:
arg_list[index].u.int_val = va_arg(ap, int);
break;
case DOUBLE_MESSAGE_ARGUMENT:
arg_list[index].u.double_val = va_arg(ap, double);
break;
case STRING_MESSAGE_ARGUMENT:
arg_list[index].u.string_val = va_arg(ap, char*);
break;
case POINTER_MESSAGE_ARGUMENT:
arg_list[index].u.pointer_val = va_arg(ap, void*);
break;
case CHARACTER_MESSAGE_ARGUMENT:
arg_list[index].u.character_val = va_arg(ap, int);
break;
/* 以下是不该出现的情况,使用assert(0)报错 */
case MESSAGE_ARGUMENT_END:
default:
assert(0);
}
index++;
assert(index < MESSAGE_ARGUMENT_MAX);
}
}
/* 在实参列表中找到指定参数名,赋给当前实参 */
static MessageArgument search_argument(MessageArgument *arg_list, char *arg_name)
{
int i;
for (i = 0; arg_list[i].type != MESSAGE_ARGUMENT_END; i++) {
/* 如果名称相同 */
if (!strcmp(arg_list[i].name, arg_name)) {
return arg_list[i];
}
}
assert(0);
}
/* 格式化报错信息 */
static void format_message(char *format, VString *message, va_list ap)
{
int i;
char buf[LINE_BUF_SIZE];
int arg_name_index;
char arg_name[LINE_BUF_SIZE];
MessageArgument arg_list[MESSAGE_ARGUMENT_MAX]; /* 变长实参信息列表 */
/* 变长实参信息存入arg_list中 */
create_message_args(arg_list, ap);
/* 遍历字串,解析$ */
for (i = 0; format[i] != '\0'; i++) {
if (format[i] != '$') {
add_character(message, format[i]);
continue;
}
assert(format[i+1] == '(');
i += 2;
/* 开始解析$的参数 */
for (arg_name_index = 0; format[i] != ')'; arg_name_index++, i++) {
arg_name[arg_name_index] = format[i];
}
arg_name[arg_name_index] = '\0';
assert(format[i] == ')');
/* 搜索实参列表,找到当前实参 */
MessageArgument cur_arg = search_argument(arg_list, arg_name);
/* 根据实参类型,写入message字串 */
switch (cur_arg.type) {
case INT_MESSAGE_ARGUMENT:
sprintf(buf, "%d", cur_arg.u.int_val);
add_string(message, buf);
break;
case DOUBLE_MESSAGE_ARGUMENT:
sprintf(buf, "%f", cur_arg.u.double_val);
add_string(message, buf);
break;
case STRING_MESSAGE_ARGUMENT:
strcpy(buf, cur_arg.u.string_val);
add_string(message, cur_arg.u.string_val);
break;
case POINTER_MESSAGE_ARGUMENT:
sprintf(buf, "%p", cur_arg.u.pointer_val);
add_string(message, buf);
break;
case CHARACTER_MESSAGE_ARGUMENT:
sprintf(buf, "%c", cur_arg.u.character_val);
add_string(message, buf);
break;
case MESSAGE_ARGUMENT_END:
default:
assert(0);
}
}
}
/* 编译型错误 */
void scp_compile_error(CompileError id, ...)
{
/* 获取不确定参数的列表 */
va_list ap;
VString message;
va_start(ap, id); /* 根据第一个参数地址找到填充参数列表 */
int line_number = scp_get_interpreter()->current_line_number;
message.string = NULL;
format_message(scp_compile_error_message_format[id], &message, ap);
fprintf(stderr, "%3d:%s\n", line_number, message.string);
va_end(ap); /* 释放变长实参列表 */
exit(1);
}
/* 运行时错误 */
void scp_runtime_error(int line_number, RuntimeError id, ...)
{
va_list ap;
VString message;
va_start(ap, id);
message.string = NULL;
format_message(scp_runtime_error_message_format[id], &message, ap);
fprintf(stderr, "%3d:%s\n", line_number, message.string);
va_end(ap);
exit(1);
}
/* 语法分析报错 */
int yyerror(char const *str)
{
char *near_token;
if (yytext[0] == '\0') {
near_token = "EOF";
} else {
near_token = yytext;
}
scp_compile_error(PARSE_ERR, STRING_MESSAGE_ARGUMENT, "token", near_token, MESSAGE_ARGUMENT_END);
return 0;
}