forked from DoctorWkt/acwj
-
Notifications
You must be signed in to change notification settings - Fork 0
/
types.c
120 lines (107 loc) · 2.88 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
109
110
111
112
113
114
115
116
117
118
119
120
#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) {
if (type == P_CHAR || type == P_INT || type == P_LONG)
return (1);
return (0);
}
// Return true if a type is of pointer type
int ptrtype(int type) {
if (type == P_VOIDPTR || type == P_CHARPTR ||
type == P_INTPTR || type == P_LONGPTR)
return (1);
return (0);
}
// Given a primitive type, return
// the type which is a pointer to it
int pointer_to(int type) {
int newtype;
switch (type) {
case P_VOID:
newtype = P_VOIDPTR;
break;
case P_CHAR:
newtype = P_CHARPTR;
break;
case P_INT:
newtype = P_INTPTR;
break;
case P_LONG:
newtype = P_LONGPTR;
break;
default:
fatald("Unrecognised in pointer_to: type", type);
}
return (newtype);
}
// Given a primitive pointer type, return
// the type which it points to
int value_at(int type) {
int newtype;
switch (type) {
case P_VOIDPTR:
newtype = P_VOID;
break;
case P_CHARPTR:
newtype = P_CHAR;
break;
case P_INTPTR:
newtype = P_INT;
break;
case P_LONGPTR:
newtype = P_LONG;
break;
default:
fatald("Unrecognised in value_at: type", type);
}
return (newtype);
}
// 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;
// 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 = genprimsize(ltype);
rsize = genprimsize(rtype);
// Tree's size is too big
if (lsize > rsize)
return (NULL);
// Widen to the right
if (rsize > lsize)
return (mkastunary(A_WIDEN, rtype, tree, 0));
}
// For pointers on the left
if (ptrtype(ltype)) {
// OK is same type on right and not doing a binary op
if (op == 0 && ltype == rtype)
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, rsize));
}
}
// If we get here, the types are not compatible
return (NULL);
}