aboutsummaryrefslogtreecommitdiff
path: root/src/sema/sema.c
blob: f86159c71562a6a27b9a6a5a619115aa1b75908a (plain)
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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "sema/sema.h"

static bool names_equal(struct Token a, struct Token b)
{
	return a.length == b.length && memcmp(a.start, b.start, a.length) == 0;
}

static bool check_duplicate_names(struct Source source, struct Program* program)
{
	size_t count = program->const_count + program->data_count + program->proc_count;
	if (count == 0)
		return true;

	struct Token* names = malloc(count * sizeof(struct Token));
	size_t n = 0;
	for (size_t i = 0; i < program->const_count; i += 1)
	{
		names[n] = program->consts[i].name;
		n += 1;
	}
	for (size_t i = 0; i < program->data_count; i += 1)
	{
		names[n] = program->data_decls[i].name;
		n += 1;
	}
	for (size_t i = 0; i < program->proc_count; i += 1)
	{
		names[n] = program->procs[i].name;
		n += 1;
	}

	bool ok = true;
	for (size_t i = 0; i < count; i += 1)
		for (size_t j = 0; j < i; j += 1)
			if (names_equal(names[i], names[j]))
			{
				char message[128];
				snprintf(message, sizeof(message), "'%.*s' is already defined",
					(int)names[i].length, names[i].start);
				report_error(source, names[i], message);
				ok = false;
			}

	free(names);
	return ok;
}

static bool check_entry_point(struct Source source, struct Program* program)
{
	if (!program->config.has_entry)
		return true;

	struct Token entry = program->config.entry;
	for (size_t i = 0; i < program->proc_count; i += 1)
		if (names_equal(program->procs[i].name, entry))
			return true;

	char message[128];
	snprintf(message, sizeof(message), "entry point '%.*s' is not defined",
		(int)entry.length, entry.start);
	report_error(source, entry, message);
	return false;
}

bool analyze_program(struct Source source, struct Program* program)
{
	bool ok = true;

	if (!check_duplicate_names(source, program))
		ok = false;
	if (!check_entry_point(source, program))
		ok = false;

	return ok;
}