Skip to content

Commit cdfdee6

Browse files
authored
Merge pull request #20 from MisakaVan/dev-field-check
feat(parser): support identifier overlapping checking within struct/union's field scope
2 parents 7e7af7f + f4e90f5 commit cdfdee6

File tree

8 files changed

+125
-51
lines changed

8 files changed

+125
-51
lines changed

.clang-format

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ AlignConsecutiveDeclarations:
2222
# AcrossComments: false
2323
# AlignCompound: false
2424
# PadOperators: false
25-
# AlignConsecutiveMacros:
26-
# Enabled: false
25+
AlignConsecutiveMacros:
26+
Enabled: True
2727
# AcrossEmptyLines: false
2828
# AcrossComments: false
2929
# AlignCompound: false

readme.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
- [ ] 利用 `lib.h` 给的哈希表存放一些类型前置定义
1212
- [x] 检查在全局变量/Struct/Union/Enum/Typedef声明中出现的标识符是否已经在全局出现过
1313
- [x] 检查Struct/Union/Enum/Typedef被使用时是否已经有前置定义
14-
- [ ] 检查Struct/Union的字段内是否有变量名重复
14+
- [x] 检查Struct/Union的字段内是否有变量名重复
15+
- [ ] 指出检查的完备性(没有遗漏检查)
1516
- [ ] 完善build、test、使用文档
1617

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
struct Foo {
2+
int var1;
3+
int var2;
4+
char var2; // Warning: redeclaration of 'var2' field
5+
};
6+
7+
union Bar {
8+
char var1; // OK: 'var1' is not declared yet in this scope
9+
int (*var2)(int); // OK: 'var2' is not declared yet in this scope
10+
struct Foo var2; // Warning: redeclaration of 'var2' field
11+
};

src/lang.c

Lines changed: 7 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ struct left_type* TNewStructType(char* name, struct type_list* fld) {
102102
res->d.NEW_STRUCT_TYPE.fld = fld;
103103

104104
register_identifier_struct(name);
105+
check_field_list(fld);
105106
return res;
106107
}
107108

@@ -122,6 +123,7 @@ struct left_type* TNewUnionType(char* name, struct type_list* fld) {
122123
res->d.NEW_UNION_TYPE.fld = fld;
123124

124125
register_identifier_union(name);
126+
check_field_list(fld);
125127

126128
return res;
127129
}
@@ -173,6 +175,7 @@ struct var_decl_expr* TOrigType(char* name) {
173175
struct var_decl_expr* res = new_var_decl_expr_ptr();
174176
res->t = T_ORIG_TYPE;
175177
res->d.ORIG_TYPE.name = name;
178+
res->d.ORIG_TYPE.lineno = yylineno;
176179
return res;
177180
}
178181

