-
Notifications
You must be signed in to change notification settings - Fork 1
/
removeNestedDecls.c
185 lines (174 loc) · 5.16 KB
/
removeNestedDecls.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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "data.h"
#define HANDLE_CHILDREN(tag, field) (pushed = append_node(pushed, handleChildren(node->node.tag.field, toplevel)))
#define REPLACE_SUBTREE(tag, subtree, toplevel) (tree->node.tag.subtree = handleList(tree->node.tag.subtree, toplevel))
static AstNode *handleNode(AstNode *, int, int);
static AstNode *handleList(AstNode *, int);
static AstNode *handleChildren(AstNode *, int);
/* This function changes replaces blocks with fixed blocks. Should include a case for each node that defines a new scope/block */
void removeNestedDecls(AstNode *tree){
switch(tree->tag){
case Prog:
REPLACE_SUBTREE(Prog, toplevels, 1);
break;
case DefineFunction:
REPLACE_SUBTREE(DefineFunction, statements, 0);
break;
case DefineTask:
REPLACE_SUBTREE(DefineTask, statements, 0);
break;
case While:
REPLACE_SUBTREE(While, statements, 0);
break;
case SwitchCase:
REPLACE_SUBTREE(SwitchCase, statements, 0);
break;
case If:
REPLACE_SUBTREE(If, statements, 0);
REPLACE_SUBTREE(If, elsePart, 0);
break;
case ElseIf:
REPLACE_SUBTREE(ElseIf, statements, 0);
REPLACE_SUBTREE(ElseIf, elsePart, 0);
break;
case Else:
REPLACE_SUBTREE(Else, statements, 0);
break;
case ReceiveCase:
REPLACE_SUBTREE(ReceiveCase, statements, 0);
break;
}
}
/* This function loops over each child in the children list, and if it is
a variable declaration, it creates a new declaration and changes the old
to a variableLocation. Returns the newly created declaration if any.
It also calls handleNode on each of the children in the list, to
traverse the whole tree. */
static AstNode *handleChildren(AstNode *children, int toplevel){
AstNode *tmp;
AstNode *pushed = NULL;
AstNode *tmpres = NULL;
for(tmp = children; tmp != NULL; tmp = tmp->next){
tmpres = handleNode(tmp, toplevel, 0);
if(tmp->tag == VarDecl){
AstNode *res = malloc(sizeof(AstNode));
memcpy(res, tmp, sizeof(AstNode));
res->next = NULL;
res->node.VarDecl.type = malloc(sizeof(AstNode));
memcpy(res->node.VarDecl.type, tmp->node.VarDecl.type, sizeof(AstNode));
res->node.VarDecl.identifier = malloc(sizeof(AstNode));
memcpy(res->node.VarDecl.identifier, tmp->node.VarDecl.identifier, sizeof(AstNode));
if(res->node.VarDecl.expression){
res->node.VarDecl.expression = malloc(sizeof(AstNode));
memcpy(res->node.VarDecl.expression, tmp->node.VarDecl.expression, sizeof(AstNode));
}
res->node.VarDecl.toplevel = toplevel;
tmp->tag = VariableLocation;
tmp->node.VariableLocation.identifier = tmp->node.VarDecl.identifier;
pushed = append_node(pushed, res);
}
pushed = append_node(tmpres, pushed);
}
return pushed;
}
/* This function returns runs handleChildren on sub parts of the node itself, which may have issues. Returns the pushed out code,
and modifies the tree in-place. */
static AstNode *handleNode(AstNode *node, int toplevel, int wrap){
AstNode *pushed = NULL;
switch(node->tag){
case Prog:
HANDLE_CHILDREN(Prog, toplevels);
break;
case While:
HANDLE_CHILDREN(While, expression);
break;
case For:
HANDLE_CHILDREN(For, expressionInit);
HANDLE_CHILDREN(For, expressionTest);
HANDLE_CHILDREN(For, expressionUpdate);
break;
case Switch:
HANDLE_CHILDREN(Switch, expression);
break;
case If:
HANDLE_CHILDREN(If, expression);
break;
case VarDecl:
HANDLE_CHILDREN(VarDecl, expression);
break;
case BinaryOperation:
HANDLE_CHILDREN(BinaryOperation, expression_left);
HANDLE_CHILDREN(BinaryOperation, expression_right);
break;
case UnaryOperation:
HANDLE_CHILDREN(UnaryOperation, expression);
break;
case ArrayLocation:
HANDLE_CHILDREN(ArrayLocation, indicies);
break;
case FunctionCall:
HANDLE_CHILDREN(FunctionCall, arguments);
break;
case Assignment:
HANDLE_CHILDREN(Assignment, expression);
break;
case TernaryOperator:
HANDLE_CHILDREN(TernaryOperator, expressionTest);
HANDLE_CHILDREN(TernaryOperator, expressionTrue);
HANDLE_CHILDREN(TernaryOperator, expressionFalse);
break;
case MessageLiteral:
HANDLE_CHILDREN(MessageLiteral, arguments);
break;
case Return:
HANDLE_CHILDREN(Return, expression);
break;
case Spawn:
HANDLE_CHILDREN(Spawn, arguments);
break;
case Send:
HANDLE_CHILDREN(Send, message);
HANDLE_CHILDREN(Send, receiver);
break;
case ExprStmt:
pushed = handleNode(node->node.ExprStmt.expression, toplevel, 0);
break;
}
/* Be sure any sub-blocks are fixed */
removeNestedDecls(node);
if(wrap){
AstNode *prev = NULL;
AstNode *tmp;
for(tmp = pushed; tmp != NULL; tmp = tmp->next){
AstNode *next = tmp->next;
tmp = mkExprStmtNode(tmp);
tmp->next = next;
if(prev)
prev->next = tmp;
else
pushed = tmp;
prev = tmp;
}
}
return pushed;
}
/* This function runs handleNode on each node in the list, and inserts the pushed out declarations if any. */
static AstNode *handleList(AstNode *list, int toplevel){
AstNode *result = NULL;
AstNode *tmp;
AstNode *n;
AstNode *pushed;
n = list;
while(n != NULL){
pushed = handleNode(n, toplevel, !toplevel);
tmp = n;
n = n->next;
tmp->next = NULL;
if(pushed)
result = append_node(result, pushed);
result = append_node(result, tmp);
}
return result;
}