forked from DoctorWkt/acwj
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtypes.c
108 lines (90 loc) · 2.98 KB
/
types.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
#include "defs.h"
#include "data.h"
#include "decl.h"
// Types and type handling
// Copyright (c) 2019 Warren Toomey, GPL3
// Return true if a type is an int type
// of any size, false otherwise
int inttype(int type) {
return (((type & 0xf) == 0) && (type >= P_CHAR && type <= P_LONG));
}
// Return true if a type is of pointer type
int ptrtype(int type) {
return ((type & 0xf) != 0);
}
// Given a primitive type, return
// the type which is a pointer to it
int pointer_to(int type) {
if ((type & 0xf) == 0xf)
fatald("Unrecognised in pointer_to: type", type);
return (type + 1);
}
// Given a primitive pointer type, return
// the type which it points to
int value_at(int type) {
if ((type & 0xf) == 0x0)
fatald("Unrecognised in value_at: type", type);
return (type - 1);
}
// Given a type and a composite type pointer, return
// the size of this type in bytes
int typesize(int type, struct symtable *ctype) {
if (type == P_STRUCT || type == P_UNION)
return (ctype->size);
return (genprimsize(type));
}
// Given an AST tree and a type which we want it to become,
// possibly modify the tree by widening or scaling so that
// it is compatible with this type. Return the original tree
// if no changes occurred, a modified tree, or NULL if the
// tree is not compatible with the given type.
// If this will be part of a binary operation, the AST op is not zero.
struct ASTnode *modify_type(struct ASTnode *tree, int rtype, int op) {
int ltype;
int lsize, rsize;
ltype = tree->type;
// XXX No idea on these yet
if (ltype == P_STRUCT || ltype == P_UNION)
fatal("Don't know how to do this yet");
if (rtype == P_STRUCT || rtype == P_UNION)
fatal("Don't know how to do this yet");
// Compare scalar int types
if (inttype(ltype) && inttype(rtype)) {
// Both types same, nothing to do
if (ltype == rtype)
return (tree);
// Get the sizes for each type
lsize = typesize(ltype, NULL);
rsize = typesize(rtype, NULL);
// Tree's size is too big
if (lsize > rsize)
return (NULL);
// Widen to the right
if (rsize > lsize)
return (mkastunary(A_WIDEN, rtype, tree, NULL, 0));
}
// For pointers
if (ptrtype(ltype) && ptrtype(rtype)) {
// We can compare them
if (op >= A_EQ && op <= A_GE)
return(tree);
// A comparison of the same type for a non-binary operation is OK,
// or when the left tree is of `void *` type.
if (op == 0 && (ltype == rtype || ltype == pointer_to(P_VOID)))
return (tree);
}
// We can scale only on A_ADD or A_SUBTRACT operation
if (op == A_ADD || op == A_SUBTRACT) {
// Left is int type, right is pointer type and the size
// of the original type is >1: scale the left
if (inttype(ltype) && ptrtype(rtype)) {
rsize = genprimsize(value_at(rtype));
if (rsize > 1)
return (mkastunary(A_SCALE, rtype, tree, NULL, rsize));
else
return (tree); // Size 1, no need to scale
}
}
// If we get here, the types are not compatible
return (NULL);
}