Pristine Ack-5.5
[Ack-5.5.git] / util / ego / share / parser.c
1 /* $Id: parser.c,v 1.7 1994/06/24 10:30:38 ceriel Exp $ */
2 /*
3  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
4  * See the copyright notice in the ACK home directory, in the file "Copyright".
5  */
6
7 #include <stdio.h>
8 #include <em_spec.h>
9 #include <em_mnem.h>
10 #include "types.h"
11 #include "debug.h"
12 #include "alloc.h"
13 #include "global.h"
14 #include "lset.h"
15 #include "aux.h"
16
17 struct class {
18         byte    src_class;
19         byte    res_class;
20 };
21
22 typedef struct class *class_p;
23
24
25 #define NOCLASS 0
26 #define CLASS1  1
27 #define CLASS2  2
28 #define CLASS3  3
29 #define CLASS4  4
30 #define CLASS5  5
31 #define CLASS6  6
32 #define CLASS7  7
33 #define CLASS8  8
34 #define CLASS9  9
35 #define CLASS10 10
36 #define CLASS11 11
37 #define CLASS12 12
38
39 #include "classdefs.h"
40 /* The file classdefs.h contains the table classtab. It is
41  * generated automatically from the file classdefs.src.
42  */
43
44 STATIC bool classes(instr,src_out,res_out)
45         int instr;
46         int *src_out, *res_out;
47 {
48         /* Determine the classes of the given instruction */
49
50         class_p c;
51
52         if (instr < sp_fmnem || instr > sp_lmnem) return FALSE;
53         c = &classtab[instr];
54         if (c->src_class == NOCLASS) return FALSE;
55         *src_out = c->src_class;
56         *res_out = c->res_class;
57         return TRUE;
58 }
59
60
61
62 STATIC bool uses_arg(class)
63         int class;
64 {
65         /* See if a member of the given class uses
66          * an argument.
67          */
68
69         switch(class) {
70                 case CLASS1:
71                 case CLASS2:
72                 case CLASS3:
73                 case CLASS4:
74                 case CLASS11:
75                 case CLASS12:
76                         return TRUE;
77                 default:
78                         return FALSE;
79         }
80         /* NOTREACHED */
81 }
82
83
84
85 STATIC bool uses_2args(class)
86         int class;
87 {
88         /* See if a member of the given class uses
89          * 2 arguments.
90          */
91
92         return class == CLASS10;
93 }
94
95
96 STATIC bool parse_locs(l,c1_out,c2_out)
97         line_p l;
98         offset *c1_out, *c2_out;
99 {
100         if (INSTR(l) == op_loc && INSTR(PREV(l)) == op_loc) {
101                 *c1_out = off_set(l);
102                 *c2_out = off_set(PREV(l));
103                 return TRUE;
104         }
105         return FALSE;
106 }
107
108
109
110 STATIC bool check_args(l,src_class,res_class,arg1_out,arg2_out)
111         line_p l;
112         int    src_class,res_class;
113         offset *arg1_out, *arg2_out;
114 {
115         /* Several EM instructions have an argument
116          * giving the size of the operand(s) of
117          * the instruction. E.g. a 'adi 4' is a 4-byte
118          * addition. The size may also be put on the
119          * stack. In this case we give up our
120          * efforts to recognize the parameter expression.
121          * Some instructions (e.g. CIU) use 2 arguments
122          * that are both on the stack. In this case we
123          * check if both arguments are LOCs (the usual case),
124          * else we give up.
125          */
126
127         if (uses_2args(src_class) || uses_2args(res_class)) {
128                 return parse_locs(PREV(l),arg1_out,arg2_out);
129         }
130         if (uses_arg(src_class) || uses_arg(res_class)) {
131                 if (TYPE(l) == OPSHORT) {
132                         *arg1_out = (offset) SHORT(l);
133                         return TRUE;
134                 } else {
135                         if (TYPE(l) == OPOFFSET) {
136                                 *arg1_out = OFFSET(l);
137                         } else {
138                                 return FALSE;
139                         }
140                 }
141         }
142         return TRUE; /* no argument needed */
143 }
144
145
146
147 STATIC offset nrbytes(class,arg1,arg2)
148         int class;
149         offset arg1,arg2;
150 {
151         /* Determine the number of bytes of the given
152          * arguments and class.
153          */
154
155         switch(class) {
156                 case CLASS1:
157                         return arg1;
158                 case CLASS2:
159                         return 2 * arg1;
160                 case CLASS3:
161                         return arg1 + ws;
162                 case CLASS4:
163                         return arg1 + ps;
164                 case CLASS5:
165                         return ws;
166                 case CLASS6:
167                         return 2 * ws;
168                 case CLASS7:
169                         return ps;
170                 case CLASS8:
171                         return 2 * ps;
172                 case CLASS9:
173                         return 0;
174                 case CLASS10:
175                         return arg2 + 2*ws;
176                 case CLASS11:
177                         return arg1 + 2*ps;
178                 case CLASS12:
179                         return (arg1 < ws ? ws : arg1);
180                 default:
181                         assert(FALSE);
182         }
183         return 0;
184 }
185
186
187
188 STATIC attrib(l,expect_out,srcb_out,resb_out)
189         line_p l;
190         offset    *expect_out, *srcb_out, *resb_out;
191 {
192         /* Determine a number of attributes of an EM
193          * instruction appearing in an expression.
194          * If it is something we don't
195          * expect in such expression (e.g. a store)
196          * expect_out is set to FALSE. Else we
197          * determine the number of bytes popped from
198          * the stack by the instruction and the
199          * number of bytes pushed on the stack as
200          * result.
201          */
202
203         int src_class,res_class;
204         offset arg1, arg2;
205
206         if (l == (line_p) 0 || !classes(INSTR(l),&src_class,&res_class) ||
207             !check_args(l,src_class,res_class,&arg1,&arg2)) {
208                 *expect_out = FALSE;
209         } else {
210                 *expect_out = TRUE;
211                 *srcb_out = nrbytes(src_class,arg1,arg2);
212                 *resb_out = nrbytes(res_class,arg1,arg2);
213         }
214 }
215
216
217
218 bool parse(l,nbytes,l_out,level,action0)
219         line_p l, *l_out;
220         offset nbytes;
221         int    level;
222         int    (*action0) ();
223 {
224         /* This is a recursive descent parser for
225          * EM expressions.
226          * It tries to recognize EM code that loads exactly
227          * 'nbytes' bytes on the stack.
228          * 'l' is the last instruction of this code.
229          * As EM is essentially postfix, this instruction
230          * can be regarded as the root node of an expression
231          * tree. The EM code is traversed from right to left,
232          * i.e. top down. On success, TRUE is returned and
233          * 'l_out' will point to the first instruction
234          * of the recognized code. On toplevel, when an
235          * expression has been recognized, the procedure-parameter
236          * 'action0' is called, with parameters: the first and
237          * last instruction of the expression and the number of
238          * bytes recognized.
239          */
240
241         offset more, expected, sourcebytes,resultbytes;
242         line_p lnp = 0;
243
244         more = nbytes; /* #bytes to be recognized */
245         while (more > 0) {
246                 attrib(l,&expected,&sourcebytes,&resultbytes);
247                 /* Get the attributes of EM instruction 'l'.
248                  * 'expected' denotes if it is something we can use;
249                  * 'sourcebytes' and 'resultbytes' are the number of
250                  * bytes popped resp. pushed by the instruction
251                  * (e.g. 'adi 2' pops 4 bytes and pushes 2 bytes).
252                  */
253                 if (!expected || (more -= resultbytes) < 0) return FALSE;
254                 if (sourcebytes == 0) {
255                         /* a leaf of the expression tree */
256                         lnp = l;
257                 } else {
258                         if (!parse(PREV(l),sourcebytes,&lnp,level+1,action0)) {
259                                 return FALSE;
260                         }
261                 }
262                 if (level == 0) {
263                         /* at toplevel */
264                         (*action0) (lnp,l,resultbytes);
265                 }
266                 l = PREV(lnp);
267         }
268         /* Now we've recognized a number of expressions that
269          * together push nbytes on the stack.
270          */
271         *l_out = lnp;
272         return TRUE;
273 }