@@ -208,6 +211,7 @@ struct glob_item* TStructDef(char* name, struct type_list* fld) {
208211
res->d.STRUCT_DEF.fld = fld;
209212

210213
register_identifier_struct(name);
214+
check_field_list(fld);
211215

212216
return res;
213217
}
@@ -229,6 +233,7 @@ struct glob_item* TUnionDef(char* name, struct type_list* fld) {
229233
res->d.UNION_DEF.fld = fld;
230234

231235
register_identifier_union(name);
236+
check_field_list(fld);
232237

233238
return res;
234239
}
@@ -271,22 +276,7 @@ struct glob_item* TTypeDef(struct left_type* t, struct var_decl_expr* e) {
271276
res->d.TYPE_DEF.e = e;
272277

273278
// get the core type name and register it
274-
struct var_decl_expr* ptr = e;
275-
while (ptr->t != T_ORIG_TYPE) {
276-
switch (ptr->t) {
277-
case T_PTR_TYPE:
278-
ptr = ptr->d.PTR_TYPE.base;
279-
break;
280-
case T_ARRAY_TYPE:
281-
ptr = ptr->d.ARRAY_TYPE.base;
282-
break;
283-
case T_FUNC_TYPE:
284-
ptr = ptr->d.FUNC_TYPE.ret;
285-
break;
286-
case T_ORIG_TYPE:
287-
break;
288-
}
289-
}
279+
struct var_decl_expr* ptr = get_core_type(e);
290280
register_identifier_typedef(ptr->d.ORIG_TYPE.name);
291281

292282
return res;
@@ -299,22 +289,7 @@ struct glob_item* TVarDef(struct left_type* t, struct var_decl_expr* e) {
299289
res->d.VAR_DEF.e = e;
300290

301291
// get the core type name and register it
302-
struct var_decl_expr* ptr = e;
303-
while (ptr->t != T_ORIG_TYPE) {
304-
switch (ptr->t) {
305-
case T_PTR_TYPE:
306-
ptr = ptr->d.PTR_TYPE.base;
307-
break;
308-
case T_ARRAY_TYPE:
309-
ptr = ptr->d.ARRAY_TYPE.base;
310-
break;
311-
case T_FUNC_TYPE:
312-
ptr = ptr->d.FUNC_TYPE.ret;
313-
break;
314-
case T_ORIG_TYPE:
315-
break;
316-
}
317-
}
292+
struct var_decl_expr* ptr = get_core_type(e);
318293
register_identifier_variable(ptr->d.ORIG_TYPE.name);
319294
return res;
320295
}

src/lang.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#ifndef LANG_H_INCLUDED
22
#define LANG_H_INCLUDED
33

4-
#include "lib.h"
54
#include <stdio.h>
65
#include <stdlib.h>
76

@@ -104,6 +103,7 @@ struct var_decl_expr {
104103
union {
105104
struct {
106105
char* name;
106+
int lineno;
107107
} ORIG_TYPE;
108108
struct {
109109
struct var_decl_expr* base;

src/lib.c

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
#include "lib.h"
2+
#include "lang.h"
23
#include <stdio.h>
34
#include <stdlib.h>
45
#include <string.h>
56

7+
int log_level = 0;
8+
69
unsigned int build_nat(char* c, int len) {
710
int s = 0, i = 0;
811
for (i = 0; i < len; ++i) {
@@ -110,6 +113,28 @@ void SLL_hash_delete(struct SLL_hash_table* t, char* key) {
110113

111114
struct SLL_hash_table* identifier_table;
112115

116+
117+
118+
struct var_decl_expr *get_core_type(struct var_decl_expr *ptr){
119+
while (ptr->t != T_ORIG_TYPE) {
120+
switch (ptr->t) {
121+
case T_PTR_TYPE:
122+
ptr = ptr->d.PTR_TYPE.base;
123+
break;
124+
case T_ARRAY_TYPE:
125+
ptr = ptr->d.ARRAY_TYPE.base;
126+
break;
127+
case T_FUNC_TYPE:
128+
ptr = ptr->d.FUNC_TYPE.ret;
129+
break;
130+
case T_ORIG_TYPE:
131+
break;
132+
}
133+
}
134+
return ptr;
135+
}
136+
137+
113138
struct IdentifierInfo* init_identifier_info() {
114139
struct IdentifierInfo* res =
115140
(struct IdentifierInfo*)malloc(sizeof(struct IdentifierInfo));
@@ -151,9 +176,18 @@ char* identifier_type_str[6] = {
151176
// use yylineno to record the line number of the first registration
152177
extern int yylineno;
153178

154-
void register_identifier(char* name, enum IdentifierType type) {
155-
pdebug("Line %d:\n", yylineno);
156-
pdebug("Registering identifier %s as %s\n", name, identifier_type_str[type]);
179+
// lineno: use -1 to fallback to yylineno.
180+
void register_identifier_in_table(char* name, enum IdentifierType type, struct SLL_hash_table *table, int lineno, char *description) {
181+
if (lineno == -1){
182+
lineno = yylineno;
183+
}
184+
if (description == NULL){
185+
// fallback to the default description
186+
description = identifier_type_str[type];
187+
}
188+
189+
pdebug("Line %d:\n", lineno);
190+
pdebug("Registering identifier %s as %s\n", name, description);
157191

158192
if (name==NULL){
159193
pdebug("Identifier name is NULL (Anonymous), skip registering\n");
@@ -162,11 +196,11 @@ void register_identifier(char* name, enum IdentifierType type) {
162196

163197
struct IdentifierInfo *info = NULL;
164198

165-
info = (struct IdentifierInfo*)SLL_hash_get(identifier_table, name);
199+
info = (struct IdentifierInfo*)SLL_hash_get(table, name);
166200
if ((long long)info == NONE) {
167201
pdebug("Identifier %s is not in the hashtable\n", name);
168202
info = init_identifier_info();
169-
SLL_hash_set(identifier_table, name, (long long)info);
203+
SLL_hash_set(table, name, (long long)info);
170204
}
171205
else{
172206
pdebug("Identifier %s is in the hashtable\n", name);
@@ -182,18 +216,22 @@ void register_identifier(char* name, enum IdentifierType type) {
182216
}
183217
if (info->flags & (1 << i)) {
184218
// identifier is already registered as a conflicting type.
185-
printf("Warning: (Line %d) Identifier %s is already registered as %s at line %d\n", yylineno, name, identifier_type_str[i], info->lineno[i]);
219+
printf("Warning: (Line %d) Identifier %s is already registered as %s at line %d\n", lineno, name, description, info->lineno[i]);
186220
conflict = 1;
187221
}
188222
}
189223

190224
if (!conflict) {
191225
pdebug("No conflict. Now register %s as %s\n", name, identifier_type_str[type]);
192226
info->flags |= (1 << type);
193-
info->lineno[type] = yylineno; // the line number of the first registration
227+
info->lineno[type] = lineno; // the line number of the first registration
194228
}
195229
}
196230

231+
void register_identifier(char* name, enum IdentifierType type) {
232+
register_identifier_in_table(name, type, identifier_table, -1, NULL);
233+
}
234+
197235
void register_identifier_variable(char* name) {
198236
register_identifier(name, IDENT_TYPE_VARIABLE);
199237
}
@@ -218,10 +256,10 @@ void register_identifier_typedef(char* name) {
218256
register_identifier(name, IDENT_TYPE_TYPEDEF);
219257
}
220258

221-
void check_identifier(char *name, enum IdentifierType using_type){
259+
void check_identifier_in_table(char* name, enum IdentifierType using_type, struct SLL_hash_table *table){
222260
pdebug("Line %d:\n", yylineno);
223261
struct IdentifierInfo *info = NULL;
224-
info = (struct IdentifierInfo*)SLL_hash_get(identifier_table, name);
262+
info = (struct IdentifierInfo*)SLL_hash_get(table, name);
225263
if ((long long)info == NONE) {
226264
printf("Warning: (Line %d) Identifier %s has never been registered\n", yylineno, name);
227265
return;
@@ -241,6 +279,10 @@ void check_identifier(char *name, enum IdentifierType using_type){
241279
}
242280
}
243281

282+
void check_identifier(char *name, enum IdentifierType using_type){
283+
check_identifier_in_table(name, using_type, identifier_table);
284+
}
285+
244286
void check_identifier_enum(char *name){
245287
check_identifier(name, IDENT_TYPE_ENUM);
246288
}
@@ -257,3 +299,20 @@ void check_identifier_typedef(char *name){
257299
check_identifier(name, IDENT_TYPE_TYPEDEF);
258300
}
259301

302+
void check_field_list(struct type_list *field_list){
303+
// build a new hash table for the field list
304+
struct SLL_hash_table *field_table = init_SLL_hash();
305+
while (field_list != NULL){
306+
struct left_type *t = field_list->t;
307+
struct var_decl_expr *e = field_list->e;
308+
struct var_decl_expr *core_type = get_core_type(e);
309+
register_identifier_in_table(
310+
core_type->d.ORIG_TYPE.name,
311+
IDENT_TYPE_VARIABLE,
312+
field_table,
313+
core_type->d.ORIG_TYPE.lineno,
314+
"field variable"
315+
);
316+
field_list = field_list->next;
317+
}
318+
}

src/lib.h

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,25 @@
11
#ifndef LIB_H_INCLUDED
22
#define LIB_H_INCLUDED
33

4+
#include "lang.h"
5+
46
#define NONE 4294967295
57

6-
#define VERBOSE 1
8+
// global variable to indicate logging level
79

8-
#ifdef VERBOSE
9-
#define pdebug(fmt, ...) printf("[DEBUG] " fmt, ##__VA_ARGS__)
10-
#else
11-
#define pdebug(fmt, ...)
12-
#endif
10+
#define LOG_LEVEL_ERROR 0
11+
#define LOG_LEVEL_VERBOSE 5
12+
13+
14+
extern int log_level;
15+
16+
#define pdebug(fmt, ...) \
17+
do { \
18+
if (log_level >= LOG_LEVEL_VERBOSE) \
19+
printf("[DEBUG] " fmt, ##__VA_ARGS__); \
20+
} while (0)
21+
22+
extern int yylineno;
1323

1424
// clang-format off
1525
unsigned int build_nat(char * c, int len);
@@ -21,6 +31,11 @@ void SLL_hash_set(struct SLL_hash_table * t, char * key, long long value);
2131
void SLL_hash_delete(struct SLL_hash_table * t, char * key);
2232
// clang-format on
2333

34+
// helper functions
35+
36+
// return the innermost core type. gaurenteed that ret->t == T_ORIG_TYPE.
37+
struct var_decl_expr *get_core_type(struct var_decl_expr *ptr);
38+
2439

2540
enum IdentifierType {
2641
IDENT_TYPE_VARIABLE = 0,
@@ -50,6 +65,7 @@ struct IdentifierInfo {
5065

5166
struct IdentifierInfo *init_identifier_info();
5267

68+
void register_identifier_in_table(char* name, enum IdentifierType type, struct SLL_hash_table *table, int lineno, char *description);
5369
void register_identifier(char *name, enum IdentifierType type);
5470

5571
void register_identifier_variable(char *name);
@@ -60,10 +76,15 @@ void register_identifier_enum(char *name);
6076
void register_identifier_typedef(char *name);
6177

6278
// check if the identifier is already declared when using it
79+
void check_identifier_in_table(char* name, enum IdentifierType type, struct SLL_hash_table *table);
6380
void check_identifier(char *name, enum IdentifierType using_type);
81+
6482
void check_identifier_enum(char *name);
6583
void check_identifier_struct(char *name);
6684
void check_identifier_union(char *name);
6785
void check_identifier_typedef(char *name);
6886

87+
// check if identifiers overlap within a field list
88+
void check_field_list(struct type_list *field_list);
89+
6990
#endif

src/main.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "astprint.h"
55
#include "lib.h"
66
#include <stdio.h>
7+
#include <stdlib.h>
78

89
// use the new printer
910
// #define ASTPRINT
@@ -24,6 +25,12 @@ int main(int argc, char** argv) {
2425
return 0;
2526
}
2627

28+
// read "PARSER_VERBOSE" environment variable
29+
char *log_level_str = getenv("PARSER_VERBOSE");
30+
if (log_level_str != NULL) {
31+
log_level = LOG_LEVEL_VERBOSE;
32+
}
33+
2734
// initialize the identifier table
2835
identifier_table = init_SLL_hash();
2936

0 commit comments

Comments
 (0)