Skip to content

Commit 4da0b6e

Browse files
authored
Merge pull request #308 from DrXiao/fix-forward-decl
Enhance function parsing
2 parents 9062977 + c0d33ed commit 4da0b6e

File tree

2 files changed

+225
-2
lines changed

2 files changed

+225
-2
lines changed

src/parser.c

Lines changed: 108 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1287,6 +1287,12 @@ void read_inner_var_decl(var_t *vd, bool anon, bool is_param)
12871287
{
12881288
/* Preserve typedef pointer level - don't reset if already inherited */
12891289
vd->init_val = 0;
1290+
if (is_param) {
1291+
/* However, if the parsed variable is a function parameter,
1292+
* reset its pointer level to zero.
1293+
*/
1294+
vd->ptr_level = 0;
1295+
}
12901296

12911297
while (lex_accept(T_asterisk)) {
12921298
vd->ptr_level++;
@@ -4917,6 +4923,49 @@ void read_func_body(func_t *func)
49174923
label_idx = 0;
49184924
}
49194925

4926+
void print_ptr_level(int level)
4927+
{
4928+
while (level > 0) {
4929+
printf("*");
4930+
level--;
4931+
}
4932+
}
4933+
4934+
void print_func_decl(func_t *func, const char *prefix, bool newline)
4935+
{
4936+
if (prefix)
4937+
printf("%s", prefix);
4938+
4939+
if (func->return_def.is_const_qualified)
4940+
printf("const ");
4941+
printf("%s ", func->return_def.type->type_name);
4942+
print_ptr_level(func->return_def.ptr_level -
4943+
func->return_def.type->ptr_level);
4944+
printf("%s(", func->return_def.var_name);
4945+
4946+
for (int i = 0; i < func->num_params; i++) {
4947+
var_t *var = &func->param_defs[i];
4948+
4949+
if (var->is_const_qualified)
4950+
printf("const ");
4951+
printf("%s ", var->type->type_name);
4952+
4953+
print_ptr_level(var->ptr_level - var->type->ptr_level);
4954+
4955+
printf("%s", var->var_name);
4956+
4957+
if (i != func->num_params - 1)
4958+
printf(", ");
4959+
}
4960+
4961+
if (func->va_args)
4962+
printf(", ...");
4963+
printf(")");
4964+
4965+
if (newline)
4966+
printf("\n");
4967+
}
4968+
49204969
/* if first token is type */
49214970
void read_global_decl(block_t *block, bool is_const)
49224971
{
@@ -4929,12 +4978,69 @@ void read_global_decl(block_t *block, bool is_const)
49294978

49304979
if (lex_peek(T_open_bracket, NULL)) {
49314980
/* function */
4932-
func_t *func = add_func(var->var_name, false);
4981+
func_t *func = find_func(var->var_name);
4982+
func_t func_tmp;
4983+
bool check_decl = false;
4984+
4985+
if (func) {
4986+
memcpy(&func_tmp, func, sizeof(func_t));
4987+
check_decl = true;
4988+
} else
4989+
func = add_func(var->var_name, false);
4990+
49334991
memcpy(&func->return_def, var, sizeof(var_t));
49344992
block->locals.size--;
4935-
49364993
read_parameter_list_decl(func, 0);
49374994

4995+
if (check_decl) {
4996+
/* Validate whether the previous declaration and the current
4997+
* one differ.
4998+
*/
4999+
if ((func->return_def.type != func_tmp.return_def.type) ||
5000+
(func->return_def.ptr_level != func_tmp.return_def.ptr_level) ||
5001+
(func->return_def.is_const_qualified !=
5002+
func_tmp.return_def.is_const_qualified)) {
5003+
printf("Error: conflicting types for the function %s.\n",
5004+
func->return_def.var_name);
5005+
print_func_decl(&func_tmp, "before: ", true);
5006+
print_func_decl(func, "after: ", true);
5007+
abort();
5008+
}
5009+
5010+
if (func->num_params != func_tmp.num_params) {
5011+
printf(
5012+
"Error: confilcting number of arguments for the function "
5013+
"%s.\n",
5014+
func->return_def.var_name);
5015+
print_func_decl(&func_tmp, "before: ", true);
5016+
print_func_decl(func, "after: ", true);
5017+
abort();
5018+
}
5019+
5020+
for (int i = 0; i < func->num_params; i++) {
5021+
var_t *func_var = &func->param_defs[i];
5022+
var_t *func_tmp_var = &func_tmp.param_defs[i];
5023+
if ((func_var->type != func_tmp_var->type) ||
5024+
(func_var->ptr_level != func_tmp_var->ptr_level) ||
5025+
(func_var->is_const_qualified !=
5026+
func_tmp_var->is_const_qualified)) {
5027+
printf("Error: confilcting types for the function %s.\n",
5028+
func->return_def.var_name);
5029+
print_func_decl(&func_tmp, "before: ", true);
5030+
print_func_decl(func, "after: ", true);
5031+
abort();
5032+
}
5033+
}
5034+
5035+
if (func->va_args != func_tmp.va_args) {
5036+
printf("Error: conflicting types for the function %s.\n",
5037+
func->return_def.var_name);
5038+
print_func_decl(&func_tmp, "before: ", true);
5039+
print_func_decl(func, "after: ", true);
5040+
abort();
5041+
}
5042+
}
5043+
49385044
if (lex_peek(T_open_curly, NULL)) {
49395045
read_func_body(func);
49405046
return;

tests/driver.sh

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5690,6 +5690,123 @@ int main() {
56905690
}
56915691
EOF
56925692

5693+
begin_category "Function parsing" "Forward declaration and implementation"
5694+
5695+
# Normal case
5696+
try_output 0 "Hello" << EOF
5697+
void func(char *ptr);
5698+
5699+
void func(char *ptr)
5700+
{
5701+
while (*ptr) {
5702+
printf("%c", *ptr);
5703+
ptr++;
5704+
}
5705+
}
5706+
5707+
int main()
5708+
{
5709+
func("Hello");
5710+
return 0;
5711+
}
5712+
EOF
5713+
5714+
# Incorrect function returning type
5715+
try_compile_error << EOF
5716+
void func(void);
5717+
5718+
int **func(void)
5719+
{
5720+
return 3;
5721+
}
5722+
5723+
int main()
5724+
{
5725+
func();
5726+
return 0;
5727+
}
5728+
EOF
5729+
5730+
# Incorrect number of parameters
5731+
try_compile_error << EOF
5732+
void func(void *a);
5733+
5734+
void func(void *a, int x)
5735+
{
5736+
return 3;
5737+
}
5738+
5739+
int main()
5740+
{
5741+
func();
5742+
return 0;
5743+
}
5744+
EOF
5745+
5746+
# Conflicting parameter types
5747+
try_compile_error << EOF
5748+
void func(void *a, char x);
5749+
5750+
void func(void *a, int x)
5751+
{
5752+
return 3;
5753+
}
5754+
5755+
int main()
5756+
{
5757+
func();
5758+
return 0;
5759+
}
5760+
EOF
5761+
5762+
# Conflicting parameter types (variadic parameters)
5763+
try_compile_error << EOF
5764+
void func(void *a);
5765+
5766+
void func(void *a, ...)
5767+
{
5768+
return 3;
5769+
}
5770+
5771+
int main()
5772+
{
5773+
func();
5774+
return 0;
5775+
}
5776+
EOF
5777+
5778+
# Incorrect function returning type (const)
5779+
try_compile_error << EOF
5780+
void *func(int *a, char x);
5781+
5782+
const void *func(int *a, char x)
5783+
{
5784+
return 3;
5785+
}
5786+
5787+
int main()
5788+
{
5789+
func();
5790+
return 0;
5791+
}
5792+
EOF
5793+
5794+
# Conflicting parameter types (const)
5795+
try_compile_error << EOF
5796+
void func(int *a, char x);
5797+
5798+
void func(const int *a, char x)
5799+
{
5800+
return 3;
5801+
}
5802+
5803+
int main()
5804+
{
5805+
func();
5806+
return 0;
5807+
}
5808+
EOF
5809+
56935810
# Test Results Summary
56945811

56955812
echo ""

0 commit comments

Comments
 (0)